spi-driver设备驱动

1、SPI主机驱动(类似I2C适配驱动)
Linux内核使用spi_master表示SPI主机驱动,spi_master是一个结构体,定义在include/linux/spi/spi.h中
struct spi_master {
struct device dev;
struct list_head list;
......
s16 bus_num;
s16 num_chipselect;
u16 dma_alignment;
u16 mode_bits;
u32 bits_per_word_mask;
......
u32 min_speed_hz;
u32 max_speed_hz;
u16 flags;
......
spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex;
bool bus_lock_flag;
......
int (*setup)(struct spi_device *spi);
......
int (*transfer)(*struct spi_device *spi, struct spi_message *mesg);
int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg);
......
};
①、spi_master申请与释放
struct spi_master *spi_alloc_master(struct device *dev, unsigned size); 、、申请
void spi_master_put(struct spi_master *master); //释放
②、spi_master的注册与注销
int spi_register_master(struct spi_master *master); //注册
void spi_unregister_master(struct spi_master *master); //注销
spi_bitbang_start()/spi_bitbang_stop()也是一对注册/注销


2、SPI设备驱动
Linux内核使用spi_driver结构体来表示spi设备驱动,spi_driver定义在include/linux/spi/spi.h 文件中
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;
};
①、驱动注册、注销
int spi_register_driver(struct spi_driver *sdrv);
void spi_unregister_driver(struct spi_master *sdrv);
②、注册流程
static int xxx_probe(struct spi_driver *spi)
{
......
return 0;
}
static int xxx_remove(struct spi_device *spi)
{
......
return 0;
}
//传统匹配方式ID表
static const struct spi_device_id xxx_id[] = {
{"xxx", 0},
{},
};
//设备树匹配表
static const struct of_device_id xxx_of_match[] = {
{.compatible = "xxx"},
{/* sentinel */}
};
static struct spi_driver xxx_driver = {
.probe = xxx_probe,
.remove = xxx_remove,
.driver = {
.owner = THIS_MODULE,
.name = "xxx",
.of_match_table = xxx_of_match,
},
.id_table = xxx_id,
};
static int __init xxx_init(void)
{
return spi_register_driver(&xxx_driver);
}
static void __exit xxx_exit(void)
{
spi_unregister_driver(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);

3、spi设备与驱动匹配
由SPI总线完成匹配,SPI总线为spi_bus_type 结构体定义在driver/spi/spi.c文件中
struct bus_type spi_bus_type ={
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
.uevent = spi_uevent,
};

4、设备区别编写流程
①、IO的pinctrl子节点创建或修改(重点检查对应的IO是否有给其他设备使用了,注意删除)
pinctrl_ecspi3: icm20608{
fsl,pins = <
MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x10b0 /* CS */
MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x10b1 /* SCLK */
MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x10b1 /* MISO */
MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x10b1 /* MOSI */
>;
};

&ecspi3 {
fsl,spi-num-chipselects = <1>; //ecspi1总线上只挂载了一从设备
cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; //CS片选信号GPIO1_IO20
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";

spidev:icm20608@0 {
compatible = "alpha, icm20608"; //匹配st的设备驱动
spi-max-frequency = <10000000>;
reg = <0>; //使用ecspi3的通道0,与icm20608@0一致,这个是CS片选?
};
};

②、spi设备数据收发处理流程
(1)申请并初始化spi_transfer,设置tx_buf,rx_buf,len等参数
(2)使用spi_message_init函数初始化spi_message
(3)使用spi_message_add_tail函数把之前设置好的spi_transfer添加到spi_message队列中
(4)使用spi_syn函数完成SPI数据同步传输
//spi 多字节发送
static int spi_send(struct spi_device *spi, u8 *buf, int len)
{
int ret;
struct spi_message m;
struct spi_transfer t={
.tx_buf = buf,
.len = len,
};

spi_message_init(&m);
spi_message_add_tail(t, &m);
ret = spi_sync(spi, &m);
return ret;
}
//spi 多字节接收
static int spi_receive(struct spi_device *spi, u8 *buf, int len)
{
int ret;
struct spi_message m;
struct spi_transfer t={
.rx_buf = buf,
.len = len,
};

spi_message_init(&m);
spi_message_add_tail(t, &m);
ret = spi_sync(spi, &m);
return ret;

}

posted @ 2023-09-28 15:30  zbl1118  阅读(89)  评论(0)    收藏  举报