i2c_client:表示I2C设备,不需要我们自己创建i2c_client,我们一般在设备树里面添加具体的I2C芯片,比如fxls8471,系统在解析设备树的时候就会知道有这个I2C设备,然后会创建对应的i2c_client。

i2c设备驱动框架,i2c_driver初始化与注册,需要II2C设备驱动编写人员编写的,IIC驱动程序就是初始化i2c_driver,然后向系统注册。注册使用i2c_register_driver、i2c_add_driver,如果注销i2c_driver使用i2c_del_driver


在IIC1上接了一个AP3216C
1、修改设备树,IO,添加AP3216C的设备节点。




P77左忠凯手撕IIC驱动代码
模仿实现:

2、编写I2C驱动框架,I2C设备驱动框架,字符设备驱动框架。
3、初始化AP3216C,实现ap3216c_read()。
重点是通过IIC控制器来向AP3216C里面发送或者读取数据。使用I2C_transfer这个API来完成数据传输。
adapt:IIC设备对应的适配器,也就是IIC接口,当IIC设备和驱动匹配之后,probe函数会执行,probe函数传递进来的第一个参数就是 i2c_client,在i2c_client里面保存了此I2C设备所对应的i2c_adapt。
msgs:就是构成的I2C传输的数据。
IIC驱动AP3216C驱动代码流程:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/semaphore.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ap3216c.h"
#define AP3216C_CNT 1
#define AP3216C_NAME "ap3216c"
struct ap3216c_dev {
struct cdev cdev;
struct class *class;/*类:为了自动创建节点*/
struct device *device;/*设备:为了自动创建节点*/
dev_t devid; //设备号
int major; //主设备号
int minor; //次设备号
void *private_data;
unsigned short ir,als,ps;
};
struct ap3216c_dev ap3216c;
/*读取AP3216C的N个寄存器的数值*/
static int ap3216c_read_regs(struct ap3216c_dev *dev,u8 reg,void *val,int len)
{
struct i2c_msg msg[2];
struct i2c_client *client = (struct i2c_client *)dev->private_data;
/*msg[0]发送要读取的寄存器首地址*/
msg[0].addr = client->addr; /*从机地址*/
msg[0].flags = 0; /*要发送的数据*/
msg[0].buf = ® /*要发送的数据,也就是寄存器地址*/
msg[0].len = 1; /*要发送的寄存器地址为1*/
/*msg[1]读取数据*/
msg[1].addr = client->addr; /*从机地址*/
msg[1].flags = I2C_M_RD; /*表示读数据*/
msg[1].buf = val; /*接收到的从机的数据*/
msg[1].len = len; /*要读取的寄存器长度*/
return i2c_transfer(client->adapter,msg,2);
}
/*读取AP3216C一个寄存器*/
static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev,u8 reg)
{
u8 data = 0;
ap3216c_read_regs(dev,reg,&data,1);
return data;
}
/*向AP3216C写入N个寄存器的数据*/
static int ap3216c_write_regs(struct ap3216c_dev *dev,u8 reg,u8 *buf,int len)
{
struct i2c_msg msg;
u8 b[256];
struct i2c_client *client = (struct i2c_client *)dev->private_data;
b[0] = reg;
//构建要发送的数据,也就是寄存器首地址+实际的地址。
memcpy(&b[1],buf,len);
msg.addr = client->addr; /*从机地址*/
msg.flags = 0; /*要发送的数据*/
msg.buf = b; /*要发送的数据,也就是寄存器地址+实际数据*/
msg.len = len+1; /*要发送的数据长度:寄存器地址+1*/
return i2c_transfer(client->adapter,&msg,1);
}
/*向AP3216C一个寄存器写数据*/
static void ap3216c_write_reg(struct ap3216c_dev *dev,u8 reg,u8 data)
{
u8 buf = 0;
buf = data;
ap3216c_write_regs(dev,reg,&buf,1);
}
void ap3216c_readdata(struct ap3216c_dev *dev)
{
unsigned char i =0;
unsigned char buf[6];
/* 循环读取所有传感器数据 */
for(i = 0; i < 6; i++)
{
buf[i] = ap3216c_read_reg(dev, AP3216C_IRDATALOW + i);
}
if(buf[0] & 0X80) /* IR_OF 位为 1,则数据无效 */
dev->ir = 0;
else /* 读取 IR 传感器的数据 */
dev->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03);
dev->als = ((unsigned short)buf[3] << 8) | buf[2];/* ALS 数据 */
if(buf[4] & 0x40) /* IR_OF 位为 1,则数据无效 */
dev->ps = 0;
else /* 读取 PS 传感器的数据 */
dev->ps = ((unsigned short)(buf[5] & 0X3F) << 4) |
(buf[4] & 0X0F);
}
static int ap3216c_open(struct inode *inode, struct file *filp)
{
/*设置私有数据*/
filp->private_data = &ap3216c;
unsigned char val = 0;
printk("ap3216c_open \r\n");
/*初始化AP3216C*/
ap3216c_write_reg(&ap3216c,AP3216C_SYSTEMCONG,0X4);//复位
mdelay(50);
ap3216c_write_reg(&ap3216c,AP3216C_SYSTEMCONG,0X3);//复位
val = ap3216c_read_reg(&ap3216c,AP3216C_SYSTEMCONG);
printk("val = %#x\r\n",val);
return 0;
}
static ssize_t ap3216c_read(struct file *filp, __user char *buf, size_t count,loff_t *ppos)
{
long err = 0;
short data[3];
struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;
ap3216c_readdata(dev);
data[0] = dev->ir;
data[1] = dev->als;
data[2] = dev->ps;
err = copy_to_user(buf, data, sizeof(data));
return 0;
}
static int ap3216c_release(struct inode *inode, struct file *filp)
{
//struct ap3216c_dev *dev = (struct ap3216c_dev *)filp->private_data;
return 0;
}
/**
* 字符设备的操作集合
*/
const struct file_operations ap3216c_fops = {
.owner = THIS_MODULE,
.open = ap3216c_open,
.read = ap3216c_read,
.release = ap3216c_release,
};
static int ap3216c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
/*搭建字符设备驱动框架*/
/*2、注册字符设备*/
printk("ap3216c_init ok\r\n");
ap3216c.major = 0;//设置为0,表示由系统申请设备号
if(ap3216c.major) //给定主设备号
{
ap3216c.devid = MKDEV(ap3216c.major,0);
ret = register_chrdev_region(ap3216c.devid,AP3216C_CNT,AP3216C_NAME);
}else{
ret = alloc_chrdev_region(&ap3216c.devid,0,AP3216C_CNT,AP3216C_NAME);
ap3216c.major = MAJOR(ap3216c.devid);
ap3216c.minor = MINOR(ap3216c.devid);
}
if(ret < 0){
printk("ap3216c chrdev_region err\r\n");
return -1;
}
printk("ap3216c majorid = %d,minorid = %d\r\n",ap3216c.major,ap3216c.minor);
/*3、初始化cdev*/
ap3216c.cdev.owner = THIS_MODULE;
cdev_init(&ap3216c.cdev, &ap3216c_fops);
cdev_add(&ap3216c.cdev,ap3216c.devid,AP3216C_CNT);
/* 4、创建类 */
ap3216c.class = class_create(THIS_MODULE, AP3216C_NAME);
if (IS_ERR(ap3216c.class)) {
return PTR_ERR(ap3216c.class);
}
/* 5、创建设备 */
ap3216c.device = device_create(ap3216c.class, NULL, ap3216c.devid, NULL, AP3216C_NAME);
if (IS_ERR(ap3216c.device)) {
return PTR_ERR(ap3216c.device);
}
ap3216c.private_data = client;
return 0;
}
static int ap3216c_remove(struct i2c_client *client)
{
/*删除字符设备*/
cdev_del(&ap3216c.cdev);
/*注销设备号*/
unregister_chrdev_region(ap3216c.devid,AP3216C_CNT);
/*先摧毁设备再摧毁类*/
device_destroy(ap3216c.class,ap3216c.devid);
/*摧毁类*/
class_destroy(ap3216c.class);
return 0;
}
/*传统的匹配表*/
static struct i2c_device_id app3216c_id[] ={
{"alentek,ap3216c",0},
{}
};
/*设备树匹配表*/
static struct of_device_id app3216c_of_match[] ={
{.compatible = "alentek,ap3216c"},
{}
};
/*i2c_driver*/
static struct i2c_driver ap3216c_driver = {
.probe = ap3216c_probe,
.remove = ap3216c_remove,
.driver = {
.name = "ap3216c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(app3216c_of_match),
},
.id_table = app3216c_id,
};
static int __init ap3216c_init(void)
{
int ret;
ret = i2c_add_driver(&ap3216c_driver);
if (ret != 0) {
pr_err("AP3216C I2C registration failed %d\n", ret);
return ret;
}
return 0;
}
static void __exit ap3216c_exit(void)
{
i2c_del_driver(&ap3216c_driver);
}
//模块加载函数
module_init(ap3216c_init);
//模块卸载
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("qhy");
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>
/*input_event 结构体变量*/
static struct input_event input_event;
int main(int argc, char **argv)
{
int fd;
char *filename;
unsigned short databuf[3];
unsigned short ir, als, ps;
int ret = 0;
if (argc != 2)
{
printf("Error Usage:\r\n");
return -1;
}
fd = open(argv[1], O_RDWR);
if (fd<0)
{
perror("open error");
exit(-1);
}
while (1)
{
ret = read(fd, databuf, sizeof(databuf));
if(ret == 0) { /* 数据读取成功 */
ir = databuf[0]; /* ir 传感器数据 */
als = databuf[1]; /* als 传感器数据 */
ps = databuf[2]; /* ps 传感器数据 */
printf("ir = %d, als = %d, ps = %d\r\n", ir, als, ps);
}
}
/*close*/
close(fd);
exit(0);
}