tegra adapter driver
adapter设备的注册
staticstructresource i2c_resource1[] = {
[0]= {
.start = INT_I2C,
.end = INT_I2C,
.flags = IORESOURCE_IRQ,
},
[1]= {
.start =TEGRA_I2C_BASE,
.end =TEGRA_I2C_BASE + TEGRA_I2C_SIZE-1,
.flags =IORESOURCE_MEM,
},
};
staticstructresource i2c_resource2[] = {
[0]= {
.start = INT_I2C2,
.end = INT_I2C2,
.flags = IORESOURCE_IRQ,
},
[1]= {
.start =TEGRA_I2C2_BASE,
.end =TEGRA_I2C2_BASE + TEGRA_I2C2_SIZE-1,
.flags =IORESOURCE_MEM,
},
};
staticstructresource i2c_resource3[] = {
[0]= {
.start = INT_I2C3,
.end = INT_I2C3,
.flags = IORESOURCE_IRQ,
},
[1]= {
.start =TEGRA_I2C3_BASE,
.end =TEGRA_I2C3_BASE + TEGRA_I2C3_SIZE-1,
.flags =IORESOURCE_MEM,
},
};
structplatform_device tegra_i2c_device1 = {
.name ="tegra-i2c",
.id =0,
.resource =i2c_resource1,
.num_resources =ARRAY_SIZE(i2c_resource1),
.dev= {
.platform_data= 0,
},
};
structplatform_device tegra_i2c_device1 = {
.name ="tegra-i2c",
.id =0,
.resource =i2c_resource1,
.num_resources =ARRAY_SIZE(i2c_resource1),
.dev= {
.platform_data= 0,
},
};
structplatform_device tegra_i2c_device2 = {
.name ="tegra-i2c",
.id =1,
.resource =i2c_resource2,
.num_resources =ARRAY_SIZE(i2c_resource2),
.dev= {
.platform_data= 0,
},
};
structplatform_device tegra_i2c_device3 = {
.name ="tegra-i2c",
.id =2,
.resource =i2c_resource3,
.num_resources =ARRAY_SIZE(i2c_resource3),
.dev= {
.platform_data= 0,
},
};
structplatform_device tegra_i2c_device4 = {
.name ="tegra-i2c",
.id =3,
.resource =i2c_resource4,
.num_resources =ARRAY_SIZE(i2c_resource4),
.dev= {
.platform_data= 0,
},
};
上面的num_resource的值计算这个资源数组里面的资源的数目
#defineARRAY_SIZE(arr) (sizeof(arr)/ sizeof((arr)[0])+ __must_be_array(arr))
看到上面的宏定义应该明白了讲解的意思了吧
接下来就需要注册这些adapter设备了
staticstructtegra_i2c_platform_data ventana_i2c1_platform_data = {
.adapter_nr =0,
.bus_count =1,
.bus_clk_rate ={ 400000, 0 },
};
staticconststructtegra_pingroup_config i2c2_ddc = {
.pingroup =TEGRA_PINGROUP_DDC,
.func =TEGRA_MUX_I2C2,
};
staticconststructtegra_pingroup_config i2c2_gen2 = {
.pingroup =TEGRA_PINGROUP_PTA,
.func =TEGRA_MUX_I2C2,
};
staticstructtegra_i2c_platform_data ventana_i2c2_platform_data = {
.adapter_nr =1,
.bus_count =2,
//.bus_clk_rate ={ 400000, 10000 },
.bus_clk_rate= {400000, 100000},
.bus_mux ={ &i2c2_ddc, &i2c2_gen2 },
.bus_mux_len ={ 1, 1 },
};
staticstructtegra_i2c_platform_data ventana_i2c3_platform_data = {
.adapter_nr =3,
.bus_count =1,
.bus_clk_rate ={ 400000, 0 },
};
staticstructtegra_i2c_platform_data ventana_dvc_platform_data = {
.adapter_nr =4,
.bus_count =1,
.bus_clk_rate ={ 400000, 0 },
.is_dvc =true,
};
staticvoidventana_i2c_init(void)
{
tegra_i2c_device1.dev.platform_data= &ventana_i2c1_platform_data;
tegra_i2c_device2.dev.platform_data= &ventana_i2c2_platform_data;
tegra_i2c_device3.dev.platform_data= &ventana_i2c3_platform_data;
tegra_i2c_device4.dev.platform_data= &ventana_dvc_platform_data;
i2c_register_board_info(0,ventana_i2c_bus1_board_info, 1);
platform_device_register(&tegra_i2c_device1);
platform_device_register(&tegra_i2c_device2);
platform_device_register(&tegra_i2c_device3);
platform_device_register(&tegra_i2c_device4);
}
很容易发现这些设备的注册是以platform方式注册的,这里需要提醒下,platform的driver的match的匹配规则,那么就是匹配device和driver的名字是否相等,如果对platform的driver不了解的话,可以去看下kernel里面是如何写的,这里就不一一的叙述了。
在上面的staticvoidventana_i2c_init(void)函数里面,我开始先将下adapter的驱动,接下来讲解adapter和client的关系
i2c_register_board_info(0,ventana_i2c_bus1_board_info,1);。其实是注册一个设备的一些信息,我接下来会详细的讲解,现在是讲解adapter的驱动
platform_device_register(&tegra_i2c_device4);不难看出是注册一个platform驱动
接下来我们看下adapter的driver部分
我涉及的是tegra平台的adapter的,所以我这里就只讲解tegra平台的,其实别的平台的架构也差不多的
我进入kernel/drivers/i2c/busses/i2c-tegra.c这个文件,这就是tegra的adapter驱动
staticstruct platform_drivertegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove = tegra_i2c_remove,
#ifdefCONFIG_PM
.suspend= tegra_i2c_suspend,
.resume = tegra_i2c_resume,
#endif
.driver = {
.name = "tegra-i2c",
.owner= THIS_MODULE,
},
};
staticint__init tegra_i2c_init_driver(void)
{
returnplatform_driver_register(&tegra_i2c_driver);
}
不难看出,adapter的driver也是以platform形式注册的,我们可以发现我们在adapter的driver和device的name都是.name = "tegra-i2c",所以他们是匹配的
我们重点讲解下adapter的driver的probe函数,这函数的核心的入点
看下:
staticint tegra_i2c_probe(structplatform_device *pdev)
{
structtegra_i2c_dev *i2c_dev;
structtegra_i2c_platform_data *plat = pdev->dev.platform_data;
structresource *res;
structresource *iomem;
structclk *clk;
structclk *i2c_clk;
void*base;
intirq;
intnbus;
inti = 0;
intret = 0;
if(!plat) {
dev_err(&pdev->dev,"no platform data?\n");
return-ENODEV;
}
if(plat->bus_count<= 0 || plat->adapter_nr< 0) {
dev_err(&pdev->dev,"invalid platform data?\n");
return-ENODEV;
}
WARN_ON(plat->bus_count> TEGRA_I2C_MAX_BUS);
nbus= min(TEGRA_I2C_MAX_BUS, plat->bus_count);
res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(!res) {
dev_err(&pdev->dev,"no memresource?\n");
return-ENODEV;
}
iomem= request_mem_region(res->start,resource_size(res), pdev->name);
if(!iomem) {
dev_err(&pdev->dev,"I2C region already claimed\n");
return-EBUSY;
}
base= ioremap(iomem->start,resource_size(iomem));
if(!base) {
dev_err(&pdev->dev,"Can't ioremapI2C region\n");
return-ENOMEM;
}
res= platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if(!res) {
dev_err(&pdev->dev,"no irqresource?\n");
ret= -ENODEV;
gotoerr_iounmap;
}
irq= res->start;
clk= clk_get(&pdev->dev,NULL);
if(!clk) {
ret= -ENOMEM;
gotoerr_release_region;
}
i2c_clk= clk_get(&pdev->dev,"i2c");
if(!i2c_clk) {
ret= -ENOMEM;
gotoerr_clk_put;
}
i2c_dev= kzalloc(sizeof(structtegra_i2c_dev) +
(nbus-1) * sizeof(structtegra_i2c_bus), GFP_KERNEL);
if(!i2c_dev) {
ret= -ENOMEM;
gotoerr_i2c_clk_put;
}
i2c_dev->base= base;
i2c_dev->clk= clk;
i2c_dev->i2c_clk= i2c_clk;
i2c_dev->iomem= iomem;
i2c_dev->irq= irq;
i2c_dev->cont_id= pdev->id;
i2c_dev->dev= &pdev->dev;
i2c_dev->last_bus_clk= plat->bus_clk_rate[0]?: 100000;
i2c_dev->msgs= NULL;
i2c_dev->msgs_num= 0;
rt_mutex_init(&i2c_dev->dev_lock);
i2c_dev->is_dvc= plat->is_dvc;
init_completion(&i2c_dev->msg_complete);
platform_set_drvdata(pdev,i2c_dev);
ret= tegra_i2c_init(i2c_dev);
if(ret)
gotoerr_free;
ret= request_irq(i2c_dev->irq,tegra_i2c_isr, IRQF_DISABLED,
pdev->name,i2c_dev);
if(ret) {
dev_err(&pdev->dev,"Failed to request irq%i\n", i2c_dev->irq);
gotoerr_free;
}
clk_enable(i2c_dev->i2c_clk);
for(i = 0; i < nbus; i++) {
structtegra_i2c_bus *i2c_bus = &i2c_dev->busses[i];
i2c_bus->dev= i2c_dev;
i2c_bus->mux= plat->bus_mux[i];
i2c_bus->mux_len= plat->bus_mux_len[i];
i2c_bus->bus_clk_rate= plat->bus_clk_rate[i]?: 100000;
i2c_bus->adapter.algo= &tegra_i2c_algo;
i2c_set_adapdata(&i2c_bus->adapter,i2c_bus);
i2c_bus->adapter.owner= THIS_MODULE;
i2c_bus->adapter.class= I2C_CLASS_HWMON;
strlcpy(i2c_bus->adapter.name,"TegraI2C adapter",
sizeof(i2c_bus->adapter.name));
i2c_bus->adapter.dev.parent= &pdev->dev;
i2c_bus->adapter.nr= plat->adapter_nr+ i;
if(plat->retries)
i2c_bus->adapter.retries= plat->retries;
else
i2c_bus->adapter.retries= TEGRA_I2C_RETRIES;
if(plat->timeout)
i2c_bus->adapter.timeout= plat->timeout;
ret= i2c_add_numbered_adapter(&i2c_bus->adapter);
if(ret) {
dev_err(&pdev->dev,"Failed to add I2C adapter\n");
gotoerr_del_bus;
}
i2c_dev->bus_count++;
}
return0;
err_del_bus:
while(i2c_dev->bus_count--)
i2c_del_adapter(&i2c_dev->busses[i2c_dev->bus_count].adapter);
free_irq(i2c_dev->irq,i2c_dev);
err_free:
kfree(i2c_dev);
err_i2c_clk_put:
clk_put(i2c_clk);
err_clk_put:
clk_put(clk);
err_release_region:
release_mem_region(iomem->start,resource_size(iomem));
err_iounmap:
iounmap(base);
returnret;
}
看了是不是很多呢??
不要害怕,代码多没事,只要慢慢的看,肯定会懂的
这个函数的前半部分主要是在申请一些资源,和得到clk还有i2c_dev的设备的初始化的工作,
看下这个
nbus的值是等于
nbus= min(TEGRA_I2C_MAX_BUS, plat->bus_count);
nbus= min(TEGRA_I2C_MAX_BUS, plat->bus_count);
#defineTEGRA_I2C_MAX_BUS 3
nbus的最终是选择比较小的一个数字
for(i = 0; i < nbus; i++) {
structtegra_i2c_bus *i2c_bus = &i2c_dev->busses[i];
i2c_bus->adapter.algo= &tegra_i2c_algo;
i2c_set_adapdata(&i2c_bus->adapter,i2c_bus);
i2c_bus->adapter.algo= &tegra_i2c_algo;是给adapter的算法赋值,每个adapter都有它自己的算法。这里面主要是一些传输的方式
看看赋值的什么,
staticconststructi2c_algorithm tegra_i2c_algo = {
.master_xfer =tegra_i2c_xfer,
.functionality =tegra_i2c_func,
};
staticinttegra_i2c_xfer(structi2c_adapter *adap, structi2c_msg msgs[],
intnum)
{
structtegra_i2c_bus *i2c_bus = i2c_get_adapdata(adap);
structtegra_i2c_dev *i2c_dev = i2c_bus->dev;
inti;
intret = 0;
if(i2c_dev->is_suspended)
return-EBUSY;
rt_mutex_lock(&i2c_dev->dev_lock);
if(i2c_dev->last_mux!= i2c_bus->mux){
tegra_pinmux_set_safe_pinmux_table(i2c_dev->last_mux,
i2c_dev->last_mux_len);
tegra_pinmux_config_pinmux_table(i2c_bus->mux,
i2c_bus->mux_len);
i2c_dev->last_mux= i2c_bus->mux;
i2c_dev->last_mux_len= i2c_bus->mux_len;
}
if(i2c_dev->last_bus_clk!= i2c_bus->bus_clk_rate){
tegra_i2c_set_clk(i2c_dev,i2c_bus->bus_clk_rate);
i2c_dev->last_bus_clk= i2c_bus->bus_clk_rate;
}
i2c_dev->msgs= msgs;
i2c_dev->msgs_num= num;
clk_enable(i2c_dev->clk);
for(i = 0; i < num; i++) {
intstop = (i == (num - 1)) ? 1 : 0;
ret= tegra_i2c_xfer_msg(i2c_bus, &msgs[i], stop);
if(ret)
gotoout;
}
ret= i;
out:
clk_disable(i2c_dev->clk);
rt_mutex_unlock(&i2c_dev->dev_lock);
i2c_dev->msgs= NULL;
i2c_dev->msgs_num= 0;
returnret;
}
staticu32tegra_i2c_func(structi2c_adapter *adap)
{
/*FIXME:For now keep it simple and don't support protocol mangling
features */
returnI2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
}
这里我需要细心的提醒下看代码的人,i2c_set_adapdata(&i2c_bus->adapter,i2c_bus);这个函数这这个函数我觉得挺重要的,刚开始我一直没有看出,这个函数的用意,我用面向对象的概念去说吧:其实就是一个子类的一个私有成员赋值为这个子类的父类,这样我就可以很容易找到父类了,我不知道这样说是否合适,还有一些像这样的函数,例如:i2c_set_client函数
接下来看下注册adapter的函数: ret= i2c_add_numbered_adapter(&i2c_bus->adapter);
这是调用i2ccore里面的函数,进行adapter的注册
看看这个函数的原型是什么呢????这就需要我们进入i2ccore里面了,很好玩吧,这是激动人心的时刻,
/**
*i2c_add_numbered_adapter - declare i2c adapter, use static bus number
*@adap: the adapter to register (with adap->nrinitialized)
*Context: can sleep
*
*This routine is used to declare an I2C adapter when its bus number
*matters. For example, use it for I2C adapters from system-on-chipCPUs,
*or otherwise built in to the system's mainboard, and wherei2c_board_info
*is used to properly configure I2C devices.
*
*If no devices have pre-been declared for this bus, then besure to
*register the adapter before any dynamically allocated ones. Otherwise
*the required bus ID may not be available.
*
*When this returns zero, the specified adapter became available for
*clients using the bus number provided in adap->nr. Also, the table
*of I2C devices pre-declared using i2c_register_board_info() isscanned,
*and the appropriate driver model device nodes are created. Otherwise, a
*negative errno value is returned.
*/
inti2c_add_numbered_adapter(structi2c_adapter *adap)
{
int id;
int status;
if(adap->nr& ~MAX_ID_MASK)
return-EINVAL;
retry:
if(idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return-ENOMEM;
mutex_lock(&core_lock);
/*"above" here means "above or equal to", sigh;
* we need the "equal to" result to force the result
*/
status= idr_get_new_above(&i2c_adapter_idr, adap, adap->nr,&id);
if(status == 0 && id != adap->nr){
status= -EBUSY;
idr_remove(&i2c_adapter_idr,id);
}
mutex_unlock(&core_lock);
if(status == -EAGAIN)
gotoretry;
if(status == 0)
status= i2c_register_adapter(adap);
returnstatus;
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
重点是看status= i2c_register_adapter(adap);
staticinti2c_register_adapter(structi2c_adapter *adap)
{
intres = 0;
/*Can't register until after driver model init*/
if(unlikely(WARN_ON(!i2c_bus_type.p))){
res= -EAGAIN;
gotoout_list;
}
rt_mutex_init(&adap->bus_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/*Set default timeout to 1 second if not already set */
if(adap->timeout== 0)
adap->timeout= HZ;
dev_set_name(&adap->dev,"i2c-%d",adap->nr);
adap->dev.bus= &i2c_bus_type;
adap->dev.type= &i2c_adapter_type;
res= device_register(&adap->dev);
if(res)
gotoout_list;
dev_dbg(&adap->dev,"adapter [%s] registered\n",adap->name);
#ifdefCONFIG_I2C_COMPAT
res= class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if(res)
dev_warn(&adap->dev,
"Failed to create compatibilityclass link\n");
#endif
/*create pre-declareddevice nodes */
if(adap->nr< __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/*Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type,NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
return0;
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr,adap->nr);
mutex_unlock(&core_lock);
returnres;
}
adap->dev.bus= &i2c_bus_type;
设置i2c的bus的type
structbus_type i2c_bus_type = {
.name ="i2c",
.match =i2c_device_match,
.probe =i2c_device_probe,
.remove =i2c_device_remove,
.shutdown =i2c_device_shutdown,
.pm =&i2c_device_pm_ops,
};
看看下i2c的bus的match的规则
staticinti2c_device_match(structdevice *dev, structdevice_driver *drv)
{
structi2c_client *client = i2c_verify_client(dev);
structi2c_driver *driver;
if(!client)
return0;
/*Attempt an OF style match */
if(of_driver_match_device(dev, drv))
return1;
driver= to_i2c_driver(drv);
/*match on an id table if there is one */
if(driver->id_table)
returni2c_match_id(driver->id_table,client) != NULL;
return0;
}
其实就是匹配id_table里面的值是否相等
adapter已经完全注册好了,那么再看下另外一个重要的函数
i2c_scan_static_board_info(adap);
staticvoidi2c_scan_static_board_info(structi2c_adapter *adapter)
{
structi2c_devinfo *devinfo;
down_read(&__i2c_board_lock);
list_for_each_entry(devinfo,&__i2c_board_list, list){
if(devinfo->busnum== adapter->nr
&&!i2c_new_device(adapter,
&devinfo->board_info))
dev_err(&adapter->dev,
"Can'tcreate device at 0x%02x\n",
devinfo->board_info.addr);
}
up_read(&__i2c_board_lock);
}
这里是重点了,这就需要回顾下,在设备开始注册的函数,不会你忘记了吧
staticvoidventana_i2c_init(void)
{
tegra_i2c_device1.dev.platform_data= &ventana_i2c1_platform_data;
tegra_i2c_device2.dev.platform_data= &ventana_i2c2_platform_data;
tegra_i2c_device3.dev.platform_data= &ventana_i2c3_platform_data;
tegra_i2c_device4.dev.platform_data= &ventana_dvc_platform_data;
i2c_register_board_info(0,ventana_i2c_bus1_board_info, 1);
platform_device_register(&tegra_i2c_device1);
platform_device_register(&tegra_i2c_device2);
platform_device_register(&tegra_i2c_device3);
platform_device_register(&tegra_i2c_device4);
}
因为我看的是atmeltouch的driver,所以我说下touch作为client的时候和adapter的关系
touch的设备的注册是在
kernel/arch/arm/mach-tegra/board-cardhu.c里面
看看注册的过程
staticstruct i2c_board_info __initdata atmel_i2c_info[] = {
{
I2C_BOARD_INFO("atmel_mxt_ts",MXT1386_I2C_ADDR1),
.irq =TEGRA_GPIO_TO_IRQ(TOUCH_GPIO_IRQ_ATMEL_T9),
.platform_data =atmel_mxt_info,
},
{
I2C_BOARD_INFO("atmel_mxt_ts",MXT1386_I2C_ADDR1),
.irq =TEGRA_GPIO_TO_IRQ(TOUCH_GPIO_IRQ_ATMEL_T9),
.platform_data =atmel_mxt_info+1,
}
};
staticint __init cardhu_touch_init(void)
{
struct board_infoBoardInfo;
tegra_gpio_enable(TEGRA_GPIO_PH4);
tegra_gpio_enable(TEGRA_GPIO_PH6);
gpio_request(TEGRA_GPIO_PH4,"atmel-irq");
gpio_direction_input(TEGRA_GPIO_PH4);
gpio_request(TEGRA_GPIO_PH6,"atmel-reset");
gpio_direction_output(TEGRA_GPIO_PH6,0);
msleep(1);
gpio_set_value(TEGRA_GPIO_PH6,1);
msleep(100);
tegra_get_board_info(&BoardInfo);
if ((BoardInfo.sku &SKU_TOUCH_MASK) == SKU_TOUCH_2000) {
atmel_mxt_info.config= config_sku2000;
atmel_mxt_info.config_crc= MXT_CONFIG_CRC_SKU2000;
}
i2c_register_board_info(1,atmel_i2c_info, 1);
return 0;
}
看下I2C_BOARD_INFO("atmel_mxt_ts",MXT1386_I2C_ADDR1), 这个函数到底在干嘛呢???
看下函数的具体的实现是如下
#defineI2C_BOARD_INFO(dev_type, dev_addr) \
.type= dev_type, .addr = (dev_addr)
接下来看下i2c_register_board_info(1,atmel_i2c_info, 1); 这个函数在干嘛
/**
* i2c_register_board_info -statically declare I2C devices
* @busnum: identifies the bus towhich these devices belong
* @info: vector of i2c devicedescriptors
* @len: how many descriptors inthe vector; may be zero to reserve
* the specified bus number.
*
* Systems using the Linux I2Cdriver stack can declare tables of board info
* while they initialize. Thisshould be done in board-specific init code
* near arch_initcall() time, orequivalent, before any I2C adapter driver is
* registered. For example,mainboard init code could define several devices,
* as could the init code for eachdaughtercard in a board stack.
*
* The I2C devices will be createdlater, after the adapter for the relevant
* bus has been registered. Afterthat moment, standard driver model tools
* are used to bind "newstyle" I2C drivers to the devices. The bus number
* for any device declared usingthis routine is not available for dynamic
* allocation.
*
* The board info passed cansafely be __initdata, but be careful of embedded
* pointers (for platform_data,functions, etc) since that won't be copied.
*/
int__init
i2c_register_board_info(intbusnum,
structi2c_board_info const *info, unsigned len)
{
intstatus;
down_write(&__i2c_board_lock);
/*dynamic bus numbers will be assigned after the last static one */
if(busnum >= __i2c_first_dynamic_bus_num)
__i2c_first_dynamic_bus_num= busnum + 1;
for(status = 0; len; len--, info++) {
structi2c_devinfo *devinfo;
devinfo= kzalloc(sizeof(*devinfo), GFP_KERNEL);
if(!devinfo) {
pr_debug("i2c-core:can't register boardinfo!\n");
status= -ENOMEM;
break;
}
devinfo->busnum= busnum;
devinfo->board_info= *info;
list_add_tail(&devinfo->list,&__i2c_board_list);
}
up_write(&__i2c_board_lock);
returnstatus;
}
/*
* Insert a new entry at the tail
*/
static__inline__ void list_add_tail(struct list_head *new, struct list_head*head)
{
__list_add(new,head->prev, head);
}
可以看出最终将设备,也就是client的信息添加到了一个静态的链表中了externstruct list_head __i2c_board_list;
这个链表中包含了所有添加到i2cbus上面的设备,接下来在i2c_core.c里面会使用到这条链表
list_for_each_entry(devinfo,&__i2c_board_list, list) {
if(devinfo->busnum== adapter->nr
&&!i2c_new_device(adapter,
&devinfo->board_info))
dev_err(&adapter->dev,
"Can'tcreate device at 0x%02x\n",
devinfo->board_info.addr);
}
以上就会遍历这个链表找到client想要挂接的设备所在的adapter,如果相等的话,那么就会i2c_new_device(adapter,&devinfo->board_info)
看下这个函数的的实现实在哪里,??
/**
*i2c_new_device - instantiate an i2c device
*@adap: the adapter managing the device
*@info: describes one I2C device; bus_num is ignored
*Context: can sleep
*
*Create an i2c device. Binding is handled through driver model
*probe()/remove() methods. A driver may be bound to this device whenwe
*return from this function, or any later moment (e.g. maybehotplugging will
*load the driver module). This call is not appropriate for use bymainboard
*initialization logic, which usually runs during an arch_initcall()long
*before any i2c_adapter could exist.
*
*This returns the new i2c client, which may be saved for later usewith
*i2c_unregister_device(); or NULL to indicate an error.
*/
structi2c_client *
i2c_new_device(structi2c_adapter *adap, structi2c_board_info const*info)
{
structi2c_client *client;
int status;
client= kzalloc(sizeof*client, GFP_KERNEL);
if(!client)
returnNULL;
client->adapter= adap;
client->dev.platform_data= info->platform_data;
if(info->archdata)
client->dev.archdata= *info->archdata;
client->flags= info->flags;
client->addr= info->addr;
client->irq= info->irq;
strlcpy(client->name,info->type,sizeof(client->name));
/*Check for address validity */
status= i2c_check_client_addr_validity(client);
if(status) {
dev_err(&adap->dev,"Invalid %d-bit I2C address0x%02hx\n",
client->flags& I2C_CLIENT_TEN ? 10 : 7, client->addr);
gotoout_err_silent;
}
/*Check for address business */
status= i2c_check_addr_busy(adap, client->addr);
if(status)
gotoout_err;
client->dev.parent= &client->adapter->dev;
client->dev.bus= &i2c_bus_type;
client->dev.type= &i2c_client_type;
#ifdefCONFIG_OF
client->dev.of_node= info->of_node;
#endif
dev_set_name(&client->dev,"%d-%04x",i2c_adapter_id(adap),
client->addr);
status= device_register(&client->dev);
if(status)
gotoout_err;
dev_dbg(&adap->dev,"client [%s] registered with bus id%s\n",
client->name,dev_name(&client->dev));
returnclient;
out_err:
dev_err(&adap->dev,"Failed to register i2c client %sat 0x%02x "
"(%d)\n",client->name,client->addr,status);
out_err_silent:
kfree(client);
returnNULL;
}
EXPORT_SYMBOL_GPL(i2c_new_device);
这个函数还是挺多的,太困了,坚持啊
这个函数所做的工作是在实例化一个client设备
重点看下这个函数:
status= i2c_check_client_addr_validity(client);
/*This is a permissive address validity check, I2C address mapconstraints
*are purposedly not enforced, except for the general calladdress. */
staticinti2c_check_client_addr_validity(conststructi2c_client *client)
{
if(client->flags& I2C_CLIENT_TEN) {
/*10-bit address, all values are valid */
if(client->addr> 0x3ff)
return-EINVAL;
}else{
/*7-bit address, reject the general call address */
if(client->addr== 0x00 || client->addr> 0x7f)
return-EINVAL;
}
return0;
}
上面是判断client设备的地址的范围的有效性的不能超过地址的范围
/*Check for address business */
status= i2c_check_addr_busy(adap, client->addr);
staticinti2c_check_addr_busy(structi2c_adapter *adapter, intaddr)
{
intresult = 0;
if(i2c_parent_is_i2c_adapter(adapter))
result= i2c_check_mux_parents(
to_i2c_adapter(adapter->dev.parent),addr);
if(!result)
result= device_for_each_child(&adapter->dev,&addr,
i2c_check_mux_children);
returnresult,不能
}
看看这个函数的作用是什么呢???
i2c_parent_is_i2c_adapter(adapter函数的实现如下
staticinlinestructi2c_adapter* i2c_parent_is_i2c_adapter(conststructi2c_adapter*adapter)
{
structdevice*parent = adapter->dev.parent;
if(parent != NULL && parent->type == &i2c_adapter_type)
returnto_i2c_adapter(parent);
else
returnNULL;
}
i2c_check_addr_busy检查是否此地址已被注册,若已经被注册,则注册失败
接下来就直接注册这个设备了
status= device_register(&client->dev);
if(status)
gotoout_err;