外设驱动→API→主机驱动→板级逻辑--具体的i2c设备(camera,ts,eeprom等等)
主机驱动:根据控制器硬件手册,操作具体的寄存器,产生波形。(单片机工程师肯定有强烈的冲动去配置i2c寄存器,产生波形!)。
linux应用工程师:屏蔽了驱动和硬件。
linux驱动工程师:屏蔽硬件!提供标准的主机驱动,驱动工程师需要完成“外设驱动”
内核函数接口:(API)。主机驱动提供给外设驱动的函数接口。
注册i2c设备:i2c_board_info
驱动注册和卸载函数以及结构体:i2c_del_driver/i2c_add_driver,i2c_driver
读写函数和结构体:i2c_transfer,i2c_msg
这几个函数是放之四海而皆准!
外设驱动:针对具体的外部器件的代码。
摄像头以及声卡中i2c用来配置外部设备(声卡和摄像头)→地址和配置的内容都不一样!
板级逻辑:描述主机和外部设备是怎么连接的。
教程中介绍:I2C函数接口(API):
设备注册:i2c_board_info
驱动注册函数和结构体:i2c_del_driver/i2c_add_driver,i2c_driver
读写函数和结构体:i2c_transfer,i2c_msg
查询i2c设备地址:
ls /sys/bus/i2c/devices/
怎么和原理图以及外部设备对应:3-0038→I2C_3_SCL(addr:datasheet中查0x38)
查询i2c设备名称:
cat /sys/bus/i2c/devices/3-0038/name
menuconfig中去掉触摸的驱动
Device Drivers --->
Input device support --->
Touchscreens --->
FT5X0X based touchscreens(去掉)
在arch\arm\mach-exynos\mach-itop4412.c中
添加i2c设备:i2c_devs3[]中添加
{
I2C_BOARD_INFO("i2c_test", 0x70>>1),
},
cat /sys/bus/i2c/devices/3-0038/name结果是i2c_test
i2c设备驱动初始化完成-进入probe函数。
i2c_del_driver/i2c_add_driver:i2c_driver
module_init和late_initcall:module_init先运行,late_initcall后运行。
i2c_transfer,i2c_msg
- struct i2c_msg {
- __u16 addr; /* slave address */
- __u16 flags;
- #define I2C_M_RD 0x0001 /* read data, from slave to master */
- __u16 len; /* msg length */
- __u8 *buf; /* pointer to msg data */
- };
要完成i2c的读,必须要先写再读!写的时候,你要通知从机,你要读哪个寄存器!
1、late_initcall(i2c_test_init);
模块延后执行i2c_test_init,在函数中调用i2c_add_driver(&i2c_test_driver);
2、i2c_add_driver(&i2c_test_driver);
将i2c_test_driver驱动添加到I2C总线上。开始调用i2c_test_driver中的i2c_test_probe。
3、i2c_test_probe
匹配我们前面注册的设备:i2c_test,i2c_test_driver驱动开始运行,
4、misc_register(&i2c_dev);
创建成杂项设备。设备名"i2c_control", // 可以在/dev目录下看到
5、i2c_ops:
定义设备操作函数
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/input.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/gpio.h>
- #include <linux/platform_device.h>
- #ifdef CONFIG_HAS_EARLYSUSPEND
- #include <linux/earlysuspend.h>
- #endif
- #include <linux/regulator/consumer.h>
- #include <mach/gpio.h>
- #include <plat/gpio-cfg.h>
- #include <asm/uaccess.h>
- #include <linux/miscdevice.h>
- static struct i2c_client *this_client;
- static int i2c_tes_read_reg(struct i2c_client *client,u8 addr, u8 *pdata) {
- u8 buf1[4] = { 0 };
- u8 buf2[4] = { 0 };
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr, //0x38
- .flags = 0, //写
- .len = 1, //要写的数据的长度
- .buf = buf1,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = buf2,
- },
- };
- int ret;
- buf1[0] = addr;
- ret = i2c_transfer(client->adapter, msgs, 2);
- if (ret < 0) {
- pr_err("read reg (0x%02x) error, %d\n", addr, ret);
- } else {
- *pdata = buf2[0];
- }
- return ret;
- }
- static int i2c_tes_read_fw_reg(struct i2c_client *client,unsigned char *val)
- {
- int ret;
- *val = 0xff;
- ret = i2c_tes_read_reg(client,0xa6, val);
- printk("ts reg 0xa6 val is %d\n",*val);
- return ret;
- }
- static int i2c_open_func(struct file *filp)
- {
- return 0;
- }
- static int i2c_release_func(struct file *filp)
- {
- return 0;
- }
- static ssize_t i2c_read_func(struct file *filp, char __user *buffer, size_t count, loff_t *ppos){
- int ret;
- u8 reg_data;
- ret = copy_from_user(®_data,buffer,1);
- struct i2c_msg msgs[] = {
- {
- .addr = this_client->addr, //0x38
- .flags = 0, //写
- .len = 1, //要写的数据的长度
- .buf = ®_data,
- },
- {
- .addr = this_client->addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = ®_data,
- },
- };
- ret = i2c_transfer(this_client->adapter, msgs, 2);
- if (ret < 0) {
- pr_err("read reg error!\n");
- }
- ret = copy_to_user(buffer,®_data,1);
- return ret;
- }
- static ssize_t i2c_write_func(struct file *filp, char __user *buffer, size_t count, loff_t *ppos){
- int ret;
- u8 buf[2];
- struct i2c_msg msgs[1];
- ret = copy_from_user(&buf,buffer,2);
- msgs[0].addr = this_client->addr; //0x38
- msgs[0].flags = 0; //写
- msgs[0].len = 2; //第一个是要写的寄存器地址,第二个是要写的内容
- msgs[0].buf = buf;
- ret = i2c_transfer(this_client->adapter, msgs, 1);
- if (ret < 0) {
- pr_err("write reg 0x%02x error!\n",buf[0]);
- }
- ret = copy_to_user(buffer,buf,1);
- return ret;
- }
- static struct file_operations i2c_ops = {
- .owner = THIS_MODULE,
- .open = i2c_open_func,
- .release= i2c_release_func,
- .write = i2c_write_func,
- .read = i2c_read_func,
- };
- static struct miscdevice i2c_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .fops = &i2c_ops,
- .name = "i2c_control", // 可以在/dev目录下看到
- };
- static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
- {
- unsigned char val;
- printk("==%s:\n", __FUNCTION__);
- i2c_tes_read_fw_reg(client,&val);
- this_client = client;
- misc_register(&i2c_dev);
- return 0;
- }
- static int __devexit i2c_test_remove(struct i2c_client *client)
- {
- i2c_set_clientdata(client, NULL);
- misc_deregister(&i2c_dev);
- printk("==%s:\n", __FUNCTION__);
- return 0;
- }
- static const struct i2c_device_id i2c_test_id[] = {
- { "i2c_test", 0 },
- { }
- };
- static struct i2c_driver i2c_test_driver = {
- .probe = i2c_test_probe,
- .remove = __devexit_p(i2c_test_remove),
- .id_table = i2c_test_id, // 驱动能匹配的设备
- .driver = {
- .name = "i2c_test", // 可以在sys/bus/i2c/drivers/目录下看到驱动名称
- .owner = THIS_MODULE,
- },
- };
- static void i2c_io_init(void)
- {
- int ret;
- ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN");
- if (ret) {
- printk(KERN_ERR "failed to request TP1_EN for "
- "I2C control\n");
- //return err;
- }
- gpio_direction_output(EXYNOS4_GPL0(2), 1);
- s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT);
- gpio_free(EXYNOS4_GPL0(2));
- mdelay(5);
- ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
- if (ret) {
- gpio_free(EXYNOS4_GPX0(3));
- ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
- if(ret)
- {
- printk("ft5xox: Failed to request GPX0_3 \n");
- }
- }
- gpio_direction_output(EXYNOS4_GPX0(3), 0);
- mdelay(200);
- gpio_direction_output(EXYNOS4_GPX0(3), 1);
- s3c_gpio_cfgpin(EXYNOS4_GPX0(3), S3C_GPIO_OUTPUT);
- gpio_free(EXYNOS4_GPX0(3));
- msleep(300);
- }
- static int __init i2c_test_init(void)
- {
- printk("==%s:\n", __FUNCTION__);
- i2c_io_init();
- printk("==%s:\n", __FUNCTION__);
- return i2c_add_driver(&i2c_test_driver);
- }
- static void __exit i2c_test_exit(void)
- {
- printk("==%s:\n", __FUNCTION__);
- i2c_del_driver(&i2c_test_driver);
- }
- late_initcall(i2c_test_init);
- module_exit(i2c_test_exit);
- MODULE_AUTHOR("xunwei_rty");
- MODULE_DESCRIPTION("TsI2CTest");
- MODULE_LICENSE("GPL");
模块运行结果
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- int main(int argc,char **argv)
- {
- int fd,ret;
- char *i2c_device = "/dev/i2c_control";
- unsigned char buffer[2];
- printf("open %s!\n",i2c_device);
- if((fd = open(i2c_device,O_RDWR|O_NDELAY))<0)
- printf("APP open %s failed",i2c_device);
- else{
- printf("APP open %s success!\n",i2c_device);
- }
- //读一个数据0xa6
- buffer[0] = 0xa6;
- ret = read(fd,buffer,1);
- if(ret<0)
- printf("i2c read failed!\n");
- else{
- printf("i2c read reg 0xa6 data is 0x%02x!\n",buffer[0]);
- }
- //01先从0x00读出一个数据,02写一个数据到0x00,03再读出来对比
- //01
- buffer[0] = 0x00;
- read(fd,buffer,1);
- printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[0]);
- //02
- buffer[0] = 0x00;
- buffer[1] = 0x40;
- ret = write(fd,buffer,2);
- if(ret<0){
- printf("i2c write failed!\n");
- goto exit;
- }
- //03
- buffer[0] = 0x00;
- read(fd,buffer,1);
- printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[0]);
- close(fd);
- exit:
- close(fd);
- return -1;
- }
运行应用程序结果
联系客服