SPI总线子系统

本文深入解析SPI总线的数据结构如spi_device和spi_master,介绍主要函数接口如spi_match_device及spi_register_master,并探讨spi同步与异步传输的区别。此外,还详细分析了SPI总线的注册过程以及驱动程序开发的基本步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 主要数据结构

  1. struct spi_device {  
  2.     struct device       dev;  
  3.     struct spi_master   *master;  
  4.     u32         max_speed_hz;  
  5.     u8          chip_select;  
  6.     u8          mode;  
  7. #define SPI_CPHA    0x01            /* clock phase */  
  8. #define SPI_CPOL    0x02            /* clock polarity */  
  9. #define SPI_MODE_0  (0|0)           /* (original MicroWire) */  
  10. #define SPI_MODE_1  (0|SPI_CPHA)  
  11. #define SPI_MODE_2  (SPI_CPOL|0)  
  12. #define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)  
  13. #define SPI_CS_HIGH 0x04            /* chipselect active high? */  
  14. #define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */  
  15. #define SPI_3WIRE   0x10            /* SI/SO signals shared */  
  16. #define SPI_LOOP    0x20            /* loopback mode */  
  17. #define SPI_NO_CS   0x40            /* 1 dev/bus, no chipselect */  
  18. #define SPI_READY   0x80            /* slave pulls low to pause */  
  19.     u8          bits_per_word;  
  20.     int         irq;  
  21.     void            *controller_state;  
  22.     void            *controller_data;  
  23.     char            modalias[SPI_NAME_SIZE];  
  24.     int         cs_gpio;    /* chip select gpio */  
  25.   
  26.     /* 
  27.      * likely need more hooks for more protocol options affecting how 
  28.      * the controller talks to each chip, like: 
  29.      *  - memory packing (12 bit samples into low bits, others zeroed) 
  30.      *  - priority 
  31.      *  - drop chipselect after each word 
  32.      *  - chipselect delays 
  33.      *  - ... 
  34.      */  
  35. };  

spi从设备,相当于i2c_client。它需要依附一个spi_master。

  1. struct spi_master {  
  2.     struct device   dev;  
  3.   
  4.     struct list_head list;  
  5.   
  6.     /* other than negative (== assign one dynamically), bus_num is fully 
  7.      * board-specific.  usually that simplifies to being SOC-specific. 
  8.      * example:  one SOC has three SPI controllers, numbered 0..2, 
  9.      * and one board's schematics might show it using SPI-2.  software 
  10.      * would normally use bus_num=2 for that controller. 
  11.      */  
  12.     s16         bus_num;  
  13.   
  14.     /* chipselects will be integral to many controllers; some others 
  15.      * might use board-specific GPIOs. 
  16.      */  
  17.     u16         num_chipselect;  
  18.   
  19.     /* some SPI controllers pose alignment requirements on DMAable 
  20.      * buffers; let protocol drivers know about these requirements. 
  21.      */  
  22.     u16         dma_alignment;  
  23.   
  24.     /* spi_device.mode flags understood by this controller driver */  
  25.     u16         mode_bits;  
  26.   
  27.     /* other constraints relevant to this driver */  
  28.     u16         flags;  
  29. #define SPI_MASTER_HALF_DUPLEX  BIT(0)      /* can't do full duplex */  
  30. #define SPI_MASTER_NO_RX    BIT(1)      /* can't do buffer read */  
  31. #define SPI_MASTER_NO_TX    BIT(2)      /* can't do buffer write */  
  32.   
  33.     /* lock and mutex for SPI bus locking */  
  34.     spinlock_t      bus_lock_spinlock;  
  35.     struct mutex        bus_lock_mutex;  
  36.   
  37.     /* flag indicating that the SPI bus is locked for exclusive use */  
  38.     bool            bus_lock_flag;  
  39.   
  40.     /* Setup mode and clock, etc (spi driver may call many times). 
  41.      * 
  42.      * IMPORTANT:  this may be called when transfers to another 
  43.      * device are active.  DO NOT UPDATE SHARED REGISTERS in ways 
  44.      * which could break those transfers. 
  45.      */  
  46.     int         (*setup)(struct spi_device *spi);  
  47.   
  48.     /* bidirectional bulk transfers 
  49.      * 
  50.      * + The transfer() method may not sleep; its main role is 
  51.      *   just to add the message to the queue. 
  52.      * + For now there's no remove-from-queue operation, or 
  53.      *   any other request management 
  54.      * + To a given spi_device, message queueing is pure fifo 
  55.      * 
  56.      * + The master's main job is to process its message queue, 
  57.      *   selecting a chip then transferring data 
  58.      * + If there are multiple spi_device children, the i/o queue 
  59.      *   arbitration algorithm is unspecified (round robin, fifo, 
  60.      *   priority, reservations, preemption, etc) 
  61.      * 
  62.      * + Chipselect stays active during the entire message 
  63.      *   (unless modified by spi_transfer.cs_change != 0). 
  64.      * + The message transfers use clock and SPI mode parameters 
  65.      *   previously established by setup() for this device 
  66.      */  
  67.     int         (*transfer)(struct spi_device *spi,  
  68.                         struct spi_message *mesg);  
  69.   
  70.     /* called on release() to free memory provided by spi_master */  
  71.     void            (*cleanup)(struct spi_device *spi);  
  72.   
  73.     /* 
  74.      * These hooks are for drivers that want to use the generic 
  75.      * master transfer queueing mechanism. If these are used, the 
  76.      * transfer() function above must NOT be specified by the driver. 
  77.      * Over time we expect SPI drivers to be phased over to this API. 
  78.      */  
  79.     bool                queued;  
  80.     struct kthread_worker       kworker;  
  81.     struct task_struct      *kworker_task;  
  82.     struct kthread_work     pump_messages;  
  83.     spinlock_t          queue_lock;  
  84.     struct list_head        queue;  
  85.     struct spi_message      *cur_msg;  
  86.     bool                busy;  
  87.     bool                running;  
  88.     bool                rt;  
  89.   
  90.     int (*prepare_transfer_hardware)(struct spi_master *master);  
  91.     int (*transfer_one_message)(struct spi_master *master,  
  92.                     struct spi_message *mesg);  
  93.     int (*unprepare_transfer_hardware)(struct spi_master *master);  
  94.     /* gpio chip select */  
  95.     int         *cs_gpios;  
  96. };  
spi_master代表一个spi主设备,相当于i2c_adapter;与硬件上的物理总线相对应。它的通信方法没有另外定义结构;而是集成到自己内部了。
  1. struct spi_driver {  
  2.     const struct spi_device_id *id_table;  
  3.     int         (*probe)(struct spi_device *spi);  
  4.     int         (*remove)(struct spi_device *spi);  
  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. };  
driver都需要和device进行bound,不为device服务的drvier,是没有存在意义的。
  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;  
  8.     void        *rx_buf;  
  9.     unsigned    len;  
  10.   
  11.     dma_addr_t  tx_dma;  
  12.     dma_addr_t  rx_dma;  
  13.   
  14.     unsigned    cs_change:1;  
  15.     u8      bits_per_word;  
  16.     u16     delay_usecs;  
  17.     u32     speed_hz;  
  18.   
  19.     struct list_head transfer_list;  
  20. };  
  1. struct spi_message {  
  2.     struct list_head    transfers;  
  3.   
  4.     struct spi_device   *spi;  
  5.   
  6.     unsigned        is_dma_mapped:1;  
  7.   
  8.     /* REVISIT:  we might want a flag affecting the behavior of the 
  9.      * last transfer ... allowing things like "read 16 bit length L" 
  10.      * immediately followed by "read L bytes".  Basically imposing 
  11.      * a specific message scheduling algorithm. 
  12.      * 
  13.      * Some controller drivers (message-at-a-time queue processing) 
  14.      * could provide that as their default scheduling algorithm.  But 
  15.      * others (with multi-message pipelines) could need a flag to 
  16.      * tell them about such special cases. 
  17.      */  
  18.   
  19.     /* completion is reported through a callback */  
  20.     void            (*complete)(void *context);  
  21.     void            *context;  
  22.     unsigned        actual_length;  
  23.     int         status;  
  24.   
  25.     /* for optional use by whatever driver currently owns the 
  26.      * spi_message ...  between calls to spi_async and then later 
  27.      * complete(), that's the spi_master controller driver. 
  28.      */  
  29.     struct list_head    queue;  
  30.     void            *state;  
  31. };  

spi_transfer定义了一对读写buffer,还有一个transfer_list;利用这个list把自己挂在spi_message的transfers上,也就是这两个结构合起来相当于i2c_msg。spi的传输单位就是一个spi_message。

  1. struct spi_board_info {  
  2.     /* the device name and module name are coupled, like platform_bus; 
  3.      * "modalias" is normally the driver name. 
  4.      * 
  5.      * platform_data goes to spi_device.dev.platform_data, 
  6.      * controller_data goes to spi_device.controller_data, 
  7.      * irq is copied too 
  8.      */  
  9.     char        modalias[SPI_NAME_SIZE];  
  10.     const void  *platform_data;  
  11.     void        *controller_data;  
  12.     int     irq;  
  13.   
  14.     /* slower signaling on noisy or low voltage boards */  
  15.     u32     max_speed_hz;  
  16.   
  17.   
  18.     /* bus_num is board specific and matches the bus_num of some 
  19.      * spi_master that will probably be registered later. 
  20.      * 
  21.      * chip_select reflects how this chip is wired to that master; 
  22.      * it's less than num_chipselect. 
  23.      */  
  24.     u16     bus_num;  
  25.     u16     chip_select;  
  26.   
  27.     /* mode becomes spi_device.mode, and is essential for chips 
  28.      * where the default of SPI_CS_HIGH = 0 is wrong. 
  29.      */  
  30.     u8      mode;  
  31.   
  32.     /* ... may need additional spi_device chip config data here. 
  33.      * avoid stuff protocol drivers can set; but include stuff 
  34.      * needed to behave without being bound to a driver: 
  35.      *  - quirks like clock rate mattering when not selected 
  36.      */  
  37. };  
spi device的info,与i2c_board_info类似。

 

二 主要函数接口

static int spi_match_device(struct device *dev, struct device_driver *drv)

相当于i2c_device_match(),i2c_device_match()->i2c_match_id()->strcmp(client->name, id->name)匹配成功返回1,否则0,结束。
spi_match_device()->spi_match_id()->strcmp(sdev->modalias, id->name))仍然是匹配成功返回1,否则返回0。不同的是,对应i2c_device_match(),如果i2c_drvier中没有定义id_table,那直接就返回0了。而spi不是,它还会继续strcmp(spi->modalias, drv->name)根据这个确定返回值。所以我们看到i2c_driver中都会定义id_table,而spi_driver有时不定义,只保证pi->modalias和drv->name一致就好了。

struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip)

调用spi_alloc_device(master)分配一个spi_device;
调用spi_add_device(proxy)把分配的spi_device添加到系统中,spi_device是一种device,添加device必然会调用 device_add(&spi->dev)。
spi_add_device()->spi_setup(spi)->( spi->master->setup(spi)这是用于设置spi的mode和clock等;spi有四种模式。

int spi_register_board_info(struct spi_board_info const *info, unsigned n)

和i2c差不多,新出现的boardinfo是对spi_board_info的一个封装;register会把自己挂在一个全局的board_list上。与i2c不同的是,此时spi就会遍历spi_master_list,根据bus_num进行master和device的匹配,匹配成功就new device。如果主设备已经register,对于spi来说只要调用register_board_info,就可以自动new spi_device了;而i2c需要手动的调用i2c_new_device。

int spi_register_master(struct spi_master *master)

spi_master是个device,所以还会用device_add();而且会把自己挂在spi_master_list全局的list上,这样register board info的时候才能找到这个master;当然,此时也会遍历board_list,找到匹配的info,创建spi device。这个函数中还有一段:
if (master->transfer)
dev_info(dev, "master is unqueued, this is deprecated\n");
else {
status = spi_master_initialize_queue(master);
if (status) {
device_unregister(&master->dev);
goto done;
}
}
master->transfer已经实现的就略过,否则需要用内核提供的一套机制。
  1. static int spi_master_initialize_queue(struct spi_master *master)  
  2. {  
  3.     int ret;  
  4.   
  5.     master->queued = true;  
  6.     master->transfer = spi_queued_transfer;  
  7.   
  8.     /* Initialize and start queue */  
  9.     ret = spi_init_queue(master);  
  10.     if (ret) {  
  11.         dev_err(&master->dev, "problem initializing queue\n");  
  12.         goto err_init_queue;  
  13.     }  
  14.     ret = spi_start_queue(master);  
  15.     if (ret) {  
  16.         dev_err(&master->dev, "problem starting queue\n");  
  17.         goto err_start_queue;  
  18.     }  
  19.   
  20.     return 0;  
  21.   
  22. err_start_queue:  
  23. err_init_queue:  
  24.     spi_destroy_queue(master);  
  25.     return ret;  
  26. }  
果然提供了一个传输函数 spi_queued_transfer,是基于排队提交的。
  1. static int spi_init_queue(struct spi_master *master)  
  2. {  
  3.     struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };  
  4.   
  5.     INIT_LIST_HEAD(&master->queue);  
  6.     spin_lock_init(&master->queue_lock);  
  7.   
  8.     master->running = false;  
  9.     master->busy = false;  
  10.   
  11.     init_kthread_worker(&master->kworker);  
  12.     master->kworker_task = kthread_run(kthread_worker_fn,  
  13.                        &master->kworker,  
  14.                        dev_name(&master->dev));  
  15.     if (IS_ERR(master->kworker_task)) {  
  16.         dev_err(&master->dev, "failed to create message pump task\n");  
  17.         return -ENOMEM;  
  18.     }  
  19.     init_kthread_work(&master->pump_messages, spi_pump_messages);  
  20.   
  21.     /* 
  22.      * Master config will indicate if this controller should run the 
  23.      * message pump with high (realtime) priority to reduce the transfer 
  24.      * latency on the bus by minimising the delay between a transfer 
  25.      * request and the scheduling of the message pump thread. Without this 
  26.      * setting the message pump thread will remain at default priority. 
  27.      */  
  28.     if (master->rt) {  
  29.         dev_info(&master->dev,  
  30.             "will run message pump with realtime priority\n");  
  31.         sched_setscheduler(master->kworker_task, SCHED_FIFO, ¶m);  
  32.     }  
  33.   
  34.     return 0;  
  35. }  

init_kthread_worker(&master->kworker);初始化一个线程工作者,其结构中会包含当前线程工作项;主要初始化worker->lock、worker->work_list和worker->task。
master->kworker_task创建了一个线程;线程函数是kthread_worker_fn,该函数的参数是&master->kworker;线程name是dev_name(&master->dev)。
init_kthread_work(&master->pump_messages, spi_pump_messages);这个就是线程工作项了,其结构会依附一个线程工作者;这里初始化了&(work)->node,这个一个list,可能是要把自己挂在线程工作者的work_list上。
(work)->func = (fn);spi_pump_messages就是线程工作项的工作函数了。
master->rt是realtime标志,若设置表示高优先级的信息处理,有必要减少传输等待时间,把传输请求和信息pump线程之间的延时缩短最小;所以需要调用sched_setscheduler()改变thread的调度策略为实现级别。未设置保持默认优先级。

  1. static int spi_start_queue(struct spi_master *master)  
  2. {  
  3.     unsigned long flags;  
  4.   
  5.     spin_lock_irqsave(&master->queue_lock, flags);  
  6.   
  7.     if (master->running || master->busy) {  
  8.         spin_unlock_irqrestore(&master->queue_lock, flags);  
  9.         return -EBUSY;  
  10.     }  
  11.   
  12.     master->running = true;  
  13.     master->cur_msg = NULL;  
  14.     spin_unlock_irqrestore(&master->queue_lock, flags);  
  15.   
  16.     queue_kthread_work(&master->kworker, &master->pump_messages);  
  17.   
  18.     return 0;  
  19. }  
queue_kthread_work(&master->kworker, &master->pump_messages);
insert_kthread_work(worker, work, &worker->work_list);
  1. static void insert_kthread_work(struct kthread_worker *worker,  
  2.                    struct kthread_work *work,  
  3.                    struct list_head *pos)  
  4. {  
  5.     lockdep_assert_held(&worker->lock);  
  6.   
  7.     list_add_tail(&work->node, pos);  
  8.     work->worker = worker;  
  9.     if (likely(worker->task))  
  10.         wake_up_process(worker->task);  
  11. }  
果然work把自己挂在了work_list上,work也就找到了依附的worker;如果worker->task当前有任务,就wake_up_process(worker->task)。
该初始化的kwoker、work、task都初始好了;现在内核里有一个线程运行起来了。
master->kworker_task = kthread_run(kthread_worker_fn, &master->kworker, dev_name(&master->dev));
  1. int kthread_worker_fn(void *worker_ptr)  
  2. {  
  3.     struct kthread_worker *worker = worker_ptr;  
  4.     struct kthread_work *work;  
  5.   
  6.     WARN_ON(worker->task);  
  7.     worker->task = current;  
  8. repeat:  
  9.     set_current_state(TASK_INTERRUPTIBLE);  /* mb paired w/ kthread_stop */  
  10.   
  11.     if (kthread_should_stop()) {  
  12.         __set_current_state(TASK_RUNNING);  
  13.         spin_lock_irq(&worker->lock);  
  14.         worker->task = NULL;  
  15.         spin_unlock_irq(&worker->lock);  
  16.         return 0;  
  17.     }  
  18.   
  19.     work = NULL;  
  20.     spin_lock_irq(&worker->lock);  
  21.     if (!list_empty(&worker->work_list)) {  
  22.         work = list_first_entry(&worker->work_list,  
  23.                     struct kthread_work, node);  
  24.         list_del_init(&work->node);  
  25.     }  
  26.     worker->current_work = work;  
  27.     spin_unlock_irq(&worker->lock);  
  28.   
  29.     if (work) {  
  30.         __set_current_state(TASK_RUNNING);  
  31.         work->func(work);  
  32.     } else if (!freezing(current))  
  33.         schedule();  
  34.   
  35.     try_to_freeze();  
  36.     goto repeat;  
  37. }  
这里会遍历&worker->work_list,找到上面依附的work并删除(不删除就会重复执行了)后执行work->func(work);如果已经没有线程工作项了,会schedule();休眠。根据前面的一系列初始化,这个work就是spi_start_queue()->queue_kthread_work(&master->kworker, &master->pump_messages)->insert_kthread_work()->list_add_tail(&work->node, pos);挂上来的&master->pump_messages;它的线程工作者函数是spi_init_queue(&master->pump_messages, spi_pump_messages)->init_kthread_work()->((work)->func = (fn))填充的spi_pump_messages。到目前为止spi_pump_messages已经运行起来了。
  1. static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)  
  2. {  
  3.     struct spi_master *master = spi->master;  
  4.     unsigned long flags;  
  5.   
  6.     spin_lock_irqsave(&master->queue_lock, flags);  
  7.   
  8.     if (!master->running) {  
  9.         spin_unlock_irqrestore(&master->queue_lock, flags);  
  10.         return -ESHUTDOWN;  
  11.     }  
  12.     msg->actual_length = 0;  
  13.     msg->status = -EINPROGRESS;  
  14.   
  15.     list_add_tail(&msg->queue, &master->queue);  
  16.     if (master->running && !master->busy)  
  17.         queue_kthread_work(&master->kworker, &master->pump_messages);  
  18.   
  19.     spin_unlock_irqrestore(&master->queue_lock, flags);  
  20.     return 0;  
  21. }  
插入一下master->transfer = spi_queued_transfer;
1 把自己挂到&master->queue。
2 master->running为true确保master已经启动,master->busy为false确保mster不忙,queue_kthread_work()->insert_kthread_work()->(&work->node, pos),这样kthread_worker_fn线程函数里才能找到这个work,然后执行spi_pump_messages(),提交message;这个动作和spi_start_queue()差不多。
3 如果此时master->running为false,master未启动直接return了;如果此时已启动但是master->busy是true的,就只把msg挂到了&master->queue上,那什么时候queue_kthread_work呢?如果&master->queue一下挂了很多msg怎么办呢?按照排队的方式,就是每调用一次master->transfer,处理一个msg,是不阻塞的;同步机制需要另外实现。
  1. static void spi_pump_messages(struct kthread_work *work)  
  2. {  
  3.     struct spi_master *master =  
  4.         container_of(work, struct spi_master, pump_messages);  
  5.     unsigned long flags;  
  6.     bool was_busy = false;  
  7.     int ret;  
  8.   
  9.     /* Lock queue and check for queue work */  
  10.     spin_lock_irqsave(&master->queue_lock, flags);  
  11.     if (list_empty(&master->queue) || !master->running) {  
  12.         if (master->busy && master->unprepare_transfer_hardware) {  
  13.             ret = master->unprepare_transfer_hardware(master);  
  14.             if (ret) {  
  15.                 spin_unlock_irqrestore(&master->queue_lock, flags);  
  16.                 dev_err(&master->dev,  
  17.                     "failed to unprepare transfer hardware\n");  
  18.                 return;  
  19.             }  
  20.         }  
  21.         master->busy = false;  
  22.         spin_unlock_irqrestore(&master->queue_lock, flags);  
  23.         return;  
  24.     }  
  25.   
  26.     /* Make sure we are not already running a message */  
  27.     if (master->cur_msg) {  
  28.         spin_unlock_irqrestore(&master->queue_lock, flags);  
  29.         return;  
  30.     }  
  31.     /* Extract head of queue */  
  32.     master->cur_msg =  
  33.         list_entry(master->queue.next, struct spi_message, queue);  
  34.   
  35.     list_del_init(&master->cur_msg->queue);  
  36.     if (master->busy)  
  37.         was_busy = true;  
  38.     else  
  39.         master->busy = true;  
  40.     spin_unlock_irqrestore(&master->queue_lock, flags);  
  41.   
  42.     if (!was_busy && master->prepare_transfer_hardware) {  
  43.         ret = master->prepare_transfer_hardware(master);  
  44.         if (ret) {  
  45.             dev_err(&master->dev,  
  46.                 "failed to prepare transfer hardware\n");  
  47.             return;  
  48.         }  
  49.     }  
  50.   
  51.     ret = master->transfer_one_message(master, master->cur_msg);  
  52.     if (ret) {  
  53.         dev_err(&master->dev,  
  54.             "failed to transfer one message from queue\n");  
  55.         return;  
  56.     }  
  57. }  
接着回来spi_pump_messages()。
1 &master->queue为空说明没有message;master->running为false说明还未开始spi_start_queue(),这个master还未启动了;无论是没有message,还是未启动master->busy = false都是成立的,直接return。
2 如果master->cur_msg不为空说明已经有message在运行了,直接return,所以在驱动中message传输完需要master->cur_msg = NULL;;否则找一个message,怎么找的呢?到master->queue上找,(master->transfer = spi_queued_transfer就是这里挂上的)。找到后从master->queue上删除,否则会重复发送这个message。
3 master->busy则was_busy就为true,否则要更改master->busy从false到true。只根据was_busy来判断master->prepare_transfer_hardware()执行与否,为什么master->transfer_one_message()不用判断?难道要根据transfer_one_message()中check到master的状态直接return。
4 ret = master->transfer_one_message(master, master->cur_msg),这种方式的msg提交需要驱动实现 master->transfer_one_message()函数,别忘了master->cur_msg = NULL,否则下一个msg永远都别想提交了。

spi_queued_transfer机制总结:

1 内核提供了通用的master->transfer = spi_queued_transfer,其调用方式与驱动中实现该函数是一样的,只是现在驱动中需要实现的是master->transfer_one_message()。
2 spi_queued_transfer负责把massage信息挂到&master->queue这个list上,然后&master->pump_messages这个work挂在&master->kworker的work_list上。
3 spi_master_initialize_queue()->spi_init_queue() run了一个线程,kthread_worker_fn会遍历&master->kworker->work_list上的work,执行其工作函数。
4 上述的工作函数是spi_init_queue()->init_kthread_work()初始化的,就是spi_pump_messages。
5 spi_pump_messages()中会遍历&master->queue找到message,提交message。
6 只有kthread_worker_fn是一直在跑的,spi_pump_messages()依赖于调用master->transfer;只有执行过spi_queued_transfer,work才会挂到worker上,spi_pump_messages()才能运行;有了message,spi_pump_messages()才能成功提交。

int spi_sync(struct spi_device *spi, struct spi_message *message)

{
return __spi_sync(spi, message, 0);
}

int spi_async(struct spi_device *spi, struct spi_message *message)

spi的同步和异步传输,同步和异步的区别在哪里?spi异步:提交完message就马上返回;不会睡眠,可以在中断上下文等不可休眠的场合使用。但是需要complete同步机制,在wait_for_completion期间,不能操作message中的信息。spi同步:就是使用异步使用的一个实例,提交message后不会立即返回,应用complete进行休眠,一直等到处理完成。 spi_sync比较常用,需要注意的是在master->transfer(spi, message)函数中要调用message->complete(message->context)来更新完成量的状态,否则wait_for_completion永远也等不到同步信号;会一直睡下去的。
__spi_sync()->spi_async_locked()->__spi_async()->(master->transfer(spi, message))

int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx)

spi同步写然后读;这个spi_sync()的一个应用实例。
1 确定一个local_buf,这个buf里要存储的是txbuf+rxbuf的数据,要求(n_tx + n_rx)>=SPI_BUFSIZ(32)。如果小于也会扩展为32。
(n_tx + n_rx) > SPI_BUFSIZ,local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL);
否则,local_buf = buf;这个buf的malloc在spi_init()->buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
2 初始化message,把spi_transfer x[2]挂在message上。
3 填充x[0].tx_buf和x[1].rx_buf结构,就是local_buf的前段和后段;x[0]是用于发送的,所以不需要rx_buf,同理x[1]不需要tx_buf。
4 spi_sync()提交message,memcpy(rxbuf, x[1].rx_buf, n_rx);。
5 善后处理,unlock、free。
 

三 spi总线注册

postcore_initcall(spi_init);
spi总线设备,注册等级2级。
spi_init()中malloc了一个buf,当n_tx + n_rx<= SPI_BUFSIZ时;
local_buf = buf;//local_buf 也是个中转站。
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
status = bus_register(&spi_bus_type);注册一个子系统。
 

四 spi驱动程序开发

1 spi_register_master(master);注册一个master;
2 实现master->transfer或者master->transfer_one_message其中之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值