我们知道,当我们注册soc_camera host时,会通过搜索链表devices来寻找需要安装到该host上的soc camera device(这就意味着soc camera device的初始化必须要早于soc camera host),当有需要安装到该host上的设备时,我们就注册该soc camera device,根据总线,设备,驱动模型,这时就会调用soc_camera_probe函数,下面再次详细分析一下soc camera probe函数。
static int soc_camera_probe(struct device *dev) { struct soc_camera_device *icd = to_soc_camera_dev(dev); struct soc_camera_host *ici = to_soc_camera_host(dev->parent); struct soc_camera_link *icl = to_soc_camera_link(icd); struct device *control = NULL; int ret; ret = ici->ops->add(icd); if (ret < 0) goto eadd; ret = soc_camera_power_set(icd, icl, 1); if (ret < 0) goto epower; /* The camera could have been already on, try to reset */ if (icl->reset) icl->reset(icd->pdev); /* Must have icd->vdev before registering the device */ ret = video_dev_create(icd); if (ret < 0) goto evdc; /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ if (icl->board_info) { ret = soc_camera_init_i2c(icd, icl); if (ret < 0) goto eadddev; } else if (!icl->add_device || !icl->del_device) { ret = -EINVAL; goto eadddev; } else { if (icl->module_name) ret = request_module(icl->module_name); ret = icl->add_device(icl, &icd->dev); if (ret < 0) goto eadddev; /* * FIXME: this is racy, have to use driver-binding notification, * when it is available */ control = to_soc_camera_control(icd); if (!control || !control->driver || !dev_get_drvdata(control) || !try_module_get(control->driver->owner)) { icl->del_device(icl); goto enodrv; } } /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) goto eiufmt; icd->field = V4L2_FIELD_ANY; icd->vdev->lock = &icd->video_lock; /* * ..._video_start() will create a device node, video_register_device() * itself is protected against concurrent open() calls, but we also have * to protect our data. */ mutex_lock(&icd->video_lock); ret = soc_camera_video_start(icd); if (ret < 0) goto evidstart; /* Do we have to sysfs_remove_link() before device_unregister()? */ if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj, "control")) dev_warn(&icd->dev, "Failed creating the control symlink\n"); ici->ops->remove(icd); soc_camera_power_set(icd, icl, 0); mutex_unlock(&icd->video_lock); return 0; evidstart: mutex_unlock(&icd->video_lock); soc_camera_free_user_formats(icd); eiufmt: if (icl->board_info) { soc_camera_free_i2c(icd); } else { icl->del_device(icl); module_put(control->driver->owner); } enodrv: eadddev: video_device_release(icd->vdev); evdc: soc_camera_power_set(icd, icl, 0); epower: ici->ops->remove(icd); eadd: return ret; }
我们着重分析一下ret =soc_camera_init_i2c(icd, icl);的过程。首先贴出soc_camera_init_i2c的代码。
static int soc_camera_init_i2c(structsoc_camera_device *icd,
struct soc_camera_link *icl)
{
structi2c_client *client;
structsoc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct i2c_adapter *adap =i2c_get_adapter(icl->i2c_adapter_id);通过icl传入的adapter_id来获取i2c adapter适配器。
structv4l2_subdev *subdev;
if(!adap) {
dev_err(&icd->dev,"Cannot get I2C adapter #%d. No driver?\n",
icl->i2c_adapter_id);
goto ei2cga;
}
icl->board_info->platform_data = icd;//这里很重要哦,是为了建立icd和i2c client之间的联系。
subdev =v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
icl->board_info,NULL);//重点分析该代码
if(!subdev)
gotoei2cnd;
client= v4l2_get_subdevdata(subdev);
/*Use to_i2c_client(dev) to recover the i2c client */
dev_set_drvdata(&icd->dev,&client->dev);
return0;
ei2cnd:
i2c_put_adapter(adap);
ei2cga:
return-ENODEV;
}
我们来贴出v4l2_i2c_new_subdev_board的源码。struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, struct i2c_adapter *adapter, struct i2c_board_info *info, const unsigned short *probe_addrs) { struct v4l2_subdev *sd = NULL; struct i2c_client *client; BUG_ON(!v4l2_dev); request_module(I2C_MODULE_PREFIX "%s", info->type); /* Create the i2c client */ ...... client = i2c_new_device(adapter, info); //初始化一个i2c client,我们来分析一下该函数的行为。 【 struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); //为client申请分配内存。 if (!client) return NULL; client->adapter = adap; client->dev.platform_data = info->platform_data;//还记得之前icl->board_info->platform_data = icd吗,这里就是将client->dev.platform_data指向icd,那么这里究竟是为了什么这样做呢,是为了在image capture驱动中获取到icd,下面会就具体驱动实例分析。 if (info->archdata) client->dev.archdata = *info->archdata; client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; strlcpy(client->name, info->type, sizeof(client->name)); /* Check for address validity */ status = i2c_check_client_addr_validity(client);//检查i2c地址是否可用。 if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); goto out_err_silent; } /* Check for address business */ status = i2c_check_addr_busy(adap, client->addr);//检查地址是否已经被占用。 if (status) goto out_err; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr); status = device_register(&client->dev); //这里注册i2c client,根据总线,设备,驱动模型,我们可以知道,此时会触发对应的i2c driver(根据name 来match),这时就会调用image capture的驱动探测函数(probe函数。) if (status) goto out_err; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); out_err_silent: kfree(client); return NULL; 】 ...... sd = i2c_get_clientdata(client);//我们知道在image capture驱动中,已经建立了client和subdev之间的联系,因此可以通过i2c_get_clientdata来获取到subdev。 /* Register with the v4l2_device which increases the module‘s use count as well. */ if (v4l2_device_register_subdev(v4l2_dev, sd)) sd = NULL; /* Decrease the module use count to match the first try_module_get. */ module_put(client->driver->driver.owner); error: /* If we have a client but no subdev, then something went wrong and we must unregister the client. */ if (client && sd == NULL) i2c_unregister_device(client); return sd; }
static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m001 *mt9m001; struct soc_camera_device *icd = client->dev.platform_data; //通过platform_data获取icd。 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); //通过client->dev.parent获取adapter,这里源于初始化client时(client->dev.parent = &client->adapter->dev;) struct soc_camera_link *icl; int ret; if (!icd) { dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); return -EINVAL; } icl = to_soc_camera_link(icd); if (!icl) { dev_err(&client->dev, "MT9M001 driver needs platform data\n"); return -EINVAL; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&adapter->dev, "I2C-Adapter doesn‘t support I2C_FUNC_SMBUS_WORD\n"); return -EIO; } mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL); if (!mt9m001) return -ENOMEM; v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);//这个是个有趣且有伏笔的地方,我们来展开代码分析: 【 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) { v4l2_subdev_init(sd, ops);//初始化subdev,并且将其ops指针指向ops. sd->flags |= V4L2_SUBDEV_FL_IS_I2C; /* the owner is the same as the i2c_client‘s driver owner */ sd->owner = client->driver->driver.owner; /* i2c_client and v4l2_subdev point to one another */ v4l2_set_subdevdata(sd, client); //使得 sd->dev_priv = client i2c_set_clientdata(client, sd);//使得client->dev->p->driver_data=sd 通过以上两行代码,建立了subdev与i2c client直接的联系。 /* initialize name */ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", client->driver->driver.name, i2c_adapter_id(client->adapter), client->addr); } 】 /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m001_ops;//icd的回调函数集,由image capture驱动来实现。 ....... }
soc camera子系统之初始化i2c client,布布扣,bubuko.com
原文:http://blog.csdn.net/smartvincent88/article/details/24260251