正点原子IMX6UL I2C驱动AT24C512

参考: https://blog.csdn.net/zlsh007/article/details/21600759

1 需求

在imx6ul上完成EEROM驱动

正点原子IMX6UL I2C驱动AT24C512_第1张图片

2 修改设备树

查询数据手册得地址为0xa0

正点原子IMX6UL I2C驱动AT24C512_第2张图片

 linux设备树里面需要全部右移一位,于是地址是0x50

正点原子IMX6UL I2C驱动AT24C512_第3张图片

 

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	/* EEPROM */
	at24c512c@50 {
		compatible = "at24c512c";
		reg = <0x50>;
		status = "ok";
	};
};

 3 驱动

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define eerom_CNT	1
#define eerom_NAME	"eerom"
#define MAX_SIZE  512
struct oled_dev {
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
	struct device_node	*nd; /* 设备节点 */
	int major;			/* 主设备号 */
	void *private_data;	/* 私有数据 */
	unsigned short ir, als, ps;		/* 三个光传感器数据 */
};

static struct oled_dev oled_dev;


// read reg
static int eerom_read_regs(u16 reg, void *val, int len)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = (struct i2c_client *)oled_dev.private_data;
	uint8_t addr[2];
	addr[0]=reg>>8;
	addr[1]=reg&0xff;

	/* msg[0]为发送要读取的首地址 */
	msg[0].addr = client->addr;			/* eerom地址 */
	msg[0].flags = 0;					/* 标记为发送数据 */
	msg[0].buf = &addr;					/* 读取的首地址 */
	msg[0].len = 2;						/* reg长度*/

	/* msg[1]读取数据 */
	msg[1].addr = client->addr;			/* eerom地址 */
	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
	msg[1].buf = val;					/* 读取数据缓冲区 */
	msg[1].len = len;					/* 要读取的数据长度*/

	ret = i2c_transfer(client->adapter, msg, 2);
	if(ret == 2) {
		ret = 0;
	} else {
		printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
		ret = -EREMOTEIO;
	}
	return ret;
}

// read buff
static int eerom_read_buff(void *val, int len)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = (struct i2c_client *)oled_dev.private_data;

	/* msg[0]为发送要读取的首地址 */
	msg[0].addr = client->addr;			/* eerom地址 */
	msg[0].flags = 0;					/* 标记为发送数据 */
	msg[0].buf = &val[0];					/* 读取的首地址 */
	msg[0].len = 2;						/* reg长度*/

	/* msg[1]读取数据 */
	msg[1].addr = client->addr;			/* eerom地址 */
	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
	msg[1].buf = val;					/* 读取数据缓冲区 */
	msg[1].len = 1;					/* 要读取的数据长度*/

	ret = i2c_transfer(client->adapter, msg, 2);
	if(ret == 2) {
		ret = 0;
	} else {
		
		ret = -EREMOTEIO;
	}

	return ret;
}

// 写寄存器
static s32 eerom_write_regs(u16 reg, u8 *buf, u8 len)
{
 	unsigned char dev_addr[MAX_SIZE];
	struct i2c_msg msg;
	struct i2c_client *client = (struct i2c_client *)oled_dev.private_data;
	
	dev_addr[0]=reg>>8;
    dev_addr[1]=reg&0xff;
	memcpy(&dev_addr[2],buf,len);

	msg.addr = client->addr;	/* eerom地址 */
	msg.flags = 0;				/* 标记为写数据 */
	
	msg.buf =  &dev_addr[0];;				/* 要写入的数据缓冲区 */
	msg.len = 2+len;			/* 要写入的数据长度 */

	return i2c_transfer(client->adapter, &msg, 1);
}

// 写缓冲
static s32 eerom_write_buff(u8 *buf, u8 len)
{
	struct i2c_msg msg;
	struct i2c_client *client = (struct i2c_client *)oled_dev.private_data;
	
	msg.addr = client->addr;	/* eerom地址 */
	msg.flags = 0;				/* 标记为写数据 */
	
	msg.buf =  &buf[0];;				/* 要写入的数据缓冲区 */
	msg.len = len;			/* 要写入的数据长度 */
	return i2c_transfer(client->adapter, &msg, 1);
}



static int oled_open(struct inode *inode, struct file *filp)
{
	
    return 0;
}

static ssize_t oled_read(struct file *filp, char __user *buf, size_t size, loff_t *offset) 
{
	if(size >= MAX_SIZE){
		return -1;
	}
	uint8_t mbuff[MAX_SIZE];
	copy_from_user(mbuff,buf,2);
	eerom_read_buff(mbuff,1);
	copy_to_user(buf,&mbuff,size); 
	return 0;
}

static ssize_t oled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *off)
{	
	
	if(cnt >= MAX_SIZE){
		return -1;
	}
	uint8_t mbuff[cnt];
	copy_from_user(mbuff,buf,cnt);
	eerom_write_buff(mbuff,cnt);
    return 0;
}


// IO控制
static long oled_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{

}
static int oled_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* eerom操作函数 */
static const struct file_operations oled_ops = {
	.owner = THIS_MODULE,
	.open = oled_open,
    .write=oled_write,
	.read = oled_read,
    .unlocked_ioctl =oled_ioctl,
	.release = oled_release,
};


static int oled_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
   
	/* 1、构建设备号 */
	if (oled_dev.major) {
		oled_dev.devid = MKDEV(oled_dev.major, 0);
		register_chrdev_region(oled_dev.devid, eerom_CNT, eerom_NAME);
	} else {
		alloc_chrdev_region(&oled_dev.devid, 0, eerom_CNT, eerom_NAME);
		oled_dev.major = MAJOR(oled_dev.devid);
	}

	/* 2、注册设备 */
	cdev_init(&oled_dev.cdev, &oled_ops);
	cdev_add(&oled_dev.cdev, oled_dev.devid, eerom_CNT);

	/* 3、创建类 */
	oled_dev.class = class_create(THIS_MODULE, eerom_NAME);
	if (IS_ERR(oled_dev.class)) {
		return PTR_ERR(oled_dev.class);
	}

	/* 4、创建设备 */
	oled_dev.device = device_create(oled_dev.class, NULL, oled_dev.devid, NULL, eerom_NAME);
	if (IS_ERR(oled_dev.device)) {
		return PTR_ERR(oled_dev.device);
	}

	oled_dev.private_data = client;
    printk("hello match:%x\r\n",client->addr);


	return 0;
}

static oled_remove(struct i2c_client *client)
{
	/* 删除设备 */
	cdev_del(&oled_dev.cdev);
	unregister_chrdev_region(oled_dev.devid, eerom_CNT);

	/* 注销掉类和设备 */
	device_destroy(oled_dev.class, oled_dev.devid);
	class_destroy(oled_dev.class);
	return 0;
}

/* 传统匹配方式ID列表 */
static const struct i2c_device_id oled_id[] = {
	{"at24c512c", 0},  
	{}
};

/* 设备树匹配列表 */
static const struct of_device_id oled_of_match[] = {
	{ .compatible = "at24c512c" },
	{ /* Sentinel */ }
};

/* i2c驱动结构体 */	
static struct i2c_driver oled_driver = {
	.probe = oled_probe,
	.remove = oled_remove,
	.driver = {
			.owner = THIS_MODULE,
		   	.name = "at24c512c",
		   	.of_match_table = oled_of_match, 
		   },
	.id_table = oled_id,
};
		   
static int __init oled_init(void)
{
	int ret = 0;

	ret = i2c_add_driver(&oled_driver);
	return ret;
}

static void __exit oled_exit(void)
{
	i2c_del_driver(&oled_driver);
}

/* module_i2c_driver(eerom_driver) */

module_init(oled_init);
module_exit(oled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kirito");

 4 应用

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "stdint.h"
#define LEDOFF 	0
#define LEDON 	1


struct gpio_ctl
{
    uint8_t io;
    uint8_t state;
};

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	
	
	if(argc != 2){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];
	/* 打开led驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}
 
    struct gpio_ctl ctl;
    int state = 0;
    int i =0;
    char buf[20];
    uint16_t addr = 1;

    while (1)
    {
     sleep(1);
     if(state){
        state = 0;

        buf[0]=addr>>8;
        buf[1]=addr&0xff;
        read(fd,buf, 1);
        printf("data:%x\r\n",buf[0]);

     }else{
        state =1;
        buf[0]=addr>>8;
        buf[1]=addr&0xff;
        buf[2]=i;
        write(fd, buf, 3);

        i++;
     }
     
    }
	return 0;
}

5 测试

正点原子IMX6UL I2C驱动AT24C512_第4张图片

 

你可能感兴趣的:(linux)