• 4412 i2c驱动


    1.Linux主机驱动和外设驱动分离思想

    外设驱动→API→主机驱动→板机逻辑--具体的i2c设备(camera,ts,eeprom等等)

    2.主机驱动

    根据控制器硬件手册,操作具体的寄存器,产生波形。

    • Linux应用工程师:屏蔽了驱动和硬件
    • Linux驱动工程师:屏蔽硬件,提供标准的主机驱动。驱动工程师需要完成“外设驱动”
    • 内核函数接口:(API)。主机驱动提供給外设驱动的函数接口
      1. 注册i2c设备:i2c_board_info
      2. 驱动注册和卸载函数以及结构体:i2c_del_driver/i2c_add_driver, i2c_driver
      3. 读写函数和结构体:i2c_transfer, i2c_msg

    这些函数放之四海之内皆准

    3.外设驱动

    针对具体的外部器件的代码。

    • 摄像头以及声卡中i2c用来配置外部设备(声卡和摄像头)→地址和配置的内容都不一样!

    4.板级逻辑

    描述主机和外部设备是怎么连接的

    5.设备-i2c设备注册以及设备注册之后的查询方法

    • 查询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(去掉)

    添加i2c设备:i2c_devs3[]中添加
            {
                    I2C_BOARD_INFO("i2c_test", 0x70>>1),
            },
    cat /sys/bus/i2c/devices/3-0038/name结果是i2c_test   

    6.驱动-i2c驱动注册和卸载

    i2c设备初始化完成-进入probe函数

    i2c_del_driver/i2c_add_driver, i2c_driver

    module_init和late_initcall:前面的优先加载,后面的延迟加载

     驱动代码:

    #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/interrupt.h>
    #include <linux/irq.h>
    #include <linux/gpio.h>
    #include <linux/platform_device.h>
    
    #include <linux/regulator/consumer.h>
    
    #include <mach/gpio.h>
    #include <plat/gpio-cfg.h>
    #include <plat/ft5x0x_touch.h>
    
    #define I2C_TEST_NAME "i2c_test"
    
    static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
            printk("==%s: 
    ", __FUNCTION__);
            return 0;
    }
    
    static int __devexit i2c_test_remove(struct i2c_client *client)
    {
            i2c_set_clientdata(client, NULL);               //设置client为NULL
            printk("==%s: 
    ", __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_NAME,
                    .owner = THIS_MODULE,
            },
    };
    
    static void i2c_io_init()
    {
            int ret;
            ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN");
            if(ret) {
                    printk(KERN_ERR "failed to request TP1_EN for I2C control
    ");
            }
    
            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("i2c_io_test: Fialed to request GPX0_3 
    ");
                    }
            }
            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: 
    ", __FUNCTION__);
            i2c_io_init();
            printk("==%s: 
    ", __FUNCTION__);
            return i2c_add_driver(&i2c_test_driver);
    }
    
    static void __exit i2c_test_exit(void)
    {
            printk("==%s: 
    ", __FUNCTION__);
            i2c_del_driver(&i2c_test_driver);
    }
    
    late_initcall(i2c_test_init);
    module_exit(i2c_test_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("TSI2CTEST");
    MODULE_AUTHOR("iTOP");
    i2c.c

    Makefile:

    TARGET_NAME = i2c
    #APP_NAME = app_pollkey
    obj-m += $(TARGET_NAME).o
    
    KDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0
    
    PWD ?= $(shell pwd)
    
    all:
            make -C $(KDIR) M=$(PWD) modules
    
    #app:$(APP_NAME)
    #       arm-none-linux-gnueabi-gcc $(APP_NAME).c -o $(APP_NAME) -static
    
    clean:
            rm -rf *.o *.ko *.mod.c *.symvers *.order 
            .$(TARGET_NAME)* $(APP_NAME)
    Makefile

    测试结果:

    [root@iTOP-4412]# insmod i2c.ko                                                        
    [  381.451187] ==i2c_test_init: 
    [  382.020037] ==i2c_test_init: 
    [  382.021601] ==i2c_test_probe: 
    [root@iTOP-4412]# rmmod i2c
    [  385.294465] ==i2c_test_exit: 
    [  385.296008] ==i2c_test_remove:
    测试结果

    7.驱动-i2c数据的传输(9.7寸或者7寸屏幕)

    i2c_transfer, i2c_msg

    struct i2c_msg {
        __u16 addr; /* slave address            */
        __u16 flags;
    #define I2C_M_TEN       0x0010  /* this is a ten bit chip address */
    #define I2C_M_RD        0x0001  /* read data, from slave to master */
    #define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
    #define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */
        __u16 len;      /* msg length               */
        __u8 *buf;      /* pointer to msg data          */
    }; 

    int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

    参数1:probe传进的client里的adapter

    代码:

    #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 <plat/ft5x0x_touch.h>
    
    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
    ", 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
    ",*val);
        return ret;
    }
    
    
    static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
        unsigned char val;
        printk("==%s:
    ", __FUNCTION__);
        
        i2c_tes_read_fw_reg(client,&val);
        
        return 0;
    }
    
    static int __devexit i2c_test_remove(struct i2c_client *client)
    {
        i2c_set_clientdata(client, NULL);
        printk("==%s:
    ", __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",
            .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
    ");
            //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 
    ");
        }
        }
        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:
    ", __FUNCTION__);
        i2c_io_init();
        printk("==%s:
    ", __FUNCTION__);
        return i2c_add_driver(&i2c_test_driver);
    }
    static void __exit i2c_test_exit(void)
    {
        printk("==%s:
    ", __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");
    i2c_test_read_9x7_7.c

    8.Liux-i2c利用字符驱动

    完成应用层对i2c的读和写(9.7寸或者7寸屏幕)

     驱动

    #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
    ", 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
    ",*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(&reg_data,buffer,1);
        
        struct i2c_msg msgs[] = {
            {
                .addr    = this_client->addr,    //0x38
                .flags    = 0,    //
                .len    = 1,    //要写的数据的长度
                .buf    = &reg_data,
            },
            {
                .addr    = this_client->addr,
                .flags    = I2C_M_RD,
                .len    = 1,
                .buf    = &reg_data,
            },
        };
        ret = i2c_transfer(this_client->adapter, msgs, 2);
        if (ret < 0) {
            pr_err("read reg error!
    ");
        }
        ret = copy_to_user(buffer,&reg_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!
    ",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",
    };
    
    static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
        unsigned char val;
        printk("==%s:
    ", __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:
    ", __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",
            .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
    ");
            //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 
    ");
        }
        }
        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:
    ", __FUNCTION__);
        i2c_io_init();
        printk("==%s:
    ", __FUNCTION__);
        return i2c_add_driver(&i2c_test_driver);
    }
    static void __exit i2c_test_exit(void)
    {
        printk("==%s:
    ", __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");
    i2c_char.c

    应用

    #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!
    ",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!
    ",i2c_device);
        }
        
    //读一个数据0xa6
        buffer[0] = 0xa6;
        ret = read(fd,buffer,1);
        if(ret<0)
            printf("i2c read failed!
    ");
        else{
            printf("i2c read reg 0xa6 data is 0x%02x!
    ",buffer[0]);
        }
        
    //01先从0x00读出一个数据,02写一个数据到0x00,03再读出来对比
        //01
        buffer[0] = 0x00;
        read(fd,buffer,1);
        printf("i2c read reg 0x00 data is 0x%02x!
    ",buffer[0]);
        //02
        buffer[0] = 0x00;
        buffer[1] = 0x40;
        ret = write(fd,buffer,2);
        if(ret<0){
            printf("i2c write failed!
    ");
            goto exit;
        }
        //03
        buffer[0] = 0x00;
        read(fd,buffer,1);
        printf("i2c read reg 0x00 data is 0x%02x!
    ",buffer[0]);
        
        close(fd);
        
    exit:
        close(fd);
        return -1;
    }
    app_i2c
  • 相关阅读:
    MySQL如何利用索引优化ORDER BY排序语句 【转载】
    c++拼接字符串效率比较(+=、append、stringstream、sprintf)
    Mysql 的字符编码机制、中文乱码问题及解决方案【转载】
    Java连接MySQL中文乱码处理【转载】
    Java 接口
    Java 抽象类和Final关键字
    Java 对象转型
    Java 动态绑定和多态
    Java 继承和访问控制
    Java Class Object
  • 原文地址:https://www.cnblogs.com/ch122633/p/9518648.html
Copyright © 2020-2023  润新知