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;
#ifdefstruct 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;
#endifi2c_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;//使用一些内核函数接口去获取设备树定义的值//如gpioint 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 1int 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的驱动和调试驱动。后面调试和编写遇到不同的情况再继续完善吧。