树莓派3B+驱动开发(8)- i2c控制PCF8591
github主页:https://github.com/snqx-lqh
本项目github地址:https://github.com/snqx-lqh/RaspberryPiDriver
本项目硬件地址:https://oshwhub.com/from_zero/shu-mei-pai-kuo-zhan-ban
欢迎交流
笔记说明
这一节,主要是设备树有点不同,其他和正点原子的教程差不多。
主要参考的文章
正点原子《I.MX6U 嵌入式 Linux 驱动开发指南 V1.81》
本节源码路径02_Firmware/16_pcf8591_drv_i2c
设备树
这里为了减少篇幅,只是写了i2c相关的,完整的看项目源代码。
// Definitions for gpio-key module
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835";
fragment@2 {
// Configure the gpio pin controller
target = <&i2c1>;
__overlay__ {
clock-frequency = <100000>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
pcf8591@48{
compatible = "shb,pcf8591";
reg = <0x48>;
};
};
};
fragment@3 {
target = <&i2c1_pins>;
pins1: __overlay__ {
brcm,pins = <2 3>;
brcm,function = <4>; /* alt 0 */
};
};
};
驱动代码
首先驱动出入口函数发生了变化,使用的是和i2c相关的注册和注销。
/* 传统匹配方式ID列表 */
static const struct i2c_device_id pcf8591_id[] = {
{"shb,pcf8591", 0},
{}
};
/* 设备树匹配列表 */
static const struct of_device_id pcf8591_of_match[] = {
{ .compatible = "shb,pcf8591" },
{ /* Sentinel */ }
};
/* i2c驱动结构体 */
static struct i2c_driver pcf8591_driver = {
.probe = pcf8591_probe,
.remove = pcf8591_remove,
.driver = {
.owner = THIS_MODULE,
.name = "pcf8591",
.of_match_table = pcf8591_of_match,
},
.id_table = pcf8591_id,
};
static int __init pcf8591_init(void)
{
int ret = 0;
ret = i2c_add_driver(&pcf8591_driver);
return ret;
}
static void __exit pcf8591_exit(void)
{
i2c_del_driver(&pcf8591_driver);
}
module_init(pcf8591_init);
module_exit(pcf8591_exit);
其他的差别不大
然后i2c的读写方式如下
static int pcf8591_read_regs(pcf8591_dev_t *dev, u8 reg, void *val, int len)
{
int ret;
struct i2c_msg msg[2];
struct i2c_client *client = (struct i2c_client *)dev->client;
/* msg[0]为发送要读取的首地址 */
msg[0].addr = client->addr; /* pcf8591地址 */
msg[0].flags = 0; /* 标记为发送数据 */
msg[0].buf = ® /* 读取的首地址 */
msg[0].len = 1; /* reg长度*/
/* msg[1]读取数据 */
msg[1].addr = client->addr; /* pcf8591地址 */
msg[1].flags = I2C_M_RD; /* 标记为读取数据*/
msg[1].buf = val; /* 读取数据缓冲区 */
msg[1].len = len; /* 要读取的数据长度*/
ret = i2c_transfer(client->adapter, msg, 2);
if(ret == 2) {
ret = 0;
} else {
printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
static s32 pcf8591_write_regs(pcf8591_dev_t *dev, u8 reg, u8 *buf, u8 len)
{
u8 b[10];
struct i2c_msg msg;
struct i2c_client *client = (struct i2c_client *)dev->client;
b[0] = reg; /* 寄存器首地址 */
memcpy(&b[1],buf,len); /* 将要写入的数据拷贝到数组b里面 */
msg.addr = client->addr; /* pcf8591地址 */
msg.flags = 0; /* 标记为写数据 */
msg.buf = b; /* 要写入的数据缓冲区 */
msg.len = len + 1; /* 要写入的数据长度 */
return i2c_transfer(client->adapter, &msg, 1);
}
其他的就是正常的读写操作了。