Linux的SPI子系統采用主機驅動和外設驅動分離的思想,首先主機SPI控制器是一種平台設備,因此它以platform的方式注冊進內核,外設的信息是以boardinfo形式靜態定義的,在創建spi_master時,會根據外設的bus_num和主機的bus_num是否相等,來選擇是否將該外設掛接在該SPI主控制器下。先看SPI子系統中幾個關鍵的數據結構:
struct spi_master用來描述一個SPI主控制器
- struct spi_master {
- struct device dev;
- s16 bus_num; /*總線編號*/
- u16 num_chipselect;/*支持的外設數量*/
- u16 dma_alignment;
- int (*transfer)(struct spi_device *spi, struct spi_message *mesg);/*用於將消息添加到隊列*/
- void (*cleanup)(struct spi_device *spi);
- };
struct spi_device用來描述一個SPI從設備
- struct spi_device {
- struct device dev;
- struct spi_master *master; /*從設備所屬的SPI主控器*/
- u32 max_speed_hz; /*最大傳輸頻率*/
- u8 chip_select; /*片選號,用於區別其他從設備*/
- u8 mode; /*傳輸模式*/
- /*各個mode的定義*/
- #define SPI_CPHA 0x01 /* clock phase */
- #define SPI_CPOL 0x02 /* clock polarity */
- #define SPI_MODE_0 (0|0) /* (original MicroWire) */
- #define SPI_MODE_1 (0|SPI_CPHA)
- #define SPI_MODE_2 (SPI_CPOL|0)
- #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
- #define SPI_CS_HIGH 0x04 /* chipselect active high? */
- #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
- #define SPI_3WIRE 0x10 /* SI/SO signals shared */
- #define SPI_LOOP 0x20 /* loopback mode */
- u8 bits_per_word; /*每個字的比特數*/
- int irq; /*所使用的中斷*/
- void *controller_state;
- void *controller_data;
- char modalias[32]; /*設備名,在和從設備驅動匹配時會用到*/
-
- };
struct spi_driver用來描述一個SPI從設備的驅動,它的形式和struct platform_driver是一致的
- struct spi_driver {
- int (*probe)(struct spi_device *spi);
- int (*remove)(struct spi_device *spi);
- void (*shutdown)(struct spi_device *spi);
- int (*suspend)(struct spi_device *spi, pm_message_t mesg);
- int (*resume)(struct spi_device *spi);
- struct device_driver driver;
- };
SPI子系統初始化的第一步就是將SPI總線注冊進內核,並且在/sys下創建一個spi_master的類,以後注冊的從設備都將掛接在該總線下
- static int __init spi_init(void)
- {
- int status;
-
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!buf) {
- status = -ENOMEM;
- goto err0;
- }
-
- status = bus_register(&spi_bus_type);//注冊SPI總線
- if (status < 0)
- goto err1;
-
- status = class_register(&spi_master_class);//注冊spi_master類
- if (status < 0)
- goto err2;
- return 0;
-
- err2:
- bus_unregister(&spi_bus_type);
- err1:
- kfree(buf);
- buf = NULL;
- err0:
- return status;
- }
我們來看spi_bus_type的定義
- struct bus_type spi_bus_type = {
- .name = "spi",
- .dev_attrs = spi_dev_attrs,
- .match = spi_match_device,
- .uevent = spi_uevent,
- .suspend = spi_suspend,
- .resume = spi_resume,
- };
來看掛接在SPI總線下的從設備和從設備驅動是如何匹配的,也就是spi_match_device函數
- static int spi_match_device(struct device *dev, struct device_driver *drv)
- {
- const struct spi_device *spi = to_spi_device(dev);
-
- return strcmp(spi->modalias, drv->name) == 0;
- }
這裡可以看到是將struct device_driver中的name字段與struct spi_device中的modalias字段進行匹配
這裡已經完成了SPI子系統初始化的第一步,也就是注冊SPI總線,這一步是和平台無關的,第二步是和平台相關的初始化,下一節再做介紹。