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方式注册的,这里需要提醒下,platformdrivermatch的匹配规则,那么就是匹配devicedriver的名字是否相等,如果对platformdriver不了解的话,可以去看下kernel里面是如何写的,这里就不一一的叙述了。

在上面的staticvoidventana_i2c_init(void)函数里面,我开始先将下adapter的驱动,接下来讲解adapterclient的关系

i2c_register_board_info(0,ventana_i2c_bus1_board_info,1);。其实是注册一个设备的一些信息,我接下来会详细的讲解,现在是讲解adapter的驱动

platform_device_register(&tegra_i2c_device4);不难看出是注册一个platform驱动

接下来我们看下adapterdriver部分

我涉及的是tegra平台的adapter的,所以我这里就只讲解tegra平台的,其实别的平台的架构也差不多的

我进入kernel/drivers/i2c/busses/i2c-tegra.c这个文件,这就是tegraadapter驱动

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);

}

不难看出,adapterdriver也是以platform形式注册的,我们可以发现我们在adapterdriverdevicename都是.name = "tegra-i2c",所以他们是匹配的

我们重点讲解下adapterdriverprobe函数,这函数的核心的入点

看下:

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;

设置i2cbustype

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,

};

看看下i2cbusmatch的规则

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);

}

因为我看的是atmeltouchdriver,所以我说下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;

i2c adapter 和client 还有i2c_core之间的联系相关推荐

  1. linux3.10修复i2c adapter无法使用dts创建device

    i2c adapter device dts 格式: i2c0: i2c@1fe01000{compatible = "loongson,ls-i2c";reg = <0x1 ...

  2. Java -- 网络编程(一):Client与Server之间的数据传送

    目前对于我这种刚接触网络编程的豆芽来说,对网络编程最直观的了解就是:一些的Client和一个Server端之间的数据传递.具体当然是复杂的,但是那是我以后要学的. 今天我知道了可以通过Socket和D ...

  3. linux i2c adapter 增加设备_LINUX设备驱动模型分析之四 设备模块相关(DEVICE)接口分析...

    本系列前几篇文章链接如下: <LINUX设备驱动模型分析之一 总体概念说明> <LINUX设备驱动模型分析之二 总线(BUS)接口分析> <LINUX设备驱动模型分析之三 ...

  4. linux i2c adapter 增加设备_Linux驱动之I2C驱动架构

    一.Linux的I2C体系结构 主要由三部分组成: (1) I2C核心 提供I2C控制器和设备驱动的注册和注销方法,I2C通信方法,与适配器无关的代码以及探测设备等. (2) I2C控制器驱动(适配器 ...

  5. linux i2c adapter 增加设备_「正点原子Linux连载」第六十二章Linux SPI驱动实验(一)...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十二章Linux SPI驱动实验 上一 ...

  6. 虚拟机VMware Horizon Client与主机之间建立共享文件夹

    因经常需要在虚拟机和主机之间传递一些日常文件,所以建立共享文件夹. 虚拟机中安装的系统为win10,主机中的系统为win10. 步骤: 第一步:先在虚拟机win10中新建文件夹(我重命名为" ...

  7. 【TWS API使用教程1】---如何在自己创建的client和TWS之间创建一个连接,并请求当前的时间

    原先翻译了最开始的TWS API的文档,官方对TWS API的讲解是相当全的,但是就是有些太官方了,不太容易理解.最近阅读Matthew Scarpino的<Algorithmic Tradin ...

  8. I2C driver编写指导二:编写i2c client driver指南

    原文地址::http://blog.csdn.net/guoshaobei/archive/2010/06/08/5656001.aspx 译者:郭少悲 日期:2010/06/08 源文:linux- ...

  9. linux kernel 2.6 i2c设备驱动程序框架介绍,linux设备驱动程序-i2c(2)-adapter和设备树的解析...

    linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 而在linux设备驱动程序--串行通信驱动框架分 ...

最新文章

  1. 01_字符串处理-----03_替换和校正标识符
  2. centos 系统初始配置优化
  3. [CODEVS 1301] 任务分配
  4. 如何获取网站icon
  5. centos 6.5 安装mysql 5.6.35–libc.so.6(GLIBC_2.14)(64bit),libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
  6. Silverlight学习笔记(3):Silverlight的界面布局
  7. 分解质因数-洛谷P3200 [HNOI2009]有趣的数列
  8. https访问http加载不出图片_前端解决第三方图片防盗链的办法
  9. 找不到tgp饥荒专用服务器,饥荒tgp版专用服务器搭建指南_游侠网
  10. Django系列:(1)PyCharm下创建并运行我们的第一个Django工程
  11. 什么是E-MapReduce
  12. eigrp配置实验_EIGRP的认证的配置
  13. SQL 中With as 的用法
  14. JavaScript多线程 html5 Worker, SharedWorker
  15. java servlet,action,struts,struts2输出流中文编码问题
  16. Vuex的API文档
  17. 退出Activity
  18. 动态链接库劫持--libc
  19. 程序员电脑(减少辐射)(¥37)
  20. 【Word】无分页符却出现异常分页情况

热门文章

  1. sql server日期比较
  2. IE9卸载后无法安装的解决办法
  3. 阿里云免费企业邮箱申请入口(2023新版)
  4. 工作一年,面试受挫,反省....
  5. mysql中使用h2_H2数据库使用
  6. 电脑装系统的详细步骤
  7. 全国快递物流 API 实现快递单号自动识别的原理解析
  8. 4c钻石净度魔术语言,吉语珠宝课堂:钻石4C分级之Clarity(净度)
  9. 学校培训半月心得体会
  10. 官宣!这款网红产品低代码平台可以终身免费使用!!!