这一篇主要是使用IMX6处理器驱动AT24C16(24LC16B)芯片。第一篇介绍设备驱动层:
IMX6有三个IIC控制器。
我在这里使用的是IIC3控制器。
根据RX8025-SA芯片手册,确定RX8025-SA的IIC地址使用的是0x32。为什么不是0x60???因为最后一位是读写位,在linux中右移一位,就是0x32了,在具体发送时,如果是读就会发送0x65,写的话发送0x64。
在我使用的开发板中IIC3还连接这触摸屏要用到的芯片。
ts2003地址就不重复说啦。。。
在我使用的开发板中,没有实际的AT24C16芯片,我将IIC3的SDA与SCL两个引脚引出,自己焊接了一块AT24C16的最小单元,并且A2/A1/A0都接地。
AT24C16的地址为0x50。
在imx6qdl-sabresd.dtsi文件中找到&i2c3。添加上AT24C16信息。如下:
compatible的字符串为:”at24cxx”。之后的match就是匹配的该字符串。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
const struct i2c_device_id at24cxx_id[] =
{
{"at24cxx", 0 },//i2c控制器的第三个控制器i2c3
{},//结束标志
};
dev_t dev;
struct at24cxx_dev
{
struct cdev cdev_at24;
struct i2c_client *client;
};
struct at24cxx_dev *at24cxx_devp = NULL;
struct class *dev_class = NULL;
struct device *dev_device = NULL;
/*
./a.out w 0 0x55
*/
ssize_t at24cxx_write(struct file *filp, const char __user *buff, size_t size, loff_t *offset)
{
int ret;
unsigned char val[2];
struct i2c_msg msg[1];
if(size != 2){
return -EINVAL;
}
ret = copy_from_user(val, buff, size);
//组织要发送的消息
msg[0].addr = 0x50;//从设备地址
//msg[0].addr = at24cxx_devp->client->addr;
msg[0].flags = 0;//0表示写入
msg[0].buf = val;
msg[0].len = 2;
//产生 start addr+w ack offset ack val ack stop 这些信号
//i2c_transfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)
i2c_transfer(at24cxx_devp->client->adapter, msg, 1);
return 2;//写入两个字节,就返回2
}
/*
./a.out r 100
*/
ssize_t at24cxx_read(struct file *filp, char __user *buff, size_t count, loff_t *offset)
{
unsigned char address;
unsigned char data;
struct i2c_msg msg[2];//msg个数可以参考i2c的start信号的个数
int ret;
ret = copy_from_user(&address, buff, 1);
msg[0].addr = at24cxx_devp->client->addr;
msg[0].flags = 0;//写
msg[0].buf = &address;//要读哪个地址
msg[0].len = 1;
msg[1].addr = at24cxx_devp->client->addr;
msg[1].flags = 1;//读
msg[1].buf = &data;//读到的数据存到data里去
msg[1].len = 1;
i2c_transfer(at24cxx_devp->client->adapter, msg, ARRAY_SIZE(msg));
ret = copy_to_user(buff, &data, 1);
return 1;
}
struct file_operations at24cxx_fops =
{
.owner = THIS_MODULE,
.read = at24cxx_read,
.write = at24cxx_write,
};
int at24cxx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
printk("at24cxx_probe \n");
printk("client->name = %s client->addr = %d \n", client->name, client->addr);
printk("i2c_device_id->name = %s i2c_device_id->driver_data = %ld \n", id->name, id->driver_data);
//注册设备号
alloc_chrdev_region(&dev, 0, 1, "AT24C02");
//申请cdev空间
at24cxx_devp = kzalloc(sizeof(struct at24cxx_dev), GFP_KERNEL);
at24cxx_devp->client = client;
//初始化cdev并添加到内核
cdev_init(&at24cxx_devp->cdev_at24, &at24cxx_fops);
cdev_add(&at24cxx_devp->cdev_at24, dev, 1);
//创建设备文件
dev_class = class_create(THIS_MODULE, "AT24CXX");
dev_device = device_create(dev_class, NULL,dev,NULL,"at24cxx0");
return 0;
}
int at24cxx_remove(struct i2c_client *client)
{
printk("at24cxx_remove \n");
device_destroy(dev_class, dev);
class_destroy(dev_class);
cdev_del(&at24cxx_devp->cdev_at24);
kfree(at24cxx_devp);
unregister_chrdev_region(dev, 1);
return 0;
}
struct i2c_driver at24cxx_driver =
{
.driver =
{
.name = "AT24C02",
.owner = THIS_MODULE,
},
.probe = at24cxx_probe,
.remove = at24cxx_remove,
/*i2c match 会使用到*/
.id_table = at24cxx_id,
};
int __init at24cxx_init(void)
{
i2c_add_driver(&at24cxx_driver);
return 0;
}
void __exit at24cxx_exit(void)
{
i2c_del_driver(&at24cxx_driver);
}
module_init(at24cxx_init);
module_exit(at24cxx_exit);
#include
#include
#include
#include
#include
#include
void print_usage(char *file)
{
printf("%s r addr \n", file);
printf("%s w addr val \n", file);
}
/*
./a.ount w 10 0x55 写的格式 在10 地址上写0x55值
./a.ount r 10 读的格式
*/
int main(int argc, char **argv){
int fd;
unsigned char buf[2];
unsigned char buf1[2];
if(argc!=3 && argc!=4){
print_usage(argv[0]);
}
fd = open("/dev/at24cxx0", O_RDWR);
if(strcmp(argv[1], "r") == 0){
buf[0] = strtoul(argv[2], NULL, 0);//字符串转换
read(fd, buf, 1);
printf("data: %c %d 0x%2x \n", buf[0], buf[0], buf[0]);
}
else if(strcmp(argv[1], "w") == 0){
buf[0] = strtoul(argv[2], NULL, 0);
buf[1] = strtoul(argv[3], NULL, 0);
write(fd, buf, 2);
}
else{
print_usage(argv[0]);
return -1;
}
return 0;
}