• 正点原子linux阿尔法开发板使用——IIC驱动


    I2C设备驱动

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

    重点

    i2c设备驱动框架,i2c_driver初始化与注册,需要II2C设备驱动编写人员编写的,IIC驱动程序就是初始化i2c_driver,然后向系统注册。注册使用i2c_register_driveri2c_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"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    IIC的设备结构体以及初始化

    #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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    读取AP3216C的N个寄存器的数值

    
    /*读取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 = &reg; 				/*要发送的数据,也就是寄存器地址*/
    	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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    向AP3216C写入N个寄存器的数据

    /*向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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    IIC读取数据

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    IIC字符设备的ap3216c_probe函数

    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;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    i2c_driver函数添加

    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,
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    IIC驱动的加载与卸载

    
    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");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    IIC应用编程实现读取传感器的数据

    #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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    Hive概念及Hive,MySQL安装、配置
    【零基础入门MyBatis系列】第七篇——Javassist生成类与接口代理机制
    Mysql 日常命令记录
    Redis从入门到精通(二十二)Redis原理之数据结构、网络模型、通心协议、内存回收
    ProcessExtensionsAutoConfiguration
    003-Java程序流程控制
    刷题知识回顾《八》完全平方数搜索二维矩阵
    springboot配置多数据源
    JavaScript流程控制-循环(循环(for 循环,双重 for 循环,while 循环,do while 循环,continue break))
    基于PHP+MySQL毕业生档案管理系统
  • 原文地址:https://blog.csdn.net/m0_46152793/article/details/125319358