SPI子系统驱动架构 - 驱动框架

来源:互联网 发布:网络推广效果评估 编辑:程序博客网 时间:2024/06/12 19:42

文章系列

SPI子系统驱动架构 - 简介

SPI子系统驱动架构 - 驱动框架

SPI子系统驱动架构 - 具体实现

SPI驱动框架

spi驱动框架如图所示,驱动框架分用户层、核心层和硬件层,用户层主要向上层开发人员提供接口,硬件层是spi模块和spi设备的硬件描述,我们主要认识核心层spi-core。

核心层中分设备层和控制器层,设备层提供spi从设备的注册,控制器层提供芯片spi控制模块的注册,一般控制器层的驱动在内核中都已经提供了,我们主要是编写自己的设备驱动,具体编写就可以参考别的器件的驱动。从图中我们可以看到控制器层有spi_master和spi_bitbang两个结构体代表控制器模块,区别在于spi_bitbang会提供一种机制,而这种机制是spi_master注册时没有的,具体下文介绍。在整个设备的注册流程中,系统驱动后会先注册控制器的驱动,然后会注册挂在spi总线上的设备层的驱动。

这里写图片描述

spi驱动的代码都在drivers/spi/目录下,进去后感觉乱糟糟的,不像i2c那样分的清楚,不过代码看多了之后就清楚了,呵呵。主要的文件是spi.c和spi-bitbang.c,这些都是核心文件,spidev.c是一个设备层的文件,其他大多是控制器代码文件。

SPI主控制器(总线)驱动介绍

spi主控制器的注册是通过platform bus来进行的,在系统初始化时会进行spi的platform_device的注册,然后具体SoC上的spi模块的platform_driver的注册在各自的文件中,注册匹配后就会进入probe函数来进行spi主控制器spi_master的注册,相关结构体下面介绍

结构体介绍

spi_master定义了SPI主控制器,spi_transfer 和spi_message 是数据传输时使用的结构体,spi_transfer的链表挂在spi_message 的链表中,所以每次数据传输时,一个spi_message 会有多个spi_transfer来进行传输,每次进行数据传输时,都会检查spi_message 的状态,看是否合适进行传输

struct spi_master {    struct device   dev;    struct list_head list;    s16         bus_num;    /* chipselects will be integral to many controllers; some others     * might use board-specific GPIOs.     */    u16         num_chipselect;    /* some SPI controllers pose alignment requirements on DMAable     * buffers; let protocol drivers know about these requirements.     */    u16         dma_alignment;    /* spi_device.mode flags understood by this controller driver */    u16         mode_bits;    /* bitmask of supported bits_per_word for transfers */    u32         bits_per_word_mask;    /* limits on transfer speed */    u32         min_speed_hz;    u32         max_speed_hz;    /* other constraints relevant to this driver */    u16         flags;    /*     * on some hardware transfer size may be constrained     * the limit may depend on device transfer settings     */    size_t (*max_transfer_size)(struct spi_device *spi);    /* lock and mutex for SPI bus locking */    spinlock_t      bus_lock_spinlock;    struct mutex        bus_lock_mutex;    /* flag indicating that the SPI bus is locked for exclusive use */    bool            bus_lock_flag;    int         (*setup)(struct spi_device *spi);    int         (*transfer)(struct spi_device *spi,                        struct spi_message *mesg);    /* called on release() to free memory provided by spi_master */    void            (*cleanup)(struct spi_device *spi);    bool            (*can_dma)(struct spi_master *master,                       struct spi_device *spi,                       struct spi_transfer *xfer);    bool                queued;    struct kthread_worker       kworker;    struct task_struct      *kworker_task;    struct kthread_work     pump_messages;    spinlock_t          queue_lock;    struct list_head        queue;    struct spi_message      *cur_msg;    bool                idling;    bool                busy;    bool                running;    bool                rt;    bool                auto_runtime_pm;    bool                            cur_msg_prepared;    bool                cur_msg_mapped;    struct completion               xfer_completion;    size_t              max_dma_len;    int (*prepare_transfer_hardware)(struct spi_master *master);    int (*transfer_one_message)(struct spi_master *master,                    struct spi_message *mesg);    int (*unprepare_transfer_hardware)(struct spi_master *master);    int (*prepare_message)(struct spi_master *master,                   struct spi_message *message);    int (*unprepare_message)(struct spi_master *master,                 struct spi_message *message);    int (*spi_flash_read)(struct  spi_device *spi,                  struct spi_flash_read_message *msg);    /*     * These hooks are for drivers that use a generic implementation     * of transfer_one_message() provied by the core.     */    void (*set_cs)(struct spi_device *spi, bool enable);    int (*transfer_one)(struct spi_master *master, struct spi_device *spi,                struct spi_transfer *transfer);    void (*handle_err)(struct spi_master *master,               struct spi_message *message);    /* gpio chip select */    int         *cs_gpios;    /* statistics */    struct spi_statistics   statistics;    /* DMA channels for use with core dmaengine helpers */    struct dma_chan     *dma_tx;    struct dma_chan     *dma_rx;    /* dummy data for full duplex devices */    void            *dummy_rx;    void            *dummy_tx;    int (*fw_translate_cs)(struct spi_master *master, unsigned cs);};
struct spi_transfer {    const void  *tx_buf;    void        *rx_buf;    unsigned    len;    dma_addr_t  tx_dma;    dma_addr_t  rx_dma;    struct sg_table tx_sg;    struct sg_table rx_sg;    unsigned    cs_change:1;    unsigned    tx_nbits:3;    unsigned    rx_nbits:3;    u8      bits_per_word;    u16     delay_usecs;    u32     speed_hz;    struct list_head transfer_list;};
struct spi_message {    struct list_head    transfers;    struct spi_device   *spi;    unsigned        is_dma_mapped:1;    /* completion is reported through a callback */    void            (*complete)(void *context);    void            *context;    unsigned        frame_length;    unsigned        actual_length;    int         status;    struct list_head    queue;    void            *state;    /* list of spi_res reources when the spi message is processed */    struct list_head        resources;};

spi_bitbang是另一套主控制器结构体,它提供一种数据传输机制,struct spi_bitbang其实就是包装了spi_maser

struct spi_bitbang {    spinlock_t      lock;    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主控制器设备驱动注册与卸载函数

extern int spi_register_master(struct spi_master *master);extern void spi_unregister_master(struct spi_master *master);

现在进行spi主控制器设备的注册一般使用下面的函数,对应于struct spi_bitbang,使用这个函数进行注册会开启开启线程来进行spi数据传输

extern int spi_bitbang_start(struct spi_bitbang *spi);extern void spi_bitbang_stop(struct spi_bitbang *spi);

SPI设备驱动介绍

结构体介绍

spi_device 等同于驱动模型中的device

struct spi_device {    struct device       dev;    struct spi_master   *master;    u32         max_speed_hz;    u8          chip_select;    u8          bits_per_word;    u16         mode;    int         irq;    void            *controller_state;    void            *controller_data;    char            modalias[SPI_NAME_SIZE];    int         cs_gpio;    /* chip select gpio */    /* the statistics */    struct spi_statistics   statistics;};

spi_driver 等同于驱动模型中的driver

struct spi_driver {    const struct spi_device_id *id_table;    int         (*probe)(struct spi_device *spi);    int         (*remove)(struct spi_device *spi);    void            (*shutdown)(struct spi_device *spi);    struct device_driver    driver;};

函数介绍

spi从设备驱动driver注册与卸载函数

spi_register_driver(driver)spi_unregister_driver()

spi从设备device注册与卸载函数

extern struct spi_device *spi_alloc_device(struct spi_master *master);extern intspi_add_device(struct spi_device *spi);extern struct spi_device *spi_new_device(struct spi_master *, struct spi_board_info *);extern void spi_unregister_device(struct spi_device *spi);
0 0
原创粉丝点击