qcom 8916平台的i2c init部分

来源:互联网 发布:mac系统连接电视hdmi 编辑:程序博客网 时间:2024/06/07 10:37
DT_MACHINE_START(MSM8226_DT,"Qualcomm Technologies, Inc. MSM 8226 (Flattened Device Tree)").map_io= msm_map_msm8226_io,.init_machine= msm8226_init,.dt_compat= msm8226_dt_match,.reserve= msm8226_reserve,.smp= &arm_smp_ops,void __init msm8226_init(void){struct of_dev_auxdata *adata = msm8226_auxdata_lookup;/* * populate devices from DT first so smem probe will get called as part * of msm_smem_init.  socinfo_init needs smem support so call * msm_smem_init before it.  msm8226_init_gpiomux needs socinfo so * call socinfo_init before it. */board_dt_populate(adata);msm_smem_init();if (socinfo_init() < 0)pr_err("%s: socinfo_init() failed\n", __func__);msm8226_init_gpiomux();msm8226_add_drivers();}void __init msm8226_add_drivers(void){msm_smd_init();msm_rpm_driver_init();msm_spm_device_init();msm_pm_sleep_status_init();rpm_smd_regulator_driver_init();qpnp_regulator_init();spm_regulator_init();msm_gcc_8226_init();msm_bus_fabric_init_driver();qup_i2c_init_driver();ncp6335d_regulator_init();fan53555_regulator_init();cpr_regulator_init();}int __init qup_i2c_init_driver(void){static bool initialized;if (initialized)return 0;elseinitialized = true;return platform_driver_register(&qup_i2c_driver);}static struct platform_driver qup_i2c_driver = {.probe= qup_i2c_probe,.remove= qup_i2c_remove,.driver= {.name= "qup_i2c",.owner= THIS_MODULE,.pm = &i2c_qup_dev_pm_ops,.of_match_table = i2c_qup_dt_match,},};static int qup_i2c_probe(struct platform_device *pdev){struct qup_i2c_dev*dev;struct resource         *qup_mem, *gsbi_mem, *qup_io, *gsbi_io, *res;struct resource*in_irq, *out_irq, *err_irq;struct clk         *clk, *pclk;int  ret = 0;int  i;int  dt_gpios[I2C_GPIOS_DT_CNT];bool use_device_tree = pdev->dev.of_node;struct msm_i2c_platform_data *pdata;gsbi_mem = NULL;dev_dbg(&pdev->dev, "qup_i2c_probe\n");if (use_device_tree) {pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);if (!pdata)return -ENOMEM;ret = msm_i2c_rsrcs_dt_to_pdata_map(pdev, pdata, dt_gpios);if (ret)goto get_res_failed;} elsepdata = pdev->dev.platform_data;if (!pdata) {dev_err(&pdev->dev, "platform data not initialized\n");return -ENOSYS;}qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,"qup_phys_addr");if (!qup_mem) {dev_err(&pdev->dev,"platform_get_resource_byname(qup_phys_addr) failed\n");ret = -ENODEV;goto get_res_failed;}/* * We only have 1 interrupt for new hardware targets and in_irq, * out_irq will be NULL for those platforms */in_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,"qup_in_intr");out_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,"qup_out_intr");err_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,"qup_err_intr");if (!err_irq) {dev_err(&pdev->dev, "no error irq resource?\n");ret = -ENODEV;goto get_res_failed;}/*请求资源,告诉其他驱动,该资源已经被占用*/  /*请求该内存资源*/qup_io = request_mem_region(qup_mem->start, resource_size(qup_mem),pdev->name);if (!qup_io) {dev_err(&pdev->dev, "QUP region already claimed\n");ret = -EBUSY;goto get_res_failed;}if (!pdata->use_gsbi_shared_mode) { /*如果该标志没有设置,则取出相应的资源*/gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,"gsbi_qup_i2c_addr");if (!gsbi_mem) {dev_dbg(&pdev->dev, "Assume BLSP\n");/* * BLSP core does not need protocol programming so this * resource is not expected */goto blsp_core_init;}gsbi_io = request_mem_region(gsbi_mem->start,resource_size(gsbi_mem),pdev->name);if (!gsbi_io) {dev_err(&pdev->dev, "GSBI region already claimed\n");ret = -EBUSY;goto err_res_failed;}}blsp_core_init: /*如果该clk不为空,通过名字取出该clk*/clk = clk_get(&pdev->dev, "core_clk");if (IS_ERR(clk)) {dev_err(&pdev->dev, "Could not get core_clk\n");ret = PTR_ERR(clk);goto err_clk_get_failed;} /*如果该pclk不为空,通过名字取出该clk*/pclk = clk_get(&pdev->dev, "iface_clk");if (IS_ERR(pclk)) {dev_err(&pdev->dev, "Could not get iface_clk\n");ret = PTR_ERR(pclk);clk_put(clk);goto err_clk_get_failed;}/* We support frequencies upto FAST Mode(400KHz) */if (pdata->clk_freq <= 0 ||pdata->clk_freq > 400000) {dev_err(&pdev->dev, "clock frequency not supported\n");ret = -EIO;goto err_config_failed;} /*分配qup_i2c_dev结构体*/dev = kzalloc(sizeof(struct qup_i2c_dev), GFP_KERNEL);if (!dev) {ret = -ENOMEM;goto err_alloc_dev_failed;}dev->dev = &pdev->dev;if (in_irq)dev->in_irq = in_irq->start;if (out_irq)dev->out_irq = out_irq->start;dev->err_irq = err_irq->start;if (in_irq && out_irq)dev->num_irqs = 3;elsedev->num_irqs = 1;dev->clk = clk;dev->pclk = pclk; /*映射请求到的内存*/dev->base = ioremap(qup_mem->start, resource_size(qup_mem));if (!dev->base) {ret = -ENOMEM;goto err_ioremap_failed;}/* Configure GSBI block to use I2C functionality */if (gsbi_mem) {dev->gsbi = ioremap(gsbi_mem->start, resource_size(gsbi_mem));if (!dev->gsbi) {ret = -ENOMEM;goto err_gsbi_failed;}}for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {if (use_device_tree && i < I2C_GPIOS_DT_CNT) {dev->i2c_gpios[i] = dt_gpios[i];} else {res = platform_get_resource_byname(pdev, IORESOURCE_IO,   i2c_rsrcs[i]);dev->i2c_gpios[i] = res ? res->start : -1;}} /*初始化完dev后,把dev设置为pdev的dev的私有数据*/platform_set_drvdata(pdev, dev);dev->one_bit_t = (USEC_PER_SEC/pdata->clk_freq) + 1;dev->pdata = pdata;dev->clk_ctl = 0;dev->pos = 0;ret = i2c_qup_clk_path_init(pdev, dev);if (ret) {dev_err(&pdev->dev,"Failed to init clock path-voting data structs. err:%d", ret);/* disable i2c_qup_clk_path_xxx() functionality */dev->pdata->master_id = 0;}if (dev->pdata->src_clk_rate <= 0) {dev_info(&pdev->dev,"No src_clk_rate specified in platfrom data\n");dev_info(&pdev->dev, "Using default clock rate %dHz\n",DEFAULT_CLK_RATE);dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;}ret = clk_set_rate(dev->clk, dev->pdata->src_clk_rate);if (ret)dev_info(&pdev->dev, "clk_set_rate(core_clk, %dHz):%d\n",dev->pdata->src_clk_rate, ret);i2c_qup_clk_prepare_enable(dev, dev->clk);i2c_qup_clk_prepare_enable(dev, dev->pclk);/* * If bootloaders leave a pending interrupt on certain GSBI's, * then we reset the core before registering for interrupts. */writel_relaxed(1, dev->base + QUP_SW_RESET);if (qup_i2c_poll_state(dev, 0, true) != 0)goto err_reset_failed;clk_disable_unprepare(dev->clk);clk_disable_unprepare(dev->pclk);/* * We use num_irqs to also indicate if we got 3 interrupts or just 1. * If we have just 1, we use err_irq as the general purpose irq * and handle the changes in ISR accordingly * Per Hardware guidelines, if we have 3 interrupts, they are always * edge triggering, and if we have 1, it's always level-triggering */if (dev->num_irqs == 3) {ret = request_irq(dev->in_irq, qup_i2c_interrupt,IRQF_TRIGGER_RISING, "qup_in_intr", dev);if (ret) {dev_err(&pdev->dev, "request_in_irq failed\n");goto err_request_irq_failed;}/* * We assume out_irq exists if in_irq does since platform * configuration either has 3 interrupts assigned to QUP or 1 */ret = request_irq(dev->out_irq, qup_i2c_interrupt,IRQF_TRIGGER_RISING, "qup_out_intr", dev);if (ret) {dev_err(&pdev->dev, "request_out_irq failed\n");free_irq(dev->in_irq, dev);goto err_request_irq_failed;}ret = request_irq(dev->err_irq, qup_i2c_interrupt,IRQF_TRIGGER_RISING, "qup_err_intr", dev);if (ret) {dev_err(&pdev->dev, "request_err_irq failed\n");free_irq(dev->out_irq, dev);free_irq(dev->in_irq, dev);goto err_request_irq_failed;}} else {ret = request_irq(dev->err_irq, qup_i2c_interrupt,IRQF_TRIGGER_HIGH, "qup_err_intr", dev);if (ret) {dev_err(&pdev->dev, "request_err_irq failed\n");goto err_request_irq_failed;}}disable_irq(dev->err_irq);if (dev->num_irqs == 3) {disable_irq(dev->in_irq);disable_irq(dev->out_irq);} /*把该dev挂载到dev->adapter的私有数据结构的driver data上*/i2c_set_adapdata(&dev->adapter, dev) /*设置该adapter的algo算法结构*/其中该结构的初始化实例如下:static const struct i2c_algorithm qup_i2c_algo = { .master_xfer = qup_i2c_xfer,//这是具体的控制器传输方法 .functionality = qup_i2c_func,//返回该I2C总线所支持的功能};dev->adapter.algo = &qup_i2c_algo; /*为该adapter的name赋值*/strlcpy(dev->adapter.name,"QUP I2C adapter",sizeof(dev->adapter.name)); /*为该adapter的编号赋值*/dev->adapter.nr = pdev->id;dev->adapter.dev.parent = &pdev->dev;if (pdata->msm_i2c_config_gpio) /*为该控制器的配置gpio*/pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);mutex_init(&dev->mlock); /*初始化dev的部分变量*/dev->pwr_state = MSM_I2C_PM_SUSPENDED;atomic_set(&dev->xfer_progress, 0);/* If the same AHB clock is used on Modem side * switch it on here itself and don't switch it * on and off during suspend and resume. */if (dev->pdata->keep_ahb_clk_on)i2c_qup_clk_prepare_enable(dev, dev->pclk);pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);pm_runtime_use_autosuspend(&pdev->dev);pm_runtime_enable(&pdev->dev); /*把该adapter加入到系统中*/ret = i2c_add_numbered_adapter(&dev->adapter);if (ret) {dev_err(&pdev->dev, "i2c_add_adapter failed\n");if (dev->num_irqs == 3) {free_irq(dev->out_irq, dev);free_irq(dev->in_irq, dev);}free_irq(dev->err_irq, dev);} else {if (dev->dev->of_node) {dev->adapter.dev.of_node = pdev->dev.of_node;of_i2c_register_devices(&dev->adapter);}return 0;}err_request_irq_failed:if (dev->gsbi)iounmap(dev->gsbi);err_reset_failed:clk_disable_unprepare(dev->clk);clk_disable_unprepare(dev->pclk);i2c_qup_clk_path_teardown(dev);err_gsbi_failed:iounmap(dev->base);err_ioremap_failed:kfree(dev);err_alloc_dev_failed:err_config_failed:clk_put(clk);clk_put(pclk);err_clk_get_failed:if (gsbi_mem)release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));err_res_failed:release_mem_region(qup_mem->start, resource_size(qup_mem));get_res_failed:if (pdev->dev.of_node)devm_kfree(&pdev->dev, pdata);return ret;}初始化dev,并把把该dev挂载到dev->adapter的私有数据结构的driver data上,然后设置adapter,把该adapter加入到系统中。下面这个函数是用静态的bus number来向系统增加一个adapter。在kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号。对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分配一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败。高通的adapter驱动使用了i2c_add_numbered_adapter()注册,总线号最初保存在platform_data中。int i2c_add_numbered_adapter(struct i2c_adapter *adap){if (adap->nr == -1) /* -1 means dynamically assign bus id */return i2c_add_adapter(adap);return __i2c_add_numbered_adapter(adap);}//////////////////////////////////////////////////int i2c_add_adapter(struct i2c_adapter *adapter){struct device *dev = &adapter->dev;int id;if (dev->of_node) {       //获取节点np对应的aliasid号id = of_alias_get_id(dev->of_node, "i2c");//获取节点np对应的aliasid号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 (id < 0)return id;adapter->nr = id;return i2c_register_adapter(adapter);}///////////////////////////////////////////////////////////////static int i2c_register_adapter(struct i2c_adapter *adap){int res = 0;/* Can't register until after driver model init */if (unlikely(WARN_ON(!i2c_bus_type.p))) {res = -EAGAIN;goto out_list;}/* Sanity checks */if (unlikely(adap->name[0] == '\0')) {pr_err("i2c-core: Attempt to register an adapter with "       "no name!\n");return -EINVAL;}if (unlikely(!adap->algo)) {pr_err("i2c-core: Attempt to register adapter '%s' with "       "no algo!\n", adap->name);return -EINVAL;}rt_mutex_init(&adap->bus_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;/*初始化adapter dev成员,然后注册该dev*/dev_set_name(&adap->dev, "i2c-%d", adap->nr);adap->dev.bus = &i2c_bus_type;  //这个i2c_bus_type包含了i2c_device_matchadap->dev.type = &i2c_adapter_type;res = device_register(&adap->dev);if (res)goto out_list;dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);#ifdef CONFIG_I2C_COMPATres = 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/* bus recovery specific initialization */if (adap->bus_recovery_info) {struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;if (!bri->recover_bus) {dev_err(&adap->dev, "No recover_bus() found, not using recovery\n");adap->bus_recovery_info = NULL;goto exit_recovery;}/* Generic GPIO recovery */if (bri->recover_bus == i2c_generic_gpio_recovery) {if (!gpio_is_valid(bri->scl_gpio)) {dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n");adap->bus_recovery_info = NULL;goto exit_recovery;}if (gpio_is_valid(bri->sda_gpio))bri->get_sda = get_sda_gpio_value;elsebri->get_sda = NULL;bri->get_scl = get_scl_gpio_value;bri->set_scl = set_scl_gpio_value;} else if (!bri->set_scl || !bri->get_scl) {/* Generic SCL recovery */dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");adap->bus_recovery_info = NULL;}}exit_recovery:/* create pre-declared device nodes */ /*扫描属于该总线的板级的i2C设备*/if (adap->nr < __i2c_first_dynamic_bus_num)i2c_scan_static_board_info(adap);/* Notify drivers */mutex_lock(&core_lock);       /*探测总线上的所有i2c设备驱动,同时完成client、driver、device、adapter的绑定*/bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);/*下面就是int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,     void *data, int (*fn)(struct device_driver *, void *)){struct klist_iter i;struct device_driver *drv;int error = 0;if (!bus)return -EINVAL;klist_iter_init_node(&bus->p->klist_drivers, &i,     start ? &start->p->knode_bus : NULL);while ((drv = next_driver(&i)) && !error)error = fn(drv, data);//找到对应的driver 然后跑probe函数klist_iter_exit(&i);return error;}*/mutex_unlock(&core_lock);return 0;out_list:mutex_lock(&core_lock);idr_remove(&i2c_adapter_idr, adap->nr);mutex_unlock(&core_lock);return res;}///////////////////////////////////////////////////////////////////////////int __initi2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len){int status;down_write(&__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);}up_write(&__i2c_board_lock);return status;}/////////////////////////////////////////////////////////////////////////////上面的程序位于i2c-boardinfo.c中,i2c_register_board_info()函数的for循环中,首先会申请I2C设备信息结构体,如果申请成功,将I2C总线号和设备信息赋值给设备信息结构体,并且将设备信息结构体的链表插入到__i2c_board_list中,此处尤为重要,此函数就是通过__i2c_board_list链表找到上面注册的设备信息,结合gsc3280_i2c_devices_init()函数和i2c_devices_info结构体,此处for循环的len为3,即正常情况下需要创建三个devinfo结构体,for循环结束后,__i2c_board_list链表中也就有了三个I2C设备的链表项,在程序的其他地方如果需要使用这里注册的设备结构信息,只需要遍历链表__i2c_board_list,通过总线号即可找到相应的设备信息。static void i2c_scan_static_board_info(struct i2c_adapter *adapter){struct i2c_devinfo*devinfo;down_read(&__i2c_board_lock);list_for_each_entry(devinfo, &__i2c_board_list, list) {if (devinfo->busnum == adapter->nr&& !i2c_new_device(adapter,&devinfo->board_info))  //This returns the new i2c client在这里完成了kobj的注册dev_err(&adapter->dev,"Can't create device at 0x%02x\n",devinfo->board_info.addr);}up_read(&__i2c_board_lock);}/////////////////////////////////////////////////////////////////// 到此位置,I2C总线驱动,I2C设备的注册和相应结构体的申请就已经完成了,接下来看下常用的I2C数据传输函数,I2C设备驱动主要调用这些数据传输接口完成数据的传输。
至于如果跑到match
首先看
#define module_i2c_driver(__i2c_driver) \module_driver(__i2c_driver, i2c_add_driver, \i2c_del_driver)
之后是
#define i2c_add_driver(driver) \i2c_register_driver(THIS_MODULE, driver)
接着
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;/* Drivers should switch to dev_pm_ops instead. */if (driver->suspend)pr_warn("i2c-core: driver [%s] using legacy suspend method\n",driver->driver.name);if (driver->resume)pr_warn("i2c-core: driver [%s] using legacy resume method\n",driver->driver.name);pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);INIT_LIST_HEAD(&driver->clients);/* Walk the adapters that are already present */i2c_for_each_dev(driver, __process_new_driver);return 0;}
然后
int driver_register(struct device_driver *drv){int ret;struct device_driver *other;BUG_ON(!drv->bus->p);if ((drv->bus->probe && drv->probe) ||    (drv->bus->remove && drv->remove) ||    (drv->bus->shutdown && drv->shutdown))printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);other = driver_find(drv->name, drv->bus);if (other) {printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);return -EBUSY;}ret = bus_add_driver(drv);if (ret)return ret;ret = driver_add_groups(drv, drv->groups);if (ret) {bus_remove_driver(drv);return ret;}kobject_uevent(&drv->p->kobj, KOBJ_ADD);return ret;}
接着
int bus_add_driver(struct device_driver *drv){struct bus_type *bus;struct driver_private *priv;int error = 0;bus = bus_get(drv->bus);if (!bus)return -EINVAL;pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);priv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv) {error = -ENOMEM;goto out_put_bus;}klist_init(&priv->klist_devices, NULL, NULL);priv->driver = drv;drv->p = priv;priv->kobj.kset = bus->p->drivers_kset;error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,     "%s", drv->name);if (error)goto out_unregister;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);if (drv->bus->p->drivers_autoprobe) {error = driver_attach(drv);if (error)goto out_unregister;}module_add_driver(drv->owner, drv);error = driver_create_file(drv, &driver_attr_uevent);if (error) {printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);}error = driver_add_attrs(bus, drv);if (error) {/* How the hell do we get out of this pickle? Give up */printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);}if (!drv->suppress_bind_attrs) {error = add_bind_files(drv);if (error) {/* Ditto */printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);}}return 0;out_unregister:kobject_put(&priv->kobj);kfree(drv->p);drv->p = NULL;out_put_bus:bus_put(bus);return error;}
其中
int driver_attach(struct device_driver *drv){return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}这下熟悉了把
int bus_for_each_dev(struct bus_type *bus, struct device *start,     void *data, int (*fn)(struct device *, void *)){struct klist_iter i;struct device *dev;int error = 0;if (!bus || !bus->p)return -EINVAL;klist_iter_init_node(&bus->p->klist_devices, &i,     (start ? &start->p->knode_bus : NULL));while ((dev = next_device(&i)) && !error)error = fn(dev, data);klist_iter_exit(&i);return error;}
struct i2c_client {    unsigned short flags;        //I2C_CLIENT_TEN表示设备使用10bit从地址,I2C_CLIENT_PEC表示设备使用SMBus检错    unsigned short addr;        //设备从地址,7bit。这里说一下为什么是7位,因为最后以为0表示写,1表示读,通过对这个7bit地址移位处理即可。addr<<1 & 0x0即写,addr<<1 | 0x01即读。    char name[I2C_NAME_SIZE];  //从设备名称    struct i2c_adapter *adapter;    //此从设备依附于哪个adapter上    struct i2c_driver *driver;    // 此设备对应的I2C驱动指针    struct device dev;        // 设备模型    int irq;            // 设备使用的中断号    struct list_head detected;  //用于链表操作};#define to_i2c_client(d) container_of(d, struct i2c_client, dev)  //通常使用device设备模型进行操作,可以通过to_i2c_client找到对应client指针struct i2c_board_info {    char        type[I2C_NAME_SIZE];  //设备名,最长20个字符,最终安装到client的name上    unsigned short    flags;  //最终安装到client.flags    unsigned short    addr;  //设备从地址slave address,最终安装到client.addr上    void        *platform_data;  //设备数据,最终存储到i2c_client.dev.platform_data上    struct dev_archdata    *archdata;    struct device_node *of_node;  //OpenFirmware设备节点指针    struct acpi_dev_node acpi_node;    int        irq;  //设备采用的中断号,最终存储到i2c_client.irq上};//可以看到,i2c_board_info基本是与i2c_client对应的。#define I2C_BOARD_INFO(dev_type, dev_addr) \    .type = dev_type, .addr = (dev_addr)//通过这个宏定义可以方便的定义I2C设备的名称和从地址(别忘了是7bit的)

0 0