Linux Kernel 设备驱动之I2C之host描述

来源:互联网 发布:用51单片机产生正弦波 编辑:程序博客网 时间:2024/04/29 11:19
 
 

对于I2C传输来说,其由三部分组成,一个是I2C控制端,二是控制端对外提供的总线,三是总线上的设备。

所以,存在三个方面的抽象,控制端一般叫host或者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 class;    /* classes to allow probing for */ const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data;这两个是I2C传输数据的关键。

 /* data fields that are valid for all devices */ const struct i2c_lock_operations *lock_ops; struct rt_mutex bus_lock; struct rt_mutex mux_lock;

 int timeout;   /* in jiffies */ int retries; struct device dev;  /* the adapter device */

 int nr; char name[48]; struct completion dev_released;

 struct mutex userspace_clients_lock; struct list_head userspace_clients;

 struct i2c_bus_recovery_info *bus_recovery_info; const struct i2c_adapter_quirks *quirks;};

对于adapter来说,要么静态定义,要么动态分配,在简单初始化后,调用函数

i2c_add_adapter()或者函数i2c_add_numbered_adapter()把adapter添加到

i2c驱动的框架层。

这两个函数都是调用i2c_register_adapter()完成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;

 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;

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

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

//PM支持回调

 pm_runtime_no_callbacks(&adap->dev); pm_suspend_ignore_children(&adap->dev, true); pm_runtime_enable(&adap->dev);

#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

 i2c_init_recovery(adap);

 /* create pre-declared device nodes */ of_i2c_register_devices(adap); i2c_acpi_register_devices(adap); i2c_acpi_install_space_handler(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);这一步是对总线上设备探测,这里的回调函数是__process_new_adapter

 return 0;

out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); return res;}

在添加总线时,我们看看是否有设备在总线上,如果有则调用设备的驱动,对设备初始化。这里并不一定对设备初始化,

也可以提前做些事情。static int __process_new_adapter(struct device_driver *d, void *data){ return i2c_do_add_adapter(to_i2c_driver(d), data);}

static int i2c_do_add_adapter(struct i2c_driver *driver,设备驱动         struct i2c_adapter *adap)host对象{ /* 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) {  dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",    driver->driver.name);  dev_warn(&adap->dev,    "Please use another way to instantiate your i2c_client\n");  /* We ignore the return code; if it fails, too bad */  driver->attach_adapter(adap); } return 0;}

 

 

 

 
0 0
原创粉丝点击