linux I2C之RTC8025、fm24cl16

https://blog.csdn.net/chenliang0224/article/details/51298682

说明:

主设备I2C-0挂载两个从设备fm24cl16铁电和RTC-rx8025t。

内核:linux3.10.32

平台:nuc972

 

1、板级文件修改 arch/arm/much-nuc970/dev.c

1.1 i2c-0的platform_device平台设备注册

 

 
  1. //i2c-0的总线配置

  2. static struct nuc970_platform_i2c nuc970_i2c0_data = {

  3. .bus_num = 0,//这个参数很重要,决定i2c-0的总线为0,从设备通过0总线挂载到i2c-0适

  4. //配器上,下面会提到从设备通过i2c_register_board_info()注册设备信息,

  5. //其中该函数的第一个参数即为总线号,这样就将从设备与相应的i2c-0适配

  6. //器连接上,从设备就可以使用该适配器的资源,对外挂I2C硬件设备进行操作。

  7. .bus_freq = 100000,

  8. };

  9.  
  10. //i2c-0的资源配置

  11. static struct resource nuc970_i2c0_resource[] = {

  12. [0] = {

  13. .start = NUC970_PA_I2C0,

  14. .end = NUC970_PA_I2C0 + NUC970_SZ_I2C0 - 1,

  15. .flags = IORESOURCE_MEM,

  16. },

  17. [1] = {

  18. .start = IRQ_I2C0,

  19. .end = IRQ_I2C0,

  20. .flags = IORESOURCE_IRQ,

  21. }

  22. };

  23.  
  24. //platform_device平台设备资源

  25. struct platform_device nuc970_device_i2c0 = {

  26. .name = "nuc970-i2c0",

  27. .id = -1,

  28. .num_resources = ARRAY_SIZE(nuc970_i2c0_resource),

  29. .resource = nuc970_i2c0_resource,

  30. .dev = {

  31. .platform_data = &nuc970_i2c0_data,

  32. }

  33. };

  34.  
  35. static struct platform_device *nuc970_public_dev[] __initdata = {

  36. &nuc970_device_i2c0,

  37. }

  38.  
  39. //注册platform_device设备

  40. platform_add_devices(nuc970_public_dev, ARRAY_SIZE(nuc970_public_dev));


1.2 注册i2c从设备信息

 

 

 
  1. //i2c-0下的从设备设备信息

  2. static struct i2c_board_info __initdata nuc970_i2c_clients0[] = {

  3. {I2C_BOARD_INFO("fm24cl16bg", 0x50),}, //由于I2C发送数据时,首现发送的第一个字节是对外围从设备进行寻址,我们知道首字节的

  4. //高4bit(bit7~4)是外围设备的厂商编码,bit3~1是外围设备的地址(具体地址由该芯片的

  5. //外围电路决定),而bit0是对表示当前'读/写'操作,这里的0x50没有包括bit0‘读写’操作, //所以这里的0x50只有7个bit,适配器在进行操作时会左移一位,0x50=01010000b -> 向左偏

  6. //移1bit=1010 000x,高bit7~4为A恰好是fm24cl16的厂商编码,bit3~1为0恰好是外围器件地址。

  7.  
  8. {I2C_BOARD_INFO("rx8025", 0x32),}, //同上。

  9. };

  10.  
  11. //注册i2c从设备信息

  12. i2c_register_board_info(0, //这里有必要说明下,0就是1.1中提到的bus_num的总线,通过该总线就将从设备与nuc970-i2c0适配器进行了连接

  13. nuc970_i2c_clients0,

  14. sizeof(nuc970_i2c_clients0)/sizeof(struct i2c_board_info));


2 platform_driver设备驱动注册 drivers/i2c/busses/i2c-nuc970-p0.c

 

2.1 平台设备驱动注册

 

 
  1. //平台设备驱动

  2. static struct platform_driver nuc970_i2c0_driver = {

  3. .probe = nuc970_i2c0_probe, //具体操作见各arm厂家

  4. .remove = nuc970_i2c0_remove,

  5. .driver = {

  6. .name = "nuc970-i2c0",

  7. .owner = THIS_MODULE,

  8. },

  9. };

  10. //注册平台设备驱动,当结构体nuc970_i2c0_driver与nuc970_device_i2c0中名字相同时将用

  11. //函数nuc970_i2c0_probe,该函数将完成具体的gpio、中断资源、及适配器和从设备的初始化。

  12. //module_platform_driver=platform_driver_register()+platform_driver_unregister()可

  13. //以省去人为对资源的释放

  14. module_platform_driver(nuc970_i2c0_driver);

 

 

3 RTC 设备驱动

3.1 RTC设备驱动注册

 

 
  1. static const struct i2c_device_id rx8025_id[] = {

  2. { "rx8025", 0 },

  3. { }

  4. };

  5. MODULE_DEVICE_TABLE(i2c, rx8025_id);

  6.  
  7. static struct i2c_driver rx8025_driver = {

  8. .driver = {

  9. .name = "rtc-rx8025",

  10. .owner = THIS_MODULE,

  11. },

  12. .probe = rx8025_probe,

  13. .remove = rx8025_remove,

  14. .id_table = rx8025_id, //这里注册的设备名很重要,一定要与1.2中的名字相同,否则在执行

  15. //module_i2c_driver()时将不能调用rx8025_probe函数。

  16. };

  17.  
  18. //同上2.1的分析是一样的

  19. module_i2c_driver(rx8025_driver);

 

3.2 内核配置单配置

 

 
  1. 为了系统一上电就同步硬件RTC时钟,需修改配置单:

  2. Device Drivers --->

  3. <*> I2C support --->

  4. --- I2C support

  5. [*] Enable compatibility bits for old user-space

  6. < > I2C device interface

  7. < > I2C bus multiplexing support

  8. [*] Autoselect pertinent helper modules

  9. I2C Hardware Bus support --->

  10. <*> GPIO-based bitbanging I2C

  11. <*> NUC970 I2C Driver for Port 0

  12. [*] Real Time Clock --->

  13. [*] Set system time from RTC on startup and resume

  14. [*] Set the RTC time based on NTP synchronization

  15. (rtc0) RTC used to set the system time

  16. [*] RTC debug support

  17. *** RTC interfaces ***

  18. [*] /sys/class/rtc/rtcN (sysfs)

  19. [*] /proc/driver/rtc (procfs for rtcN)

  20. [*] /dev/rtcN (character devices)

  21. [ ] RTC UIE emulation on dev interface

  22.  
  23. <*> Epson RX-8025SA/NB

3.3 编译、烧录内核

 

终端在上电之后会同步时间,并生成相应的设备/dev/rtc0, 通过date -s "2016-05-02 22:59:00", hwclock -w 将时间写到RTC时钟,

再次重启之后终端时间为之前设置的。

 

4 fm24cl16驱动

 

之前使用内核自带的设备驱动程序 i2c-dev.c,其中自己增加了lseek函数实现对外挂铁电设备进行指定地址读写,由于存在风险,还是直

接用at24.c代码进行小部分修改。

 

4.1 fm24cl16设备驱动程序注册

 

 
  1. static const struct i2c_device_id at24_ids[] = {

  2. { "fm24cl16bg", AT24_DEVICE_MAGIC(16384 / 8, 0) }, //FM24CL16 add by CL

  3. };

  4. MODULE_DEVICE_TABLE(i2c, at24_ids);

  5.  
  6. static struct i2c_driver at24_driver = {

  7. .driver = {

  8. .name = "at24", //这个参数不重要,随便定义都可以

  9. .owner = THIS_MODULE,

  10. },

  11. .probe = at24_probe,

  12. .remove = at24_remove,

  13. .id_table = at24_ids, //id表里的名称一定要与1.2中的名字相同,否则无法执行at24_probe

  14. };

  15.  
  16. //驱动程序注册

  17. static int __init at24_init(void)

  18. {

  19. if (!io_limit) {

  20. pr_err("at24: io_limit must not be 0!\n");

  21. return -EINVAL;

  22. }

  23. io_limit = rounddown_pow_of_two(io_limit);

  24. return i2c_add_driver(&at24_driver);

  25. }

  26. module_init(at24_init);

  27.  
  28. //驱动程序释放

  29. static void __exit at24_exit(void)

  30. {

  31. i2c_del_driver(&at24_driver);

  32. }

  33. module_exit(at24_exit);

  34.  
  35. MODULE_DESCRIPTION("Driver for most I2C fm24cl16");

  36. MODULE_AUTHOR("ZDH-CL");

  37. MODULE_LICENSE("GPL");

4.2 应用程序测试

 


由于使用4.1中的方式没有在/dev目录下生成相应的设备,在对设备进行open\read\write操作,需使用该路径/sys/bus/i2c/devices/0-0050/fram,其中fram是我修改了at24.c的源码
//at24->bin.attr.name = "eeprom";
at24->bin.attr.name = "fram";

open("/sys/bus/i2c/devices/0-0050/fram", O_RDWR);
....

你可能感兴趣的:(NUC977,Linux)