SPI子系統分析之二:數據結構


內核版本:3.9.5

spi_master

struct spi_master用來描述一個SPI主控制器,我們一般不需要自己編寫spi控制器驅動.

  1 /*結構體master代表一個SPI接口,或者叫一個SPI主機控制器,一個接口對應一條SPI總線,master->bus_num則記錄了這個總線號*/
  2 struct spi_master {
  3     struct device    dev;
  4 
  5     struct list_head list;
  6 
  7     /* other than negative (== assign one dynamically), bus_num is fully
  8      * board-specific.  usually that simplifies to being SOC-specific.
  9      * example:  one SOC has three SPI controllers, numbered 0..2,
 10      * and one board's schematics might show it using SPI-2.  software
 11      * would normally use bus_num=2 for that controller.
 12      */
 13     s16            bus_num;/*總線編號,從零開始.系統會用這個值去和系統中board_list鏈表中加入的每一個boardinfo結構
 14     (每個boardinfo結構都是一個spi_board_info的集合,每一個spi_board_info都是對應一個SPI(從)設備的描述)中的每一個
 15     spi_board_info中的bus_num進行匹配,如果匹配上就說明這個spi_board_info描述的SPI(從)設備是鏈接在此總線上的,因
 16     此就會調用spi_new_device去創建一個spi_device*/
 17 
 18     /* chipselects will be integral to many controllers; some others
 19      * might use board-specific GPIOs.
 20      */
 21     u16            num_chipselect;//支持的片選的數量.從設備的片選號不能大於這個數.該值當然不能為0,否則會注冊失敗
 22 
 23     /* some SPI controllers pose alignment requirements on DMAable
 24      * buffers; let protocol drivers know about these requirements.
 25      */
 26     u16            dma_alignment;
 27 
 28     /* spi_device.mode flags understood by this controller driver */
 29     u16            mode_bits;
 30 
 31     /* other constraints relevant to this driver */
 32     u16            flags;
 33 #define SPI_MASTER_HALF_DUPLEX    BIT(0)        /* can't do full duplex */
 34 #define SPI_MASTER_NO_RX    BIT(1)        /* can't do buffer read */
 35 #define SPI_MASTER_NO_TX    BIT(2)        /* can't do buffer write */
 36 
 37     /* lock and mutex for SPI bus locking */
 38     spinlock_t        bus_lock_spinlock;
 39     struct mutex        bus_lock_mutex;
 40 
 41     /* flag indicating that the SPI bus is locked for exclusive use */
 42     bool            bus_lock_flag;
 43 
 44     /* Setup mode and clock, etc (spi driver may call many times).
 45      *
 46      * IMPORTANT:  this may be called when transfers to another
 47      * device are active.  DO NOT UPDATE SHARED REGISTERS in ways
 48      * which could break those transfers.
 49      */
 50     int            (*setup)(struct spi_device *spi);//根據spi設備更新硬件配置
 51 
 52     /* bidirectional bulk transfers
 53      *
 54      * + The transfer() method may not sleep; its main role is
 55      *   just to add the message to the queue.
 56      * + For now there's no remove-from-queue operation, or
 57      *   any other request management
 58      * + To a given spi_device, message queueing is pure fifo
 59      *
 60      * + The master's main job is to process its message queue,
 61      *   selecting a chip then transferring data
 62      * + If there are multiple spi_device children, the i/o queue
 63      *   arbitration algorithm is unspecified (round robin, fifo,
 64      *   priority, reservations, preemption, etc)
 65      *
 66      * + Chipselect stays active during the entire message
 67      *   (unless modified by spi_transfer.cs_change != 0).
 68      * + The message transfers use clock and SPI mode parameters
 69      *   previously established by setup() for this device
 70      */
 71     int            (*transfer)(struct spi_device *spi,
 72                         struct spi_message *mesg);/*添加消息到隊列的方法.此函數不可睡眠,其作用只是安排需要的傳送,並且在適當的時候(傳\
 73     送完成或者失敗)調用spi_message中的complete方法,來將結果報告給用戶*/
 74 
 75     /* called on release() to free memory provided by spi_master */
 76     void            (*cleanup)(struct spi_device *spi);/*cleanup函數會在spidev_release函數中被調用,spidev_release被登記為spi dev的release
 77     函數*/
 78 
 79     /*
 80      * These hooks are for drivers that want to use the generic
 81      * master transfer queueing mechanism. If these are used, the
 82      * transfer() function above must NOT be specified by the driver.
 83      * Over time we expect SPI drivers to be phased over to this API.
 84      */
 85     bool                queued;
 86     struct kthread_worker        kworker;
 87     struct task_struct        *kworker_task;
 88     struct kthread_work        pump_messages;
 89     spinlock_t            queue_lock;
 90     struct list_head        queue;
 91     struct spi_message        *cur_msg;
 92     bool                busy;
 93     bool                running;
 94     bool                rt;
 95 
 96     int (*prepare_transfer_hardware)(struct spi_master *master);
 97     int (*transfer_one_message)(struct spi_master *master,
 98                     struct spi_message *mesg);
 99     int (*unprepare_transfer_hardware)(struct spi_master *master);
100     /* gpio chip select */
101     int            *cs_gpios;
102 };

spi控制器的驅動一般在arch/.../mach-*/board-*.c聲明,注冊一個平台設備,然后在driver/spi下面建立一個平台驅動.spi_master注冊過程中會掃描arch/.../mach-*/board-*.c 中調用spi_register_board_info注冊的信息,為每一個與本總線編號相同的信息建立一個spi_device.根據Linux內核的驅動模型,注冊在同一總線下的驅動和設備會進行匹配.spi_bus_type總線匹配的依據是名字.這樣當自己編寫的spi_driver和spi_device同名的時候,spi_driver的probe方法就會被調用.spi_driver就能看到與自己匹配的spi_device了.

spi_device

struct spi_device用來描述一個SPI從設備.

 1 /*該結構用於描述SPI設備,也就是從設備的相關信息.
 2 NOTE:SPI子系統只支持主模式,也就是說SOC上的SPI只能工作在master模式,外圍設備只能為slave模式*/
 3 struct spi_device {
 4     struct device        dev;
 5     struct spi_master    *master;//對應的控制器指針
 6     u32            max_speed_hz;//spi傳輸時鍾
 7     u8            chip_select;//片選號,用來區分同一主控制器上的設備
 8     u8            mode;//各bit的定義如下,主要是傳輸模式/片選極性
 9 #define    SPI_CPHA    0x01            /* clock phase */
10 #define    SPI_CPOL    0x02            /* clock polarity */
11 #define    SPI_MODE_0    (0|0)            /* (original MicroWire) */
12 #define    SPI_MODE_1    (0|SPI_CPHA)
13 #define    SPI_MODE_2    (SPI_CPOL|0)
14 #define    SPI_MODE_3    (SPI_CPOL|SPI_CPHA)
15 #define    SPI_CS_HIGH    0x04            /* chipselect active high? *//*片選電位為高*/
16 #define    SPI_LSB_FIRST    0x08            /* per-word bits-on-wire *//*先輸出低比特*/
17 #define    SPI_3WIRE    0x10            /* SI/SO signals shared *//*輸入輸出共享接口,此時只能做半雙工*/
18 #define    SPI_LOOP    0x20            /* loopback mode *//*回寫/回顯模式*/
19 #define    SPI_NO_CS    0x40            /* 1 dev/bus, no chipselect */
20 #define    SPI_READY    0x80            /* slave pulls low to pause */
21     u8            bits_per_word;/*每個字長的比特數*/
22     int            irq;/*使用到的中斷號*/
23     void            *controller_state;
24     void            *controller_data;
25     char            modalias[SPI_NAME_SIZE];/*spi設備的名字*/
26     int            cs_gpio;    /* chip select gpio */
27 
28     /*
29      * likely need more hooks for more protocol options affecting how
30      * the controller talks to each chip, like:
31      *  - memory packing (12 bit samples into low bits, others zeroed)
32      *  - priority
33      *  - drop chipselect after each word
34      *  - chipselect delays
35      *  - ...
36      */
37 };

spi_driver

struct spi_driver用於描述SPI(從)設備驅動.驅動核心將根據driver.name和spi_board_info的modalias進行匹配,如過modalia和name相等,則綁定驅動程序和arch/.../mach-xxx/board-xxx.c中調用spi_register_board_info注冊的信息對應的spi_device設備.它的形式和struct platform_driver是一致的.

1 struct spi_driver {
2     const struct spi_device_id *id_table;
3     int            (*probe)(struct spi_device *spi);/*和spi_device匹配成功之后會調用這個方法.因此這個方法需要對設備和私有數據進行初始化*/
4     int            (*remove)(struct spi_device *spi);/*解除spi_device和spi_driver的綁定,釋放probe申請的資源*/
5     void            (*shutdown)(struct spi_device *spi);/*一般牽扯到電源管理會用到,關閉*/
6     int            (*suspend)(struct spi_device *spi, pm_message_t mesg);/*一般牽扯到電源管理會用到,掛起*/
7     int            (*resume)(struct spi_device *spi);/*一般牽扯到電源管理會用到,恢復*/
8     struct device_driver    driver;
9 };

spi_board_info

struct spi_board_info是板級信息,是在移植時就寫好的,並且要將其注冊.

 1 /*該結構也是對SPI(從)設備(spi_device)的描述,只不過它是板級信息,最終該結構的所有字段都將用於初始化SPI設備結構體spi_device*/
 2 struct spi_board_info {
 3     /* the device name and module name are coupled, like platform_bus;
 4      * "modalias" is normally the driver name.
 5      *
 6      * platform_data goes to spi_device.dev.platform_data,
 7      * controller_data goes to spi_device.controller_data,
 8      * irq is copied too
 9      */
10     char        modalias[SPI_NAME_SIZE];/*spi設備名,會拷貝到spi_device的相應字段中.這是設備spi_device在SPI總線spi_bus_type上匹配驅動的唯一標識*/
11     const void    *platform_data;/*平台數據*/
12     void        *controller_data;
13     int        irq;/*中斷號*/
14 
15     /* slower signaling on noisy or low voltage boards */
16     u32        max_speed_hz;/*SPI設備工作時的波特率*/
17 
18 
19     /* bus_num is board specific and matches the bus_num of some
20      * spi_master that will probably be registered later.
21      *
22      * chip_select reflects how this chip is wired to that master;
23      * it's less than num_chipselect.
24      */
25     u16        bus_num;/*該SPI(從)設備所在總線的總線號,就記錄了所屬的spi_master之中的bus_num編號.一個spi_master就對應一條總線*/
26     u16        chip_select;/*片選號.該SPI(從)設備在該條SPI總線上的設備號的唯一標識*/
27 
28     /* mode becomes spi_device.mode, and is essential for chips
29      * where the default of SPI_CS_HIGH = 0 is wrong.
30      */
31     u8        mode;/*參考spi_device中的成員*/
32 
33     /* ... may need additional spi_device chip config data here.
34      * avoid stuff protocol drivers can set; but include stuff
35      * needed to behave without being bound to a driver:
36      *  - quirks like clock rate mattering when not selected
37      */
38 };

spi_transfer

struct spi_transfer是對一次完整的數據傳輸的描述.每個spi_transfer總是讀取和寫入同樣長度的比特數,但是可以很容易的使用空指針舍棄讀或寫.為spi_transfer和spi_message分配的內存應該在消息處理期間保證是完整的.

 1 struct spi_transfer {
 2     /* it's ok if tx_buf == rx_buf (right?)
 3      * for MicroWire, one buffer must be null
 4      * buffers must work with dma_*map_single() calls, unless
 5      *   spi_message.is_dma_mapped reports a pre-existing mapping
 6      */
 7     const void    *tx_buf;/*發送緩沖區地址,這里存放要寫入設備的數據(必須是dma_safe),或者為NULL*/
 8     void        *rx_buf;/*接收緩沖區地址,從設備中讀取的數據(必須是dma_safe)就放在這里,或者為NULL*/
 9     unsigned    len;/*傳輸數據的長度.記錄了tx和rx的大小(字節數),這里不是指它的和,而是各自的長度,他們總是相等的*/
10 
11     dma_addr_t    tx_dma;/*如果spi_message.is_dma_mapped是真,這個是tx的dma地址*/
12     dma_addr_t    rx_dma;/*如果spi_message.is_dma_mapped是真,這個是rx的dma地址*/
13 
14     unsigned    cs_change:1;/*影響此次傳輸之后的片選.指示本次transfer結束之后是否要重新片選並調用setup改變設置.若為1則表示當該transfer
15     傳輸完后,改變片選信號.這個標志可以減少系統開銷*/
16     u8        bits_per_word;/*每個字長的比特數.如果是0,使用默認值*/
17     u16        delay_usecs;/*此次傳輸結束和片選改變之間的延時,之后就會啟動另一個傳輸或者結束整個消息*/
18     u32        speed_hz;/*通信時鍾.如果是0,使用默認值*/
19 
20     struct list_head transfer_list;/*用來連接的雙向鏈表節點,用於將該transfer鏈入message*/
21 };

再說一下:cs_change影響此transfer完成后是否禁用片選線並調用setup改變配置.(這個標志量就是chip select change片選改變的意思).沒有特殊情況,一個spi_message因該只在最后一個transfer置位該標志量.

spi_message

struct spi_message就是對多個spi_transfer的封裝.spi_message用來原子的執行spi_transfer表示的一串數組傳輸請求.這個傳輸隊列是原子的,這意味着在這個消息完成之前不會有其它消息占用總線.消息的執行總是按照FIFO的順序.向底層提交spi_message的代碼要負責管理它的內存空間.未顯示初始化的內存需要使用0來初始化.為spi_transfer和spi_message分配的內存應該在消息處理期間保證是完整的.

 1 struct spi_message {
 2     struct list_head    transfers;/*此次消息的傳輸段(spi_transfer)隊列,一個消息可以包含多個傳輸段(spi_transfer)*/
 3 
 4     struct spi_device    *spi;/*傳輸的目的設備,無論如何這里都是spi從設備,至於數據流向(是從主機到從設備還是從從設備到主機)這是由write/read
 5     每個傳輸段(spi_transfer)內部的tx_buf或者是rx_buf決定的*/
 6 
 7     unsigned        is_dma_mapped:1;/*如果為真,此次調用提供dma和cpu虛擬地址.spi主機提供了dma緩存池.如果此消息確定要使用dma(那當然更好
 8     了).則從那個緩存池中申請高速緩存.替代傳輸段(spi_transfer)中的tx_buf/rx_buf*/
 9 
10     /* REVISIT:  we might want a flag affecting the behavior of the
11      * last transfer ... allowing things like "read 16 bit length L"
12      * immediately followed by "read L bytes".  Basically imposing
13      * a specific message scheduling algorithm.
14      *
15      * Some controller drivers (message-at-a-time queue processing)
16      * could provide that as their default scheduling algorithm.  But
17      * others (with multi-message pipelines) could need a flag to
18      * tell them about such special cases.
19      */
20 
21     /* completion is reported through a callback */
22     void            (*complete)(void *context);/*用於異步傳輸完成時調用的回調函數*/
23     void            *context;/*回調函數的參數*/
24     unsigned        actual_length;/*此次傳輸的實際長度,這個長度包括了此消息spi_message中所有傳輸段spi_transfer傳輸的長度之和(不管每個傳
25     輸段spi_transfer到底是輸入還是輸出,因為本來具體的傳輸就是針對每一個傳輸段spi_transfer來進行的)*/
26     int            status;/*執行的結果.成功被置0,否則是一個負的錯誤碼*/
27 
28     /* for optional use by whatever driver currently owns the
29      * spi_message ...  between calls to spi_async and then later
30      * complete(), that's the spi_master controller driver.
31      */
32     /*下面兩個成員是給擁有本消息的驅動選用的.spi_master會使用它們.自己最好不要使用*/
33     struct list_head    queue;/*用於將該message鏈入bitbang等待隊列*/
34     void            *state;
35 };

spi_bitbang

struct spi_bitbang結構用於控制實際的數據傳輸.

 1 struct spi_bitbang {
 2     struct workqueue_struct    *workqueue;/*工作隊列*/
 3     struct work_struct    work;
 4 
 5     spinlock_t        lock;
 6     struct list_head    queue;
 7     u8            busy;
 8     u8            use_dma;
 9     u8            flags;        /* extra spi->mode support */
10 
11     struct spi_master    *master;/*bitbang所屬的master*/
12 
13     /* setup_transfer() changes clock and/or wordsize to match settings
14      * for this transfer; zeroes restore defaults from spi_device.
15      */
16     int    (*setup_transfer)(struct spi_device *spi,
17             struct spi_transfer *t);/*用於設置設備傳輸時的時鍾,字長等*/
18 
19     void    (*chipselect)(struct spi_device *spi, int is_on);
20 #define    BITBANG_CS_ACTIVE    1    /* normally nCS, active low */
21 #define    BITBANG_CS_INACTIVE    0
22 
23     /* txrx_bufs() may handle dma mapping for transfers that don't
24      * already have one (transfer.{tx,rx}_dma is zero), or use PIO
25      */
26     int    (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
27 
28     /* txrx_word[SPI_MODE_*]() just looks like a shift register */
29     u32    (*txrx_word[4])(struct spi_device *spi,
30             unsigned nsecs,
31             u32 word, u8 bits);
32 };

本文引用:http://blog.csdn.net/yuanlulu/article/details/6318165

http://blog.csdn.net/vanbreaker/article/details/7733476

http://blog.csdn.net/wuhzossibility/article/details/7868000


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM