zoukankan      html  css  js  c++  java
  • 和菜鸟一起学linux总线驱动之初识spi驱动主要结构

           既然知道了协议了,那么就可以开始去瞧瞧linux kenerl中的spi的驱动代码了,代码中有很多的结构体,还是对主要的结构体先做个了解吧,那样才可以很好的理解驱动。主要是include/linux/spi.h

     

    首先是SPI的主机和从机通信接口,也就是SPI总线,

    extern struct bus_type spi_bus_type;
    
     

    bus_type定义在linux/device.h

     

    struct bus_type {
           const char              *name;     //总线的名字
           struct bus_attribute *bus_attrs;
           struct device_attribute    *dev_attrs;
           struct driver_attribute    *drv_attrs; 
    
    //总线上的device和driver的匹配,匹配成功返回非0值
           int (*match)(struct device *dev, struct device_driver *drv);
           int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
           //当新的device或driver加到总线上的时候,调用driver中的probe函数经行匹配
           int (*probe)(struct device *dev);
           int (*remove)(struct device *dev);
           void (*shutdown)(struct device *dev);
           int (*suspend)(struct device *dev, pm_message_t state);
           int (*resume)(struct device *dev);
           const struct dev_pm_ops *pm;
           struct subsys_private *p;
    };
    
    

    SPI设备

     

    struct spi_device {
          struct device          dev;
          struct spi_master    *master;    //SPI控制器
           u32                max_speed_hz;  //最大时钟频率
           u8                  chip_select;     //片选
           u8                  mode;          //SPI模式
    #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 */
    #define    SPI_NO_CS   0x40                     /* 1 dev/bus, no chipselect */
    #define    SPI_READY  0x80                     /* slave pulls low to pause */
           u8                  bits_per_word;              //一次传输的bits,可以是8、16、32,默认是8
           int                 irq;                 
           void               *controller_state;
           void               *controller_data;        
           char               modalias[SPI_NAME_SIZE];  //别名,用于device和driver的匹配
    };
    
    


     

     

    SPI驱动

     

    struct spi_driver {
           const struct spi_device_id *id_table;
           int                 (*probe)(struct spi_device *spi);  //绑定驱动和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主控制器

     

    struct spi_master {
           struct device   dev;   //驱动的设备接口
           struct list_head list;        //SPI控制器的链表头
           s16                bus_num;    //总线号
    
           /* chipselects will be integral to many controllers; some others
            * might use board-specific GPIOs.
            */
           u16                num_chipselect;    //SPI设备的片选号
             u16                dma_alignment;     //dma模式  
     
            /* spi_device.mode flags understood by this controller driver */
           u16                mode_bits;         
    
           /* other constraints relevant to this driver */
           u16                flags;
    
    #define SPI_MASTER_HALF_DUPLEX    BIT(0)           /* can't do full duplex */
    #define SPI_MASTER_NO_RX   BIT(1)           /* can't do buffer read */
    #define SPI_MASTER_NO_TX    BIT(2)           /* can't do buffer write */
    
            /* lock and mutex for SPI bus locking */
          spinlock_t              bus_lock_spinlock;
           struct mutex           bus_lock_mutex;
    
            bool               bus_lock_flag;
           int                 (*setup)(struct spi_device *spi);   //更新SPI设备的模式和SPI设备的采样时钟
           int                 (*transfer)(struct spi_device *spi,    //添加一个消息到控制器的传输队列
                                              struct spi_message *mesg);
           void               (*cleanup)(struct spi_device *spi);
    
    };
    
    


     

    SPI传输

     

    struct spi_transfer {
          /* it's ok if tx_buf == rx_buf (right?)
           * for MicroWire, one buffer must be null
            * buffers must work with dma_*map_single() calls, unless
            *   spi_message.is_dma_mapped reports a pre-existing mapping
            */
    
         const void       *tx_buf;    //要写的数据
           void        *rx_buf;                //要读的数据
           unsigned  len;                       //数据长度
    
     
    
           dma_addr_t    tx_dma;       //tx_buf的DMA地址
           dma_addr_t    rx_dma;         //rx_buf的DMA地址
    
          unsigned  cs_change:1;
          u8           bits_per_word;       //传输的bytes数,不选就用默认的
           u16         delay_usecs;                  //微秒延时,用以传输数据后,改变片选信号前
           u32         speed_hz;            //传输速率,不选就用默认的
    
           struct list_head transfer_list;     //传输链表,用以传输spi_message
    
    };
    
    


     

    SPI消息

     

    struct spi_message {
           struct list_head       transfers;   // 
    
           struct spi_device     *spi;      //加到传输队列中的spi设备
            unsigned         is_dma_mapped:1;   //DMA传输控制位
    
           /* completion is reported through a callback */
           void               (*complete)(void *context);      //传输完成
           void               *context;                                    //complete函数的参数                
           unsigned         actual_length;             //所有成功传输字段的总长度
           int                 status;                                 //传输成功返回0,否则返回错误
    
     
    
           /* for optional use by whatever driver currently owns the
           * spi_message ...  between calls to spi_async and then later
            * complete(), that's the spi_master controller driver.
            */
    
           struct list_head       queue;
           void               *state;
    
    };
    
    


     

    SPI bitbang

     

    struct spi_bitbang {
           struct workqueue_struct *workqueue;
           struct work_struct   work;
    
           spinlock_t              lock;
           struct list_head       queue;
    
           u8                  busy;
           u8                  use_dma;
           u8                  flags;             /* extra spi->mode support */
    
           struct spi_master    *master;
    
           /* setup_transfer() changes clock and/or wordsize to match settings
          * for this transfer; zeroes restore defaults from spi_device.
            */
           int   (*setup_transfer)(struct spi_device *spi,
                         struct spi_transfer *t);
    
            void (*chipselect)(struct spi_device *spi, int is_on);
    #define    BITBANG_CS_ACTIVE      1     /* normally nCS, active low */
    #define    BITBANG_CS_INACTIVE   0
    
     
    
           /* txrx_bufs() may handle dma mapping for transfers that don't
            * already have one (transfer.{tx,rx}_dma is zero), or use PIO
            */
           int   (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
    
           /* txrx_word[SPI_MODE_*]() just looks like a shift register */
           u32  (*txrx_word[4])(struct spi_device *spi,
                         unsigned nsecs,
                         u32 word, u8 bits);
    
    };
    
    


            在SPI控制器里面最常用的用来处理传输的结构体spi_bitbang了。

     

    SPI borad info

    struct spi_board_info {
     /* the device name and module name are coupled, like platform_bus;
      * "modalias" is normally the driver name.
      *
      * platform_data goes to spi_device.dev.platform_data,
      * controller_data goes to spi_device.controller_data,
      * irq is copied too
      */
     char  modalias[SPI_NAME_SIZE];
     const void *platform_data;
     void  *controller_data;
     int  irq;
    
     /* slower signaling on noisy or low voltage boards */
     u32  max_speed_hz;
    
    
     /* bus_num is board specific and matches the bus_num of some
      * spi_master that will probably be registered later.
      *
      * chip_select reflects how this chip is wired to that master;
      * it's less than num_chipselect.
      */
     u16  bus_num;
     u16  chip_select;
    
     /* mode becomes spi_device.mode, and is essential for chips
      * where the default of SPI_CS_HIGH = 0 is wrong.
      */
     u8  mode;
    
     /* ... may need additional spi_device chip config data here.
      * avoid stuff protocol drivers can set; but include stuff
      * needed to behave without being bound to a driver:
      *  - quirks like clock rate mattering when not selected
      */
    };
    
    

           控制器里会读取borad info里的参数

    SPI gpio_platform_data

     

    struct spi_gpio_platform_data {
           unsigned  sck;
           unsigned  mosi;
           unsigned  miso;
    
           u16         num_chipselect;
    
    };
    
    


            因为我用的比较多的是GPIO模拟的,所以还是记录下这个从platform传进来的管脚号。

     

           OK,对于SPI用到的结构体基本上已经介绍完了,那么接下来就介绍其主要函数了。

     

  • 相关阅读:
    随机森林算法参数调优
    BAYES和朴素BAYES
    阿里云 金融接口 token PHP
    PHP mysql 按时间分组 表格table 跨度 rowspan
    MySql按周,按月,按日分组统计数据
    PHP 获取今日、昨日、本周、上周、本月的等等常用的起始时间戳和结束时间戳的时间处理类
    thinkphp5 tp5 会话控制 session 登录 退出 检查检验登录 判断是否应该跳转到上次url
    微信 模板消息
    php 腾讯 地图 api 计算 坐标 两点 距离 微信 网页 WebService API
    php添加http头禁止浏览器缓存
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300060.html
Copyright © 2011-2022 走看看