Linux 2.6.32 下i2c 之 内核源码驱动分析

参考http://www.100ask.net/forum/showtopic-3842.aspx

自己也做了一下分析,对Linux2.6.32内核下I2C驱动的大致框架有了更加深入的了解

 static struct platform_driver s3c24xx_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.id_table	= s3c24xx_driver_ids,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c-i2c",
		.pm	= S3C24XX_DEV_PM_OPS,
	},
};
 
 
 
  platform_driver_register(&s3c24xx_i2c_driver);  //i2c-s3c24xx.c
 					drv->driver.bus = &platform_bus_type;
 					
 					driver_register(&drv->driver);
 					      ret = bus_add_driver(drv);
 					           driver_attach(drv);
 					                bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
 					                     error = fn(dev, data);  //fn = __driver_attach
 					                         driver_match_device(drv, dev)  //调用platform 总线的mach 函数即plat_form_mach
 					                              drv->bus->match  //bus 为plat_form_bus
 					                         
 					                         driver_probe_device(drv, dev);
 					                         			really_probe(dev, drv);
 					                         					if (dev->bus->probe) {
																								ret = dev->bus->probe(dev);  //如果总线的probe函数存在,则调用总线的probe函数
																						} else if (drv->probe) {
																								ret = drv->probe(dev);			 //否则,如果驱动的probe函数存在,则调用驱动的probe
																						}
		  																    该probe函数即为平台驱动s3c24xx_i2c_driver的probe函数s3c24xx_i2c_probe
 




 platform_driver_register(&s3c24xx_i2c_driver);  //i2c-s3c24xx.c
 		s3c24xx_i2c_probe
 				 i2c_add_numbered_adapter(&i2c->adap);
 				       i2c_register_adapter(adap);
 				       			dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,i2c_do_add_adapter);
 				       					error = fn(drv, data); //= i2c_do_add_adapter
 				       					i2c_do_add_adapter
 				       							i2c_detect(adap, driver); //driver 为i2c bus上的i2c_driver
 				       									const struct i2c_client_address_data *address_data;
 				       									address_data = driver->address_data;
																if (!driver->detect || !address_data)  //如果i2c_driver中没有address_data 和 detect函数就立马返回
																		return 0;		
													
 				       							if (driver->attach_adapter) {  //为了兼容以前的版本
																driver->attach_adapter(adap);
														}
 				       					
i2c_add_driver				    
		 i2c_register_driver(THIS_MODULE, driver);
		 			driver->driver.bus = &i2c_bus_type;   //这个驱动所属的总线为i2c_bus
		 					driver_register(&driver->driver);   //注册i2c driver中的driver,不管,跟我没关系,我关心的知识i2c
		 							 bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
		 							 			__attach_adapter
		 							 					i2c_detect(adapter, driver);  //driver 为注册进来的i2c_driver
																			address_data = driver->address_data;
																			if (!driver->detect || !address_data)
																				return 0;
																			if (address_data->forces) {
																			}
																			if (!(adapter->class & driver->class))// ( s3c24xx_i2c_probe中)i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
																					goto exit_free;
																			if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
																			}
																			//检查i2c_algorithm里的functionality
					                            //在i2c-s3c2410.c已经设置,
					                            
					                            for  (i  =  0;  address_data->probe  !=  I2C_CLIENT_END;  i  +=  2)  {    //ignore
					                                    ...
					                              }
																			
																			/* Normal entries are done last, unless shadowed by an ignore entry */  //Normal地址的处理
																			for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
																						//struct i2c_client *temp_client;
																						//temp_client->adapter = adapter;
																						//temp_client->addr = address_data->normal_i2c[i];
																						i2c_detect_address(temp_client, -1, driver);  //这里发出start信号,发出设备地址(确认该设备在总线上存在),在linux-2.6.22中为i2c_probe_address
																									if i2c_smbus_xfer(adapter, addr, 0, 0, 0,I2C_SMBUS_QUICK, NULL) < 0) //如果存在该设备
																															if (adapter->algo->smbus_xfer) {//我们在算法中如果设置的smbus_xfer
																																	res = adapter->algo->smbus_xfer(adapter, addr, flags,read_write, command,protocol, data);	
																														  else
																														  		i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command, protocol, data);
																														  		 			 i2c_transfer(adapter, msg, num);			
																														  		 			 				if (adap->algo->master_xfer) {  //如果我们的算法中设置了master_xfer函数
																														  		 			 							.master_xfer		= s3c24xx_i2c_xfer  //最终传递消息的是mater_xfer函数
																														  		 			 										ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
																														  		 			 															i2c->msg     = msgs;
																																																			i2c->state   = STATE_START;
																																																			s3c24xx_i2c_message_start(i2c, msgs);
																																																			timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
																														  		 			 				
																														  		 			 				else
																														  		 			 						 返回错误
																									driver->detect(temp_client, kind, &info); //调用i2c_driver的detect 函数,我们要实现		  		 				
																								  if (info.type[0] == '\0') { //这个type数组用来以后制作出client的name ,再用其匹配 i2c_driver中的id_table
																								  		出错返回,我们要在detect函数中设置info结构体
																								  }
																								  else
																								 		 struct i2c_client *client;
																										 client = i2c_new_device(adapter, &info);
																										 			client->adapter = adap;
																										 			client->addr = info->addr;	
																										 			client->irq = info->irq;
																										 			client->dev.bus = &i2c_bus_type;
																										 			strlcpy(client->name, info->type, sizeof(client->name)); //设置client的name 为以后匹配i2c_driver做准备
																										 			status = device_register(&client->dev);
																										 					device_add(dev);
																										 							bus_probe_device(dev);
																										 									 device_attach(dev);
																										 									 			if (dev->driver) { //如果其驱动已连接
																										 									 					 	device_bind_driver(dev);
																										 									 			else
																										 								<font color="#000000"></font>	 						 bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
																										 									 						 			__device_attach
																										 									 						 						driver_match_device(drv, dev) //调用bus的match,这里的bus为i2c_bus_type!!
																										 									 						 									 i2c_device_match
																										 									 						 									 				if (driver->id_table)   //匹配i2c_driver中的id_table了
																																																									return i2c_match_id(driver->id_table, client) != NULL;
																																																														if (strcmp(client->name, id->name) == 0)//比较clint的名字和id_table中的名字。一定要成功!!
																										 									 						 						
																										 									 						 						
																										 									 						 						//如果mach成功
																										 									 						 						
																										 									 						 						driver_probe_device(drv, dev);	
																										 									 						 							   really_probe(dev, drv);
																										 									 						 							   				drv->probe(dev);  //调用i2c_driver的probe函数,这是自己定义的
																										 									 						 							   				
																										 									 						 										 	
																										 									 		
																										 list_add_tail(&client->detected, &driver->clients);  //将新探测建立的client加入i2c_driver的client链表中 		
																									}
                            			
                            
														/* Legacy drivers scan i2c busses directly */
														if (driver->attach_adapter)
															driver->attach_adapter(adapter);
		 					 					


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值