3、i2c 核心

1、增加/删除i2c_adapter

int i2c_add_adapter(struct i2c_adapter *adapter)

{

struct device *dev = &adapter->dev;

int id;

if (dev->of_node) {

id = of_alias_get_id(dev->of_node, "i2c");

if (id >= 0) {

adapter->nr = id;

return __i2c_add_numbered_adapter(adapter);

}

}

mutex_lock(&core_lock);

id = idr_alloc(&i2c_adapter_idr, adapter,

       __i2c_first_dynamic_bus_num, 0, GFP_KERNEL);

mutex_unlock(&core_lock);

if (WARN(id < 0, "couldn't get idr"))

return id;

adapter->nr = id;

return i2c_register_adapter(adapter);

}

void i2c_del_adapter(struct i2c_adapter *adap)

{

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("attempting to delete unregistered adapter [%s]\n", adap->name);

return;

}

i2c_acpi_remove_space_handler(adap);

/* Tell drivers about this removal */

mutex_lock(&core_lock);

bus_for_each_drv(&i2c_bus_type, NULL, adap,

       __process_removed_adapter);

mutex_unlock(&core_lock);

/* Remove devices instantiated from sysfs */

mutex_lock_nested(&adap->userspace_clients_lock,

  i2c_adapter_depth(adap));

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

 * check the returned value. This is a two-pass process, because

 * we can't remove the dummy devices during the first pass: they

 * could have been instantiated by real devices wishing to clean

 * them up properly, so we give them a chance to do that first. */

device_for_each_child(&adap->dev, NULL, __unregister_client);

device_for_each_child(&adap->dev, NULL, __unregister_dummy);

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

pm_runtime_disable(&adap->dev);

i2c_host_notify_irq_teardown(adap);

/* wait until all references to the device are gone

 *

 * FIXME: This is old code and should ideally be replaced by an

 * alternative which results in decoupling the lifetime of the struct

 * device from the i2c_adapter, like spi or netdev do. Any solution

 * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled!

 */

init_completion(&adap->dev_released);

device_unregister(&adap->dev);

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

}

2、增加/删除i2c_driver

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

{

int res;

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

if (WARN_ON(!is_registered))

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;

INIT_LIST_HEAD(&driver->clients);

/* 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("driver [%s] registered\n", driver->driver.name);

/* Walk the adapters that are already present */

i2c_for_each_dev(driver, __process_new_driver);

return 0;

}

void i2c_del_driver(struct i2c_driver *driver)

{

i2c_for_each_dev(driver, __process_removed_driver);

driver_unregister(&driver->driver);

pr_debug("driver [%s] unregistered\n", driver->driver.name);

}

3、I2C传输、 发送和接收

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

{

int ret;

if (!adap->algo->master_xfer) {

dev_dbg(&adap->dev, "I2C level transfers not supported\n");

return -EOPNOTSUPP;

}

/* 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).

 */

ret = __i2c_lock_bus_helper(adap);

if (ret)

return ret;

ret = __i2c_transfer(adap, msgs, num);

i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);

return ret;

}

int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

{

unsigned long orig_jiffies;

int ret, try;

if (WARN_ON(!msgs || num < 1))

return -EINVAL;

ret = __i2c_check_suspended(adap);

if (ret)

return ret;

if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))

return -EOPNOTSUPP;

/*

 * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets

 * enabled.  This is an efficient way of keeping the for-loop from

 * being executed when not needed.

 */

if (static_branch_unlikely(&i2c_trace_msg_key)) {

int i;

for (i = 0; i < num; i++)

if (msgs[i].flags & I2C_M_RD)

trace_i2c_read(adap, &msgs[i], i);

else

trace_i2c_write(adap, &msgs[i], i);

}

/* Retry automatically on arbitration loss */

orig_jiffies = jiffies;

for (ret = 0, try = 0; try <= adap->retries; try++) {

if (i2c_in_atomic_xfer_mode() && adap->algo->master_xfer_atomic)

ret = adap->algo->master_xfer_atomic(adap, msgs, num);

else

ret = adap->algo->master_xfer(adap, msgs, num);

if (ret != -EAGAIN)

break;

if (time_after(jiffies, orig_jiffies + adap->timeout))

break;

}

if (static_branch_unlikely(&i2c_trace_msg_key)) {

int i;

for (i = 0; i < ret; i++)

if (msgs[i].flags & I2C_M_RD)

trace_i2c_reply(adap, &msgs[i], i);

trace_i2c_result(adap, num, ret);

}

return ret;

}

static inline int i2c_master_send(const struct i2c_client *client,

  const char *buf, int count)

{

return i2c_transfer_buffer_flags(client, (char *)buf, count, 0);

};

int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,

      int count, u16 flags)

{

int ret;

struct i2c_msg msg = {

.addr = client->addr,

.flags = flags | (client->flags & I2C_M_TEN),

.len = count,

.buf = buf,

};

ret = i2c_transfer(client->adapter, &msg, 1);

/*

 * If everything went ok (i.e. 1 msg transferred), return #bytes

 * transferred, else error code.

 */

return (ret == 1) ? count : ret;

}

static inline int i2c_master_recv(const struct i2c_client *client,

  char *buf, int count)

{

return i2c_transfer_buffer_flags(client, buf, count, I2C_M_RD);

};

int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,

      int count, u16 flags)

{

int ret;

struct i2c_msg msg = {

.addr = client->addr,

.flags = flags | (client->flags & I2C_M_TEN),

.len = count,

.buf = buf,

};

ret = i2c_transfer(client->adapter, &msg, 1);

/*

 * If everything went ok (i.e. 1 msg transferred), return #bytes

 * transferred, else error code.

 */

return (ret == 1) ? count : ret;

}

4、注册i2c adapter

static int i2c_register_adapter(struct i2c_adapter *adap)

{

int res = -EINVAL;

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

if (WARN_ON(!is_registered)) {

res = -EAGAIN;

goto out_list;

}

/* Sanity checks */

if (WARN(!adap->name[0], "i2c adapter has no name"))

goto out_list;

if (!adap->algo) {

pr_err("adapter '%s': no algo supplied!\n", adap->name);

goto out_list;

}

if (!adap->lock_ops)

adap->lock_ops = &i2c_adapter_lock_ops;

adap->locked_flags = 0;

rt_mutex_init(&adap->bus_lock);

rt_mutex_init(&adap->mux_lock);

mutex_init(&adap->userspace_clients_lock);

INIT_LIST_HEAD(&adap->userspace_clients);

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

if (adap->timeout == 0)

adap->timeout = HZ;

/* register soft irqs for Host Notify */

res = i2c_setup_host_notify_irq_domain(adap);

if (res) {

pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n",

       adap->name, res);

goto out_list;

}

dev_set_name(&adap->dev, "i2c-%d", adap->nr);

adap->dev.bus = &i2c_bus_type;

adap->dev.type = &i2c_adapter_type;

res = device_register(&adap->dev);

if (res) {

pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);

goto out_list;

}

res = of_i2c_setup_smbus_alert(adap);

if (res)

goto out_reg;

pm_runtime_no_callbacks(&adap->dev);

pm_suspend_ignore_children(&adap->dev, true);

pm_runtime_enable(&adap->dev);

res = i2c_init_recovery(adap);

if (res == -EPROBE_DEFER)

goto out_reg;

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

#ifdef CONFIG_I2C_COMPAT

res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,

       adap->dev.parent);

if (res)

dev_warn(&adap->dev,

 "Failed to create compatibility class link\n");

#endif

/* create pre-declared device nodes */

of_i2c_register_devices(adap);

i2c_acpi_install_space_handler(adap);

i2c_acpi_register_devices(adap);

if (adap->nr < __i2c_first_dynamic_bus_num)

i2c_scan_static_board_info(adap);

/* Notify drivers */

mutex_lock(&core_lock);

bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

mutex_unlock(&core_lock);

return 0;

out_reg:

init_completion(&adap->dev_released);

device_unregister(&adap->dev);

wait_for_completion(&adap->dev_released);

out_list:

mutex_lock(&core_lock);

idr_remove(&i2c_adapter_idr, adap->nr);

mutex_unlock(&core_lock);

return res;

}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值