前面第一篇已经讲了有关IIC的相关知识这边就不再重复,
本篇我们使用内核原代码提供的at24.c驱动来操作I2C的at24lc04 EEPROM
内核I2C子系统的架构请参考第一篇文章,这边只讲at24.c相关的部份
接下来因为驱动使用的是内核 at24.c 文件当然得先分析一下该文件
首先看到的是ar24.c驱动支持的设备
static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
/* spd is a 24c02 in memory DIMMs */
{ "spd", AT24_DEVICE_MAGIC(2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
/* 24rf08 quirk is handled at i2c-core */
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
我们24c04是在列表中的,总共有4096位/8 = 512字节
在初始化驱动时有这样的代码片段
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.owner = THIS_MODULE,
},
.probe = at24_probe,
.remove = __devexit_p(at24_remove),
.id_table = at24_ids,
};
static int __init at24_init(void)
{
if (!io_limit) {
pr_err("at24: io_limit must not be 0!\n");
return -EINVAL;
}
io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&at24_driver);
}
也就是说这是采用总线的驱动,总线的过程是当有设备加入总线,会调用驱动的 probe 方法来捕获设备,
驱动已经实现了probe 方法剩下的是得把我们的设备加入总线,寻找smart210的设备加入总线的操作部分,
发现坑人的是明明是 smart210 应该是s5kv210的核心结果对应到的文件居然是 Mach-mini210.c 而不是Mach-smdkv210.c
找到该文件加入以下的代码
//add by yang
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
以上是使用at24.c 的头文件
//add by yang
static struct at24_platform_data at24c04 = {
.byte_len = 4096 / 8,
.page_size = 16,
.flags = 0,
};
static struct i2c_board_info __initdata smdkv210_i2c_devices[] = {
{
I2C_BOARD_INFO("24c04", 0x50),
.platform_data = &at24c04,
},
};
这个是我们设备的描述,因为at24.c是对应多种设备的,所以需要加上板载的一些资讯,
然后找到mini210_machine_init 这个函数将上面的设备信息加入总线
static void __init mini210_machine_init(void)
{
arm_pm_restart = smdkc110_pm_restart;
.....这边省略一堆代码.....
#ifdef CONFIG_TOUCHSCREEN_GOODIX
if (mini210_get_ctp() == CTP_GT80X) {
i2c2_data.frequency = 260*1000;
}
#endif
//add by yang
i2c_register_board_info(0, smdkv210_i2c_devices,ARRAY_SIZE(smdkv210_i2c_devices));
s3c_i2c2_set_platdata(&i2c2_data);
i2c_register_board_info(0, mini210_i2c_devs0,
ARRAY_SIZE(mini210_i2c_devs0));
i2c_register_board_info(1, mini210_i2c_devs1,
ARRAY_SIZE(mini210_i2c_devs1));
i2c_register_board_info(2, mini210_i2c_devs2,
ARRAY_SIZE(mini210_i2c_devs2));
....下面省略一堆代码.......
主要将刚刚定义好的设备描述加入总线
最后检查一下内核中的EEPROM支持是否已经开启
内核中的eeprom没打开,请先到内核配置以下选项
Device Drivers --->
[*] Misc devices --->
EEPROM support --->
<*>I2C EEPROMs from most vendors重新编译下载内核之后可以发现在 /sys/bus/i2c/devices/0-0050/ 目录下应该要有 eeprom 设备文件
这样就算准备就绪
最后实现应用程序代码如下
/***********************************************
* 档名:i2c_app.c
* 作者:yang@wapoop.com
* 日期:2016/10/13
* 描述:使用Linux内核提供的at24.c驱动读写板载AT24C04
************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <unistd.h>
int main()
{
int fd;
int i;
char write_data[8] = {
0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40
};
char read_data[256] = {0};
fd = open("/sys/bus/i2c/devices/0-0050/eeprom",O_RDWR);
for(i=0;i<8;i++)
write_data[i] = i;
//使用lseek来定位数据地址
lseek(fd,0,SEEK_SET);
write(fd,write_data,8);
lseek(fd,0,SEEK_SET);
read(fd,read_data,256);
for(i=0;i<256;i++)
{
if(i%16 == 0)
printf("\n");
printf("%02x ",read_data[i]);
}
printf("\n");
}