spi_peripherals_driver
linux kernel spi外设驱动的编写,可以分为四步:
通过spi_sync()读写spi外设寄存器
配置设备树dts spi子节点
注册/注销 struct spi_driver 变量
当设备树与驱动匹配后,调用probe函数
通过spi_sync()读写spi外设寄存器
通过regmap API读写spi外设寄存器
配置设备树dts spi子节点(同上)
注册/注销 struct spi_driver 变量(同上)
当设备树与驱动匹配后,调用probe函数
通过regmap API读写spi外设寄存器
通过spi_sync()读写spi外设寄存器
1. 配置设备树dts spi子节点
&spi {
cs-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>;
status = "okay";
xxx {
compatible = "xxx,xxx";
status = "okay";
};
};
2. 注册/注销 struct spi_driver 变量
定义 struct spi_driver 变量
const struct of_device_id xxx_of_match_table[] = { { .compatible = "xxx,xxx", }, }; const struct spi_device_id xxx_id_table[] = { { .name = "xxx,xxx", }, }; struct spi_driver xxx_spi_drv = { .probe = xxx_probe, .remove = xxx_remove, .driver = { .owner = THIS_MODULE, .name = "xxx", .of_match_table = xxx_of_match_table, }, .id_table = xxx_id_table, };
调用相关API注册/注销
spi_register_driver(&xxx_spi_drv); // 注册 spi_unregister_driver(&xxx_spi_drv);// 注销
3. 当设备树与驱动匹配后,调用probe函数
设备树与驱动匹配,即设备树dts spi子节点的compatible属性 与 xxx_of_match_table结构体的.compatible变量相同,调用probe函数
int xxx_probe(struct spi_device *spi)
{
struct device dev = spi->dev;
struct device_node *np = dev.of_node;
unsigned int cs_gpio;
cs_gpio = of_get_named_gpio(np->parent, "cs-gpio", 0); // 从dts获得CS引脚
gpio_direction_output(cs_gpio, 1); // 将CS引脚设置为输出,高电平状态
spi->mode = SPI_MODE_0; /*MODE0,CPOL=0,CPHA=0*/
spi_setup(spi);
xxxDev.spi = spi;
xxxDev.cs_gpio = cs_gpio;
return 0;
}
4. 通过spi_sync()读写spi外设寄存器
读操作
void xxx_read_regs(u8 reg, void *buf, int len) { struct spi_device *spi = xxxDev.spi; struct spi_message m; struct spi_transfer *t; u8 spiReg = reg | 0x80; // 寄存器地址+读标志 t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); gpio_set_value(xxxDev.cs_gpio, 0); // 使能CS引脚 t->tx_buf = &spiReg; t->len = 1; spi_message_init(&m); spi_message_add_tail(t, &m); spi_sync(spi, &m); t->rx_buf = buf; // 读出的数据缓冲区 t->len = len; // 读出的数据长度 spi_message_init(&m); spi_message_add_tail(t, &m); spi_sync(spi, &m); gpio_set_value(xxxDev.cs_gpio, 1); // 失能CS引脚 kfree(t); }
写操作
void xxx_write_regs(u8 reg, void *buf, int len) { struct spi_device *spi = xxxDev.spi; struct spi_message m; struct spi_transfer *t; u8 spiReg = reg & (~0x80); // 寄存器地址+写标志 t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); gpio_set_value(xxxDev.cs_gpio, 0);// 使能CS引脚 t->tx_buf = &spiReg; t->len = 1; spi_message_init(&m); spi_message_add_tail(t, &m); spi_sync(spi, &m); t->tx_buf = buf; // 写入的数据缓冲区 t->len = len; // 写入的数据长度 spi_message_init(&m); spi_message_add_tail(t, &m); spi_sync(spi, &m); gpio_set_value(xxxDev.cs_gpio, 1);// 失能CS引脚 kfree(t); }
通过regmap API读写spi外设寄存器
前提:spi控制器自动使能/失能CS引脚 或 spi控制器驱动手动使能/失能CS引脚,即 不需要spi外设驱动使能/失能CS引脚
1. 配置设备树dts spi子节点(同上)
2. 注册/注销 struct spi_driver 变量(同上)
3. 当设备树与驱动匹配后,调用probe函数
设备树与驱动匹配,即设备树dts spi子节点的compatible属性 与 xxx_of_match_table结构体的.compatible变量相同,调用probe函数
int xxx_probe(struct spi_device *spi)
{
struct device dev = spi->dev;
struct regmap_config config;
struct regmap *regmap;
spi->mode = SPI_MODE_0; /*MODE0,CPOL=0,CPHA=0*/
spi_setup(spi);
memset(&config, 0, sizeof(config));
config.reg_bits = 8; // spi外设寄存器地址 8bits
config.val_bits = 8; // spi外设寄存器数据 8bits
regmap = devm_regmap_init_spi(spi, &config); // 初始化regmap
xxxDev.spi = spi;
xxxDev.regmap = regmap;
return 0;
}
4. 通过regmap API读写spi外设寄存器
读操作
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
写操作
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
Last updated
Was this helpful?