Linux 编写I2C驱动简单模板

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的驱动和调试驱动。后面调试和编写遇到不同的情况再继续完善吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

赟赟、嵌入式

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

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

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

打赏作者

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

抵扣说明:

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

余额充值