linux I2C之RTC8025、fm24cl16

说明:

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

内核:linux3.10.32

平台:nuc972


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

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

	//i2c-0的总线配置
	static struct nuc970_platform_i2c nuc970_i2c0_data = {
		.bus_num = 0,//这个参数很重要,决定i2c-0的总线为0,从设备通过0总线挂载到i2c-0适
			//配器上,下面会提到从设备通过i2c_register_board_info()注册设备信息,
			//其中该函数的第一个参数即为总线号,这样就将从设备与相应的i2c-0适配
			//器连接上,从设备就可以使用该适配器的资源,对外挂I2C硬件设备进行操作。
		.bus_freq = 100000,
	};
	
	//i2c-0的资源配置
	static struct resource nuc970_i2c0_resource[] = {
		[0] = {
				.start = NUC970_PA_I2C0,
				.end   = NUC970_PA_I2C0 + NUC970_SZ_I2C0 - 1,
				.flags = IORESOURCE_MEM,
		},
		[1] = {
				.start = IRQ_I2C0,
				.end   = IRQ_I2C0,
				.flags = IORESOURCE_IRQ,
		}
	};
	
	//platform_device平台设备资源
	struct platform_device nuc970_device_i2c0 = {
		.name		  = "nuc970-i2c0",
		.id		  = -1,
		.num_resources	  = ARRAY_SIZE(nuc970_i2c0_resource),
		.resource	  = nuc970_i2c0_resource,
		.dev = {
			.platform_data = &nuc970_i2c0_data,
		}
	};	
		
	static struct platform_device *nuc970_public_dev[] __initdata = {
		&nuc970_device_i2c0,
	}
	
	//注册platform_device设备
	platform_add_devices(nuc970_public_dev, ARRAY_SIZE(nuc970_public_dev));

1.2 注册i2c从设备信息

<span style="white-space:pre">	</span>//i2c-0下的从设备设备信息
	static struct i2c_board_info __initdata nuc970_i2c_clients0[] = {
	{I2C_BOARD_INFO("fm24cl16bg", 0x50),},	//由于I2C发送数据时,首现发送的第一个字节是对外围从设备进行寻址,我们知道首字节的
						//高4bit(bit7~4)是外围设备的厂商编码,bit3~1是外围设备的地址(具体地址由该芯片的
						//外围电路决定),而bit0是对表示当前'读/写'操作,这里的0x50没有包括bit0‘读写’操作,<span style="white-space:pre">							</span>//所以这里的0x50只有7个bit,适配器在进行操作时会左移一位,0x50=01010000b -> 向左偏
			<span style="white-space:pre">		</span>//移1bit=1010 000x,高bit7~4为A恰好是fm24cl16的厂商编码,bit3~1为0恰好是外围器件地址。
												
	{I2C_BOARD_INFO("rx8025", 0x32),},	//同上。
	};
	
	//注册i2c从设备信息
	i2c_register_board_info(0, //这里有必要说明下,0就是1.1中提到的bus_num的总线,通过该总线就将从设备与nuc970-i2c0适配器进行了连接
				nuc970_i2c_clients0, 
				sizeof(nuc970_i2c_clients0)/sizeof(struct i2c_board_info));

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

2.1 平台设备驱动注册

	//平台设备驱动
	static struct platform_driver nuc970_i2c0_driver = {
		.probe		= nuc970_i2c0_probe,	//具体操作见各arm厂家
		.remove		= nuc970_i2c0_remove,
		.driver		= {
			.name	= "nuc970-i2c0",
			.owner	= THIS_MODULE,
		},
	};
	//注册平台设备驱动,当结构体nuc970_i2c0_driver与nuc970_device_i2c0中名字相同时将用
	//函数nuc970_i2c0_probe,该函数将完成具体的gpio、中断资源、及适配器和从设备的初始化。
	//module_platform_driver=platform_driver_register()+platform_driver_unregister()可
	//以省去人为对资源的释放
	module_platform_driver(nuc970_i2c0_driver);	

3 RTC 设备驱动

3.1 RTC设备驱动注册

	static const struct i2c_device_id rx8025_id[] = {
		{ "rx8025", 0 },
		{ }
	};
	MODULE_DEVICE_TABLE(i2c, rx8025_id);
	
	static struct i2c_driver rx8025_driver = {
		.driver = {
			.name = "rtc-rx8025",
			.owner = THIS_MODULE,
		},
		.probe		= rx8025_probe,
		.remove		= rx8025_remove,
		.id_table	= rx8025_id,	//这里注册的设备名很重要,一定要与1.2中的名字相同,否则在执行
						//module_i2c_driver()时将不能调用rx8025_probe函数。
	};
	
	//同上2.1的分析是一样的
	module_i2c_driver(rx8025_driver);

3.2 内核配置单配置

	为了系统一上电就同步硬件RTC时钟,需修改配置单:
	Device Drivers  --->
	   <*> I2C support  --->
		 --- I2C support                                                                
			 [*]   Enable compatibility bits for old user-space                            
			 < >   I2C device interface                                                     
			 < >   I2C bus multiplexing support                                            
			 [*]   Autoselect pertinent helper modules                                      
			 I2C Hardware Bus support  --->
				<*> GPIO-based bitbanging I2C                                                 
				<*> NUC970 I2C Driver for Port 0 	  
		[*] Real Time Clock  --->
		        [*]   Set system time from RTC on startup and resume                          
			[*]   Set the RTC time based on NTP synchronization                            
			(rtc0)  RTC used to set the system time                                        
			[*]   RTC debug support                                                       
			*** RTC interfaces ***                                                     
			[*]   /sys/class/rtc/rtcN (sysfs)                                             
			[*]   /proc/driver/rtc (procfs for rtcN)                                       
			[*]   /dev/rtcN (character devices)                                           
			[ ]     RTC UIE emulation on dev interface  
				
			<*>   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设备驱动程序注册

	static const struct i2c_device_id at24_ids[] = {
		{ "fm24cl16bg", AT24_DEVICE_MAGIC(16384 / 8, 0) },	//FM24CL16	add by CL
	};
	MODULE_DEVICE_TABLE(i2c, at24_ids);
	
	static struct i2c_driver at24_driver = {
		.driver = {
			.name = "at24",		//这个参数不重要,随便定义都可以
			.owner = THIS_MODULE,
		},
		.probe = at24_probe,
		.remove = at24_remove,
		.id_table = at24_ids,	//id表里的名称一定要与1.2中的名字相同,否则无法执行at24_probe
	};

	//驱动程序注册
	static int __init at24_init(void)
	{
		if (!io_limit) {
	<span style="white-space:pre">		</span>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);
	}
	module_init(at24_init);

	//驱动程序释放
	static void __exit at24_exit(void)
	{
		i2c_del_driver(&at24_driver);
	}
	module_exit(at24_exit);

	MODULE_DESCRIPTION("Driver for most I2C fm24cl16");
	MODULE_AUTHOR("ZDH-CL");
	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);
....


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值