內核版本:3.9.5
SPI控制器層(平台相關)
上一節講了SPI核心層的注冊和匹配函數,它是平台無關的.正是在核心層抽象了SPI控制器層的相同部分然后提供了統一的API給SPI設備層來使用.我們這一節就能看到,一個SPI控制器以platform_device的形式注冊進內核,並且調用spi_register_board_info函數注冊了spi_board_info結構.我們前面說過,struct spi_board_info結構是對spi_device的描述,其中的內從最終是要用來初始化struct spi_device實例的.
哎!閑話少說了,越說越糊塗.我們以davinci的dm365平台為例,來看看SPI控制器的相關內容.在arch/arm/mach-davinci/board-dm365-evm.c中有:
1 static struct spi_board_info dm365_evm_spi_info[] __initconst = { 2 { 3 .modalias = "at25", 4 .platform_data = &at25640, 5 .max_speed_hz = 10 * 1000 * 1000, 6 .bus_num = 0, 7 .chip_select = 0, 8 .mode = SPI_MODE_0, 9 }, 10 }; 11 12 static __init void dm365_evm_init(void) 13 { 14 …… 15 dm365_init_spi0(BIT(0), dm365_evm_spi_info, 16 ARRAY_SIZE(dm365_evm_spi_info)); 17 }
dm365_evm_init這個函數是dm365平台初始化函數,我略去了和SPI無關的部分.可以看到其中調用了dm365_init_spi0函數,並且將一個struct spi_board_info這個結構類型的數組作為參數傳了進去.那么來看看dm365_init_spi0函數,在arch/arm/mach-davinci/dm365.c中:
1 static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32); 2 3 static struct davinci_spi_platform_data dm365_spi0_pdata = { 4 .version = SPI_VERSION_1, 5 .num_chipselect = 2, 6 .dma_event_q = EVENTQ_3, 7 }; 8 9 static struct resource dm365_spi0_resources[] = { 10 { 11 .start = 0x01c66000, 12 .end = 0x01c667ff, 13 .flags = IORESOURCE_MEM, 14 }, 15 { 16 .start = IRQ_DM365_SPIINT0_0, 17 .flags = IORESOURCE_IRQ, 18 }, 19 { 20 .start = 17, 21 .flags = IORESOURCE_DMA, 22 }, 23 { 24 .start = 16, 25 .flags = IORESOURCE_DMA, 26 }, 27 }; 28 29 static struct platform_device dm365_spi0_device = { 30 .name = "spi_davinci",/*這個是和platform_driver匹配的依據,具體到davinci的板子就是davinci_spi_driver*/ 31 .id = 0,/*對於SPI,這個值最后會在初始化spi_master的時候用來初始化master->bus_num*/ 32 .dev = { 33 .dma_mask = &dm365_spi0_dma_mask, 34 .coherent_dma_mask = DMA_BIT_MASK(32), 35 .platform_data = &dm365_spi0_pdata, 36 }, 37 .num_resources = ARRAY_SIZE(dm365_spi0_resources), 38 .resource = dm365_spi0_resources, 39 }; 40 41 void __init dm365_init_spi0(unsigned chipselect_mask, 42 const struct spi_board_info *info, unsigned len) 43 { 44 davinci_cfg_reg(DM365_SPI0_SCLK); 45 davinci_cfg_reg(DM365_SPI0_SDI); 46 davinci_cfg_reg(DM365_SPI0_SDO); 47 48 /* not all slaves will be wired up */ 49 if (chipselect_mask & BIT(0)) 50 davinci_cfg_reg(DM365_SPI0_SDENA0); 51 if (chipselect_mask & BIT(1)) 52 davinci_cfg_reg(DM365_SPI0_SDENA1); 53 54 spi_register_board_info(info, len); 55 56 platform_device_register(&dm365_spi0_device); 57 }
第54行注冊了struct spi_board_info實例,就是我們傳進來的dm365_evm_spi_info.在設備移植時填充結構體spi_board_info是移植的重要工作.我們來看看這個函數的實現,在drivers/spi/spi.c中:
1 int spi_register_board_info(struct spi_board_info const *info, unsigned n) 2 { 3 struct boardinfo *bi; 4 int i; 5 6 bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);/*為結構體boardinfo分配內存空間*/ 7 if (!bi) 8 return -ENOMEM; 9 10 for (i = 0; i < n; i++, bi++, info++) { 11 struct spi_master *master; 12 13 memcpy(&bi->board_info, info, sizeof(*info)); 14 mutex_lock(&board_lock); 15 list_add_tail(&bi->list, &board_list);/*添加到板級描述符鏈表*/ 16 list_for_each_entry(master, &spi_master_list, list)/*將SPI主機控制類鏈表所有的節點匹配板級信息的設備初始化*/ 17 spi_match_master_to_boardinfo(master, &bi->board_info); 18 mutex_unlock(&board_lock); 19 } 20 21 return 0; 22 }
這里又看到了一個結構struct boardinfo,其實它簡單的就像沒穿褲子的女人,我們來看,在同文件中:
1 struct boardinfo { 2 struct list_head list; 3 struct spi_board_info board_info; 4 }; 5 6 static LIST_HEAD(board_list); 7 static LIST_HEAD(spi_master_list); 8 9 /* 10 * Used to protect add/del opertion for board_info list and 11 * spi_master list, and their matching process 12 */ 13 /*boardinfo鏈表操作鎖*/ 14 static DEFINE_MUTEX(board_lock);
這個結構是一個板級相關信息鏈表,就是說它是一些描述spi_device的信息的集合.結構體boardinfo管理多個結構體spi_board_info,結構體spi_board_info中掛在SPI總線上的設備的平台信息.一個結構體spi_board_info對應着一個SPI設備spi_device.
同時我們也看到了,函數中出現的board_list和spi_master_list都是全局的鏈表,她們分別記錄了系統中所有的boardinfo和所有的spi_master.至於spi_match_master_to_boardinfo函數是什么意思,我們后面還會遇到,到時候再講.
dm365_init_spi0函數中第56行注冊平台設備.我們看到這個platform_device的的name是"spi_davinci",那么就必然還存在一個名為"spi_davinci"的platform_driver.那好辦了,搜一下發現在drivers/spi/spi_davinci.c中:
1 static struct platform_driver davinci_spi_driver = { 2 .driver = { 3 .name = "spi_davinci", 4 .owner = THIS_MODULE, 5 .of_match_table = davinci_spi_of_match, 6 }, 7 .probe = davinci_spi_probe, 8 .remove = davinci_spi_remove, 9 }; 10 module_platform_driver(davinci_spi_driver);
Linux設備模型常識告訴我們,當系統中注冊了一個名為"spi_davinci"的platform_device時,同時又住了一個名為"spi_davinci"的platform_driver.那么就會執行這里的probe回調.這里我們來看davinci_spi_probe函數.
1 static int davinci_spi_probe(struct platform_device *pdev) 2 { 3 struct spi_master *master; 4 struct davinci_spi *dspi;/*davinci_spi這個結構用來描述具體的davinci平台上的spi控制器,等於說是對spi_master的一個封裝*/ 5 struct davinci_spi_platform_data *pdata; 6 struct resource *r, *mem; 7 resource_size_t dma_rx_chan = SPI_NO_RESOURCE; 8 resource_size_t dma_tx_chan = SPI_NO_RESOURCE; 9 int i = 0, ret = 0; 10 u32 spipc0; 11 12 /*分配master結構體,其中包括davinci_spi結構的內存空間,使用master.dev.driver_data指向它*/ 13 master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi)); 14 if (master == NULL) { 15 ret = -ENOMEM; 16 goto err; 17 } 18 19 dev_set_drvdata(&pdev->dev, master);/*pdev->dev.device_private->driver_data = master*/ 20 21 dspi = spi_master_get_devdata(master);/*就是獲取上文master.dev.driver_data指向的對象地址,其實就是davinci_spi結構對象的空間地址,將 22 其賦給dspi*/ 23 if (dspi == NULL) {/*dspi不能為空哦*/ 24 ret = -ENOENT; 25 goto free_master; 26 } 27 28 /*下面這幾行就是填充dspi的pdata字段*/ 29 if (pdev->dev.platform_data) { 30 pdata = pdev->dev.platform_data;/*具體到對於dm365來說就是dm365_spi0_pdata*/ 31 dspi->pdata = *pdata; 32 } else { 33 /* update dspi pdata with that from the DT */ 34 ret = spi_davinci_get_pdata(pdev, dspi); 35 if (ret < 0) 36 goto free_master; 37 } 38 39 /* pdata in dspi is now updated and point pdata to that */ 40 pdata = &dspi->pdata;/*pdata指針再指向dspi->pdata*/ 41 42 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*獲取IO資源*/ 43 if (r == NULL) { 44 ret = -ENOENT; 45 goto free_master; 46 } 47 48 dspi->pbase = r->start; 49 50 mem = request_mem_region(r->start, resource_size(r), pdev->name);/*申請IO內存*/ 51 if (mem == NULL) { 52 ret = -EBUSY; 53 goto free_master; 54 } 55 56 dspi->base = ioremap(r->start, resource_size(r));/*建立內存映射*/ 57 if (dspi->base == NULL) { 58 ret = -ENOMEM; 59 goto release_region; 60 } 61 62 dspi->irq = platform_get_irq(pdev, 0);/*獲取irq號*/ 63 if (dspi->irq <= 0) { 64 ret = -EINVAL; 65 goto unmap_io; 66 } 67 68 ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn, 69 0, dev_name(&pdev->dev), dspi);/*申請spi中斷,中斷處理函數為davinci_spi_irq*/ 70 if (ret) 71 goto unmap_io; 72 73 /*設置bitbang的所屬master*/ 74 dspi->bitbang.master = spi_master_get(master); 75 if (dspi->bitbang.master == NULL) { 76 ret = -ENODEV; 77 goto irq_free; 78 } 79 80 dspi->clk = clk_get(&pdev->dev, NULL);/*獲取spi時鍾*/ 81 if (IS_ERR(dspi->clk)) { 82 ret = -ENODEV; 83 goto put_master; 84 } 85 clk_prepare_enable(dspi->clk); 86 87 master->dev.of_node = pdev->dev.of_node; 88 master->bus_num = pdev->id;/*bus_num*/ 89 master->num_chipselect = pdata->num_chipselect;/*保存SPI主機控制器支持的片選數量.具體到dm365可以看到dm365_spi0_pdata中將其定義為2*/ 90 master->setup = davinci_spi_setup; 91 92 /*設置bitbang控制傳輸的相關函數*/ 93 dspi->bitbang.chipselect = davinci_spi_chipselect; 94 dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; 95 96 dspi->version = pdata->version;/*具體到dm365可以看到dm365_spi0_pdata中將其定義為0*/ 97 98 dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; 99 if (dspi->version == SPI_VERSION_2) 100 dspi->bitbang.flags |= SPI_READY; 101 102 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);/*獲取DMA資源,這作為輸入緩沖*/ 103 if (r) 104 dma_rx_chan = r->start; 105 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);/*由參數就能知道davinci的DMA資源定義了兩個,這里就獲取第二個.這作為輸出緩沖*/ 106 if (r) 107 dma_tx_chan = r->start; 108 109 dspi->bitbang.txrx_bufs = davinci_spi_bufs;/*傳輸數據最終要調用的函數*/ 110 if (dma_rx_chan != SPI_NO_RESOURCE && 111 dma_tx_chan != SPI_NO_RESOURCE) { 112 dspi->dma_rx_chnum = dma_rx_chan; 113 dspi->dma_tx_chnum = dma_tx_chan; 114 115 ret = davinci_spi_request_dma(dspi); 116 if (ret) 117 goto free_clk; 118 119 dev_info(&pdev->dev, "DMA: supported\n"); 120 dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, " 121 "event queue: %d\n", dma_rx_chan, dma_tx_chan, 122 pdata->dma_event_q); 123 } 124 125 dspi->get_rx = davinci_spi_rx_buf_u8; 126 dspi->get_tx = davinci_spi_tx_buf_u8; 127 128 init_completion(&dspi->done);/*初始化completion,用於實現同步I/O*/ 129 130 /* Reset In/OUT SPI module */ 131 iowrite32(0, dspi->base + SPIGCR0); 132 udelay(100); 133 iowrite32(1, dspi->base + SPIGCR0); 134 135 /* Set up SPIPC0. CS and ENA init is done in davinci_spi_setup */ 136 spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK; 137 iowrite32(spipc0, dspi->base + SPIPC0); 138 139 /* initialize chip selects */ 140 if (pdata->chip_sel) {/*davinci的pdata中chip_sel字段並沒有設置,這里為空,因此不會進來*/ 141 for (i = 0; i < pdata->num_chipselect; i++) { 142 if (pdata->chip_sel[i] != SPI_INTERN_CS) 143 gpio_direction_output(pdata->chip_sel[i], 1); 144 } 145 } 146 147 if (pdata->intr_line)/*dm365這個字段為空*/ 148 iowrite32(SPI_INTLVL_1, dspi->base + SPILVL); 149 else 150 iowrite32(SPI_INTLVL_0, dspi->base + SPILVL); 151 152 iowrite32(CS_DEFAULT, dspi->base + SPIDEF); 153 154 /* master mode default */ 155 set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK); 156 set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);/*默認設置SPI主控制器工作在master方式*/ 157 set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); 158 159 ret = spi_bitbang_start(&dspi->bitbang);/*注冊我們的主機SPI控制器*/ 160 if (ret) 161 goto free_dma; 162 163 dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base); 164 165 return ret; 166 167 free_dma: 168 dma_release_channel(dspi->dma_rx); 169 dma_release_channel(dspi->dma_tx); 170 free_clk: 171 clk_disable_unprepare(dspi->clk); 172 clk_put(dspi->clk); 173 put_master: 174 spi_master_put(master);/*減少引用計數*/ 175 irq_free: 176 free_irq(dspi->irq, dspi); 177 unmap_io: 178 iounmap(dspi->base); 179 release_region: 180 release_mem_region(dspi->pbase, resource_size(r)); 181 free_master: 182 kfree(master); 183 err: 184 return ret; 185 }
該函數首先為spi_master結構體以及davinci_spi結構體分配了空間,同時,spi_master.dev.driver_data指向了davinci_spi.接着執行了該條語句:
pdata = pdev->dev.platform_data;/*具體到對於dm365來說就是dm365_spi0_pdata*/
dspi->pdata = *pdata;
NOTE:在這里獲取platform_device.dev.platform_data,也就是平台設備的相關數據,這是平台設備移植最需要關注的地方.
隨后,為master定義了setup方法,為bitbang定義了3個方法.之后獲取了一系列的資源,同時注冊了中斷服務程序.接着再初始化了completion,這個東東將用於實現同步I/O,他的偉大之處后面會體現出來的.最后調用spi_bitbang_start注冊主機控制器.我們來看這個函數,在drivers/spi/spi_bitbang.c中:
1 int spi_bitbang_start(struct spi_bitbang *bitbang) 2 { 3 struct spi_master *master = bitbang->master; 4 int status; 5 6 if (!master || !bitbang->chipselect) 7 return -EINVAL; 8 9 INIT_WORK(&bitbang->work, bitbang_work);/*初始化一個struct work,處理函數為bitbang_work*/ 10 spin_lock_init(&bitbang->lock);/*初始化自旋鎖*/ 11 INIT_LIST_HEAD(&bitbang->queue);/*初始化鏈表頭,鏈表為雙向循環鏈表*/ 12 13 if (!master->mode_bits) 14 master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; 15 16 /*檢測bitbang中的函數是否都定義了,如果沒定義,則默認使用spi_bitbang_xxx*/ 17 if (!master->transfer)/*master的transfer方法沒有定義過*/ 18 master->transfer = spi_bitbang_transfer;/*使用默認的spi_bitbang_transfe方法*/ 19 if (!bitbang->txrx_bufs) {/*如果bitbang沒有txrx_bufs方法,其實對於davinci在davinci_spi_probe函數中定義過該方法*/ 20 bitbang->use_dma = 0; 21 bitbang->txrx_bufs = spi_bitbang_bufs; 22 if (!master->setup) { 23 if (!bitbang->setup_transfer) 24 bitbang->setup_transfer = 25 spi_bitbang_setup_transfer; 26 master->setup = spi_bitbang_setup; 27 master->cleanup = spi_bitbang_cleanup; 28 } 29 } else if (!master->setup)/*對於davinci在davinci_spi_probe函數中定義過該方法*/ 30 return -EINVAL; 31 if (master->transfer == spi_bitbang_transfer && 32 !bitbang->setup_transfer) 33 return -EINVAL; 34 35 /* this task is the only thing to touch the SPI bits */ 36 bitbang->busy = 0; 37 bitbang->workqueue = create_singlethread_workqueue( 38 dev_name(master->dev.parent));/*創建bitbang的工作隊列*/ 39 if (bitbang->workqueue == NULL) { 40 status = -EBUSY; 41 goto err1; 42 } 43 44 /* driver may get busy before register() returns, especially 45 * if someone registered boardinfo for devices 46 */ 47 status = spi_register_master(master);/*注冊spi控制器*/ 48 if (status < 0) 49 goto err2; 50 51 return status; 52 53 err2: 54 destroy_workqueue(bitbang->workqueue); 55 err1: 56 return status; 57 } 58 EXPORT_SYMBOL_GPL(spi_bitbang_start);
定義了控制器的transfer方法為spi_bitbang_transfer.創建了一個工作隊列和一個工作bitbang_work,同時創建了一個鏈表.這些東東后面都會看到.最后,調用了spi_register_master函數,該函數將完成SPI控制器的注冊,其中還牽涉到spi_device的注冊.我們來看看這個函數.下列函數位於drivers/spi/spi.c:
1 int spi_register_master(struct spi_master *master) 2 { 3 static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); 4 struct device *dev = master->dev.parent; 5 struct boardinfo *bi; 6 int status = -ENODEV; 7 int dynamic = 0; 8 9 if (!dev) 10 return -ENODEV; 11 12 status = of_spi_register_master(master); 13 if (status) 14 return status; 15 16 /* even if it's just one always-selected device, there must 17 * be at least one chipselect 18 */ 19 if (master->num_chipselect == 0)/*SPI主控制器支持的片選數當然不能為0,否則還怎么掛接從設備啊.一個接口對應一個master,一個master對應 20 一條SPI總線,一條總線上可能掛有多個設備,num_chipselect就表示該總線上的設備數*/ 21 return -EINVAL; 22 23 if ((master->bus_num < 0) && master->dev.of_node) 24 master->bus_num = of_alias_get_id(master->dev.of_node, "spi"); 25 26 /* convention: dynamically assigned bus IDs count down from the max */ 27 if (master->bus_num < 0) {/*總線號從最大開始減*/ 28 /* FIXME switch to an IDR based scheme, something like 29 * I2C now uses, so we can't run out of "dynamic" IDs 30 */ 31 master->bus_num = atomic_dec_return(&dyn_bus_id); 32 dynamic = 1; 33 } 34 35 spin_lock_init(&master->bus_lock_spinlock); 36 mutex_init(&master->bus_lock_mutex); 37 master->bus_lock_flag = 0;/*這個標志指示SPI總線是否被鎖*/ 38 39 /* register the device, then userspace will see it. 40 * registration fails if the bus ID is in use. 41 */ 42 dev_set_name(&master->dev, "spi%u", master->bus_num); 43 status = device_add(&master->dev);/*向內核注冊設備*/ 44 if (status < 0) 45 goto done; 46 dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), 47 dynamic ? " (dynamic)" : ""); 48 49 /* If we're using a queued driver, start the queue */ 50 if (master->transfer)/*對於具體到davinci,此字段在spi_bitbang_start中被初始化為spi_bitbang_transfer*/ 51 dev_info(dev, "master is unqueued, this is deprecated\n"); 52 else { 53 status = spi_master_initialize_queue(master); 54 if (status) { 55 device_unregister(&master->dev); 56 goto done; 57 } 58 } 59 60 mutex_lock(&board_lock); 61 list_add_tail(&master->list, &spi_master_list);/*把這個SPI主機控制器添加進全局的spi_master_list鏈表*/ 62 list_for_each_entry(bi, &board_list, list)/*遍歷全局的board_list鏈表,為每一個boardinfo結構節點查找其中的指向的spi_board_info結構,通過 63 對spi_board_info的bus_bum和SPI主機控制器(spi_master)的bus_num進行匹配,來確定SPI從設備是否由此SPI主機控制器來控制.如果匹配,則通 64 過調用spi_new_device函數創建spi_device從設備,並且將其注冊進內核*/ 65 spi_match_master_to_boardinfo(master, &bi->board_info); 66 mutex_unlock(&board_lock); 67 68 /* Register devices from the device tree and ACPI */ 69 of_register_spi_devices(master); 70 acpi_register_spi_devices(master); 71 done: 72 return status; 73 } 74 EXPORT_SYMBOL_GPL(spi_register_master);
該函數注釋一目了然,我們來看看spi_match_master_to_boardinfo這個函數吧.在同文件中有:
1 /*使用SPI主控制類和板級信息匹配則添加一個新設備*/ 2 static void spi_match_master_to_boardinfo(struct spi_master *master, 3 struct spi_board_info *bi) 4 { 5 struct spi_device *dev; 6 7 if (master->bus_num != bi->bus_num)/*通過bus_num對spi設備和master進行匹配*/ 8 return; 9 10 dev = spi_new_device(master, bi);/*執行到此,表示匹配完成,SPI設備由該SPI接口來控制,開始創建spi_device*/ 11 if (!dev) 12 dev_err(master->dev.parent, "can't create new device for %s\n", 13 bi->modalias); 14 }
地球人都知道這段代碼什么意思,好了繼續看spi_new_device函數.在同文件中:
1 struct spi_device *spi_new_device(struct spi_master *master, 2 struct spi_board_info *chip) 3 { 4 struct spi_device *proxy; 5 int status; 6 7 /* NOTE: caller did any chip->bus_num checks necessary. 8 * 9 * Also, unless we change the return value convention to use 10 * error-or-pointer (not NULL-or-pointer), troubleshootability 11 * suggests syslogged diagnostics are best here (ugh). 12 */ 13 14 proxy = spi_alloc_device(master);/*分配spi_device結構,並初始化一些字段*/ 15 if (!proxy) 16 return NULL; 17 18 WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias)); 19 20 /*從spi_board_info獲取SPI從設備的參數*/ 21 proxy->chip_select = chip->chip_select; 22 proxy->max_speed_hz = chip->max_speed_hz; 23 proxy->mode = chip->mode; 24 proxy->irq = chip->irq; 25 strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); 26 proxy->dev.platform_data = (void *) chip->platform_data; 27 proxy->controller_data = chip->controller_data; 28 proxy->controller_state = NULL; 29 30 status = spi_add_device(proxy);/*將新設備添加進內核*/ 31 if (status < 0) { 32 spi_dev_put(proxy);/*從內核模塊中撤銷這個SPI(從)設備,但是這貌似並沒有釋放spi_alloc_device開辟的內存.實質上這個函數只是減少 33 了SPI(從)設備的引用計數*/ 34 return NULL; 35 } 36 37 return proxy; 38 } 39 EXPORT_SYMBOL_GPL(spi_new_device);
這個函數首先創建了spi_device結構,讓后通過板級信息spi_board_info將SPI從設備的相關信息復制給spi_device結構,從而完成了spi_device結構的定義,最后調用spi_add_device,完成spi_device的注冊.其中struct spi_board_info *chip這就是我們當初arch/arm/mach-davinci/board-dm365-evm.c中定義的dm365_evm_spi_info數組中的結構實例.
第25行我們就知道,這里注冊的spi_device的modalias字段就被初始化為"at25".那么與其對應的spi_driver的device_driver中的name字段肯定為"at25".只有這樣才能在SPI核心層的spi_match_device函數中匹配.搜了一遍內核,看到在drivers/msic/eeprom/at25.c中有:
1 static struct spi_driver at25_driver = { 2 .driver = { 3 .name = "at25", 4 .owner = THIS_MODULE, 5 }, 6 .probe = at25_probe,/*與相應的SPI(從)設備spi_device匹配成功后,則調用這里的probe函數*/ 7 .remove = at25_remove, 8 }; 9 10 module_spi_driver(at25_driver);
第10行這個宏是SPI架構專門定義的,在include/linux/spi/spi.h中,我們來看:
1 #define module_spi_driver(__spi_driver) \ 2 module_driver(__spi_driver, spi_register_driver, \ 3 spi_unregister_driver)
讓暴風雨來的更猛烈些吧,研究內核的孩紙都傷不起啊,我們只有硬着頭皮往下看,在include/linux/device.h中:
1 #define module_driver(__driver, __register, __unregister, ...) \ 2 static int __init __driver##_init(void) \ 3 { \ 4 return __register(&(__driver) , ##__VA_ARGS__); \ 5 } \ 6 module_init(__driver##_init); \ 7 static void __exit __driver##_exit(void) \ 8 { \ 9 __unregister(&(__driver) , ##__VA_ARGS__); \ 10 } \ 11 module_exit(__driver##_exit);
山重水復疑無路,柳暗花明又一村.這東東你讓我說啥~沒說的.相信大家也不想在聽我嘮叨.但是這里為什么多此一舉寫了這么一個叫宏,而不是像其他的linux模塊那樣直接寫兩個module_xxx呢?這是因為這個設備eeprom本身是不可插拔的,也就不需要什么加載卸載的過程,系統上電運行直接就注冊了.
那么我們知道了,現在因為SPI子系統核心層我們已經注冊了一條SPI總線,就是spi_bus_type.它里面的match回調函數我們已經看過了,就是spi_match_device.就是在這個函數中將完成這個spi_device和spi_driver的匹配,匹配成功就會去執行spi_driver的probe回調了.我們來看,at25_probe函數在drivers/msic/eeprom/at25.c中:
1 static int at25_probe(struct spi_device *spi) 2 { 3 struct at25_data *at25 = NULL;/*這個結構其實就是對spi_device的封裝,我們可以像理解面向對象那樣將這個結構理解為對spi_device的實例*/ 4 struct spi_eeprom chip;/*此結構用來作為記錄一個SPI EEPROMS的句柄,它保存了platform_data的數據*/ 5 struct device_node *np = spi->dev.of_node; 6 int err; 7 int sr; 8 int addrlen; 9 10 /* Chip description */ 11 if (!spi->dev.platform_data) {/*具體到dm365平台,此platform_data就是arch/arm/mach-davinci/board-ddm365-evm.c中定義的的at25640*/ 12 if (np) { 13 err = at25_np_to_chip(&spi->dev, np, &chip); 14 if (err) 15 goto fail; 16 } else { 17 dev_err(&spi->dev, "Error: no chip description\n"); 18 err = -ENODEV; 19 goto fail; 20 } 21 } else 22 chip = *(struct spi_eeprom *)spi->dev.platform_data; 23 24 /* For now we only support 8/16/24 bit addressing */ 25 if (chip.flags & EE_ADDR1)/*flags用來標志eeprom的位寬和讀寫模式,具體到dm365平台此flags為EE_ADDR2*/ 26 addrlen = 1; 27 else if (chip.flags & EE_ADDR2) 28 addrlen = 2; 29 else if (chip.flags & EE_ADDR3) 30 addrlen = 3; 31 else { 32 dev_dbg(&spi->dev, "unsupported address type\n"); 33 err = -EINVAL; 34 goto fail; 35 } 36 37 /* Ping the chip ... the status register is pretty portable, 38 * unlike probing manufacturer IDs. We do expect that system 39 * firmware didn't write it in the past few milliseconds! 40 */ 41 /*ping一下芯片,狀態寄存器是很容易被檢測的,不像制造商ID那樣麻煩.我們期待系統固件之前沒有寫入它.*/ 42 sr = spi_w8r8(spi, AT25_RDSR);/*同步的讀取狀態寄存器的值,返回的八位數據保存在sr中.spi_w8r8這個函數有可能會睡眠*/ 43 if (sr < 0 || sr & AT25_SR_nRDY) { 44 dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr); 45 err = -ENXIO; 46 goto fail; 47 } 48 49 if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) {/*以kmalloc分配內存,並清0*/ 50 err = -ENOMEM; 51 goto fail; 52 } 53 54 mutex_init(&at25->lock);/*初始化互斥體*/ 55 at25->chip = chip;/*記錄下spi_eeprom*/ 56 at25->spi = spi_dev_get(spi);/*記錄下這個片子對應的spi_device*/ 57 dev_set_drvdata(&spi->dev, at25);/*spi->dev.device_private->driver_data = at25*/ 58 at25->addrlen = addrlen;/*我覺得應該可以理解為這個片子使用的位寬是多少個字節.那根據上文分析,此處值為2*/ 59 60 /* Export the EEPROM bytes through sysfs, since that's convenient. 61 * And maybe to other kernel code; it might hold a board's Ethernet 62 * address, or board-specific calibration data generated on the 63 * manufacturing floor. 64 * 65 * Default to root-only access to the data; EEPROMs often hold data 66 * that's sensitive for read and/or write, like ethernet addresses, 67 * security codes, board-specific manufacturing calibrations, etc. 68 */ 69 /*通過sysfs文件系統導出EEPROM的字節,因為這是很方便的.也許其他內核代碼也是這樣做的:比如保存板子的以太網地址,或者是生產商的特定板的校驗數據. 70 默認只有root用戶能夠訪問的數據.EEPROMs經常保存一些敏感的讀或寫的數據,像是以太網地址,安全碼,特定板的校准數據等*/ 71 sysfs_bin_attr_init(&at25->bin);/*初始化一個動態分配的bin_attribute屬性*/ 72 at25->bin.attr.name = "eeprom";/*屬性的名字*/ 73 at25->bin.attr.mode = S_IRUSR;/*屬性的模式(用戶可讀)*/ 74 at25->bin.read = at25_bin_read;/*屬性的讀方法*/ 75 at25->mem.read = at25_mem_read;/*片子的內存讀函數*/ 76 77 at25->bin.size = at25->chip.byte_len; 78 if (!(chip.flags & EE_READONLY)) {/*flags用來標志eeprom的位寬和讀寫模式,具體到dm365平台此flags為EE_ADDR2*/ 79 at25->bin.write = at25_bin_write;/*如果eeprom片子不是只讀的話,那么就設置屬性的寫方法*/ 80 at25->bin.attr.mode |= S_IWUSR;/*增加屬性的模式(用戶可寫)*/ 81 at25->mem.write = at25_mem_write;/*片子的內存寫函數*/ 82 } 83 84 err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);/*創建一個二進制的屬性文件*/ 85 if (err) 86 goto fail; 87 88 if (chip.setup)/*如果片子定義了setup函數,具體到dm365平台,此platform_data就是arch/arm/mach-davinci/board-ddm365-evm.c中定義的的at25640里並沒有 89 定義這個函數,因此為空*/ 90 chip.setup(&at25->mem, chip.context);/*使用片子的setup函數做一些初始化*/ 91 92 dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", 93 (at25->bin.size < 1024) 94 ? at25->bin.size 95 : (at25->bin.size / 1024), 96 (at25->bin.size < 1024) ? "Byte" : "KByte", 97 at25->chip.name, 98 (chip.flags & EE_READONLY) ? " (readonly)" : "", 99 at25->chip.page_size); 100 return 0; 101 fail: 102 dev_dbg(&spi->dev, "probe err %d\n", err); 103 kfree(at25); 104 return err; 105 }
根據代碼就能知道,這個spi_device實際上對應的是一個eeprom,而這里就是它的操作的一些初始化.也就是說,對於分析的這個davinci代碼的實例,是dm365平台的,其開發板上應該是將eeprom通過spi總線掛接在了spi_master上.也就是掛接在了SOC上,因為我們的dm365片子本身就集成了spi_master.之后要訪問eeprom其實回調最終的都是這里提供的一些接口.聽起來有點黏糊,看個圖吧:

哎,就寫到這里,本人不會用visio,畫個這圖畫了一下午~丟人啊!
