i2c-core.c

/drivers/i2c/i2c-core.c
I2C核心提供了一组不依赖于硬件平台的接口函数,这个文件一般不需要工程师修改。
I2C总线驱动和设备驱动之间,依赖I2C核心作为纽带。
I2C核心主要函数如下:
1. 增加删除i2c_adapter:
    /**
     * i2c_add_adapter - declare i2c adapter, use dynamic bus number
     * @adapter: the adapter to add
     * Context: can sleep
     *
     * This routine is used to declare an I2C adapter when its bus number
     * doesn't matter. Examples: for I2C adapters dynamically added by
     * USB links or PCI plugin cards.
     *
     * When this returns zero, a new bus number was allocated and stored
     * in adap->nr, and the specified adapter became available for clients.
     * Otherwise, a negative errno value is returned.
     */
    int i2c_add_adapter(struct i2c_adapter *adapter)
    {
        int    id, res = 0;
    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 */
        res = idr_get_new_above(&i2c_adapter_idr, adapter,
                    __i2c_first_dynamic_bus_num, &id);
        mutex_unlock(&core_lock);
        if (res < 0) {
            if (res == -EAGAIN)
                goto retry;
            return res;
        }
        adapter->nr = id;
        return i2c_register_adapter(adapter);
    }
    EXPORT_SYMBOL(i2c_add_adapter);

    /**
     * i2c_del_adapter - unregister I2C adapter
     * @adap: the adapter being unregistered
     * Context: can sleep
     *
     * This unregisters an I2C adapter which was previously registered
     * by @i2c_add_adapter or @i2c_add_numbered_adapter.
     */
    int i2c_del_adapter(struct i2c_adapter *adap)
    {
        int res = 0;
        struct i2c_adapter *found;
        struct i2c_client *client, *next;
        /* First make sure that this adapter was ever added */
        mutex_lock(&core_lock);
        found = idr_find(&i2c_adapter_idr, adap->nr);
        mutex_unlock(&core_lock);
        if (found != adap) {
            pr_debug("i2c-core: attempting to delete unregistered "
                 "adapter [%s]\n", adap->name);
            return -EINVAL;
        }
        /* Tell drivers about this removal */
        mutex_lock(&core_lock);
        res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 __process_removed_adapter);
        mutex_unlock(&core_lock);
        if (res)
            return res;
        /* Remove devices instantiated from sysfs */
        mutex_lock(&adap->userspace_clients_lock);
        list_for_each_entry_safe(client, next, &adap->userspace_clients,
                     detected) {
            dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
                client->addr);
            list_del(&client->detected);
            i2c_unregister_device(client);
        }
        mutex_unlock(&adap->userspace_clients_lock);
        /* Detach any active clients. This can't fail, thus we do not
         checking the returned value. */
        res = device_for_each_child(&adap->dev, NULL, __unregister_client);
    #ifdef CONFIG_I2C_COMPAT
        class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
                     adap->dev.parent);
    #endif
        /* device name is gone after device_unregister */
        dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
        /* clean up the sysfs representation */
        init_completion(&adap->dev_released);
        device_unregister(&adap->dev);
        /* wait for sysfs to drop all references */
        wait_for_completion(&adap->dev_released);
        /* free bus id */
        mutex_lock(&core_lock);
        idr_remove(&i2c_adapter_idr, adap->nr);
        mutex_unlock(&core_lock);
        /* Clear the device structure in case this adapter is ever going to be
         added again */
        memset(&adap->dev, 0, sizeof(adap->dev));
        return 0;
    }
    EXPORT_SYMBOL(i2c_del_adapter);

2.增加/删除i2c_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.
     */
    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);
        if (res)
            return res;
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
        INIT_LIST_HEAD(&driver->clients);
        /* Walk the adapters that are already present */
        mutex_lock(&core_lock);
        bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
        mutex_unlock(&core_lock);
        return 0;
    }
    EXPORT_SYMBOL(i2c_register_driver);

    /**
     * i2c_del_driver - unregister I2C driver
     * @driver: the driver being unregistered
     * Context: can sleep
     */
    void i2c_del_driver(struct i2c_driver *driver)
    {
        mutex_lock(&core_lock);
        bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver);
        mutex_unlock(&core_lock);
        driver_unregister(&driver->driver);
        pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
    }
    EXPORT_SYMBOL(i2c_del_driver);

3.i2c_client 的依附与脱离

    /**
     * i2c_use_client - increments the reference count of the i2c client structure
     * @client: the client being referenced
     *
     * Each live reference to a client should be refcounted. The driver model does
     * that automatically as part of driver binding, so that most drivers don't
     * need to do this explicitly: they hold a reference until they're unbound
     * from the device.
     *
     * A pointer to the client with the incremented reference counter is returned.
     */
    struct i2c_client *i2c_use_client(struct i2c_client *client)
    {
        if (client && get_device(&client->dev))
            return client;
        return NULL;
    }
    EXPORT_SYMBOL(i2c_use_client);
    /**
     * i2c_release_client - release a use of the i2c client structure
     * @client: the client being no longer referenced
     *
     * Must be called when a user of a client is finished with it.
     */
    void i2c_release_client(struct i2c_client *client)
    {
        if (client)
            put_device(&client->dev);
    }
    EXPORT_SYMBOL(i2c_release_client);

4.I2C传输、发送、接收:

i2c_transfer()用于进行I2C适配器和I2C设备之间一组消息交互。

i2c_transfer()函数本身不具备驱动适配器物理硬件完成消息交互。它只是寻找i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm 中的 master_xfer()函数真正驱动硬件流程。

    /* ----------------------------------------------------
     * the functional interface to the i2c busses.
     * ----------------------------------------------------
     */
    /**
     * 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.
     */
    int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
    {
        unsigned long orig_jiffies;
        int ret, try;
        /* 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 = i2c_trylock_adapter(adap);
                if (!ret)
                    /* I2C activity is ongoing. */
                    return -EAGAIN;
            } else {
                i2c_lock_adapter(adap);
            }
            /* Retry automatically on arbitration loss */
            orig_jiffies = jiffies;
            for (ret = 0, try = 0; try <= adap->retries; try++) {
                ret = adap->algo->master_xfer(adap, msgs, num);
                if (ret != -EAGAIN)
                    break;
                if (time_after(jiffies, orig_jiffies + adap->timeout))
                    break;
            }
            i2c_unlock_adapter(adap);
            return ret;
        } else {
            dev_dbg(&adap->dev, "I2C level transfers not supported\n");
            return -EOPNOTSUPP;
        }
    }
    EXPORT_SYMBOL(i2c_transfer);

i2c_master_send() 和 i2c_master_recv()函数内部会调用i2c_transfer()完成一条写消息和一条读消息。

    /**
     * i2c_master_send - issue a single I2C message in master transmit mode
     * @client: Handle to slave device
     * @buf: Data that will be written to the slave
     * @count: How many bytes to write, must be less than 64k since msg.len is u16
     *
     * Returns negative errno, or else the number of bytes written.
     */
    int i2c_master_send(struct i2c_client *client, const char *buf, int count)
    {
        int ret;
        struct i2c_adapter *adap = client->adapter;
        struct i2c_msg msg;
        msg.addr = client->addr;
        msg.flags = client->flags & I2C_M_TEN;
        msg.len = count;
        msg.buf = (char *)buf;
        ret = i2c_transfer(adap, &msg, 1);
        /* If everything went ok (i.e. 1 msg transmitted), return #bytes
         transmitted, else error code. */
        return (ret == 1) ? count : ret;
    }
    EXPORT_SYMBOL(i2c_master_send);
    /**
     * i2c_master_recv - issue a single I2C message in master receive mode
     * @client: Handle to slave device
     * @buf: Where to store data read from slave
     * @count: How many bytes to read, must be less than 64k since msg.len is u16
     *
     * Returns negative errno, or else the number of bytes read.
     */
    int i2c_master_recv(struct i2c_client *client, char *buf, int count)
    {
        struct i2c_adapter *adap = client->adapter;
        struct i2c_msg msg;
        int ret;
        msg.addr = client->addr;
        msg.flags = client->flags & I2C_M_TEN;
        msg.flags |= I2C_M_RD;
        msg.len = count;
        msg.buf = buf;
        ret = i2c_transfer(adap, &msg, 1);
        /* If everything went ok (i.e. 1 msg transmitted), return #bytes
         transmitted, else error code. */
        return (ret == 1) ? count : ret;
    }
    EXPORT_SYMBOL(i2c_master_recv);

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值