免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2769 | 回复: 0
打印 上一主题 下一主题

I2C architecture in linux kernel [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-17 20:54 |只看该作者 |倒序浏览

I2C architecture in linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I2C(Inter-Integrated Circuit) bus is a very cheap yet effective network used to interconnect periphral devices within small-scale embedded systems.
I2c uses two wires to connect multiple devices in a multi-drop bus. The bus is bidirectional, low-speed, and synchronous to a common clock. Devices may be attached or detached from the I2C bus without affecting other devices. Several manufactures, such as Microchip, Philips, Intel, and others produce small microcontrollers with I2C built in . The data rate of I2C is somewhat slower than SPI, at 100kbps in standard mode, and 400 kbps in fast mode.
The two wires used to interconnect with I2C are SDA(serial data) and SCL(serial clock). Both lines are open-drain. They are connected to a positive supply via a pull-up resistor and therefore remain high when not in use. A device using the I2C bus to communicate drives the lines low or leaves them pulled high as appropriate. Each device connected to the I2C bus has a unique address and can operate as either a transmitter(a bus master), a receiver(a bus slave), or both. I2C is a multi-master bus, meaning that more than one device may assume the role of bus master.
key data structs
~~~~~~~~~~~~~~~~~~
/*
* The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can
* be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
* to name two of the most common.
*/
struct i2c_algorithm {
    /* If an adapter algorithm can't do I2C-level access, set master_xfer
       to NULL. If an adapter algorithm can do SMBus access, set
       smbus_xfer. If set to NULL, the SMBus protocol is simulated
       using common I2C messages */
    /* master_xfer should return the number of messages successfully
       processed, or a negative value on error */
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
               int num);
    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
               unsigned short flags, char read_write,
               u8 command, int size, union i2c_smbus_data *data);
    /* To determine what the adapter supports */
    u32 (*functionality) (struct i2c_adapter *);
};
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
* with the access algorithms necessary to access it.
*/
struct i2c_adapter {
    struct module *owner;
    unsigned int id;
    unsigned int class;          /* classes to allow probing for */
    const struct i2c_algorithm *algo; /* the algorithm to access the bus */
    void *algo_data;
    /* --- administration stuff. */
    int (*client_register)(struct i2c_client *);
    int (*client_unregister)(struct i2c_client *);
    /* data fields that are valid for all devices    */
    u8 level;             /* nesting level for lockdep */
    struct mutex bus_lock;
    struct mutex clist_lock;
    int timeout;            /* in jiffies */
    int retries;
    struct device dev;        /* the adapter device */
    int nr;
    struct list_head clients;    /* DEPRECATED */
    char name[48];
    struct completion dev_released;
};
/**
* struct i2c_driver - represent an I2C device driver
* @id: Unique driver ID (optional)
* @class: What kind of i2c device we instantiate (for detect)
* @attach_adapter: Callback for bus addition (for legacy drivers)
* @detach_adapter: Callback for bus removal (for legacy drivers)
* @detach_client: Callback for device removal (for legacy drivers)
* @probe: Callback for device binding (new-style drivers)
* @remove: Callback for device unbinding (new-style drivers)
* @shutdown: Callback for device shutdown
* @suspend: Callback for device suspend
* @resume: Callback for device resume
* @command: Callback for bus-wide signaling (optional)
* @driver: Device driver model driver
* @id_table: List of I2C devices supported by this driver
* @detect: Callback for device detection
* @address_data: The I2C addresses to probe, ignore or force (for detect)
* @clients: List of detected clients we created (for i2c-core use only)
*
* The driver.owner field should be set to the module owner of this driver.
* The driver.name field should be set to the name of this driver.
*
* For automatic device detection, both @detect and @address_data must
* be defined. @class should also be set, otherwise only devices forced
* with module parameters will be created. The detect function must
* fill at least the name field of the i2c_board_info structure it is
* handed upon successful detection, and possibly also the flags field.
*
* If @detect is missing, the driver will still work fine for enumerated
* devices. Detected devices simply won't be supported. This is expected
* for the many I2C/SMBus devices which can't be detected reliably, and
* the ones which can always be enumerated in practice.
*
* The i2c_client structure which is handed to the @detect callback is
* not a real i2c_client. It is initialized just enough so that you can
* call i2c_smbus_read_byte_data and friends on it. Don't do anything
* else with it. In particular, calling dev_dbg and friends on it is
* not allowed.
*/
struct i2c_driver {
    int id;
    unsigned int class;
    /* Notifies the driver that a new bus has appeared. This routine
     * can be used by the driver to test if the bus meets its conditions
     * & seek for the presence of the chip(s) it supports. If found, it
     * registers the client(s) that are on the bus to the i2c admin. via
     * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)
     */
    int (*attach_adapter)(struct i2c_adapter *);
    int (*detach_adapter)(struct i2c_adapter *);
    /* tells the driver that a client is about to be deleted & gives it
     * the chance to remove its private data. Also, if the client struct
     * has been dynamically allocated by the driver in the function above,
     * it must be freed here.  (LEGACY I2C DRIVERS ONLY)
     */
    int (*detach_client)(struct i2c_client *) __deprecated;
    /* Standard driver model interfaces, for "new style" i2c drivers.
     * With the driver model, device enumeration is NEVER done by drivers;
     * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
     */
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);
    /* driver model interfaces that don't relate to enumeration  */
    void (*shutdown)(struct i2c_client *);
    int (*suspend)(struct i2c_client *, pm_message_t mesg);
    int (*resume)(struct i2c_client *);
    /* a ioctl like command that can be used to perform specific functions
     * with the device.
     */
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
    struct device_driver driver;
    const struct i2c_device_id *id_table;
    /* Device detection callback for automatic device creation */
    int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);
    const struct i2c_client_address_data *address_data;
    struct list_head clients;
};
/**
* struct i2c_client - represent an I2C slave device
* @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
*    I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
* @addr: Address used on the I2C bus connected to the parent adapter.
* @name: Indicates the type of the device, usually a chip name that's
*    generic enough to hide second-sourcing and compatible revisions.
* @adapter: manages the bus segment hosting this I2C device
* @driver: device's driver, hence pointer to access routines
* @dev: Driver model device node for the slave.
* @irq: indicates the IRQ generated by this device (if any)
* @list: list of active/busy clients (DEPRECATED)
* @detected: member of an i2c_driver.clients list
* @released: used to synchronize client releases & detaches and references
*
* An i2c_client identifies a single device (i.e. chip) connected to an
* i2c bus. The behaviour exposed to Linux is defined by the driver
* managing the device.
*/
struct i2c_client {
    unsigned short flags;        /* div., see below        */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the    */
                    /* _LOWER_ 7 bits        */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    /* the adapter we sit on    */
    struct i2c_driver *driver;    /* and our access routines    */
    struct device dev;        /* the device structure        */
    int irq;            /* irq issued by device        */
    struct list_head list;        /* DEPRECATED */
    struct list_head detected;
    struct completion released;
};
/**
* struct i2c_board_info - template for device creation
* @type: chip type, to initialize i2c_client.name
* @flags: to initialize i2c_client.flags
* @addr: stored in i2c_client.addr
* @platform_data: stored in i2c_client.dev.platform_data
* @archdata: copied into i2c_client.dev.archdata
* @irq: stored in i2c_client.irq
*
* I2C doesn't actually support hardware probing, although controllers and
* devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
* a device at a given address.  Drivers commonly need more information than
* that, such as chip type, configuration, associated IRQ, and so on.
*
* i2c_board_info is used to build tables of information listing I2C devices
* that are present.  This information is used to grow the driver model tree
* for "new style" I2C drivers.  For mainboards this is done statically using
* i2c_register_board_info(); bus numbers identify adapters that aren't
* yet available.  For add-on boards, i2c_new_device() does this dynamically
* with the adapter already known.
*/
struct i2c_board_info {
    char        type[I2C_NAME_SIZE];
    unsigned short    flags;
    unsigned short    addr;
    void        *platform_data;
    struct dev_archdata    *archdata;
    int        irq;
};
How to register a I2C adapter?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To be concrete, let's take the registration of I2C bus of s3c2410 development board as an example.
I2C bus of s3c2410 can also be treated as an abstract platform device, so that it's registered by means of general used kernel API, platform_driver_register(), and platform_device_register().
/* device driver for platform bus bits */
static struct platform_driver s3c2410_i2c_driver = {
    .probe        = s3c24xx_i2c_probe,
    .remove        = s3c24xx_i2c_remove,
    .suspend_late    = s3c24xx_i2c_suspend_late,
    .resume        = s3c24xx_i2c_resume,
    .driver        = {
        .owner    = THIS_MODULE,
        .name    = "s3c2410-i2c",
    },
};
static int __init i2c_adap_s3c_init(void)
{
    int ret;
    ret = platform_driver_register(&s3c2410_i2c_driver);
    if (ret == 0) {
        ....
        if (ret)
            platform_driver_unregister(&s3c2410_i2c_driver);
    }
    return ret;
}
static struct resource s3c_i2c_resource[] = {
    [0] = {
        .start = S3C_PA_IIC,
        .end   = S3C_PA_IIC + SZ_4K - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = IRQ_IIC,
        .end   = IRQ_IIC,
        .flags = IORESOURCE_IRQ,
    },
};
struct platform_device s3c_device_i2c0 = {
    .name          = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
    .id          = 0,
#else
    .id          = -1,
#endif
    .num_resources      = ARRAY_SIZE(s3c_i2c_resource),
    .resource      = s3c_i2c_resource,
};
static struct platform_device *smdk2410_devices[] __initdata = {
    &s3c_device_usb,
    &s3c_device_lcd,
    &s3c_device_wdt,
    &s3c_device_i2c0,    cfg_gpio)
        npd->cfg_gpio = s3c_i2c0_cfg_gpio;
    s3c_device_i2c0.dev.platform_data = npd;
}
static void __init smdk2410_init(void)
{
    s3c_i2c0_set_platdata(NULL);
    platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));   driver->name is identical with s3c_device_i2c0->name, the probe() method of s3c2410_i2c_driver is called with s3c_device_i2c0 as argument.
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
*/
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
    struct s3c24xx_i2c *i2c;
    struct s3c2410_platform_i2c *pdata;
    struct resource *res;
    int ret;
    pdata = pdev->dev.platform_data;
    if (!pdata) {
        dev_err(&pdev->dev, "no platform data\n");
        return -EINVAL;
    }
    i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); dev, "no memory for state\n");
        return -ENOMEM;
    }
    strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
    i2c->adap.owner   = THIS_MODULE;
    i2c->adap.algo    = &s3c24xx_i2c_algorithm;  adap.retries = 2;
    i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
    i2c->tx_setup     = 50;
    spin_lock_init(&i2c->lock);
    init_waitqueue_head(&i2c->wait);
    /* find the clock and enable it */
    i2c->dev = &pdev->dev;
    i2c->clk = clk_get(&pdev->dev, "i2c");
    if (IS_ERR(i2c->clk)) {
        dev_err(&pdev->dev, "cannot get clock\n");
        ret = -ENOENT;
        goto err_noclk;
    }
    dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
    clk_enable(i2c->clk);
    /* map the registers */
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);      dev, "cannot find IO resource\n");
        ret = -ENOENT;
        goto err_clk;
    }
    i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, name);
    if (i2c->ioarea == NULL) {
        dev_err(&pdev->dev, "cannot request IO\n");
        ret = -ENXIO;
        goto err_clk;
    }
    i2c->regs = ioremap(res->start, (res->end-res->start)+1); regs == NULL) {
        dev_err(&pdev->dev, "cannot map IO\n");
        ret = -ENXIO;
        goto err_ioarea;
    }
    dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
        i2c->regs, i2c->ioarea, res);
    /* setup info block for the i2c core */
    i2c->adap.algo_data = i2c;
    i2c->adap.dev.parent = &pdev->dev;
    /* initialise the i2c controller */
    ret = s3c24xx_i2c_init(i2c);
    if (ret != 0)
        goto err_iomap;
    /* find the IRQ for this unit (note, this relies on the init call to
     * ensure no current IRQs pending
     */
    i2c->irq = ret = platform_get_irq(pdev, 0);
    if (ret dev, "cannot find IRQ\n");
        goto err_iomap;
    }
    ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  dev), i2c);
    if (ret != 0) {
        dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
        goto err_iomap;
    }
    ret = s3c24xx_i2c_register_cpufreq(i2c);
    if (ret dev, "failed to register cpufreq notifier\n");
        goto err_irq;
    }
    /* Note, previous versions of the driver used i2c_add_adapter()
     * to add the bus at any number. We now pass the bus number via
     * the platform data, so if unset it will now default to always
     * being bus 0.
     */
    i2c->adap.nr = pdata->bus_num;  adap); dev, "failed to add bus to i2c core\n");
        goto err_cpufreq;
    }
    platform_set_drvdata(pdev, i2c);
    dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
    return 0;
err_cpufreq:
    s3c24xx_i2c_deregister_cpufreq(i2c);
err_irq:
    free_irq(i2c->irq, i2c);
err_iomap:
    iounmap(i2c->regs);
err_ioarea:
    release_resource(i2c->ioarea);
    kfree(i2c->ioarea);
err_clk:
    clk_disable(i2c->clk);
    clk_put(i2c->clk);
err_noclk:
    kfree(i2c);
    return ret;
}
/**
* 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.
*/
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);  nr) {            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);
    }
    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    adap->dev.release = &i2c_adapter_dev_release;
    adap->dev.class = &i2c_adapter_class;
    res = device_register(&adap->dev);  dev, "adapter [%s] registered\n", adap->name);
    /* create pre-declared device nodes for new-style drivers */
    if (adap->nr nr);
    goto out_unlock;
}
/**
* i2c_register_board_info - statically declare I2C devices
* @busnum: identifies the bus to which these devices belong
* @info: vector of i2c device descriptors
* @len: how many descriptors in the vector; may be zero to reserve
*    the specified bus number.
*
* Systems using the Linux I2C driver stack can declare tables of board info
* while they initialize.  This should be done in board-specific init code
* near arch_initcall() time, or equivalent, before any I2C adapter driver is
* registered.  For example, mainboard init code could define several devices,
* as could the init code for each daughtercard in a board stack.
*
* The I2C devices will be created later, after the adapter for the relevant
* bus has been registered.  After that moment, standard driver model tools
* are used to bind "new style" I2C drivers to the devices.  The bus number
* for any device declared using this routine is not available for dynamic
* allocation.
*
* The board info passed can safely 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(int busnum,
    struct i2c_board_info const *info, unsigned len)
{
    int status;
    mutex_lock(&__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++) {
        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;
        devinfo->board_info = *info;
        list_add_tail(&devinfo->list, &__i2c_board_list);
    }
    mutex_unlock(&__i2c_board_lock);
    return status;
}
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo    *devinfo;
    mutex_lock(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,     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->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));  adapter;
    int res;
    /* Check for address business */
    res = i2c_check_addr(adapter, client->addr);
    if (res)
        return res;
    client->dev.parent = &client->adapter->dev;
    client->dev.bus = &i2c_bus_type;  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;
    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),   addr);
    res = device_register(&client->dev); 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, dev_name(&client->dev));
    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;
}
[1] res = device_register(&client->dev);
        -- > device_add()
            -- > bus_attach_device(dev)
                -- > device_attach(dev)
                    -- > bus_for_each_drv(dev->bus, NULL, dev, __device_attach)
    __device_attach()
        -- > driver_probe_device(drv, dev)
/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* First, we call the bus's match function, if one present, which should
* compare the device IDs the driver supports with the device IDs of the
* device. Note we don't do this ourselves because we don't know the
* format of the ID structures, nor what is to be considered a match and
* what is not.
*
* This function returns 1 if a match is found, -ENODEV if the device is
* not registered, and 0 otherwise.
*
* This function must be called with @dev->sem held.  When called for a
* USB interface, @dev->parent->sem must be held as well.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;
    if (!device_is_registered(dev))
        return -ENODEV;
    if (drv->bus->match && !drv->bus->match(dev, drv))  bus->name, __func__, dev_name(dev), drv->name);
    ret = really_probe(dev, drv); bus->probe) {
        ret = dev->bus->probe(dev);    probe) {
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }
    driver_bound(dev);
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
         drv->bus->name, __func__, dev_name(dev), drv->name);
     ...
}
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;  name[0]) {
        if (strcmp(client->name, id->name) == 0)
            return id;
        id++;
    }
    return NULL;
}
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;
    status = driver->probe(client, i2c_match_id(driver->id_table, client)); driver = NULL;
    return status;
}
How to register i2c device?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i2c device can be registered statically and dynamically. The static way has been introduced above, the i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len) function is called to register the static info of i2c device to list __i2c_board_list, the corresponding i2c driver is registered, then in the registration to i2c adapter, the i2c client created by scan the device in list __i2c_board_list, then attach its corresponding i2c driver.
dynamic registration of i2c device is by means of i2c_new_device(adapter, &info), but first of all , you must create a struct i2c_board_info variable and fill it with the necessary info of i2c device, such as the slave address, name of i2c device, which is sure to match one of id_table->name in i2c driver.
following is a good example. kernel/sound/soc/codecs/wm8731.c
static const struct i2c_device_id wm8731_i2c_id[] = {
    { "wm8731", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
static struct i2c_driver wm8731_i2c_driver = {
    .driver = {
        .name = "WM8731 I2C Codec",
        .owner = THIS_MODULE,
    },
    .probe =    wm8731_i2c_probe,
    .remove =   wm8731_i2c_remove,
    .id_table = wm8731_i2c_id,
};
static int wm8731_add_i2c_device(struct platform_device *pdev,
                 const struct wm8731_setup_data *setup)
{
    struct i2c_board_info info;
    struct i2c_adapter *adapter;
    struct i2c_client *client;
    int ret;
    ret = i2c_add_driver(&wm8731_i2c_driver);  dev, "can't add i2c driver\n");
        return ret;
    }
    memset(&info, 0, sizeof(struct i2c_board_info));
    info.addr = setup->i2c_address;
    strlcpy(info.type, "wm8731", I2C_NAME_SIZE);  i2c_bus);
    if (!adapter) {
        dev_err(&pdev->dev, "can't get i2c adapter %d\n",
            setup->i2c_bus);
        goto err_driver;
    }
    client = i2c_new_device(adapter, &info);  dev, "can't add i2c device at 0x%x\n",
            (unsigned int)info.addr);
        goto err_driver;
    }
    return 0;
err_driver:
    i2c_del_driver(&wm8731_i2c_driver);
    return -ENODEV;
}
Order of registrations to i2c driver, i2c device, i2c adapter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that, in the current i2c subsystem, it only support to use i2c device to detect its i2c driver, the revert operation is not avaliable, so it's important to take care of the order to register the three critical components of i2c subsystem. so, generally, i2c driver will be registered first, registration of i2c device comes next, if the i2c device is configured statically and registered with i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len) function, while i2c_add_adapter() or i2c_add_numbered_adapter() is called, the representation of i2c device -- the client is created, and try to detect i2c driver for itself, in the other way, the client is created dynamically by means of invoking i2c_new_device() function, and the same detection behavior is carried out.
In summary, the order of registration is supposed to be:
i2c driver  -->  i2c adapter --> i2c device.
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/43047/showart_2030163.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP