說明:
平臺設備:正點原子IMX6ULL,板子自帶ap3216c
第一部分:
修改設備樹,添加ap3216c設備:
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
ap3216c@1e {
compatible = "fsl,ap3216c";
reg = <0x1e>;
};
};
第二部分:
i2c_ap3216c.c 驅(qū)動文件:
#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_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "i2c_ap3216c.h"
struct ap3216c_dev {
dev_t devid;
int major;
int minor;
struct cdev cdev;
struct class *class;
struct device *device;
void *private_data;
unsigned short ir, als, ps;
};
struct ap3216c_dev ap3216c;
static int i2c_write_reg(unsigned char addr, unsigned char para)
{
unsigned char data[2];
struct i2c_msg msg;
struct i2c_client *client = (struct i2c_client *)ap3216c.private_data;
data[0] = addr;
data[1] = para;
msg.addr = client->addr;
msg.flags = 0;
msg.buf = data;
msg.len = 2;
return i2c_transfer(client->adapter, &msg, 1);
}
static int i2c_read_reg(unsigned char addr, unsigned char *value)
{
struct i2c_msg msg[2];
struct i2c_client *client = (struct i2c_client *)ap3216c.private_data;
msg[0].addr = client->addr;
msg[0].flags = 0; //寫標記
msg[0].buf = &addr; //讀取的地址
msg[0].len = 1; //要發(fā)送的數(shù)據(jù)長度
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD; //標記為讀數(shù)據(jù)
msg[1].buf = value; //讀取的地址
msg[1].len = 1; //要讀取的數(shù)據(jù)長度
return i2c_transfer(client->adapter, msg, 2);
}
void ap3216c_init(void)
{
i2c_write_reg(ADDR_SYSTEM_CFG, CMD_RST);
mdelay(50);
i2c_write_reg(ADDR_SYSTEM_CFG, CMD_CFG_ALS_PS_IR);
}
static int ap3216c_open(struct inode *inode, struct file *filp)
{
printk("ap3216c_open \r\n");
ap3216c_init();
return 0;
}
static int ap3216c_write(struct file *file, const char __user *buf,size_t count, loff_t *pos)
{
printk("ap3216c_write \r\n");
return 0;
}
static ssize_t ap3216c_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
int ret, i;
unsigned short data[3];
unsigned char pbuf[6];
printk("ap3216c_read \r\n");
for(i=0; i<6; i++)
{
i2c_read_reg(ADDR_IR_DATA_LOW + i, &pbuf[i]);
}
if(pbuf[0] & 0x80)
{
data[0] = ap3216c.ir = 0;
}
else
{
data[0] = ap3216c.ir = (unsigned short)(pbuf[1] << 2) | (pbuf[0] & 0x03);
}
data[1] = ap3216c.als = (unsigned short)(pbuf[3] << 8) | pbuf[2];
if(pbuf[4] & 0x40)
{
data[2] = ap3216c.ps = 0;
}
else
{
data[2] = ap3216c.ps = (unsigned short)((pbuf[5] & 0x3f) << 4) | (pbuf[4] & 0x0f);
}
ret = copy_to_user(buf, data, sizeof(data));
if(ret)
{
printk("copy to user failed \r\n");
}
return 0;
}
static struct file_operations ap3216c_fops = {
.owner = THIS_MODULE,
.open = ap3216c_open,
.read = ap3216c_read,
.write = ap3216c_write,
};
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk("ap3216c_probe \r\n");
if(ap3216c.major) //申請設備號
{
ap3216c.devid = MKDEV(ap3216c.major, 0);
register_chrdev_region(ap3216c.devid, DEV_CNT, DEV_NAME);
}
else
{
alloc_chrdev_region(&ap3216c.devid, 0, DEV_CNT, DEV_NAME);
ap3216c.major = MAJOR(ap3216c.devid);
ap3216c.minor = MINOR(ap3216c.devid);
}
cdev_init(&ap3216c.cdev, &ap3216c_fops); //初始化字符設備, 并向內(nèi)核進行添加
cdev_add(&ap3216c.cdev, ap3216c.devid, DEV_CNT);
ap3216c.class = class_create(THIS_MODULE, DEV_NAME); //創(chuàng)建設備類
if (IS_ERR(ap3216c.class))
{
printk("class create fail \r\n");
return PTR_ERR(ap3216c.class);
}
ap3216c.device = device_create(ap3216c.class, NULL, ap3216c.devid, NULL, DEV_NAME); //創(chuàng)建設備
if (IS_ERR(ap3216c.device))
{
printk("device create fail \r\n");
return PTR_ERR(ap3216c.device);
}
ap3216c.private_data = client;
return 0;
}
static int ap3216c_remove(struct i2c_client *client)
{
printk("ap3216c_remove \r\n");
cdev_del(&ap3216c.cdev); //注銷設字符設備
unregister_chrdev_region(ap3216c.devid, DEV_CNT); //注銷設備號
device_destroy(ap3216c.class, ap3216c.devid); //注銷設備類
class_destroy(ap3216c.class); //注銷設備
return 0;
}
static const struct i2c_device_id ap3216c_id[] = {
{"fsl,ap3216c", 0},
{ },
};
static struct of_device_id ap3216c_of_match[] = {
{.compatible = "fsl,ap3216c"},
{ },
};
static struct i2c_driver ap3216c_dirver = {
.probe = ap3216c_probe,
.remove = ap3216c_remove,
.id_table = ap3216c_id,
.driver = {
.owner = THIS_MODULE,
.name = "ap3216c",
.of_match_table = ap3216c_of_match,
},
};
static int __init ap3216c_module_init(void)
{
int ret = 0;
printk("ap3216c_init \r\n");
ret = i2c_add_driver(&ap3216c_dirver);
return ret;
}
static void __exit ap3216c_module_exit(void)
{
printk("ap3216c_exit \r\n");
i2c_del_driver(&ap3216c_dirver);
}
module_init(ap3216c_module_init);
module_exit(ap3216c_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lianmeng");
oled.h 頭文件:
#ifndef __I2C_AP3216C_H
#define __I2C_AP3216C_H
#define DEV_CNT 1
#define DEV_NAME "ap3216c"
#define CMD_RST 0x04
#define CMD_CFG_ALS_PS_IR 0x03
#define ADDR_SYSTEM_CFG 0x00
#define ADDR_IR_DATA_LOW 0x0A
#define ADDR_IR_DATA_HIGH 0x0B
#define ADDR_ALS_DATA_LOW 0x0C
#define ADDR_ALS_DATA_HIGH 0x0D
#define ADDR_PS_DATA_LOW 0x0E
#define ADDR_PS_DATA_HIGH 0x0F
#endif
第三部分:
Makefile 文件:
KERNELDIR := /home/lmeng/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := i2c_ap3216c.o
build : kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
第四部分:
ap3216cApp.c 應用文件
#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>
int main(int argc, char *argv[])
{
int fd, ret;
char *filename;
unsigned short buf[3];
unsigned short ir, als, ps;
filename = argv[1];
fd = open(filename, O_RDWR);
if(fd < 0)
{
printf("can't open file %s \r\n", filename);
return -1;
}
while(1)
{
ret = read(fd, buf, sizeof(buf));
if(ret)
{
printf("read data failed \r\n");
return -1;
}
else
{
ir = buf[0];
als = buf[1];
ps = buf[2];
printf("ir = %d, als = %d, ps = %d \r\n", ir, als, ps);
}
usleep(200000);
}
close(fd);
return 0;
}