首页 > 系统相关 >Linux驱动开发之I2C设备驱动(ap3216c)

Linux驱动开发之I2C设备驱动(ap3216c)

时间:2025-02-17 22:57:22浏览次数:10  
标签:AP3216C dev client ret Linux 驱动 I2C data ap3216c

设备树

底板原理图

 

核心板原理图

 由上面原理图可知,AP3216C设备挂在I2C1总线上:

在内核源码目录下搜索:

 芯片数据手册

修改设备树 

在I2C1控制器节点添加ap3216c设备节点:

 

 

 驱动代码编写

ap3216c数据手册

根据ap3216c芯片手册编写驱动代码,芯片手册的主要数据如下:

 

 

驱动代码参考

//ap3216c.h
#ifndef __AP3216C_H
#define __AP3216C_H
#include <linux/ioctl.h>

typedef struct _ap3216c_data{
   unsigned short ir; 
   unsigned short als; 
   unsigned short ps;     
}ap3216c_data;

#define AP3216C_SYSTEMCONG    0x00    /* 配置寄存器       */
#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数据高字节     */
#define MAGIC_NUM              'k'
#define AP3216C_PATH          "/dev/ap3216c_dev"

#define AP3216C_GET_IR       _IOR(MAGIC_NUM , 0, ushort)
#define AP3216C_GET_ALS        _IOR(MAGIC_NUM , 1, ushort)
#define AP3216C_GET_PS       _IOR(MAGIC_NUM , 2, ushort)



#endif // !__AP3216C_H

 

//ap3216c.c
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ap3216c.h"
#include <linux/uaccess.h>


#define DEV_NAME "ap3216c_dev"
#define DEV_NUM      1

typedef struct ap3216c{
	int major;
	dev_t dev;
	struct cdev cdev;
	struct i2c_client *client;
	struct class *class;
	struct device *device;
}AP3216C_DEV;

static AP3216C_DEV dev;

static int ap3216c_reg_read(struct i2c_client *client, unsigned char reg)
{
	int ret;
	unsigned char w_buf[1] = {reg};
	unsigned char r_buf[1];
	struct i2c_msg msg[2] = {
		{ client->addr,0,1,w_buf},
		{ client->addr,I2C_M_RD,1,r_buf}

	};
	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
	if(ret < 0){
		printk("i2c_transfer failed: %d\n", ret);
		return ret;
	}

	return r_buf[0];
}

static int ap3216c_reg_write(struct i2c_client *client, unsigned char reg,unsigned char val)
{
	int ret;
	unsigned char w_buf[2] = {reg,val};
	struct i2c_msg msg[1] = {
		{ client->addr,0,2,w_buf},

	};
	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
	if(ret < 0){
		printk("i2c_transfer failed: %d\n", ret);
		return ret;
	}

	return 0;
}

long ap3216c_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	AP3216C_DEV *ap3216c_dev = (AP3216C_DEV *)filp->private_data;
	unsigned short data = 0;
	unsigned char tmp;
	unsigned short __user *argp = (unsigned short *)arg;
	if(_IOC_TYPE(cmd) != MAGIC_NUM)
		return -ENOTTY;

	switch(cmd){
		case AP3216C_GET_IR:
			tmp = ap3216c_reg_read(ap3216c_dev->client, AP3216C_IRDATALOW );
			if(tmp & 0X80){
				printk(KERN_WARNING "AP3216C read IR data failed\n");
				return -ENOTTY;
			}
			tmp &= 0X3;
			data = ap3216c_reg_read(ap3216c_dev->client, AP3216C_IRDATAHIGH);
			data = (data << 2) | tmp;
			if(copy_to_user(argp, &data, sizeof(data))){
				printk(KERN_WARNING " failed to copy ap3216c data to user\n");
				return -EINVAL;
			}
			break;

		case AP3216C_GET_ALS:
			tmp = ap3216c_reg_read(ap3216c_dev->client, AP3216C_ALSDATALOW );
			data = ap3216c_reg_read(ap3216c_dev->client, AP3216C_ALSDATAHIGH);
			data = (data << 8) | tmp;
			if(copy_to_user(argp, &data, sizeof(data))){
				printk(KERN_WARNING " failed to copy ap3216c data to user\n");
				return -EINVAL;
			}
			break;

		case AP3216C_GET_PS:
			tmp = ap3216c_reg_read(ap3216c_dev->client, AP3216C_PSDATALOW );
			if(tmp & 0X40){
				printk(KERN_WARNING "AP3216C read PS data failed\n");
				return -ENOTTY;
			}
			tmp &= 0X0F;
			data = ap3216c_reg_read(ap3216c_dev->client, AP3216C_PSDATAHIGH);
			data = (data << 4) | tmp;
			if(copy_to_user(argp, &data, sizeof(data))){
				printk(KERN_WARNING " failed to copy ap3216c data to user\n");
				return -EINVAL;
			}
			break;
		default:
			printk(KERN_WARNING "Unknown AP3216C  CMD: 0x%d\n", cmd);
			return -EINVAL;
	}

	return sizeof(data);

}

static int ap3216c_open(struct inode *node, struct file *filp){
	filp->private_data = &dev;
	ap3216c_reg_write(dev.client, AP3216C_SYSTEMCONG, 0X04);
	msleep(15);
	ap3216c_reg_write(dev.client, AP3216C_SYSTEMCONG, 0X03);
	msleep(125);
	return 0;
}


int ap3216c_release(struct inode *node, struct file *filp){
	return 0;
}
static const struct file_operations ap3216c_fops = {
	.owner = THIS_MODULE,
	.open  = ap3216c_open,
	.unlocked_ioctl = ap3216c_ioctl,
	.release = ap3216c_release,
};


static void ap3216c_reg_init(struct i2c_client *client){
	ap3216c_reg_write(dev.client, AP3216C_SYSTEMCONG, 0X04);
	msleep(15);
	ap3216c_reg_write(dev.client, AP3216C_SYSTEMCONG, 0X03);
	msleep(125);
}
static int ap3216c_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	int ret;
	dev.client = client;
	printk(KERN_INFO "ap3216c_probe\n");
	ret = alloc_chrdev_region(&dev.dev, 0, DEV_NUM, DEV_NAME);
	dev.major = MAJOR(dev.dev);
	if (ret < 0) {
		printk(KERN_ERR "alloc_chrdev_region() failed for ap3216c\n");
		goto out_err_2;
	}

	cdev_init(&dev.cdev, &ap3216c_fops);
	ret = cdev_add(&dev.cdev, dev.dev, DEV_NUM);
	if (ret) {
		printk(KERN_ERR "cdev add failed for ap3216c\n");
		goto out_err;
	}

	dev.class = class_create(THIS_MODULE, DEV_NAME);
	if (IS_ERR(dev.class)){
		printk(KERN_ERR "cdev class creation failed\n"); 
		goto out_err;
	}

	dev.device = device_create(dev.class, NULL, dev.dev, NULL, DEV_NAME);
	if (IS_ERR(dev.device)) {
		printk(KERN_ERR "cdev device creation failed\n");
		goto put_dev;
	}

	ap3216c_reg_init(client);

	return 0;

put_dev:
	class_destroy(dev.class);
out_err:
	unregister_chrdev_region(dev.dev, DEV_NUM);
out_err_2:
	return -EFAULT;
}

static int ap3216c_remove(struct i2c_client *client)
{
	printk(KERN_ERR "ap3216c_remove\n");
	device_destroy(dev.class, dev.dev);
	class_destroy(dev.class);
	unregister_chrdev_region(dev.dev, DEV_NUM);
	return 0;
}

static const struct of_device_id ap3216c_dt_ids[] = {
	{ .compatible = "LITE-ON,ap3216c", },
	{},
};

static const struct i2c_device_id ap3216c_id[] = {
	{ "ap3216c", 0 },
	{ }
};

static struct i2c_driver ap3216c_driver = {
	.driver = {
		.name = "ap3216c",
		.owner = THIS_MODULE,
		.of_match_table = ap3216c_dt_ids,
	},
	.probe = ap3216c_probe,
	.remove = ap3216c_remove,
	.id_table = ap3216c_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);
MODULE_LICENSE("GPL");

 应用层测试代码参考

//ap3216c_test.c
#include "ap3216c.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main(int argc, char *argv[])
{
	int fd,ret;
	unsigned short data[3];
	fd = open(AP3216C_PATH, O_RDONLY);
	if(fd < 0){
		perror("open AP3216C_PATH");
		return EXIT_FAILURE;
	}
	while(1){
		ret = ioctl(fd, AP3216C_GET_IR, &data[0]);
		if(ret < 0){
			fprintf(stderr, "AP3216C_GET_IR failed: %d\n", ret);
			close(fd);
			return EXIT_FAILURE;
		}
		printf("AP3216C_GET_IR: %d\n", data[0]);
		ret = ioctl(fd, AP3216C_GET_ALS , &data[1]);
		if(ret < 0){
			fprintf(stderr, "AP3216C_GET_ALS failed: %d\n", ret);
			close(fd);
			return EXIT_FAILURE;
		}
		printf("AP3216C_GET_ALS: %d\n", data[1]);
		ret = ioctl(fd, AP3216C_GET_PS, &data[2]);
		if(ret < 0){
			fprintf(stderr, "AP3216C_GET_PS failed: %d\n", ret);
			close(fd);
			return EXIT_FAILURE;
		}

		printf("AP3216C_GET_PS: %d\n\n", data[2]);
		sleep(2);
	}


	close(fd);
	return 0;
}

 Makefile文件参考

ARCH = arch
CROSS_COMPILE = arm-linux-gnueabihf
CC = ${CROSS_COMPILE}-gcc
KERNELDIR := /home/linux_0
CURRENT_PATH := $(shell pwd)
	obj-m := ap3216c.o

build: kernel_modules

kernel_modules:

	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
	$(CC) -o test ap3216c_test.c
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
	@rm test ap3216c.ko -f

驱动代码验证

将make生成的ap3216c.ko文件与test文件拷贝到开发板,进行功能验证:

 

标签:AP3216C,dev,client,ret,Linux,驱动,I2C,data,ap3216c
From: https://blog.csdn.net/m0_53955705/article/details/145653914

相关文章