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: \n", __FUNCTION__);
return ;
} static int __devexit i2c_test_remove(struct i2c_client *client)
{
i2c_set_clientdata(client, NULL); //设置client为NULL
printk("==%s: \n", __FUNCTION__);
return ;
} static const struct i2c_device_id i2c_test_id[] = {
{ "i2c_test", },
{ }
}; 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(), "TP1_EN");
if(ret) {
printk(KERN_ERR "failed to request TP1_EN for I2C control\n");
} gpio_direction_output(EXYNOS4_GPL0(), );
s3c_gpio_cfgpin(EXYNOS4_GPL0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPL0()); mdelay(); ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if(ret) {
gpio_free(EXYNOS4_GPX0()); ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if(ret) {
printk("i2c_io_test: Fialed to request GPX0_3 \n");
}
}
gpio_direction_output(EXYNOS4_GPX0(), );
mdelay(); gpio_direction_output(EXYNOS4_GPX0(), ); s3c_gpio_cfgpin(EXYNOS4_GPX0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPX0());
msleep();
} 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");

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. 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-]# insmod i2c.ko
[ 381.451187] ==i2c_test_init:
[ 382.020037] ==i2c_test_init:
[ 382.021601] ==i2c_test_probe:
[root@iTOP-]# 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[] = { };
u8 buf2[] = { };
struct i2c_msg msgs[] = {
{
.addr = client->addr, //0x38
.flags = , //写
.len = , //要写的数据的长度
.buf = buf1,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = ,
.buf = buf2,
},
};
int ret;
buf1[] = addr;
ret = i2c_transfer(client->adapter, msgs, );
if (ret < ) {
pr_err("read reg (0x%02x) error, %d\n", addr, ret);
} else {
*pdata = buf2[];
}
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_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 ;
} static int __devexit i2c_test_remove(struct i2c_client *client)
{
i2c_set_clientdata(client, NULL);
printk("==%s:\n", __FUNCTION__);
return ;
} static const struct i2c_device_id i2c_test_id[] = {
{ "i2c_test", },
{ }
}; 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(), "TP1_EN");
if (ret) {
printk(KERN_ERR "failed to request TP1_EN for "
"I2C control\n");
//return err;
}
gpio_direction_output(EXYNOS4_GPL0(), );
s3c_gpio_cfgpin(EXYNOS4_GPL0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPL0());
mdelay(); ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if (ret) {
gpio_free(EXYNOS4_GPX0());
ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if(ret)
{
printk("ft5xox: Failed to request GPX0_3 \n");
}
}
gpio_direction_output(EXYNOS4_GPX0(), );
mdelay();
gpio_direction_output(EXYNOS4_GPX0(), );
s3c_gpio_cfgpin(EXYNOS4_GPX0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPX0());
msleep();
} 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");

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[] = { };
u8 buf2[] = { };
struct i2c_msg msgs[] = {
{
.addr = client->addr, //0x38
.flags = , //写
.len = , //要写的数据的长度
.buf = buf1,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = ,
.buf = buf2,
},
};
int ret;
buf1[] = addr;
ret = i2c_transfer(client->adapter, msgs, );
if (ret < ) {
pr_err("read reg (0x%02x) error, %d\n", addr, ret);
} else {
*pdata = buf2[];
}
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 ;
} static int i2c_release_func(struct file *filp)
{
return ;
} 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,); struct i2c_msg msgs[] = {
{
.addr = this_client->addr, //0x38
.flags = , //写
.len = , //要写的数据的长度
.buf = &reg_data,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = ,
.buf = &reg_data,
},
};
ret = i2c_transfer(this_client->adapter, msgs, );
if (ret < ) {
pr_err("read reg error!\n");
}
ret = copy_to_user(buffer,&reg_data,); return ret;
} static ssize_t i2c_write_func(struct file *filp, char __user *buffer, size_t count, loff_t *ppos){
int ret;
u8 buf[];
struct i2c_msg msgs[]; ret = copy_from_user(&buf,buffer,); msgs[].addr = this_client->addr; //0x38
msgs[].flags = ; //写
msgs[].len = ; //第一个是要写的寄存器地址,第二个是要写的内容
msgs[].buf = buf; ret = i2c_transfer(this_client->adapter, msgs, );
if (ret < ) {
pr_err("write reg 0x%02x error!\n",buf[]);
}
ret = copy_to_user(buffer,buf,); 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:\n", __FUNCTION__); i2c_tes_read_fw_reg(client,&val); this_client = client; misc_register(&i2c_dev); return ;
} static int __devexit i2c_test_remove(struct i2c_client *client)
{
i2c_set_clientdata(client, NULL);
misc_deregister(&i2c_dev);
printk("==%s:\n", __FUNCTION__);
return ;
} static const struct i2c_device_id i2c_test_id[] = {
{ "i2c_test", },
{ }
}; 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(), "TP1_EN");
if (ret) {
printk(KERN_ERR "failed to request TP1_EN for "
"I2C control\n");
//return err;
}
gpio_direction_output(EXYNOS4_GPL0(), );
s3c_gpio_cfgpin(EXYNOS4_GPL0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPL0());
mdelay(); ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if (ret) {
gpio_free(EXYNOS4_GPX0());
ret = gpio_request(EXYNOS4_GPX0(), "GPX0_3");
if(ret)
{
printk("ft5xox: Failed to request GPX0_3 \n");
}
}
gpio_direction_output(EXYNOS4_GPX0(), );
mdelay();
gpio_direction_output(EXYNOS4_GPX0(), );
s3c_gpio_cfgpin(EXYNOS4_GPX0(), S3C_GPIO_OUTPUT);
gpio_free(EXYNOS4_GPX0());
msleep();
} 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");

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[]; printf("open %s!\n",i2c_device);
if((fd = open(i2c_device,O_RDWR|O_NDELAY))<)
printf("APP open %s failed",i2c_device);
else{
printf("APP open %s success!\n",i2c_device);
} //读一个数据0xa6
buffer[] = 0xa6;
ret = read(fd,buffer,);
if(ret<)
printf("i2c read failed!\n");
else{
printf("i2c read reg 0xa6 data is 0x%02x!\n",buffer[]);
} //01先从0x00读出一个数据,02写一个数据到0x00,03再读出来对比
//
buffer[] = 0x00;
read(fd,buffer,);
printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[]);
//
buffer[] = 0x00;
buffer[] = 0x40;
ret = write(fd,buffer,);
if(ret<){
printf("i2c write failed!\n");
goto exit;
}
//
buffer[] = 0x00;
read(fd,buffer,);
printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[]); close(fd); exit:
close(fd);
return -;
}

app_i2c

4412 i2c驱动的更多相关文章

  1. Smart210学习记录-----Linux i2c驱动

    一:Linux i2c子系统简介: 1.Linux 的 I2C 体系结构分为 3 个组成部分: (1) I2C 核心. I2C 核心提供了 I2C 总线驱动和设备驱动的注册.注销方法,I2C 通信方法 ...

  2. linux下i2c驱动笔记 转

    1. 几个基本概念 1.1. 设备模型 由 总线(bus_type) + 设备(device) + 驱动(device_driver) 组成,在该模型下,所有的设备通过总线连接起来,即使有些设备没有连 ...

  3. 【转】 i2c驱动调试经验

    原文网址:http://blog.csdn.net/cmm20071020/article/details/7179958 把一个i2c驱动从2.6.21升级到2.6.39 上网查到一篇帖子,讲了驱动 ...

  4. 驱动: i2c驱动 >>>>

    1. IIC协议: <<um_s3c2440a_rev10.pdf>>  p481 Figure 20-3. IIC-Bus Interface Data Format< ...

  5. linux i2c驱动架构-dm368 i2c驱动分析

      linux i2c驱动架构-dm368 i2c驱动分析   在阅读本文最好先熟悉一种i2c设备的驱动程序,并且浏览一下i2c-core.c以及芯片提供商的提供的i2c总线驱动(i2c-davinc ...

  6. I2C驱动框架 (kernel-3.4.2)

    先用韦老师的图: 注:  新版本内核的i2c驱动框架采用了    i2c_client -------> i2c_bus_type  <-------- i2c_driver   框架 如 ...

  7. 【Linux高级驱动】I2C驱动框架分析

    1.i2c-dev.c(i2c设备驱动组件层) 功能:1)给用户提供接口 i2c_dev_init  //入口函数 /*申请主设备号*/ register_chrdev(I2C_MAJOR(), &q ...

  8. Linux驱动:I2C驱动编写要点

    继续上一篇博文没讲完的内容“针对 RepStart 型i2c设备的驱动模型”,其中涉及的内容有:i2c_client 的注册.i2c_driver 的注册.驱动程序的编写. 一.i2c 设备的注册分析 ...

  9. 【驱动】linux下I2C驱动架构全面分析

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

随机推荐

  1. jenkins持续集成、插件以及凭据

    Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. Jenkins功能包括: ...

  2. 下载工具 qBittorrent 使用

    官网地址,软件可以在官网上下载. GitHub 源码 知乎的参考链接 qBittorrent 是开源软件,支持用 BT 种子或种子的链接下载,也可以用磁力链接进行下载. 搜索功能 qBittorren ...

  3. Python笔记(十六)_else语句、with语句

    else的多种用法 1.try except + else:检测到代码无异常,才执行else 例如: def func(num): count=num//2 while count>1: if ...

  4. SEC7 - MySQL 查询语句--------------进阶3:排序查询

    # 进阶3:排序查询 /* 引入: select * from employees; 语法: select 查询列表 from 表 [where 筛选条件] order by 排序的列表 asc/de ...

  5. IOS-swift5.1快速入门之旅

    快速之旅 传统表明,新语言中的第一个程序应在屏幕上打印“Hello,world!”字样.在Swift中,这可以在一行中完成: print("Hello, world!") // P ...

  6. spring-第四篇之让bean获取所在的spring容器

    1.如上一篇文章所述,有时候bean想发布一些容器事件,就需要先获取spring容器,然后将Event交由spring容器将事件发布出去. 为了让bean获取它所在的spring容器,可以让该bean ...

  7. Ubuntu12.04安装MariaDB并修改字符集为UTF-8

    其实按照MariaDB官网的步骤来安装MariaDB特别的简单,只要按照步骤来做,很容易就搞定了. 首先,到MariaDB官网: https://downloads.mariadb.org/maria ...

  8. 前端最常用的跨域方式--jsonp

    jsonp通过动态创建script标签的方式来实现跨域通信.原理是浏览器允许html标签在不同的域名下加载资源. <script> var script = document.create ...

  9. ubuntu下修改子网掩码

    1.修改网络配置 修改 /etc/netplan/01-network-manager-all.yaml 文件 vi /etc/netplan/01-network-manager-all.yaml ...

  10. 2、单线性变量的回归(Linear Regression with One Variable)

    2.1 模型表示 我们通过一个例子来开始:这个例子是预测住房价格的,我们要使用一个数据集,数据集包含俄勒冈州波特兰市的住房价格.在这里,我要根据不同房屋尺寸所售出的价格,画出我的数据集.比方说,如果你 ...