• 三、I.MX6 SPI驱动(控制器驱动、设备驱动)


      1 I.MX6Q的SPI适配器驱动(3.0.35版本内核)
      2 文件路径:Kernel/linux_IMX6_CoreC_3.0.35_for_Linux/drivers/spi/spi_imx.c
      3 一、控制器驱动
      4 入口函数:spi_imx_init()
      5 static int __init spi_imx_init(void)
      6 {
      7     return platform_driver_register(&spi_imx_driver);//注册平台总线设备
      8 }
      9 
     10 static struct platform_driver spi_imx_driver = {
     11     .driver = {
     12            .name = DRIVER_NAME,
     13            .owner = THIS_MODULE,
     14            },
     15     .id_table = spi_imx_devtype,//传统的设备id匹配表通过名字来匹配
     16     .probe = spi_imx_probe,
     17     .remove = __devexit_p(spi_imx_remove),
     18 };
     19 
     20 //官方的SPI控制器驱动和控制器匹配表
     21 static struct platform_device_id spi_imx_devtype[] = {
     22     {
     23         .name = "imx1-cspi",
     24         .driver_data = SPI_IMX_VER_IMX1,
     25     },
     26     {
     27         .name = "imx6q-ecspi",
     28         .driver_data = SPI_IMX_VER_2_3,
     29     },
     30     {
     31         /* sentinel */
     32     }
     33 };
     34 
     35 //控制器驱动和匹配之后调用这个函数对SPI进行初始化
     36 static int __devinit spi_imx_probe(struct platform_device *pdev)
     37 {
     38     ...
     39     mxc_platform_info = dev_get_platdata(&pdev->dev);//获取设备信息
     40     ...
     41     master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));//申请一个sip控制器
     42     ...
     43     platform_set_drvdata(pdev, master);//设置控制器数据
     44     ...
     45     spi_imx->chipselect = mxc_platform_info->chipselect;//获取片选
     46     ...
     47     //通过一个循环来依次申请片选引脚
     48     for (i = 0; i < master->num_chipselect; i++)
     49     {
     50         if (spi_imx->chipselect[i] < 0)
     51             continue;
     52         ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
     53         if (ret) {
     54             while (i > 0) {
     55                 i--;
     56                 if (spi_imx->chipselect[i] >= 0)
     57                     gpio_free(spi_imx->chipselect[i]);
     58             }
     59             dev_err(&pdev->dev, "can't get cs gpios
    ");
     60             goto out_master_put;
     61         }
     62     }
     63     //SPI控制器设置(设置片选、传输函数等)
     64     spi_imx->bitbang.chipselect = spi_imx_chipselect;
     65     spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;//使用 spi_imx_setupxfer 函数来设置 spi_imx 的 tx 和 rx 函数
     66         static int spi_imx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
     67         {
     68             ...
     69             /* Initialize the functions for transfer */
     70             //不同的数据宽度赋值不同的发送和接收函数
     71             if (config.bpw <= 8)
     72             {
     73                 spi_imx->rx = spi_imx_buf_rx_u8;//这些函数在文件开头的宏定义可以展开得到
     74                 spi_imx->tx = spi_imx_buf_tx_u8;
     75                     //spi_imx_buf_tx_u8 函数是通过 MXC_SPI_BUF_TX 宏来实现
     76                     //的。将要发送的数据值写入到 ECSPI 的 TXDATA 寄存器里面去,
     77                     //将 MXC_SPI_BUF_TX(u8)展开就是 spi_imx_buf_tx_u8 函数
     78                     MXC_SPI_BUF_RX(u8)//由下面的宏展开得到
     79                         #define MXC_SPI_BUF_RX(type)                                        
     80                         static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)        
     81                         {                                                                    
     82                             unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);        
     83                                                                                             
     84                             if (spi_imx->rx_buf)            
     85                             {                                            
     86                                 *(type *)spi_imx->rx_buf = val;                                
     87                                 spi_imx->rx_buf += sizeof(type);                            
     88                             }                                                                
     89                         }
     90                     MXC_SPI_BUF_TX(u8)
     91                         #define MXC_SPI_BUF_TX(type)                        
     92                         static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx)        
     93                         {                                    
     94                             type val = 0;                            
     95                                     
     96                             if (spi_imx->tx_buf)    
     97                             {                        
     98                                 val = *(type *)spi_imx->tx_buf;                
     99                                 spi_imx->tx_buf += sizeof(type);            
    100                             }                                
    101                                     
    102                             spi_imx->count -= sizeof(type);                    
    103                                     
    104                             writel(val, spi_imx->base + MXC_CSPITXDATA);            
    105                         }
    106             } 
    107             else if (config.bpw <= 16)
    108             {
    109                 spi_imx->rx = spi_imx_buf_rx_u16;//MXC_SPI_BUF_RX(u16)
    110                 spi_imx->tx = spi_imx_buf_tx_u16;//MXC_SPI_BUF_TX(u16)
    111             } 
    112             else if (config.bpw <= 32)
    113             {
    114                 spi_imx->rx = spi_imx_buf_rx_u32;//等价MXC_SPI_BUF_RX(u32)
    115                 spi_imx->tx = spi_imx_buf_tx_u32;//MXC_SPI_BUF_TX(u32)    
    116             }
    117             else
    118             {
    119                 BUG();    
    120             }
    121             spi_imx->devtype_data.config(spi_imx, &config);
    122             ...
    123         }
    124     spi_imx->bitbang.txrx_bufs = spi_imx_transfer;//SPI控制器数据传输函数,SPI就是通过这个和器件进行通信
    125         spi_imx->tx_buf = transfer->tx_buf;//发送缓冲去赋值
    126         spi_imx->rx_buf = transfer->rx_buf;//同理,赋值接收缓冲区
    127         spi_imx->count = transfer->len;
    128         spi_imx->txfifo = 0;
    129 
    130         init_completion(&spi_imx->xfer_done);//初始化工作队列(SPI维护一个工作队列来传送数据)
    131             init_waitqueue_head(&x->wait);
    132         spi_imx_push(spi_imx);//spi数据发送(真正的发送函数)
    133             while (spi_imx->txfifo < spi_imx->devtype_data.fifosize)
    134             {
    135                 if (!spi_imx->count)
    136                     break;
    137                 spi_imx->tx(spi_imx);//调用发送函数发送数据,前面spi_imx_setupxfer()函数中,有对spi_imx->tx赋值了
    138                 spi_imx->txfifo++;
    139             }
    140 
    141     spi_imx->bitbang.master->setup = spi_imx_setup;
    142     spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
    143     spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;//设置SPI控制器的模式
    144     ...
    145     //获取设备资源
    146     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    147     //申请内存
    148     if (!request_mem_region(res->start, resource_size(res), pdev->name)) 
    149     {
    150         dev_err(&pdev->dev, "request_mem_region failed
    ");
    151         ret = -EBUSY;
    152         goto out_gpio_free;
    153     }
    154     //虚拟地址映射
    155     spi_imx->base = ioremap(res->start, resource_size(res));
    156     if (!spi_imx->base) {
    157         ret = -EINVAL;
    158         goto out_release_mem;
    159     }
    160     //获取中断
    161     spi_imx->irq = platform_get_irq(pdev, 0);
    162     if (spi_imx->irq < 0) {
    163         ret = -EINVAL;
    164         goto out_iounmap;
    165     }
    166     //申请注册中断函数spi_imx_isr
    167     ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
    168     if (ret) {
    169         dev_err(&pdev->dev, "can't get irq%d: %d
    ", spi_imx->irq, ret);
    170         goto out_iounmap;
    171     }
    172     ...
    173     spi_imx->devtype_data.intctrl(spi_imx, 0);
    174     ret = spi_bitbang_start(&spi_imx->bitbang);//里面注册了spi控制器驱动
    175         INIT_WORK(&bitbang->work, bitbang_work);//初始化一个工作队列
    176         ...
    177         bitbang->workqueue = create_singlethread_workqueue(dev_name(bitbang->master->dev.parent));//创建一个工作队列
    178         ...
    179         status = spi_register_master(bitbang->master);//注册spi控制器驱动,对应的注销函数spi_unregister_master(bitbang->master);
    180 }
    181 
    182 //SPI控制器中断函数
    183 static irqreturn_t spi_imx_isr(int irq, void *dev_id)
    184 {
    185     ...
    186     if (spi_imx->count)
    187     {
    188         spi_imx_push(spi_imx);//发送
    189             spi_imx->tx(spi_imx);//调用发送函数发送数据spi_imx_setupxfer()函数中,有对spi_imx->tx赋值了
    190                 spi_imx->tx = spi_imx_buf_tx_u8;
    191                 spi_imx->tx = spi_imx_buf_tx_u16;
    192                 spi_imx->tx = spi_imx_buf_tx_u32;
    193     }    
    194         return IRQ_HANDLED;
    195     }
    196     ...
    197     if (spi_imx->txfifo) {
    198         /* No data left to push, but still waiting for rx data,
    199          * enable receive data available interrupt.
    200          */
    201         spi_imx->devtype_data.intctrl(
    202                 spi_imx, MXC_INT_RR);//接收数据中断使能
    203         return IRQ_HANDLED;
    204     }
    205     ...
    206     ...
    207     return IRQ_HANDLED;
    208 }
    209 
    210 
    211 二、SPI设备驱动
    212 初始化(板级文件指定设备信息)
  • 相关阅读:
    ceph服务日志分析
    ceph 守护进程管理
    ceph 数据一致性检查(scrub)
    ceph osd坏盘更换
    OSD操作(扩容/缩容/换盘/数据重平衡/数据一致性)
    SharePoint REST API 获取文件夹下的项目数
    SharePoint REST API 设置SummaryLength属性
    庄子逍遥哲学的六个主要思想
    详细解说,无人机构造及原理
    如何写好项目规划和方案设计文档
  • 原文地址:https://www.cnblogs.com/timemachine213/p/12839952.html
Copyright © 2020-2023  润新知