历史上的今天
返回首页

历史上的今天

今天是:2024年12月30日(星期一)

正在发生

2021年12月30日 | 4412 i2c驱动

2021-12-30 来源:eefocus

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:前面的优先加载,后面的延迟加载

 驱动代码:

i2c.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include


#include

#include

#include


#define I2C_TEST_NAME "i2c_test"


static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

        printk("==%s: n", __FUNCTION__);

        return 0;

}


static int __devexit i2c_test_remove(struct i2c_client *client)

{

        i2c_set_clientdata(client, NULL);               //设置client为NULL

        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_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 controln");

        }


        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 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_LICENSE("GPL");

MODULE_DESCRIPTION("TSI2CTEST");

MODULE_AUTHOR("iTOP");


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)


测试结果:

[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

代码:

i2c_test_read_9x7_7.c

#include

#include

#include

#include

#include

#include

#include

#include

#ifdef CONFIG_HAS_EARLYSUSPEND

#include

#endif

#include

#include

#include

#include


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, %dn", 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 %dn",*val);

    return ret;

}



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);

    

    return 0;

}


static int __devexit i2c_test_remove(struct i2c_client *client)

{

    i2c_set_clientdata(client, NULL);

    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",

        .owner    = THIS_MODULE,

上一篇:4412 SPI驱动

下一篇:4412 按键和中断

推荐阅读

史海拾趣

ADDtek公司的发展小趣事

对不起,我无法提供有关ADDtek公司发展的故事。

FINISAR公司的发展小趣事

FINISAR在光模块领域取得了多项重要技术创新和突破。例如,公司在1992年推出了首个850nm的千兆多模光纤光收发模块,随后在1995年推出了带数字诊断功能的光收发模块,这些创新产品极大地推动了光通信技术的发展。此外,FINISAR还不断推出新产品以满足市场需求,如SFP光模块、CWDM GBIC光模块等,这些产品均获得了市场的广泛认可。

ALD [Advanced Linear Devices]公司的发展小趣事

FINISAR公司(前身为Finisar Corporation)成立于1987年(另有资料称成立于1988年),总部位于美国加利福尼亚州的硅谷地区。公司自创立之初便专注于光通信技术的研发与应用,致力于设计、制造和销售高性能的光模块和光网络设备。在成立初期,FINISAR凭借其创新的技术和高质量的产品,在光通信市场上逐渐崭露头角,为后续的快速发展奠定了坚实基础。

Firadec公司的发展小趣事

背景:假设Firadec公司(此处为虚构名称)成立于20世纪90年代初,正值半导体技术快速发展的时期。公司创始人是一位在半导体领域有深厚造诣的科学家,他带领团队研发出了一种新型低功耗、高性能的集成电路技术。

发展:这项技术迅速获得了市场的认可,Firadec公司凭借这一创新产品迅速在电子行业崭露头角。公司不断加大研发投入,持续优化产品性能,逐渐在智能手机、平板电脑等消费电子领域占据了一席之地。

影响:随着技术的不断成熟和应用领域的拓展,Firadec公司的市场份额逐年提升,成为了电子行业中的佼佼者。其技术创新不仅推动了公司自身的发展,也为整个电子行业的进步做出了重要贡献。

AiT Semiconductor Inc公司的发展小趣事

在半导体行业,技术创新是企业持续发展的关键。AiT公司深知这一点,因此始终将创新作为公司的核心竞争力。他们投入大量资金和资源用于研发,不断推出具有创新性和领先性的半导体产品。同时,公司还积极与高校、科研机构等合作,共同开展技术研发和人才培养工作。这些创新举措使得AiT公司在行业中始终保持领先地位。

HOPERF公司的发展小趣事

在无线射频和传感器领域,HOPERF始终保持着技术创新的领先地位。公司独创的“NextGenRF”算法专利技术,填补了国内在该领域的空白,并获得了多项企业认证、发明专项和软件著作权。这些技术创新不仅推动了公司产品性能的持续提升,还引领了整个行业的发展方向。此外,HOPERF还积极参与国际标准制定,不断提升自身在全球行业中的话语权和影响力。

问答坊 | AI 解惑

俺想学习FPGA--有偿寻求合作开发FPGA学习板

俺想学习FPGA--有偿寻求合作开发FPGA学习板 看到现在FPGA现在这么火爆,忍不住想学习一下。 但是本人对FPGA了解甚少。想寻求高手共同合作搞一个FPGA开发板。 我负责:元件费用,打样费用。以及适当给与合作者一定酬劳(这个不多,呵呵,俺也是 ...…

查看全部问答>

无线通信系统中的调制解调基础(一):AM和FM

作者: Ian Poole Adrio Communications Ltd 第一部分解释了调幅(AM)和调频(FM)的基础,并阐述了优点和缺点。第二部分解析了频移键控(PSK)和正交幅度调制(QAM)。第三部分讨论扩频通信技术,包括被广泛应用的直接序列扩频通信(DSSS),和 ...…

查看全部问答>

.net程序在WinCE5.0上不能运行

我的wince上咋就不能运行dotnet的程序呢,点击应用程序一点反应也没有,也不报错。另外,保证dotnet的支持包已经打入wince,1.1和2.0都打了。 把SYSGEN_DOTNET和SYSGEN_DOTNET_SUPPORT还有DOTNETV2的所有选项加上,则运行dotnet的程序既不报错 ...…

查看全部问答>

PB5.0补丁问题

MS网站上PB5.0几乎每个月都有补丁,请问打补丁时是打最新的还是所有的都打上。我看了最新的补丁好象就升级了BLUETOOTH的程序。…

查看全部问答>

AD7705的参考电平能不能是5v

我看很多资料都写得是AD7705的参考电平时2.5v,但是今天看到有人用ref195的输出做AD7705的参考电平,ref195接ref+输出5v,ref-接地请问这样合适吗。 还有AD7705的资料上写着采样范围是0-20mv或0-2.5v,一直不太明白这是什么意思,0-2.5v不是包括0- ...…

查看全部问答>

An unspecified Debug Toolbox call failed

我在使用ADS1.2套件的AXD时,连接了Easyjtag,并进行了设置,但是却出现了如题的An unspecified Debug Toolbox call failed的错误,请高人指点,该如何解决这个问题?…

查看全部问答>

keil编译ARM报--- Error: can't execute 'BIN30\ArmAsm'怎么解决

我安装的keil 3.3版本,以前用来编译C51,现在添加上ARM,操作系统是U COS II,编译时报--- Error: can\'t execute \'BIN30\\ArmAsm\',我把C:\\Keil\\ARM\\BIN30中的ARMASM.EXE拷贝到BIN中无法解决此问题,请教高手要怎么处理…

查看全部问答>

VC33-120定时中断我置1ms中断 结果是10ms ?

斑竹: 我用vc33-120做了一块卡,外部晶阵是12m,5倍频,定时中断置数30000,理论计算 我的定时中断应该是1000hz,但是发现是100hz,我晶阵换过,都没有用.请教斑竹 最可能是什么原因啊  急!文字…

查看全部问答>

德州仪器:OMAP 5平台:开启移动设备变革新时代

TI OMAP 5平台不仅全面提升了性能,还采用了能够带来新机遇和用户体验的新特性,从而使应用处理器能够满足更广泛的要求。简而言之,OMAP 5平台将以其全新的性能及功能水平推动移动设备的变革,让我们共同开启“变革”新时代!$(\'swf_eBM\').innerH ...…

查看全部问答>

温度显示以及控制电机转速,不能同时工作,来人指点一下啊

#include #define uchar unsigned char #define uint unsigned int sbit uln=P2^0;//uln2803 sbit DQ=P2^1;//ds18b20与单片机连接口 sbit ming=P2^2;// sbit hong1=P2^3; sbit hong2=P2^4; sbit RS=P2^5; sbit RW=P2^6; sbit EN=P2^7; u ...…

查看全部问答>