SPI总线子系统

来源:互联网 发布:org.apache.ant jar 编辑:程序博客网 时间:2024/06/18 16:05

一 主要数据结构

[cpp] view plain copy
  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。

[cpp] view plain copy
  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;与硬件上的物理总线相对应。它的通信方法没有另外定义结构;而是集成到自己内部了。
[cpp] view plain copy
  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,是没有存在意义的。
[cpp] view plain copy
  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. };  
[cpp] view plain copy
  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。

[cpp] view plain copy
  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已经实现的就略过,否则需要用内核提供的一套机制。
[cpp] view plain copy
  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,是基于排队提交的。
[cpp] view plain copy
  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的调度策略为实现级别。未设置保持默认优先级。

[cpp] view plain copy
  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);
[cpp] view plain copy
  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));
[cpp] view plain copy
  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已经运行起来了。
[cpp] view plain copy
  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,是不阻塞的;同步机制需要另外实现。
[cpp] view plain copy
  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其中之一。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 健身教练岁数大了以后怎么办 超变战陀玩具手柄坏了怎么办 飓风战魂三陀螺中轴坏了怎么办 怎么办晚安角和铁陀螺 白衣服染上荧光剂了怎么办 指尖陀螺不亮了怎么办 手指陀螺不转了怎么办 月经推迟私处还老是流水怎么办 苹果手机刷机后忘记id密码怎么办 锤基意外怀孕怎么办零6 职场遇到心机婊怎么办 高二会考没过怎么办 保险柜没电了打不开怎么办 保险柜没有电了打不开怎么办 小保险箱没电了怎么办 bim墙的颜色反了怎么办 眼睛大但是无神怎么办 吃了凉的胃难受怎么办 吃凉东西胃疼怎么办 游戏只有一个分辨率选项怎么办 玩游戏心态易崩怎么办 打游戏心态炸了怎么办 赛鸽比赛回来拉稀怎么办 鸽子拉竹节水便怎么办 新买的鸽子拉稀怎么办 信鸽羽毛上长了虫子怎么办 羊肉煮熟了太硬怎么办 切菜不小心切到手指怎么办 打荷盘子端错了怎么办 学厨师不会翻锅怎么办? 在饭店上班不给工资怎么办 炒菜的左手拿不起锅怎么办?? 厨师想尽快上手炒菜怎么办? 空调吹的肩膀痛怎么办 学厨师翻锅不会怎么办 肋软骨隆鼻太硬怎么办 百度云下载速度慢怎么办 买的种子没出怎么办 铃木小r烧整流器怎么办 厨师在厨房太热怎么办 被家长投诉体罚孩子怎么办