Chinaunix首页 | 论坛 | 博客
  • 博客访问: 151395
  • 博文数量: 25
  • 博客积分: 165
  • 博客等级: 入伍新兵
  • 技术积分: 460
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-15 19:24
文章分类

全部博文(25)

文章存档

2013年(21)

2012年(4)

我的朋友

分类: LINUX

2013-03-22 14:22:58

linux spi驱动开发学习(一)-----spi子系统架构

一.spi设备(各定义在include/linux/spi.h)

  1. struct spi_device {  
  2.     struct device   dev;    //设备文件  
  3.     struct spi_master   *master;    //spi主机  
  4.     u32 max_speed_hz;   //最大速率  
  5.     u8  chip_select;    //片选  
  6.     u8  mode;   //模式  
  7.     u8  bits_per_word;  //一个字有多少位  
  8.     int irq;    //中断号  
  9.     void    *controller_state;  //控制器状态  
  10.     void    *controller_data;   //控制器数据  
  11.     char    modalias[SPI_NAME_SIZE];//名字  
  12. };  


2.spi传输模式:

  1. #define SPI_CPHA        0x01            //时钟相位  
  2. #define SPI_CPOL        0x02            //时钟继续  
  3. #define SPI_MODE_0  (0|0)           //模式0  
  4. #define SPI_MODE_1  (0|SPI_CPHA)    //模式1  
  5. #define SPI_MODE_2  (SPI_CPOL|0)    //模式2  
  6. #define SPI_MODE_3  (SPI_CPOL|SPI_CPHA) //模式3  
  7. #define SPI_CS_HIGH 0x04            //片选高电平  
  8. #define SPI_LSB_FIRST   0x08            //LSB  
  9. #define SPI_3WIRE       0x10            //3线模式 SI和SO同一根线  
  10. #define SPI_LOOP        0x20            //回送模式  
  11. #define SPI_NO_CS       0x40            //单个设备占用一根SPI总线,所以没片选  
  12. #define SPI_READY       0x80            //从机拉低电平停止数据传输  


3.spi设备的添加spi_new_device

  1. struct spi_device *spi_new_device(struct spi_master *master,struct spi_board_info *chip)  
  2. {  
  3.     struct spi_device   *proxy;  
  4.     int status;  
  5.       
  6.     proxy = spi_alloc_device(master);   //3.1 spi设备初始化  
  7.     if (!proxy)  
  8.         return NULL;  
  9.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));  
  10.     proxy->chip_select = chip->chip_select;   //片选  
  11.     proxy->max_speed_hz = chip->max_speed_hz; //最大速率  
  12.     proxy->mode = chip->mode; //模式  
  13.     proxy->irq = chip->irq;   //中断号  
  14.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));  
  15.     proxy->dev.platform_data = (void *) chip->platform_data;  
  16.     proxy->controller_data = chip->controller_data;  
  17.     proxy->controller_state = NULL;  
  18.     status = spi_add_device(proxy); //3.2 添加spi设备  
  19.     if (status < 0) {  
  20.         spi_dev_put(proxy); //增加spi设备引用计数  
  21.         return NULL;  
  22.     }  
  23.     return proxy;  
  24. }  
  25. EXPORT_SYMBOL_GPL(spi_new_device);  

 

3.1.分配spi设备

  1. struct spi_device *spi_alloc_device(struct spi_master *master)  
  2. {  
  3.     struct spi_device   *spi;  
  4.     struct device       *dev = master->dev.parent;  
  5.   
  6.     if (!spi_master_get(master))    //判断spi主机是否存在  
  7.         return NULL;  
  8.     spi = kzalloc(sizeof *spi, GFP_KERNEL); //分配内存  
  9.     if (!spi) {  
  10.         dev_err(dev, "cannot alloc spi_device\n");  
  11.         spi_master_put(master); //增加主机引用计数  
  12.         return NULL;  
  13.     }  
  14.     spi->master = master;    //设置spi主机  
  15.     spi->dev.parent = dev;   //spi设备文件的父设备为spi主机设备文件的父设备  
  16.     spi->dev.bus = &spi_bus_type;    //总线类型  
  17.     spi->dev.release = spidev_release;   //释放方法  
  18.     device_initialize(&spi->dev);    //设备初始化  
  19.     return spi;  
  20. }  
  21. EXPORT_SYMBOL_GPL(spi_alloc_device);  


3.2 添加spi设备

  1. int spi_add_device(struct spi_device *spi)  
  2. {  
  3.     static DEFINE_MUTEX(spi_add_lock);  
  4.     struct device *dev = spi->master->dev.parent;  
  5.     struct device *d;  
  6.     int status;  
  7.   
  8.     if (spi->chip_select >= spi->master->num_chipselect) {  
  9.         dev_err(dev, "cs%d >= max %d\n",spi->chip_select,spi->master->num_chipselect);  
  10.         return -EINVAL;  
  11.     }  
  12.     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),spi->chip_select);  
  13.     mutex_lock(&spi_add_lock);  
  14.     d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));   //查找总线上的spi设备  
  15.     if (d != NULL) {    //判断是否已经在使用了  
  16.         dev_err(dev, "chipselect %d already in use\n",spi->chip_select);  
  17.         put_device(d);  
  18.         status = -EBUSY;  
  19.         goto done;  
  20.     }  
  21.     status = spi_setup(spi);    //调用spi主机 setup方法  
  22.     if (status < 0) {  
  23.         dev_err(dev, "can't setup %s, status %d\n",dev_name(&spi->dev), status);  
  24.         goto done;  
  25.     }  
  26.     status = device_add(&spi->dev);  //添加设备  
  27.     if (status < 0)  
  28.         dev_err(dev, "can't add %s, status %d\n",dev_name(&spi->dev), status);  
  29.     else  
  30.         dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));  
  31. done:  
  32.     mutex_unlock(&spi_add_lock);  
  33.     return status;  
  34. }  
  35. EXPORT_SYMBOL_GPL(spi_add_device);  


3.2.1 spi setup方法

  1. int spi_setup(struct spi_device *spi)  
  2. {  
  3.     unsigned    bad_bits;  
  4.     int status;  
  5.     bad_bits = spi->mode & ~spi->master->mode_bits;    //比较spi设备的模式和spi主机支持的模式  
  6.     if (bad_bits) { //存在不支持的模式  
  7.         dev_err(&spi->dev, "setup: unsupported mode bits %x\n",bad_bits);  
  8.         return -EINVAL;  
  9.     }  
  10.     if (!spi->bits_per_word) //若没设置设备的每个字含多少位  
  11.         spi->bits_per_word = 8;  //则默认设置为8  
  12.   
  13.     status = spi->master->setup(spi); //调用spi主机的setup方法  
  14.   
  15.     dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s""%u bits/w, %u Hz max --> %d\n",  
  16.             (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",  
  17.             (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",(spi->mode & SPI_3WIRE) ? "3wire, " : "",  
  18.             (spi->mode & SPI_LOOP) ? "loopback, " : "",spi->bits_per_word, spi->max_speed_hz,status);  
  19.     return status;  
  20. }  
  21. EXPORT_SYMBOL_GPL(spi_setup);  


二.spi板级设备

1.板级设备结构体

  1. struct spi_board_info {  
  2.     char    modalias[SPI_NAME_SIZE];    //名字  
  3.     const void  *platform_data; //平台数据  
  4.     void    *controller_data;   //控制器数据  
  5.     int irq;            //中断号  
  6.     u32 max_speed_hz;   //最大速率  
  7.     u16 bus_num;        //spi总线编号  
  8.     u16 chip_select;    //片选  
  9.     u8  mode;           //模式  
  10. };  

 

2.板级设备注册(静态注册,一般在板级初始化函数中调用)

  1. int __init 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);  //分配内存  
  7.     if (!bi)  
  8.         return -ENOMEM;  
  9.     for (i = 0; i < n; i++, bi++, info++) {  
  10.         struct spi_master *master;  
  11.         memcpy(&bi->board_info, info, sizeof(*info));    //设置bi的板级信息  
  12.         mutex_lock(&board_lock);  
  13.         list_add_tail(&bi->list, &board_list);   //添加bi->list到全局board_list链表  
  14.         list_for_each_entry(master, &spi_master_list, list) //遍历spi主机链表  
  15.             spi_match_master_to_boardinfo(master, &bi->board_info);  
  16.         mutex_unlock(&board_lock);  
  17.     }  
  18.     return 0;  
  19. }  


2.1.spi板级设备与spi主机匹配

  1. static void spi_match_master_to_boardinfo(struct spi_master *master,struct spi_board_info *bi)  
  2. {  
  3.     struct spi_device *dev;  
  4.     if (master->bus_num != bi->bus_num)  
  5.         return;  
  6.     dev = spi_new_device(master, bi);  
  7.     if (!dev)  
  8.         dev_err(master->dev.parent, "can't create new device for %s\n",bi->modalias);  
  9. }  


三.spi设备驱动

1.spi设备驱动结构体

  1. struct spi_driver {  
  2.     const struct spi_device_id *id_table;   //spi设备id表  
  3.     int     (*probe)(struct spi_device *spi);   //probe方法(探测到设备)  
  4.     int     (*remove)(struct spi_device *spi);  //remove方法(设备移除)  
  5.     void    (*shutdown)(struct spi_device *spi);    //shutdown方法(关闭设备)  
  6.     int     (*suspend)(struct spi_device *spi, pm_message_t mesg);  //suspend方法(挂起设备)  
  7.     int     (*resume)(struct spi_device *spi);  //resume方法(唤醒设备)  
  8.     struct device_driver    driver; //设备驱动文件  
  9. };  


2.spi设备驱动注册

  1. int spi_register_driver(struct spi_driver *sdrv)  
  2. {  
  3.     sdrv->driver.bus = &spi_bus_type;    //总线类型  
  4.     if (sdrv->probe) //若存在probe方法  
  5.         sdrv->driver.probe = spi_drv_probe;  //设置其设备驱动文件的probe方法为spi_drv_probe  
  6.     if (sdrv->remove)    //若存在remove方法  
  7.         sdrv->driver.remove = spi_drv_remove;    //设置其设备驱动文件的remove方法为spi_drv_remove  
  8.     if (sdrv->shutdown)  ////若存在shutdown方法  
  9.         sdrv->driver.shutdown = spi_drv_shutdown;    //设置其设备驱动文件的shutdown方法为spi_drv_shutdown  
  10.     return driver_register(&sdrv->driver);   //注册设备驱动  
  11. }  
  12. EXPORT_SYMBOL_GPL(spi_register_driver);  

这里的probe方法会在设备与驱动匹配的时候给调用
参看really_probe函数的部分代码

  1. if (dev->bus->probe) {        //若总线有probe方法(spi子系统的没有)  
  2.     ret = dev->bus->probe(dev);   //则调用总线的probe方法  
  3.     if (ret)  
  4.         goto probe_failed;  
  5. }   
  6. else if (drv->probe) {   //若存在设备驱动的probe方法  
  7.     ret = drv->probe(dev);       //则调用设备驱动的probe方法  
  8.     if (ret)  
  9.         goto probe_failed;  
  10. }  

 

2.1 spi_drv_probe

  1. static int spi_drv_probe(struct device *dev)  
  2. {  
  3.     const struct spi_driver *sdrv = to_spi_driver(dev->driver);  //根据设备文件的设备驱动找到spi设备驱动  
  4.     return sdrv->probe(to_spi_device(dev));  //调用spi设备驱动的probe方法  
  5. }  


3.spi设备驱动注销

  1. static inline void spi_unregister_driver(struct spi_driver *sdrv)  
  2. {  
  3.     if (sdrv)  
  4.         driver_unregister(&sdrv->driver);    //注销设备驱动  
  5. }  


四.spi主机

1.spi主机结构体

  1. struct spi_master {  
  2.     struct device   dev;    //spi主机设备文件  
  3.     struct list_head list;  
  4.     s16 bus_num;    //spi总线号  
  5.     u16 num_chipselect; //片选号  
  6.     u16 dma_alignment;  //dma算法  
  7.     u16 mode_bits;  //模式位  
  8.     u16 flags;  //传输类型标志  
  9.     spinlock_t  bus_lock_spinlock;  //spi总线自旋锁  
  10.     struct mutex    bus_lock_mutex; //spi总线互斥锁  
  11.     bool    bus_lock_flag;  //上锁标志  
  12.     int (*setup)(struct spi_device *spi);   //setup方法  
  13.     int (*transfer)(struct spi_device *spi,struct spi_message *mesg);   //传输方法  
  14.     void    (*cleanup)(struct spi_device *spi); //cleanup方法  
  15. };  


1.2.flags标志

  1. #define SPI_MASTER_HALF_DUPLEX  BIT(0)  //半双工  
  2. #define SPI_MASTER_NO_RX    BIT(1)      //不读  
  3. #define SPI_MASTER_NO_TX    BIT(2)      //不写  


2.spi主机初始化spi_alloc_master

  1. struct spi_master *spi_alloc_master(struct device *dev, unsigned size)  
  2. {  
  3.     struct spi_master   *master;  
  4.     if (!dev)  
  5.         return NULL;  
  6.     master = kzalloc(size + sizeof *master, GFP_KERNEL);    //分配内存  
  7.     if (!master)  
  8.         return NULL;  
  9.     device_initialize(&master->dev); //初始化主机设备文件  
  10.     master->dev.class = &spi_master_class;   //指定设备类spi_master_class  
  11.     master->dev.parent = get_device(dev);    //设置spi主机设备的父设备  
  12.     spi_master_set_devdata(master, &master[1]); //设置设备数据  
  13.     return master;  
  14. }  
  15. EXPORT_SYMBOL_GPL(spi_alloc_master);  


3.注册spi主机

  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;   //获得spi主机设备的父设备  
  5.     struct boardinfo    *bi;  
  6.     int status = -ENODEV;  
  7.     int dynamic = 0;  
  8.   
  9.     if (!dev)  
  10.         return -ENODEV;  
  11.     if (master->num_chipselect == 0) //判断片选个数  
  12.         return -EINVAL;  
  13.     if (master->bus_num < 0) {    //验证spi总线编号  
  14.         master->bus_num = atomic_dec_return(&dyn_bus_id);  
  15.         dynamic = 1;  
  16.     }  
  17.     spin_lock_init(&master->bus_lock_spinlock);  
  18.     mutex_init(&master->bus_lock_mutex);  
  19.       
  20.     master->bus_lock_flag = 0;  
  21.     dev_set_name(&master->dev, "spi%u", master->bus_num); //设置spi主机设备名  
  22.     status = device_add(&master->dev);   //添加spi主机设备  
  23.     if (status < 0)  
  24.         goto done;  
  25.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),dynamic ? " (dynamic)" : "");  
  26.     mutex_lock(&board_lock);  
  27.     list_add_tail(&master->list, &spi_master_list);  //spi主机list链表添加进全局spi_master_list链表  
  28.     list_for_each_entry(bi, &board_list, list)      //遍历全局board_list查找bi结构体  
  29.         spi_match_master_to_boardinfo(master, &bi->board_info);  //找到匹配的板级spi设备  
  30.           
  31.     mutex_unlock(&board_lock);  
  32.     status = 0;  
  33.     of_register_spi_devices(master);  
  34. done:  
  35.     return status;  
  36. }  
  37. EXPORT_SYMBOL_GPL(spi_register_master);  


3.1 匹配spi主机和板级spi设备

  1. static void spi_match_master_to_boardinfo(struct spi_master *master,struct spi_board_info *bi)  
  2. {  
  3.     struct spi_device *dev;  
  4.     if (master->bus_num != bi->bus_num)   //判断是否所属的spi总线  
  5.         return;  
  6.     dev = spi_new_device(master, bi);   //添加新的spi设备  
  7.     if (!dev)  
  8.         dev_err(master->dev.parent, "can't create new device for %s\n",bi->modalias);  
  9. }  

在注册板级设备或主机设备的时候都会添加
spi板级设备添加进board_list链表,spi主机设备添加进spi_master_list链表
不管是先注册spi板级设备还是先注册spi主机设备
都会调用list_for_each_entry遍历对应的要匹配的设备的链表,查找是否有匹配的例子
若找到都会调用spi_match_master_to_boardinfo函数添加spi设备

4.注销spi主机

  1. void spi_unregister_master(struct spi_master *master)  
  2. {  
  3.     int dummy;  
  4.     mutex_lock(&board_lock);  
  5.     list_del(&master->list); //删除链表  
  6.     mutex_unlock(&board_lock);  
  7.     dummy = device_for_each_child(&master->dev, NULL, __unregister); //调用__unregister函数注销子设备  
  8.     device_unregister(&master->dev); //注销设备  
  9. }  
  10. EXPORT_SYMBOL_GPL(spi_unregister_master);  


4.1 注销挂载该总线上的spi子设备

  1. static int __unregister(struct device *dev, void *null)  
  2. {  
  3.     spi_unregister_device(to_spi_device(dev));  
  4.     return 0;  
  5. }  


5.spi主机设备类

  1. static struct class spi_master_class = {  
  2.     .name   = "spi_master",  
  3.     .owner  = THIS_MODULE,  
  4.     .dev_release    = spi_master_release,  
  5. };  


五.spi总线

1.spi总线结构体

  1. struct bus_type spi_bus_type = {  
  2.     .name       = "spi",  
  3.     .dev_attrs  = spi_dev_attrs,  
  4.     .match      = spi_match_device, //匹配方法  
  5.     .uevent     = spi_uevent,  
  6.     .suspend    = spi_suspend,  
  7.     .resume     = spi_resume,  
  8. };  
  9. EXPORT_SYMBOL_GPL(spi_bus_type);  


2.设备匹配方法spi_match_device

前面的匹配方法是spi板级设备与spi主机设备的匹配方法,匹配的结果是添加新spi设备spi_new_device
这里的匹配是spi设备和spi驱动的匹配,匹配的结果是会调用spi驱动的设备驱动文件probe方法,既spi_drv_probe

  1. static int spi_match_device(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     const struct spi_device *spi = to_spi_device(dev);  
  4.     const struct spi_driver *sdrv = to_spi_driver(drv);  
  5.   
  6.     if (of_driver_match_device(dev, drv))   //设备文件驱动表的匹配  
  7.         return 1;  
  8.     if (sdrv->id_table)  //spi设备驱动存在支持id表  
  9.         return !!spi_match_id(sdrv->id_table, spi);  //spi设备驱动表的匹配  
  10.     return strcmp(spi->modalias, drv->name) == 0; //比较spi设备的名字和spi设备驱动的名字  
  11. }  


2.1 of_driver_match_device

  1. static inline int of_driver_match_device(const struct device *dev,const struct device_driver *drv)  
  2. {  
  3.     return of_match_device(drv->of_match_table, dev) != NULL;    //调用of_match_device函数  
  4. }  


2.1.1 of_match_device

  1. const struct of_device_id *of_match_device(const struct of_device_id *matches,const struct device *dev)  
  2. {  
  3.     if ((!matches) || (!dev->of_node))   //id表和设备节点都不存在  
  4.         return NULL;    //则返回  
  5.     return of_match_node(matches, dev->of_node); //调用of_match_node函数  
  6. }  
  7. EXPORT_SYMBOL(of_match_device);  


2.1.1.1 of_match_node //drv->of_match_table,dev->of_node

  1. const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)  
  2. {  
  3.     while (matches->name[0] || matches->type[0] || matches->compatible[0]) {   //名字,类型,兼容方法有一个存在  
  4.         int match = 1;  
  5.         if (matches->name[0])    //判断名字  
  6.             match &= node->name && !strcmp(matches->name, node->name);  
  7.         if (matches->type[0])    //判断类型  
  8.             match &= node->type && !strcmp(matches->type, node->type);  
  9.         if (matches->compatible[0])  //兼容方法  
  10.             match &= of_device_is_compatible(node,matches->compatible);  
  11.         if (match)  //匹配  
  12.             return matches; //返回匹配的id  
  13.         matches++;  //matches指针++,指向下一个id  
  14.     }  
  15.     return NULL;  
  16. }  
  17. EXPORT_SYMBOL(of_match_node);  


2.2 spi_match_id

  1. static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,const struct spi_device *sdev)  
  2. {  
  3.     while (id->name[0]) {    //id表的成员的名字域不为空  
  4.         if (!strcmp(sdev->modalias, id->name))    //则判断其名字是否与spi设备的名字一样  
  5.             return id;  //一样则返回该id  
  6.         id++;   //id表指针++,指向下一个id  
  7.     }  
  8.     return NULL;  
  9. }  


六 spi消息和spi传输

1.spi消息结构体

  1. struct spi_message {  
  2.     struct list_head    transfers;  //spi传输事务链表头  
  3.     struct spi_device   *spi;   //所属spi设备  
  4.     unsigned    is_dma_mapped:1;  
  5.     void    (*complete)(void *context);   
  6.     void    *context;  
  7.     unsigned    actual_length;  
  8.     int     status; //传输状态  
  9.     struct list_head    queue;  
  10.     void    *state;  
  11. };  


2.初始化spi消息

  1. static inline void spi_message_init(struct spi_message *m)  
  2. {  
  3.     memset(m, 0, sizeof *m);  
  4.     INIT_LIST_HEAD(&m->transfers);   //初始化spi消息的事务链表头  
  5. }  


3.添加传输事务到spi传输链表

  1. static inline void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)  
  2. {  
  3.     list_add_tail(&t->transfer_list, &m->transfers);  
  4. }  


4.spi传输结构体

  1. struct spi_transfer {  
  2.     const void  *tx_buf;    //发送缓冲区指针  
  3.     void        *rx_buf;    //接收缓冲区指针  
  4.     unsigned    len;    //消息长度  
  5.     dma_addr_t  tx_dma; //DMA发送地址  
  6.     dma_addr_t  rx_dma; //DMA接收地址  
  7.     unsigned    cs_change:1;      
  8.     u8      bits_per_word;  //一个字多少位  
  9.     u16     delay_usecs;    //毫秒级延时  
  10.     u32     speed_hz;   //速率  
  11.     struct list_head transfer_list; //传输链表头  
  12. };  

 

七.spi子系统的初始化spi_init

  1. static int __init spi_init(void)  
  2. {  
  3.     int status;  
  4.     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);  //分配数据收发缓冲区  
  5.     if (!buf) {  
  6.         status = -ENOMEM;  
  7.         goto err0;  
  8.     }  
  9.     status = bus_register(&spi_bus_type);   //注册spi总线  
  10.     if (status < 0)  
  11.         goto err1;    
  12.     status = class_register(&spi_master_class); //注册spi主机类 "/sys/class/spi_master"  
  13.     if (status < 0)  
  14.         goto err2;  
  15.     return 0;  
  16. err2:  
  17.     bus_unregister(&spi_bus_type);  
  18. err1:  
  19.     kfree(buf);  
  20.     buf = NULL;  
  21. err0:  
  22.     return status;  
  23. }  
  24. postcore_initcall(spi_init);    //入口声明 #define postcore_initcall(fn)    __define_initcall("2",fn,2)   


八.spi子系统的API

1.spi读 spi_read

  1. static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len)  
  2. {  
  3.     struct spi_transfer t = {  
  4.             .rx_buf     = buf,  
  5.             .len        = len,  
  6.         };  
  7.     struct spi_message  m;  
  8.     spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头)  
  9.     spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表  
  10.     return spi_sync(spi, &m);   //spi同步传输  
  11. }  

 

2.spi写 spi_write

  1. static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len)  
  2. {  
  3.     struct spi_transfer t = {  
  4.             .tx_buf     = buf,  
  5.             .len        = len,  
  6.         };  
  7.     struct spi_message  m;  
  8.     spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头)  
  9.     spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表  
  10.     return spi_sync(spi, &m);   //spi同步传输  
  11. }  

spi的读写操作都是初始化一个spi_transfer传输结构体,并将其添加进spi消息传输事务链表中
然后通过spi_sync来同步读写操作,接着看下spi_sync的具体代码


2.1 spi_sync

  1. int spi_sync(struct spi_device *spi, struct spi_message *message)  
  2. {  
  3.     return __spi_sync(spi, message, 0); //调用__spi_sync函数  
  4. }  
  5. EXPORT_SYMBOL_GPL(spi_sync);  


2.1.1 __spi_sync函数

  1. static int __spi_sync(struct spi_device *spi, struct spi_message *message,int bus_locked)  
  2. {  
  3.     DECLARE_COMPLETION_ONSTACK(done);   //声明一个工作队列  
  4.     int status;  
  5.     struct spi_master *master = spi->master; //获取spi主机  
  6.   
  7.     message->complete = spi_complete;    //设置spi消息的complete方法为spi_complete  
  8.     message->context = &done;    //设置spi消息的context  
  9.     if (!bus_locked)      
  10.         mutex_lock(&master->bus_lock_mutex); //上锁  
  11.     status = spi_async_locked(spi, message);  
  12.     if (!bus_locked)  
  13.         mutex_unlock(&master->bus_lock_mutex);   //解锁  
  14.     if (status == 0) {  
  15.         wait_for_completion(&done); //等待完成  
  16.         status = message->status;    //设置spi消息传输状态  
  17.     }  
  18.     message->context = NULL;  
  19.     return status;  
  20. }  

 

2.1.1.1 spi_async_locked 函数

  1. int spi_async_locked(struct spi_device *spi, struct spi_message *message)  
  2. {  
  3.     struct spi_master *master = spi->master; //获取spi主机  
  4.     int ret;  
  5.     unsigned long flags;  
  6.     spin_lock_irqsave(&master->bus_lock_spinlock, flags);    //上自旋锁  
  7.     ret = __spi_async(spi, message);    //调用了spi异步同步方法  
  8.     spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);   //解自旋锁  
  9.     return ret;  
  10. }  
  11. EXPORT_SYMBOL_GPL(spi_async_locked);  


2.1.1.1.1 __spi_async函数(异步)

  1. static int __spi_async(struct spi_device *spi, struct spi_message *message)  
  2. {  
  3.     struct spi_master *master = spi->master;  
  4.     //主机为半双工或spi设备为3线设备  
  5.     if ((master->flags & SPI_MASTER_HALF_DUPLEX)|| (spi->mode & SPI_3WIRE)) {  
  6.         struct spi_transfer *xfer;  
  7.         unsigned flags = master->flags;    
  8.         list_for_each_entry(xfer, &message->transfers, transfer_list) {  //遍历spi消息的传输事务链表  
  9.             if (xfer->rx_buf && xfer->tx_buf) //判断接收或发送缓冲区是否为空  
  10.                 return -EINVAL;  
  11.             if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)  //检验无spi数据发送的情况  
  12.                 return -EINVAL;  
  13.             if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)  //检验无spi数据接收的情况  
  14.                 return -EINVAL;  
  15.         }  
  16.     }  
  17.     message->spi = spi;  //设置spi消息所属的spi设备  
  18.     message->status = -EINPROGRESS;  //设置spi消息的传输状态  
  19.     return master->transfer(spi, message);   //调用spi主机的transfer方法,收发spi信息给spi设备  
  20. }  


3.spi先写后读 spi_write_then_read

  1. int spi_write_then_read(struct spi_device *spi,const u8 *txbuf, unsigned n_tx,u8 *rxbuf, unsigned n_rx)  
  2. {  
  3.     static DEFINE_MUTEX(lock);  
  4.     int status;  
  5.     struct spi_message  message;  
  6.     struct spi_transfer x[2];   //声明两个spi传输结构体  
  7.     u8  *local_buf;  
  8.       
  9.     if ((n_tx + n_rx) > SPI_BUFSIZ)  //验证发送和接收的数据总和是否溢出  
  10.         return -EINVAL;  
  11.     spi_message_init(&message);     //spi消息初始化(初始化传输事务链表头)  
  12.     memset(x, 0, sizeof x); //  
  13.     if (n_tx) {  
  14.         x[0].len = n_tx;  
  15.         spi_message_add_tail(&x[0], &message);  //添加spi传输到spi消息传输链表  
  16.     }  
  17.     if (n_rx) {  
  18.         x[1].len = n_rx;  
  19.         spi_message_add_tail(&x[1], &message);  //添加spi传输到spi消息传输链表  
  20.     }  
  21.     if (!mutex_trylock(&lock)) {    //尝试上锁 失败  
  22.         local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);    //则分配local_buf内存  
  23.         if (!local_buf)  
  24.             return -ENOMEM;  
  25.     } else  
  26.         local_buf = buf;    //指向默认分配好内存的缓冲区(spi_init中初始化的)  
  27.     memcpy(local_buf, txbuf, n_tx); //发送缓冲区的内容复制到local_buf中  
  28.     x[0].tx_buf = local_buf;        //发送的spi传输结构体  
  29.     x[1].rx_buf = local_buf + n_tx; //接收的spi传输结构体  
  30.     status = spi_sync(spi, &message);   //spi同步传输--发送数据  
  31.     if (status == 0)  
  32.         memcpy(rxbuf, x[1].rx_buf, n_rx);   //接收返回的数据复制到rxbuf中  
  33.     if (x[0].tx_buf == buf)  
  34.         mutex_unlock(&lock);    //解锁  
  35.     else  
  36.         kfree(local_buf);   //释放内存  
  37.     return status;  
  38. }  
  39. EXPORT_SYMBOL_GPL(spi_write_then_read);  


4.spi写8位后读8位数据 spi_w8r8 

  1. static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)  
  2. {  
  3.     ssize_t status;  
  4.     u8  result;  
  5.     status = spi_write_then_read(spi, &cmd, 1, &result, 1); //写8位读8位  
  6.     return (status < 0) ? status : result;  
  7. }  


5.spi写8位数据后读16位数据 spi_w8r16

  1. static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)  
  2. {  
  3.     ssize_t status;  
  4.     u16 result;  
  5.     status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);  //写8位读16位  
  6.     return (status < 0) ? status : result;  
  7. }  

这里的API是内核空间使用的接口,设备驱动程序调用这些API直接操作spi的读写操作,来完成任务

阅读(1721) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~