您的位置:首页 > 其它

qcom 8916平台的i2c init部分

2017-02-22 15:23 447 查看
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;
else
initialized = 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;
} else
pdata = 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;
else
dev->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_match
adap->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_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

/* 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;
else
bri->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 __init
i2c_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的)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: