linux2.6.28 I2C核心层

/

//postcore_initcall优先级比module_init高
postcore_initcall(i2c_init);

static int __init i2c_init(void)
{
retval = bus_register(&i2c_bus_type);
retval = class_register(&i2c_adapter_class);
retval = i2c_add_driver(&dummy_driver);
}
/

static struct i2c_driver dummy_driver = {
.driver.name = “dummy”,
.probe = dummy_probe,
.remove = dummy_remove,
.id_table = dummy_id,
};
/

static struct device_attribute i2c_adapter_attrs[] = {
__ATTR(name, S_IRUGO, show_adapter_name, NULL),
{ },
};

static struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = “i2c-adapter”,
.dev_attrs = i2c_adapter_attrs,
};
/

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,
};

总线提供了match和probe方法:match方法的用来进行client device( 是i2c_client 吧)和client driver的配对。
在向总线i2c_bus_type注册设备或者驱动时 (i2c_add_driver函数或(i2c_register_driver)函数)会调用此方法
/

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
//可以看出匹配的对象是struct i2c_client和 struct i2c_driver实例
//也就是struct i2c_client被看成device了?
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver = to_i2c_driver(drv);

/* make legacy i2c drivers bypass driver model probing entirely;
 * such drivers scan each i2c adapter/bus themselves.
 */
if (!is_newstyle_driver(driver))
    return 0;

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

//匹配
//可知
//static struct i2c_driver at24_driver
// .id_table = at24_ids,这个ID表是用来匹配的,和i2c client的名字进行匹配
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;

return 0;

}

/

i2c_bus_type的probe方法是通过传递进来的drv找到

包含此drv的i2c_driver驱动,然后再去调用i2c_driver的probe方法,此处就是at24_probe。为什么要这

样呢?因为driver_register后,注册的是i2c_driver->drv,而drv中的probe未初始化,我们需要调用的是

i2c-driver的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)
    return -ENODEV;
client->driver = driver;
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));
if (status)
    client->driver = NULL;
return status;

}

/

/**

  • i2c_add_numbered_adapter - declare i2c adapter, use static bus number
  • @adap: the adapter to register (with adap->nr initialized)
  • 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-chip CPUs,
  • or otherwise built in to the system’s mainboard, and where i2c_board_info
  • is used to properly configure I2C devices.
  • If no devices have pre-been declared for this bus, then be sure 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() is scanned,
  • and the appropriate driver model device nodes are created. Otherwise, a
  • negative errno value is returned.
    */
    //这个函数在i2c核心层
    //<>在匹配完成后调用s3c24xx_i2c_probe函数调用i2c_add_numbered_adapter
    //执行完i2c_add_numbered_adapter函数后,内核的i2c总线上已有adapter device和client device

//只和client匹配,不和adapter匹配,adapter和client已经关联?。
int i2c_add_numbered_adapter(struct i2c_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)
    goto retry;

if (status == 0)

//注册adapter设备
status = i2c_register_adapter(adap);
return status;
}

/

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

mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock);
INIT_LIST_HEAD(&adap->clients);

mutex_lock(&core_lock);

/* Add the adapter to the driver core.
 * If the parent pointer is not set up,
 * we add this adapter to the host bus.
 */
if (adap->dev.parent == NULL) {
    adap->dev.parent = &platform_bus;
    pr_debug("I2C adapter driver [%s] forgot to specify "
         "physical device\n", adap->name);
}

// /sys/bus/i2c/devices/i2c-0
// /sys/bus/i2c/devices/i2c-1
//i2c-0 就是adapter device
sprintf(adap->dev.bus_id, “i2c-%d”, adap->nr);
adap->dev.release = &i2c_adapter_dev_release;
// 看看 driver->driver.bus = &i2c_bus_type;

//struct i2c_adapter ------>绑定i2c_adapter_class
//struct i2c_client(i2c_device)------>绑定i2c_bus_type
//struct i2c_driver (at24.c at24_driver) ------>绑定i2c_bus_type
adap->dev.class = &i2c_adapter_class;
//将名为i2c-0的adapter设备注册
res = device_register(&adap->dev);

/* create pre-declared device nodes for new-style drivers */
if (adap->nr < __i2c_first_dynamic_bus_num)
    i2c_scan_static_board_info(adap);

/* Notify drivers */

//识别一下,看看有没有
///尝试和i2c总线上所有的dev进行一次匹配,只要获取的dev为adapter时,就可执行后续操作
//bus_for_each_drv()是对BUS上所有的Driver都进行__device_attach()操作;
//同样的,bus_for_each_dev()是对BUS上所有的Device都进行__driver_attach()操作
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
i2c_do_add_adapter);
}
/
/

首先从__i2c_board_list链表上获取一个devinfo信息结构体,此结构体由前面的
smdk6410_machine_init函数调用 i2c_register_board_info()添加到i2c设备链表上的。结构体中包含板上的i2c at24c02设备相关信息。然后在此函数中调用i2c_new_device()以从链表上获取的devinfo作为参 数,i2c_new_device函数根据devinfo中的设备相关信息来创建client,内核中使用client来代表at24c02设备。
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;

mutex_lock(&__i2c_board_lock);

//遍历__i2c_board_list链表
//
//static struct i2c_board_info i2c_devs0[]
//smdk6410_machine_init()—>
// i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
// i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
//此处的0和1是+1后就是devinfo->busnum,也就是adapter->nr,应该就是代表第几组寄存器组吧?

//i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
list_for_each_entry(devinfo, &__i2c_board_list, list) {
//
// s3c24xx_i2c_probe函数 i2c->adap.nr = pdata->bus_num;
//如果adapter的号码和节点中的号码相同,才会调用i2c_new_device创建i2c clien
if (devinfo->busnum == adapter->nr
&& !i2c_new_device(adapter,
&devinfo->board_info))
printk(KERN_ERR “i2c-core: can’t create i2c%d-%04x\n”,
i2c_adapter_id(adapter),
devinfo->board_info.addr);
}
mutex_unlock(&__i2c_board_lock);
}
/

/**

  • i2c_new_device - instantiate an i2c device for use with a new style driver

  • @adap: the adapter managing the device

  • @info: describes one I2C device; bus_num is ignored

  • Context: can sleep

  • Create a device to work with a new style i2c driver, where binding is

  • handled through driver model probe()/remove() methods. This call is not

  • appropriate for use by mainboad 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 use with

  • i2c_unregister_device(); or NULL to indicate an error.
    */
    struct i2c_client *
    i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
    {
    struct i2c_client *client;
    int status;

    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
    return NULL;
    //client 和adap是相互关联到一起的。
    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;
    // i2c_board_info中的名字给了client
    //
    //static struct i2c_board_info i2c_devs0[] __initdata = {
    // { I2C_BOARD_INFO(“24c08”, 0x50), }, //0x50为IIC芯片设备地址
    //"24c08"这个名字就是用来创建i2c_client来和里static struct i2c_driver at24_driver进行匹配的。
    strlcpy(client->name, info->type, sizeof(client->name));

    /* a new style driver may be bound to this device when we

    • return from this function, or any later moment (e.g. maybe
    • hotplugging will load the driver module). and the device
    • refcount model is the standard driver model one.
      */
      status = i2c_attach_client(client);
      if (status < 0) {
      kfree(client);
      client = NULL;
      }
      return client;
      }
      /

int i2c_attach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
int res;

/* Check for address business */
res = i2c_check_addr(adapter, client->addr);
if (res)
    return res;

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

//struct i2c_adapter ------>绑定i2c_adapter_class
//struct i2c_client(i2c_device)------>绑定i2c_bus_type
//struct i2c_driver (at24.c at24_driver) ------>绑定i2c_bus_type
//client被注册到i2c_bus_type总线
//static struct i2c_driver dummy_driver 这个也是注册到i2c_bus_type总线
client->dev.bus = &i2c_bus_type;

if (client->driver)
    client->dev.driver = &client->driver->driver;

if (client->driver && !is_newstyle_driver(client->driver)) {
    client->dev.release = i2c_client_release;
    client->dev.uevent_suppress = 1;
} else
    client->dev.release = i2c_client_dev_release;

///sys/bus/i2c/devices # ls
// 0-001b 0-0050 i2c-0 i2c-1 i2c-2
// /sys/bus/i2c/devices/0-001b
// /sys/bus/i2c/devices/0-0050
//0-001b就是client device
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
“%d-%04x”, i2c_adapter_id(adapter), client->addr);
//注册client的父类到内核
//int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
// driver->driver.bus = &i2c_bus_type;
// res = driver_register(&driver->driver);
//这么像,应该能猜到client->dev就是device->dev
res = device_register(&client->dev);
if (res)
goto out_err;

mutex_lock(&adapter->clist_lock);
list_add_tail(&client->list, &adapter->clients);
mutex_unlock(&adapter->clist_lock);

dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
    client->name, client->dev.bus_id);

if (adapter->client_register)  {
    if (adapter->client_register(client)) {
        dev_dbg(&adapter->dev, "client_register "
            "failed for client [%s] at 0x%02x\n",
            client->name, client->addr);
    }
}

return 0;

out_err:
dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
“(%d)\n”, client->name, client->addr, res);
return res;
}

///

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) {
    /* We ignore the return code; if it fails, too bad */

//调用
//static struct i2c_driver i2cdev_driver = {
// .attach_adapter = i2cdev_attach_adapter,
//此处调用i2cdev_attach_adapter函数
driver->attach_adapter(adap);
}
return 0;
}
///

//和 i2c_do_add_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;

}

static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}

/*

  • An i2c_driver is used with one or more i2c_client (device) nodes to access

  • i2c slave chips, on a bus instance associated with some i2c_adapter. There

  • are two models for binding the driver to its device: “new style” drivers

  • follow the standard Linux driver model and just respond to probe() calls

  • issued if the driver core sees they match(); “legacy” drivers create device

  • nodes themselves.
    */
    //对比
    //static int i2c_register_adapter(struct i2c_adapter *adap)
    //这两个函数里面是何其形似,所以 i2c_register_adapter相当于 i2c_register_device,和i2c_register_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;

    /* new style driver methods can’t mix with legacy ones */
    if (is_newstyle_driver(driver)) {
    if (driver->attach_adapter || driver->detach_adapter
    || driver->detach_client) {
    printk(KERN_WARNING
    “i2c-core: driver [%s] is confused\n”,
    driver->driver.name);
    return -EINVAL;
    }
    }

    /* add the driver to the list of i2c drivers in the driver core */
    driver->driver.owner = owner;
    //
    //int i2c_attach_client(struct i2c_client *client)
    // client->dev.bus = &i2c_bus_type;
    //client被注册到i2c_bus_type总线
    //static struct i2c_driver dummy_driver 这个也是注册到i2c_bus_type总线
    //struct i2c_adapter ------>绑定i2c_adapter_class
    //struct i2c_client(i2c_device)------>绑定i2c_bus_type
    //struct i2c_driver ------>绑定i2c_bus_type
    driver->driver.bus = &i2c_bus_type;

//见
//int i2c_attach_client(struct i2c_client client)
//—> client->dev.parent = &client->adapter->dev;
// client->dev.bus = &i2c_bus_type;
// res = device_register(&client->dev);
//这么像,是不是必须client是device.呵呵
/
for new style drivers, when registration returns the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);
if (res)
return res;

mutex_lock(&core_lock);

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

INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */

// i2c_register_adapter里也有一个 bus_for_each_drv
class_for_each_device(&i2c_adapter_class, NULL, driver,
__attach_adapter);

mutex_unlock(&core_lock);
return 0;

}

/**

  • i2c_transfer - execute a single or combined I2C message
  • @adap: Handle to I2C bus
  • @msgs: One or more messages to execute before STOP is issued to
  • terminate the operation; each message begins with a START.
  • @num: Number of messages to be executed.
  • Returns negative errno, else the number of messages executed.
  • Note that there is no requirement that each message be sent to
  • the same slave address, although that is the most common model.
    */

at24_eeprom_read调用i2c_transfer
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
int ret;

/* REVISIT the fault reporting model here is weak:
 *
 *  - When we get an error after receiving N bytes from a slave,
 *    there is no way to report "N".
 *
 *  - When we get a NAK after transmitting N bytes to a slave,
 *    there is no way to report "N" ... or to let the master
 *    continue executing the rest of this combined message, if
 *    that's the appropriate response.
 *
 *  - When for example "num" is two and we successfully complete
 *    the first message but get an error part way through the
 *    second, it's unclear whether that should be reported as
 *    one (discarding status on the second message) or errno
 *    (discarding status on the first one).
 */

if (adap->algo->master_xfer) {

#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
“len=%d%s\n”, ret, (msgs[ret].flags & I2C_M_RD)
? ‘R’ : ‘W’, msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? “+” : “”);
}
#endif

    if (in_atomic() || irqs_disabled()) {
        ret = mutex_trylock(&adap->bus_lock);
        if (!ret)
            /* I2C activity is ongoing. */
            return -EAGAIN;
    } else {
        mutex_lock_nested(&adap->bus_lock, adap->level);
    }

//发送数据
//
//static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
// .master_xfer = s3c24xx_i2c_xfer,
//此处调用 s3c24xx_i2c_xfer函数
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);

    return ret;
} else {
    dev_dbg(&adap->dev, "I2C level transfers not supported\n");
    return -EOPNOTSUPP;
}

}

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx-xx-xxx-xxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值