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 初始化(板级文件指定设备信息)