概述
文章目录
- 一、设备树
- 二、驱动程序
- 三、应用程序
- 四、测试
ap3216c手册资料
一、设备树
在pinctrl中添加(已经有):
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
>;
};
在&i2c1中添加:
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
ap3216c@1e {
compatible = "luatao,ap3216c";
reg = <0x1e>;
};
};
二、驱动程序
ap3216c.h
#ifndef AP3216C_H
#define AP3216C_H
#define AP3216C_ADDR 0x1E /* AP3216C 器件地址 */
/* AP3216C 寄存器 */
#define AP3216C_SYSTEMCONG 0x00 /* 配置寄存器 */
#define AP3216C_INTSTATUS 0X01 /* 中断状态寄存器 */
#define AP3216C_INTCLEAR 0X02 /* 中断清除寄存器 */
#define AP3216C_IRDATALOW 0x0A /* IR数据低字节 */
#define AP3216C_IRDATAHIGH 0x0B /* IR数据高字节 */
#define AP3216C_ALSDATALOW 0x0C /* ALS数据低字节 */
#define AP3216C_ALSDATAHIGH 0X0D /* ALS数据高字节 */
#define AP3216C_PSDATALOW 0X0E /* PS数据低字节 */
#define AP3216C_PSDATAHIGH 0X0F /* PS数据高字节 */
#endif
ap3216c.c
#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 <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include "ap3216c.h"
/**
* file name:ap3216c
* date: 2021-08-15 09:24
* version:1.0
* author:luatao
* describe:ap3216c device drive
*/
#define AP3216C_CNT 1 /* 设备号个数 */
#define AP3216C_NAME "ap3216c" /* 设备名*/
/* 设备结构体 自定义 */
struct ap3216c_dev{
dev_t devid; /*设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类*/
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct device_node *nd; /* 设备节点 */
void *private_date; /* 私有数据 */
unsigned short ir, als, ps; /* 三个光传感器数据 */
};
/* 定义一个设备结构体 */
struct ap3216c_dev ap3216c; /*ap3216c 设备 */
/* 从ap3216c读取多个寄存器数据
@param - *dev : ap3216设备
@param - reg : 要读取的寄存器首地址
@param - *val : 读取到的数据
@param - len : 要读取的数据长度
@return :操作结果
*/
static int ap3216c_read_regs(struct ap3216c_dev *dev, u8 reg, void *val, int len)
{
int ret = 0;
struct i2c_msg msg[2]; /* 传输的消息 读的命令 */
struct i2c_client *client = (struct i2c_client *)dev->private_date; /* 私有数据 */
/* msg[0] 为发送要读取的首地址 */
msg[0].addr = client->addr; /* 器件地址 */
msg[0].flags = 0; /* 标记为发送数据 */
msg[0].buf = ® /* 要读取数据的首地址 */
msg[0].len = 1; /* reg长度 */
/* msg[1]读取数据 */
msg[1].addr = client->addr; /* 器件地址 */
msg[1].flags = I2C_M_RD; /* 标记为读取数据 */
msg[1].buf = val; /* 读取数据缓冲区 */
msg[1].len = len; /* 读取数据长度 */
ret = i2c_transfer(client->adapter, msg, 2); /* 向总线发送2个消息 */
if(ret == 2){ /* 传输成功 */
ret = 0;
}else{
printk("i2c_transfer failed!rn");
return -EREMOTEIO;
}
return ret;
}
/* 从ap3216c多个寄存器写入数据
@param - *dev : ap3216设备
@param - reg : 要写入的寄存器首地址
@param - *buf : 写入的数据缓冲区
@param - len : 要写入的数据长度
@return :操作结果
*/
static s32 ap3216c_write_regs(struct ap3216c_dev *dev, u8 reg, void *buf, int len)
{
u8 buf1[256];
struct i2c_msg msg; /* 传输的消息 */
struct i2c_client *client = (struct i2c_client *)dev->private_date; /* 私有数据 */
buf1[0] = reg; /* 寄存器首地址 */
memcpy(&buf1[1], buf, len); /* 要写入的数据拷贝到数据buf1中 */
/* msg处理数据 */
msg.addr = client->addr; /* 器件地址 */
msg.flags = 0; /* 标记为写入数据 */
msg.buf = buf1; /* 要写入的数据缓冲区 */
msg.len = len + 1; /* 写入的数据长度 */
return i2c_transfer(client->adapter, &msg, 1); /* 向总线发送1个消息 */
}
/* 从ap3216c读取指定寄存器值 读取一个寄存器
@param - *dev : ap3216设备
@param - reg : 要读取的寄存器
@return :读取到的寄存器值
*/
static unsigned char ap3216c_read_reg(struct ap3216c_dev *dev, u8 reg)
{
struct i2c_client *client = (struct i2c_client *)dev->private_date; /* 私有数据 */
return i2c_smbus_read_byte_data(client, reg); /* 读取一个字节数据 */
}
/* 向ap3216c指定寄存器写入指定的值,写一个寄存器
@param - *dev : ap3216设备
@param - reg : 要写入的寄存器
@param - data : 要写入的值
@return :无
*/
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); /* 调用写入多个寄存器的方法 */
}
/* 读取ap3216c的数据 读取原始数据 包括als ps 和 ir
@param - *dev : ap3216设备
@return :无
*/
static 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]);
if(buf[4] & 0x40){ /* IR_OF 为1 则数据位无效 */
dev->ps = 0;
}else{
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; /* 设置私有数据 */
/* 初始化ap3216c */
ap3216c_write_reg(&ap3216c, AP3216C_SYSTEMCONG, 0x04); /* 复位ap3216c */
mdelay(50); /* ap3216c复位最少10ms */
ap3216c_write_reg(&ap3216c, AP3216C_SYSTEMCONG, 0x03); /* 开启als ps+ir */
return 0;
}
/* 从设备读取数据 */
static ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
short data[3]; /* 存放读取到的数据 */
long ret = 0;
struct ap3216c_dev *dev = filp->private_data; // 获取私有数据
ap3216c_readdata(dev); // 读取数据
data[0] = dev->ir;
data[1] = dev->als;
data[2] = dev->ps;
ret = copy_to_user(buf, data, sizeof(data)); // 发送给用户空间
return 0;
}
/* 往设备写数据 */
static ssize_t ap3216c_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
printk("no write operation!rn");
return 0;
}
/* 释放设备 */
static int ap3216c_release(struct inode *inode, struct file *filp)
{
//printk("ap3216c release!rn");
return 0;
}
/* 设备操作函数结构体 */
static struct file_operations ap3216c_fops = {
.owner = THIS_MODULE,
.open =ap3216c_open,
.read =ap3216c_read,
.write =ap3216c_write,
.release =ap3216c_release,
};
/* i2C驱动的probe函数 ,当驱动与设备匹配以后此函数就会执行 */
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk("ap3216c driver and device has match!rn"); // 提示信息
/* 1. 创建设备号 */
if(ap3216c.major){ // 定义了设备号
ap3216c.devid = MKDEV(ap3216c.major, 0 ); // 根据主设备号和次设备号合成设备号
register_chrdev_region(ap3216c.devid, AP3216C_CNT, AP3216C_NAME); // 注册设备号
}else{ // 没有定义设备号 动态生成
alloc_chrdev_region(&ap3216c.devid,0,AP3216C_CNT, AP3216C_NAME ); // 申请设备号
ap3216c.major = MAJOR(ap3216c.devid); // 获取主设备号
ap3216c.minor = MINOR(ap3216c.devid); // 获取次设备号
}
printk("ap3216c major = %d,minor = %drn",ap3216c.major, ap3216c.minor); // 打印主设备号和次设备号
/* 2. 初始化 cdev */
ap3216c.cdev.owner = THIS_MODULE;
cdev_init(&ap3216c.cdev, &ap3216c_fops); // 初始化cdev
/* 3. 添加cdev */
cdev_add(&ap3216c.cdev, ap3216c.devid, AP3216C_CNT ); // 向linux系统添加cdev
/* 自动创建设备节点文件 */
/* 4. 创建类 */
ap3216c.class = class_create(THIS_MODULE, AP3216C_NAME); // 创建类
if(IS_ERR(ap3216c.class)){
return PTR_ERR(ap3216c.class);
}
/* 创建设备 */
ap3216c.device = device_create(ap3216c.class, NULL, ap3216c.devid, NULL, AP3216C_NAME);
if(IS_ERR(ap3216c.device)){
return PTR_ERR(ap3216c.device);
}
ap3216c.private_date = client; /* 私有数据为当前设备 */
return 0;
}
/* i2c驱动后的remove函数 */
static int ap3216c_remove(struct i2c_client *client)
{
/* 注销设备驱动 */
cdev_del(&ap3216c.cdev); /* 删除 cdev */
unregister_chrdev_region(ap3216c.devid, AP3216C_CNT ); /* 注销设备号 */
device_destroy(ap3216c.class, ap3216c.devid); /* 注销设备 */
class_destroy(ap3216c.class); /* 注销类 */
printk("ap3216c drive unregsister ok !rn");
return 0;
}
/* 传统匹配方式ID列表 */
static const struct i2c_device_id ap3216c_id[] = {
{"luatao,ap3216c", 0},
{}
};
/* 匹配列表 */
static const struct of_device_id ap3216c_of_match[] = {
{.compatible = "luatao,ap3216c"},
{/* Sentinel */}
};
/* i2c驱动结构体 */
static struct i2c_driver ap3216c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ap3216c", /* 驱动名字 用于和设备匹配 适用于没有设备树的情况*/
.of_match_table =ap3216c_of_match, /* 设备树匹配列表 */
},
.probe =ap3216c_probe,
.remove =ap3216c_remove,
.id_table = ap3216c_id, /* id配置列表 */
};
/* 驱动入口函数 */
static int __init ap3216c_init(void)
{
return i2c_add_driver(&ap3216c_driver);
}
/* 驱动出口函数 */
static void __exit ap3216c_exit(void)
{
i2c_del_driver(&ap3216c_driver);
}
/* 加载驱动入口和出口函数 */
module_init(ap3216c_init);
module_exit(ap3216c_exit);
/* 上面4步可以直接合成下面一步 */
// module_i2c_driver(ap3216c_driver);
/* LICENSE 和 AUTHOR 信息*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luatao");
三、应用程序
ap3216cApp.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
/**
* file name:ap3216cApp
* date: 2021-08-15 10:42
* version:1.0
* author:luatao
* describe:ap3216c测试APP
* 执行命令:./ap3216cApp 读取按键值
*/
/* 主程序 */
int main(int argc, char *argv[])
{
char *filename; // 可执行文件名
int fd,ret = 0; // fd: 文件句柄 ret:函数操作返回值
unsigned short databuf[3]; // 读出来的数据
unsigned short ir, als, ps; // 实际的数据
/* 先判断输入的参数 */
if(argc != 2){ // 本身文件名带1个 执行文件1个
printf("parameter error!rn");
return -1;
}
/* 分析参数 ,提取有用的信息 */
filename = argv[1]; // 可执行文件名
/* 打开key文件 */
fd = open(filename, O_RDWR); // 可读可写
if(fd < 0){
printf("can't open file:%srn",filename);
return -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 = %drn", ir, als, ps);
}
sleep(1); /* 延时1s*/
}
/* 关闭文件 */
ret = close(fd);
if(ret < 0){
printf("can't close file %s rn", filename);
return -1;
}
return 0;
}
四、测试
加载驱动:
运行程序:
卸载驱动:
最后
以上就是清新滑板为你收集整理的I2C驱动ap3216c的实验一、设备树二、驱动程序三、应用程序四、测试的全部内容,希望文章能够帮你解决I2C驱动ap3216c的实验一、设备树二、驱动程序三、应用程序四、测试所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复