Chinaunix首页 | 论坛 | 博客
  • 博客访问: 642823
  • 博文数量: 75
  • 博客积分: 7001
  • 博客等级: 少将
  • 技术积分: 1465
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-11 17:39
文章分类

全部博文(75)

文章存档

2010年(1)

2009年(25)

2008年(49)

我的朋友

分类: LINUX

2009-08-17 20:54:52


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

static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
    .flags        = 0,
    .slave_addr    = 0x10,
    .bus_freq    = 100*1000,
    .max_freq    = 400*1000,
    .sda_delay    = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
};

void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
{
    struct s3c2410_platform_i2c *npd;

    if (!pd)
        pd = &default_i2c_data0;

    npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
    if (!npd)
        printk(KERN_ERR "%s: no memory for platform data\n", __func__);
    else if (!npd->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));   <--------------------
    smdk_machine_init();
}

During the registration of the i2c-s3c2410 with the platform bus, when the infastructure of platform bus finds that  field  s3c2410_i2c_driver->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); <-------------------- create an instance of struct s3c24xx_i2c, in which strcut i2c_adapter is built.
    if (!i2c) {
        dev_err(&pdev->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;  <-------------------- fill algorithm field of struct i2c_adapter with specific struct i2c_argorithm instance, which implement the transaction of s3c2410 i2c bus.

    i2c->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);      <-------------------- obtain io mem space defined in struct resource s3c_i2c_resource
    if (res == NULL) {
        dev_err(&pdev->dev, "cannot find IO resource\n");
        ret = -ENOENT;
        goto err_clk;
    }

    i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, <-------------------- request a region of memory space.
                     pdev->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); <-------------------- map the region in to kernel space.

    if (i2c->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 <= 0) {
        dev_err(&pdev->dev, "cannot find IRQ\n");
        goto err_iomap;
    }

    ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  <-------------------- register i2c bus interrupt.
              dev_name(&pdev->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 < 0) {
        dev_err(&pdev->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;  <-------------------- assign s3c2410 i2c bus number as defined in struct s3c2410_platform_i2c default_i2c_data0, herein is 0.

    ret = i2c_add_numbered_adapter(&i2c->adap); <-------------------- register s3c2410 i2c bus with assigned bus number, let's see the details of i2c_add_numbered_adapter().
    if (ret < 0) {
        dev_err(&pdev->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);  <-------------------- allocate a new i2c adapter bus number saved in argument __id__.
    if (status == 0 && id != adap->nr) {            <-------------------- if the __id__ doesn't match with assigned i2c bus number, return error.
        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);    <-------------------- register i2c bus with i2c subsystem in linux kernel.
    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);
    }


    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);  <---------------create i2c-0, i2c-1, ...,files under directory /sys/class/i2c-adapter/, which denotes the i2c addapters registed on the system.
    if (res)
        goto out_list;

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

    /* create pre-declared device nodes for new-style drivers */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);     <-------------------- if the i2c deivces have already been statically registered to system with API i2c_register_board_info(int busnum,
                                        struct i2c_board_info const *info, unsigned len), the program with step into this function, we will analyze this function                                                              in the following portion.

    /* Notify drivers */
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 i2c_do_add_adapter);   <-------------------- detect the i2c device drivers are implemented in obsolete mode with method attach_adapter() with each of the i2c devices                                             which have already been registered into i2c bus.

out_unlock:
    mutex_unlock(&core_lock);
    return res;

out_list:
    idr_remove(&i2c_adapter_idr, adap->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,     <--------------------create a client instance and bound it to the corresponding i2c driver of new style with API i2c_attach_client().
                        &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->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));  <-------------------- fill the i2c device name field with that of i2c device registered statically by i2c_register_board_info()

    /* 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); <-------------------- register the client --i2c device into i2c bus and try to attach it to the corresponding i2c driver, if success, return 0.
    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;
    client->dev.bus = &i2c_bus_type;  <-------------------- the client is on the i2c bus.

    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;

    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),   <-------------------- set the name of the i2c device, which consits of i2c bus number and the slave address of the i2c device.
             client->addr);
    res = device_register(&client->dev); <-------------------- the call graph of this function is depicted below.[1]
    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, 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))  <-------------------- herein, i2c_device_match(struct device *dev, struct device_driver *drv) will be called, which is one staff function of
                                        struct bus_type i2c_bus_type.
        goto done;

    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
         drv->bus->name, __func__, dev_name(dev), drv->name);

    ret = really_probe(dev, drv); <--------------------

done:
    return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    .....

    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);    <-------------------- herein, static int i2c_device_probe(struct device *dev) will be called, which is one staff function of
                                        struct bus_type i2c_bus_type
        if (ret)
            goto probe_failed;
    } else if (drv->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;  <-------------------- does the i2c device match i2c driver, depending on the name filed of i2c device __client__ and that of                                                     id_table of i2c driver.
    ...

    return 0;
}


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)
            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)); <-------------------- the prob method of new style i2c driver is invoked here.
    if (status)
        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);  <--------------------
    if (ret != 0) {
        dev_err(&pdev->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);  <--------------------

    adapter = i2c_get_adapter(setup->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);  <--------------------
    i2c_put_adapter(adapter);
    if (!client) {
        dev_err(&pdev->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.






阅读(3940) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-11-24 20:08:08

荣哥,猜猜我是谁?