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\n"); 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\n"); 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\n", 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 初始化(板級文件指定設備信息)