您的位置:首页 > 运维架构 > Linux

我对linux理解之i2c一

2012-10-27 13:56 323 查看
转载出处:amingriyue.blog.chinaunix.net

i2c设备是非常普遍的一种设备,我们现在开始i2c子系统的分析。

我们先从注册开始:

static const struct i2c_device_id IT7260_ts_id[] = {

{ IT7260_I2C_NAME, 0 },

{ }

};

static struct i2c_driver IT7260_ts_driver = {

.probe = IT7260_ts_probe,

.remove = IT7260_ts_remove,

#ifdef CONFIG_PM

.resume = IT7260_ts_resume,

.suspend = IT7260_ts_suspend,

#endif

.id_table = IT7260_ts_id,

.driver = {

.name = "IT7260-ts",

},

};

i2c_add_driver(&IT7260_ts_driver)我们看这是典型的具体i2c添加驱动实例。

static inline int i2c_add_driver(struct i2c_driver *driver)

{

return i2c_register_driver(THIS_MODULE, driver);

}

转而i2c_register_driver(THIS_MODULE, driver):

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

{

int res;

/* Can't register until after driver model init */

if (unlikely(WARN_ON(!i2c_bus_type.p)))

return -EAGAIN;

/* add the driver to the list of i2c drivers in the driver core */

driver->driver.owner = owner;

driver->driver.bus = &i2c_bus_type;

/* When registration returns, the driver core

* will have called probe() for all matching-but-unbound devices.

*/

res = driver_register(&driver->driver);//这个我们在driver_register中分析过了,它会去匹配总线(这里就是i2c了)上的的所有设备的client,如果找到,则执行bus的probe函数,我们下面去看下bus的probe函数

if (res)

return res;

pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

INIT_LIST_HEAD(&driver->clients);//初始化clients列表

/* Walk the adapters that are already present */

mutex_lock(&core_lock);

class_for_each_device(&i2c_adapter_class, NULL, driver,

__attach_adapter);//对i2c_adapter_class下的每个设备都进行匹配

mutex_unlock(&core_lock);

return 0;

}

我们看下__attach_adapter:

static int __attach_adapter(struct device *dev, void *data)

{

struct i2c_adapter *adapter = to_i2c_adapter(dev);

struct i2c_driver *driver = data;

i2c_detect(adapter, driver);

/* Legacy drivers scan i2c busses directly */

if (driver->attach_adapter)//没有定义

driver->attach_adapter(adapter);

return 0;

}

转到i2c_detect(adapter, driver):

static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)

{

const struct i2c_client_address_data *address_data;

struct i2c_client *temp_client;

int i, err = 0;

int adap_id = i2c_adapter_id(adapter);//总线序号

address_data = driver->address_data;

if (!driver->detect || !address_data)//我们系统中这两个都为null,故在这里就返回了

return 0;

......

}

可以看出__attach_adapter没有做具体的工作对于i2c。

我们回到i2c_register_driver看driver_register(&driver->driver),它去匹配设备的client,匹配上后会执行bus的probe函数,我们看下i2c_bus的probe:

struct bus_type i2c_bus_type = {

.name = "i2c",

.dev_attrs = i2c_dev_attrs,

.match = i2c_device_match,

.uevent = i2c_device_uevent,

.probe = i2c_device_probe,

.remove = i2c_device_remove,

.shutdown = i2c_device_shutdown,

.suspend = i2c_device_suspend,

.resume = i2c_device_resume,

};

这里我们先看下bus的match函数,因为driver_register这个寻找设备的时候会执行bus的match函数:

static int i2c_device_match(struct device *dev, struct device_driver *drv)

{

struct i2c_client *client = to_i2c_client(dev);

struct i2c_driver *driver = to_i2c_driver(drv);

/* match on an id table if there is one */

if (driver->id_table)

return i2c_match_id(driver->id_table, client) != NULL;//只匹配id的名字和client的名字,跟驱动的名字没有关系,注意这里的client是设备转换过来,而不是设备的本身!!!

return 0;

}

转而调用i2c_match_id();

static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,

const struct i2c_client *client)

{

while (id->name[0]) {

if (strcmp(client->name, id->name) == 0) //匹配设备client名字和id_table中的名字

return id;

id++;

}

return NULL;

}

所以i2c总线根据设备client名字和id_table中的名字进行匹配的。如果匹配了,则返回id值。然后会执行bus的probe函数,对应了i2c_device_probe:

static int i2c_device_probe(struct device *dev)

{

struct i2c_client *client = to_i2c_client(dev);

struct i2c_driver *driver = to_i2c_driver(dev->driver);

int status;

if (!driver->probe || !driver->id_table)//i2c driver这两个是必须要定义的

return -ENODEV;

client->driver = driver;//赋值给client

if (!device_can_wakeup(&client->dev))

device_init_wakeup(&client->dev,

client->flags & I2C_CLIENT_WAKE);

dev_dbg(dev, "probe\n");

status = driver->probe(client, i2c_match_id(driver->id_table, client));//执行i2c的driver的probe函数,这个就是开头具体驱动中的probe(如IT7260_ts_probe)

if (status)

client->driver = NULL;

return status;

}

那这里我们看到了i2c驱动怎么执行的了。

至此,我们只看了i2c driver的注册分析,那i2c device呢?

我们到平台文件里面可以看到这样的代码:

static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {

......

{

.type = "IT7260",

.addr = 0x46,

.irq = IOMUX_TO_IRQ_V3(F101_TP_INT),

.platform_data = &it7260_data,

},

......

};

i2c_register_board_info(0, mxc_i2c0_board_info,

ARRAY_SIZE(mxc_i2c0_board_info));

这是具体i2c驱动设备的信息注册,我们看下定义:

int __init

i2c_register_board_info(int busnum, //这个busnum就是i2c的序号

struct i2c_board_info const *info, unsigned len) //len表示有几个info,也就是有i2c上挂几个外设

{

int status;

down_write(&__i2c_board_lock); //i2c core的读写锁

/* 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;//比最大的busnum大1

for (status = 0; len; len--, info++) {

struct i2c_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; //该外设所挂的i2c号

devinfo->board_info = *info; //该外设的基本信息(如名字,地址,私有数据等)

list_add_tail(&devinfo->list, &__i2c_board_list); //这里__i2c_board_list是一个全局变量,记录着所有i2c外设的信息,然后adapter注册的时候会使用这个列表,所以这个函数要放在adapter注册之前

}

up_write(&__i2c_board_lock);

return status;

}

这个函数主要就是将i2c驱动设备信息整理到__i2c_board_list列表里面。那这个信息列表什么时候用呢?别忘了,我们还有一个没分析,就是cpu自身的i2c控制器。它是怎么注册的呢?怎么跟具体的i2c驱动联系起来的呢?下面我们就看下i2c控制器的驱动。

static struct platform_driver mxci2c_driver = {//我们在tty分析中已经分析过platform注册过程了,它是先匹配id_table中的名字,然后在匹配driver的名字,有一个匹配即可

.driver = {

.name = "mxc_i2c",

.owner = THIS_MODULE,

},

.probe = mxci2c_probe,

.remove = mxci2c_remove,

.suspend_late = mxci2c_suspend,

.resume_early = mxci2c_resume,

};

这就是这个平台的i2c控制器驱动结构定义。

static int __init mxc_i2c_init(void)

{

/* Register the device driver structure. */

return platform_driver_register(&mxci2c_driver);

}

我们看到在init函数里面有对它的注册,platform总线以前就分析过了,相信大家不陌生了。它注册的时候会先按照id_table去找设备,然后按驱动名字去找。这里没id_table,那就按驱动名字去找了,我们可以看到平台设备定义下有这样的定义:

struct platform_device mxci2c_devices[] = {

{

.name = "mxc_i2c",

.id = 0,

.num_resources = ARRAY_SIZE(mxci2c1_resources),

.resource = mxci2c1_resources,

},

{

.name = "mxc_i2c",

.id = 1,

.num_resources = ARRAY_SIZE(mxci2c2_resources),

.resource = mxci2c2_resources,

},

{

.name = "mxc_i2c",

.id = 2,

.num_resources = ARRAY_SIZE(mxci2c3_resources),

.resource = mxci2c3_resources,

},

};

同样还有这样的注册设备的代码:

mxc_register_device(&mxci2c_devices[0], &mxci2c_data);

mxc_register_device(&mxci2c_devices[1], &mxci2c_data);

这样,mxci2c就可以顺利注册了。注册成功后,会调用paltform总线的probe,最终会执行driver的probe。我们看到mxci2c_driver的probe对应为:

static int mxci2c_probe(struct platform_device *pdev)

{

mxc_i2c_device *mxc_i2c;

struct mxc_i2c_platform_data *i2c_plat_data = pdev->dev.platform_data;//在dev注册的时候有赋值

struct resource *res;

int id = pdev->id;

u32 clk_freq;

int ret = 0;

int i;

mxc_i2c = kzalloc(sizeof(mxc_i2c_device), GFP_KERNEL);

if (!mxc_i2c) {

return -ENOMEM;

}

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if (res == NULL) {

ret = -ENODEV;

goto err1;

}

mxc_i2c->membase = ioremap(res->start, res->end - res->start + 1);

/*

* Request the I2C interrupt

*/

mxc_i2c->irq = platform_get_irq(pdev, 0);

if (mxc_i2c->irq < 0) {

ret = mxc_i2c->irq;

goto err2;

}

ret = request_irq(mxc_i2c->irq, mxc_i2c_handler,

0, pdev->name, mxc_i2c);

if (ret < 0) {

goto err2;

}

init_waitqueue_head(&mxc_i2c->wq);

mxc_i2c->low_power = false;

gpio_i2c_active(id);

mxc_i2c->clk = clk_get(&pdev->dev, "i2c_clk");

clk_freq = clk_get_rate(mxc_i2c->clk);

mxc_i2c->clkdiv = -1;

if (i2c_plat_data->i2c_clk) {

/* Calculate divider and round up any fractional part */

int div = (clk_freq + i2c_plat_data->i2c_clk - 1) /

i2c_plat_data->i2c_clk;

for (i = 0; i2c_clk_table[i].div != 0; i++) {

if (i2c_clk_table[i].div >= div) {

mxc_i2c->clkdiv = i2c_clk_table[i].reg_value;

break;

}

}

}

if (mxc_i2c->clkdiv == -1) {

i--;

mxc_i2c->clkdiv = 0x1F; /* Use max divider */

}

dev_dbg(&pdev->dev, "i2c speed is %d/%d = %d bps, reg val = 0x%02X\n",

clk_freq, i2c_clk_table[i].div,

clk_freq / i2c_clk_table[i].div, mxc_i2c->clkdiv);

/*

* Set the adapter information

*/

strlcpy(mxc_i2c->adap.name, pdev->name, 48); //adapter名字最长是48

mxc_i2c->adap.id = mxc_i2c->adap.nr = id; //总线编号

mxc_i2c->adap.algo = &mxc_i2c_algorithm; //向adapter赋值i2c_algorithm结构,后面传输函数分析会用到

mxc_i2c->adap.timeout = 1;

platform_set_drvdata(pdev, mxc_i2c);

i2c_set_adapdata(&mxc_i2c->adap, mxc_i2c); //从设备定义那边获得的数据保存起来

if ((ret = i2c_add_numbered_adapter(&mxc_i2c->adap)) < 0) { //为每条i2c注册一个adapter

goto err3;

}

printk(KERN_INFO "MXC I2C driver\n");

return 0;

err3:

free_irq(mxc_i2c->irq, mxc_i2c);

gpio_i2c_inactive(id);

err2:

iounmap(mxc_i2c->membase);

err1:

dev_err(&pdev->dev, "failed to probe i2c adapter\n");

kfree(mxc_i2c);

return ret;

}

在初始化了mxc_i2c结构体后会执行i2c_add_numbered_adapter(&mxc_i2c->adap):

int i2c_add_numbered_adapter(struct i2c_adapter *adap)

{

int id;

int status;

if (adap->nr & ~MAX_ID_MASK)

return -EINVAL;

//idr机制我们这里不去深究,知道意思就行了,也就是将整数ID号和特定指针关联在一起的机制,这样很方便查找,查找到id也就查找到对应的指针了

retry:

if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) //为i2c的idr准备空间

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); //根据adap->nr申请id号,将id和adap关联起来

if (status == 0 && id != adap->nr) {

status = -EBUSY;

idr_remove(&i2c_adapter_idr, id); //错误的话不要忘了释放之前申请的空间

}

mutex_unlock(&core_lock);

if (status == -EAGAIN)

goto retry;

if (status == 0)

status = i2c_register_adapter(adap);//注册adapter

return status;

}

转到i2c_register_adapter(adap):

static int i2c_register_adapter(struct i2c_adapter *adap)

{

int res = 0, dummy;

/* Can't register until after driver model init */

if (unlikely(WARN_ON(!i2c_bus_type.p))) {

res = -EAGAIN;

goto out_list;

}

mutex_init(&adap->bus_lock);

/* Set default timeout to 1 second if not already set */

if (adap->timeout == 0)//mxc_i2c中设为1,即1个jiffies

adap->timeout = HZ;

dev_set_name(&adap->dev, "i2c-%d", adap->nr);//形如i2c-0,i2c-1等

adap->dev.release = &i2c_adapter_dev_release;

adap->dev.class = &i2c_adapter_class;

res = device_register(&adap->dev); //在device_register中已分析,这里是将adapter注册到/sys/系统中,属于i2c-adapter类,在/sys/class/i2c-adapter/下注册具体的adapter,如i2c-0,i2c-1等,同时键一些属性文件

if (res)

goto out_list;

dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

/* create pre-declared device nodes */

if (adap->nr < __i2c_first_dynamic_bus_num)//__i2c_first_dynamic_bus_num总比i2c总数目大1

i2c_scan_static_board_info(adap);

/* Notify drivers */

mutex_lock(&core_lock);

dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,

i2c_do_add_adapter); //对bus上注册的驱动执行该函数

mutex_unlock(&core_lock);

return 0;

out_list:

mutex_lock(&core_lock);

idr_remove(&i2c_adapter_idr, adap->nr);

mutex_unlock(&core_lock);

return res;

}

好,我们看下i2c_scan_static_board_info(adap):

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)

{

struct i2c_devinfo *devinfo;

down_read(&__i2c_board_lock);

list_for_each_entry(devinfo, &__i2c_board_list, list) {//__i2c_board_list是所有i2c外设组成的列表,所以这个列表必须在这之前准备好

if (devinfo->busnum == adapter->nr //匹配总线序号

&& !i2c_new_device(adapter,//在该总线上添加外设

&devinfo->board_info))

dev_err(&adapter->dev,

"Can't create device at 0x%02x\n",

devinfo->board_info.addr);

}

up_read(&__i2c_board_lock);

}

__i2c_board_list?!想起来了吧,就上面注册的所有i2c驱动设备信息列表。这里将按照设备所属的i2c总线,然后添加到对应的i2c上,我们下面看下i2c_new_device(adapter, &devinfo->board_info):

struct i2c_client *

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

{

struct i2c_client *client;

int status;

//client是一个很重要的结构,它联系了adapter,driver,dev,在i2c架构中起到纽带作用

client = kzalloc(sizeof *client, GFP_KERNEL);

if (!client)

return NULL;

client->adapter = adap; //赋值给client,驱动会通过client使用adapter之前开始时初始化的变量,包括i2c_algorithm

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

//上面主要是对client初始化

/* Check for address business */

status = i2c_check_addr(adap, client->addr);//检查这个地址是否已经有其它外设在使用了

if (status)

goto out_err;

client->dev.parent = &client->adapter->dev;

client->dev.bus = &i2c_bus_type;

client->dev.release = i2c_client_dev_release;

dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),//可以知道client名字为总线号加地址

client->addr);

status = device_register(&client->dev);//注册client的dev到i2c bus下的device列表

if (status)

goto out_err;

dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",

client->name, dev_name(&client->dev));

return client;

out_err:

dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "

"(%d)\n", client->name, client->addr, status);

kfree(client);

return NULL;

}

这样我们的设备和驱动就可以联系起来了。我们下面在看一下i2c_register_adapter中的i2c_do_add_adapter:

static int i2c_do_add_adapter(struct device_driver *d, void *data)

{

struct i2c_driver *driver = to_i2c_driver(d);

struct i2c_adapter *adap = data;

/* Detect supported devices on that bus, and instantiate them */

i2c_detect(adap, driver);

/* Let legacy drivers scan this bus for matching devices */

if (driver->attach_adapter) {//driver没有定义

/* We ignore the return code; if it fails, too bad */

driver->attach_adapter(adap);

}

return 0;

}

跟上面的__attach_adapter一样呢!没什么具体作用的。仔细想想也是有道理的,i2c驱动已经可以通过client访问adapter了,所以驱动再去匹配adapter是多此一举。可能有的驱动通过其它方式注册的,是需要匹配adapter的,这个另当别论吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: