linux中spi驱动框架

    xiaoxiao2022-06-30  55

    linux下的SPI总线驱动在driver/spi目录中。

    SPI驱动分为三层

    SPI核心层  drivers/spi/spi.c 与平台无关

    SPI控制器驱动层

    SPI设备驱动层

    每层的主要结构体和函数

    SPI控制器驱动层(include/linux/spi/spi.h)

    struct spi_master { struct device dev; s16 bus_num;//控制器对应的SPI总线号 u16 num_chipselect;//支持片选数量 int (* setup) (struct spi_device *spi);//SPI模式设备,在spi_add_device中调用 int (* transfer) (struct spi_device *spi,struct spi_message *mesg);//读写方法的函数,可能会睡眠 void (* cleanup) (struct spi_device *spi);//注销时候调用 };

    SPI设备驱动层

    spi_device对应某个特定的slave

    struct spi_driver { int (* probe) (struct spi_device *spi);//匹配时调用,完成spi_transfer,spi_message,spi_message_init,spi_meassage_add_tail,spi_sync,spi_write_then_read的调用 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; }; struct spi_device { struct device dev; struct spi_master * master; u32 max_speed_hz; u8 chip_select; u8 mode; #define SPI_CPHA 0x01 #define SPI_CPOL 0x02 #define SPI_MODE_0 (0|0) #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 #define SPI_LSB_FIRST 0x08 #define SPI_3WIRE 0x10 #define SPI_LOOP 0x20 u8 bits_per_word; int irq; void * controller_state; void * controller_data; const char * modalias; }; struct spi_transfer { const void * tx_buf; void * rx_buf; unsigned len; dma_addr_t tx_dma; dma_addr_t rx_dma; unsigned cs_change:1; u8 bits_per_word; u16 delay_usecs; u32 speed_hz; struct list_head transfer_list; }; int spi_register_driver ( struct spi_driver * sdrv); struct spi_message { struct list_head transfers; struct spi_device * spi; unsigned is_dma_mapped:1; void (* complete) (void *context); void * context; unsigned actual_length; int status; struct list_head queue; void * state; }; 在每次使用spi_message可以使用函数: void spi_message_init(structspi_message *m); 来初始化。 向spi_message添加transfers可以使用spi_message_add_tail()函数: void spi_message_add_tail(structspi_transfer *t, struct spi_message *m); 一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了: int spi_async(struct spi_device *spi,struct spi_message *message); 因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。 使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。 使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync(): int spi_sync(struct spi_device *spi,struct spi_message *message); 因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()在drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。

    spi_device的板信息用spi_board_info来描述,在init函数调用时会初始化。

    struct spi_board_info { char modalias[KOBJ_NAME_LEN]; const void * platform_data; void * controller_data; int irq; u32 max_speed_hz; u16 bus_num; u16 chip_select; u8 mode; }; int __init spi_register_board_info ( struct spi_board_info const * info, unsigned n); 会把spi_board_info注册到链表board_list上。

    之后,spi_master注册会调用scan_board_info扫描board_list找到挂接在它上面的spi设备。

    然后创建并注册spi_device.

    一个结构体spi_board_info对应着一个SPI设备spi_device

    struct boardinfo{ struct list_head list; struct spi_board_info board_info; } static LIST_HEAD(board_list); static LIST_HEAD(spi_master_list);//初始化一个空链表 #define LIST_HEAD(name)

    struct list_head name=LIST_HEAD_INIT(name)

    #define LIST_HEAD_INIT(name)  {&(name),&(name)}

    struct list_head {struct list_head* next,*prev;};

    struct device_driver结构体被定义在/include/linux/device.h,原型是:

    struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 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 attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };

    举例SPI驱动

    spi_device设备

    spi_board_info

    init入口调用,spi_register_board_info(S3C_SPI_devs,ARRAY_SIZE(S3C_SPI_devs));

    会把spi_board_info注册到board_list链表上。

    之后会创建并注册spi_device

    spi_driver驱动

    1、声明并设置spi_driver结构体

    2、注册spi_register_driver(&spi_driver);

    3、实现probe操作,spi_transfer,spi_message的构建

    spi_message_init,spi_message_add_tail,spi_sync调用

    3.1、定义并设置 spi_transfer结构体

    3.2、定义spi_message结构体

    3.3、初始化meg,spi_message_init(&meg);

    3.4、将st放入message队列spi_message_add_tail(&st,&meg);

    3.5、将message与spi_device关联,发送meg,spi_sync(spi_device,&meg);

    转载请注明原文地址: https://ju.6miu.com/read-1125620.html

    最新回复(0)