三、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 初始化(板级文件指定设备信息)
原文地址:https://www.cnblogs.com/timemachine213/p/12839952.html