十九、I2C驱动及应用
一、概述
1、Linux主機驅動和外設驅動分離思想
????????外設驅動→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?
2.設備-i2c設備注冊以及設備注冊之后的查詢方法
????????查詢i2c設備地址:
ls /sys/bus/i2c/devices/????????怎么和原理圖以及外部設備對應:3-0038→I2C_3_SCL(addr:datasheet中查0x38)
????????查詢i2c設備名稱:
????????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?? ?
3.驅動-i2c驅動注冊和卸載。
????????i2c設備驅動初始化完成-進入probe函數。
????????i2c_del_driver/i2c_add_driver:i2c_driver
????????module_init和late_initcall:module_init先運行,late_initcall后運行。
4.驅動-i2c數據的傳輸
????????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; //0x38msgs[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);}//讀一個數據0xa6buffer[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再讀出來對比//01buffer[0] = 0x00;read(fd,buffer,1);printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[0]);//02buffer[0] = 0x00;buffer[1] = 0x40;ret = write(fd,buffer,2);if(ret<0){printf("i2c write failed!\n");goto exit;}//03buffer[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; }運行應用程序結果
?
總結
以上是生活随笔為你收集整理的十九、I2C驱动及应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十八、中断之独立按键
- 下一篇: 二十、SPI设备驱动及应用(一)