当前位置: 首页 > article >正文

Linux 编写I2C驱动简单模板

I2C驱动简单模板

  • 1、开发环境
  • 2、驱动编写模板
    • 2.1 加载/卸载模块
    • 2.2 定义一个i2c_driver结构体和驱动自身使用的结构体
    • 2.3 设备探测函数和设备移除函数
    • 2.4 获取设备树中的参数值
    • 2.5 读取/写入数据
    • 3.总结

1、开发环境

Linux版本:Linux3.10以上的内核即可
适用驱动:I2C类型的驱动

2、驱动编写模板

2.1 加载/卸载模块

static int __init xxx_init(void)
{
	return i2c_add_driver(xxx_i2c_driver);
}
static void __exit xxx_exit(void)
{
	i2c_del_driver(&xxx_i2c_driver);
}

2.2 定义一个i2c_driver结构体和驱动自身使用的结构体


struct i2c_device_id of_i2c_match[] = {
	{I2C_DEVICE_NAME,0},
	{}
};
//设备树匹配
struct of_device_id of_device_match[] = {
	{.compatible = "xxxx_dts_name"},
	{}
};
static struct i2c_driver xxx_i2c_driver = {
	.driver = {
		.owner = THIS_MODULE,
		.of_match_table = of_device_match,
		.name = I2C_DEVICE_NAME,
	},
	.id_table = of_i2c_match,
	.probe = xxx_i2c_probe,
	.remove = xxx_i2c_remove,
};

struct xxx_dev
{
	struct device *dev;
	struct i2c_client *client;
#ifdef
	struct regmap *regmap;
#endif
};

2.3 设备探测函数和设备移除函数

static int xxx_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct xxx_dev *lt;
	struct device *dev = &client->dev;
	
	pdev = kzalloc(sizeof(*pdev),GFP_KERNEL);
	if (pdev == NULL)
	{
		printk("kzalloc GFP_KERNEL Failed!\n");
		return -ENOMEM;
	}
	
	//判断该I2C总线是否可以使用
	if (! i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
	{
		printk("i2c check Failed!\n");
		return -EINVAL;
	}
	
	lt->dev = dev;
	lt->client = client;
	
	
	//如果有设备树节点的话
	if(dev->of_node)
	{
		if (get_parse_dt(&client->dev))
		{
			printk("get dt info Failed!\n");
			return -EINVAL;
		}
	}
#ifdef REGMAP
	//如果通过regmap_write/regmap_read访问设备的寄存器的话
	struct regmap * regmap;//放在函数开头
	
	regmap = devm_regmap_init_i2c(client, &xxx_i2c_regmap_config);
	lt->regmap = regmap;
#endif
	i2c_set_clientdata(client, lt);//
	return 0;
}


int xxx_i2c_remove(struct i2c_client *client)
{
	return 0;
}

2.4 获取设备树中的参数值

static bool get_parse_dt(struct device *dev)
{
	struct device_node *np = dev->of_node;
	int ret = 0;
	int value;
	//使用一些内核函数接口去获取设备树定义的值
	//如gpio
	
	int gpio = of_get_named_gpio(np, "xxx_gpio", 0);
	if (gpio)
	{
		ret = gpio_request(gpio, "xxx_gpio");
		if (ret)
		{
			printk("Failed to request xxx_gpio !\n");
			return false;
		}
	}
	//获取数值
	
	of_property_read_u32(np, "xxx_name", &value);
	return true;
} 

2.5 读取/写入数据

这种方法适合需要初始化或读写比较多寄存器的设备
#ifdef
//如果通过regmap_write/regmap_read访问设备的寄存器的话
static const struct regmap_config xxx_i2c_regmap_config = {
	.reg_bits = 8;
	.val_bits = 8;
	.max_register = 0xff;
};
void read_xxx_register(struct i2c_client *client)
{
	int value;
	struct xxx_dev *lt = i2c_get_clientdata(client);
	regmap_read (lt->regmap, 0x00, value);
}

void write_xxx_register(struct i2c_client *client)
{
	struct xxx_dev *lt = i2c_get_clientdata(client);
	regmap_write(lt->regmap, 0x00 , 0x00);
	
}
#endif

第二种方法:第一种方法通过了内核相关函数调用i2c_transfer,现在是直接使用i2c_transfer函数

u32 i2c_read_byte(struct i2c_client *client, u8 *buf, u32 len)
{
    #define EXECUTE_CNT 2
	#define I2C_ADDR_LENGTH 1	int ret;
	struct i2c_msg msg[2];
	msg[0].flag = !I2C_M_RD;
	msg[0].addr = client->addr;
	msg[0].len = I2C_ADDR_LENGTH;
	msg[0].buf = &buf[0];
	
	msg[1].flag = I2C_M_RD;
	msg[1].addr = client->addr;
	msg[1].len = len - I2C_ADDR_LENGTH;
	msg[1].buf = &buf[I2C_ADDR_LENGTH];

	ret = i2c_transfer(client->adapter, &msg, EXECUTE_CNT);
	if (ret == EXECUTE_CNT)
	{
		for(int i = I2C_ADDR_LENGTH; i < len; i++)
				printk("read success!,%d-%d\n",i,buf[i]);
	}
}

u32 i2c_write_byte(struct i2c_client* client,u8 *buf, s32 len)
{
	#define EXECUTE_CNT 1
	int ret;
	struct i2c_msg msg;
	msg.flag = !I2C_M_RD;//读
	msg.addr = client->addr;
	msg.len = len;
	msg.buf = buf;
	
	ret = i2c_transfer(client->adapter, &msg , EXECUTE_CNT);
	if (ret == EXECUTE_CNT)
	{
		printk("write success!\n");
	}
}

3.总结

为了方便以后写关于I2C的驱动和调试驱动。后面调试和编写遇到不同的情况再继续完善吧。


http://www.kler.cn/a/286948.html

相关文章:

  • 深度学习中Batch Normalization(BN)原理、作用浅析
  • 系统思考—转型
  • 可以自己部署的微博 Mastodon
  • TiDB与Oracle:数据库之争,谁能更胜一筹?
  • 麒麟操作系统服务架构保姆级教程(十三)tomcat环境安装以及LNMT架构
  • 上位机工作感想-2024年工作总结和来年计划
  • 数据结构(6.4_4)——Floyd算法
  • 单元测试 Mock不Mock?
  • 基于QT与STM32的电力参数采集系统(华为云IOT)(211)
  • 【RabbitMQ应用篇】常见应用问题
  • 【Canvas与数学】N边形中的N边形
  • linux本地库迁移到阿里云云redis
  • GoLang:Go语言开发环境的配置
  • 探索AntSKPro AI知识库一体机:离线智能的便捷之选
  • 什么是CSRF跨站请求伪造
  • 国产开源最强?Qwen2-VL强势发布,效果实测!
  • mysql高可用之组复制
  • 数据结构(邓俊辉)学习笔记】串 06——KMP算法:构造next[]表
  • 鸿蒙界面开发(12):选项卡布局(Tabs)
  • Rust到底值不值得学,之二
  • JAVA呵护晚年从智慧开始养老护理代办陪诊陪护小程序
  • 《自然语言处理》—— jieba库的介绍与使用
  • 024、架构_资源_主机
  • Django开发
  • 深度学习基础-- 浅层神经网络
  • 【Rust练习】11.struct