LINUX驱动开发(SPI)SPI主机驱动代码解析

1. 驱动调用过程

分析代码可以在内核中看相关驱动代码和驱动框架。

  1. 注册platform_driver结构体,填充成员函数;
  2. 驱动中的compatible属性与设备树中的compatible属性匹配成功后,调用probe函数;
  3. 在probe函数中注册和设置spi;
  4. 在remove函数中注销和释放spi;

2. spi_master驱动框架

static const struct of_device_id spi_virtual_dt_ids[] = {
	{ .compatible = "my,spidev", },
	{ /* sentinel */ }
};

static int spi_virtual_probe(struct platform_device *pdev)
{
	return 0;
}

static int spi_virtual_remove(struct platform_device *pdev)
{
	return 0;
}


static struct platform_driver spi_virtual_driver = {
	.probe = spi_virtual_probe,
	.remove = spi_virtual_remove,
	.driver = {
		.name = "virtual_spi",
		.of_match_table = spi_virtual_dt_ids,
	},
};

static int virtual_master_init(void)
{
	printk("***virtual_master_init***\r\n");
	return platform_driver_register(&spi_virtual_driver);
}

static void virtual_master_exit(void)
{
	printk("***virtual_master_exit***\r\n");
	platform_driver_unregister(&spi_virtual_driver);
}

module_init(virtual_master_init);
module_exit(virtual_master_exit);

MODULE_DESCRIPTION("Virtual SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lljwork2021");

2. 分配spi_master

/* 针对ST芯片 */
static struct completion g_xfer_done;

static int spi_virtual_probe(struct platform_device *pdev)
{
	struct spi_master *master;
	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_bitbang));
	init_completion(&g_xfer_done);
	return 0;
}
/* 针对NXP芯片 */
static struct spi_master *g_virtual_master;
static struct spi_bitbang *g_virtual_bitbang;
static struct completion g_xfer_done;

static int spi_virtual_probe(struct platform_device *pdev)
{
	struct spi_master *master;
	g_virtual_master = master = spi_alloc_master(&pdev->dev, sizeof(struct spi_bitbang));
	if (!master)
		return -ENOMEM;
	g_virtual_bitbang  = spi_master_get_devdata(master);
	init_completion(&g_xfer_done);
	return 0;
}

3. 注册spi_master

/* 
* 针对ST芯片
* linux/drivers/spi/spi-stm32.c 
*/
/* 注册代码 */
ret = spi_register_master(master); /* 注册函数 */
if (ret) {
	printk("spi_register_master fail\n");
	spi_master_put(master); 
	return ret;
}
	
/* 注销代码 */
spi_unregister_master(g_virtual_master); /* 注销函数 */
/* 
* 方法二: 针对NXP芯片
* linux-kernel/drivers/spi/spi-imx.c
* linux-kernel/include/linux/spi/spi.h
* linux-kernel/include/linux/spi/spi_bitbang.h
* linux-kernel/drivers/spi/spi-bitbang.c
*/
函数:
int spi_bitbang_start(struct spi_bitbang *bitbang); /* 注册函数 */
void spi_bitbang_stop(struct spi_bitbang *bitbang); /* 注销函数 */
spi_master_put(_ctlr)	/* 释放内存 */
#define spi_master_put(_ctlr)		spi_controller_put(_ctlr)
static inline void spi_controller_put(struct spi_controller *ctlr)

参考代码:
/* 注册代码 */
ret = spi_bitbang_start(g_virtual_bitbang);
if (ret) {
	printk("spi_bitbang_start fail\n");
	return ret;

/* 注销代码 */
spi_bitbang_stop(g_virtual_bitbang);
spi_master_put(g_virtual_master);

4. 设置spi-master

static int spi_virtual_transfer(struct spi_device *spi, struct spi_transfer *transfer)
{
	int timeout;
	reinit_completion(&g_xfer_done);
	complete(&g_xfer_done);
	timeout = wait_for_completion_timeout(&g_xfer_done, 100);
	if (!timeout) {
		dev_err(&spi->dev, "I/O Error in PIO\n");
		return -ETIMEDOUT;
	}
	return transfer->len;
}

static void	spi_virtual_chipselect(struct spi_device *spi, int is_on)
{

}
/* 针对NXP 
 * linux-kernel/include/linux/spi/spi_bitbang.h  
 */
g_virtual_bitbang->master = master;
g_virtual_bitbang->txrx_bufs  = spi_virtual_transfer;
g_virtual_bitbang->chipselect = spi_virtual_chipselect;
/*
针对ST
linux-kernel/include/spi/spi.h
#define spi_master spi_controller
struct spi_controller {
......
}
*/
master->dev.of_node = pdev->dev.of_node;

5. 内核API

/* linux-kernel/Documentation/scheduler/completion.rst */
init_completion
reinit_completion
unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lljwork2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值