【Linux驱动开发】SPI

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数据收发步骤

  1. 申请并初始化spi_transfer,设置spi_transfer的tx_buf成员变量、rx_buf成员变量、len成员变量。
  2. 使用spi_message_init初始化spi_message。
  3. 使用spi_message_add_tail将spi_transfer添加到spi_message队列中。
  4. 使用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;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部