Linux内核将SPI驱动分成两部分
- SPI主机驱动:SOC的SPI控制器驱动。半导体厂商编写。
- SPI设备驱动:具体SPI设备的驱动。SOC使用者编写。
SPI主机驱动
Linux定义spi_master结构体表示SPI主机驱动,include/linux/spi.spi.h。SPI主机驱动申请spi_master,初始化spi_master,向内核注册spi_master。
使用spi_alloc_master申请spi_master。
struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
- dev:platform_device中的成员变量。
- size:私有数据private_data大小。
- 返回值:申请的spi_master。
使用spi_master_put释放spi_master。
void spi_master_put(struct spi_master *master)
- master:要释放的spi_master。
- 返回值:无。
使用spi_register_master注册spi_master。
int spi_register_master(struct spi_master *master)
- master:要注册的spi_master。
- 返回值:0,成功;负值,失败。
使用spi_unregister_master注销spi_master。
void spi_unregister_master(struct spi_master *master)
- master:要注销的spi_master。
- 返回自:无。
SPI设备驱动
Linux使用spi_driver结构体表示spi设备驱动,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;
};
当SPI设备和驱动匹配成功后,执行probe函数。
使用spi_register_driver注册spi_driver。
int spi_register_driver(struct spi_driver *sdrv)
- sdrv:要注册的spi_driver。
- 返回值:0,成功;负值,失败。
使用spi_unregister_driver注销spi_driver。
void spi_unregister_driver(struct spi_driver *sdrv)
- sdrv:要注销的spi_driver。
- 返回值:无。
SPI设备和驱动匹配
SPI设备和驱动匹配是由SPI总线完成,SPI总线为spi_bus_type,drivers/spi/spi.c。
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI */
if (acpi_driver_match_device(dev, drv))
return 1;
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);
return strcmp(spi->modalias, drv->name) == 0;
}
struct bus_type spi_bus_type = {
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
.uevent = spi_uevent,
};
SPI设备和驱动的匹配函数为spi_match_device。of_driver_match_device完成设备树设备和驱动匹配,acpi_driver_match_device用于ACPI形式匹配,spi_match_id用于无设备树匹配。
SPI设备数据收发
SPI数据收发步骤
- 申请并初始化spi_transfer,设置spi_transfer的tx_buf成员变量、rx_buf成员变量、len成员变量。
- 使用spi_message_init初始化spi_message。
- 使用spi_message_add_tail将spi_transfer添加到spi_message队列中。
- 使用spi_sync或spi_async完成数据同步/异步传输。
Linux定义spi_transfer结构体描述SPI传输信息。
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;
#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
u8 bits_per_word;
u16 delay_usecs;
u32 speed_hz;
struct list_head transfer_list;
};
- tx_buf:保存要发送的数据。
- rx_buf:保存接收到的数据。
- len:数据传输长度。
spi_transfer需要组织成spi_message结构体。
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;
};
使用spi_message_init初始化spi_message。
void spi_message_init(struct spi_message *m)
- m:要初始化的spi_message。
- 返回值:无。
使用spi_message_add_tail将spi_transfer添加到spi_message队列中。
void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
- t:要添加到队列的spi_transfer。
- m:spi_transfer要加入的spi_message。
- 返回值:无。?
使用spi_sync进行同步数据传输。
int spi_sync(struct spi_device *spi, struct spi_message *message)
- spi:要进行数据传输的spi_device。
- message:要传输的spi_message。
- 返回值:无。
使用spi_async进行异步数据传输,异步传输完成后执行complete回调函数。
int spi_async(struct spi_device *spi, struct spi_message *message)
- spi:要进行数据传输的spi_device。
- message:要传输的spi_message。
- 返回值:无。
通过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;
}
|