soc camera子系統之初始化i2c client

我們知道,當我們註冊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;//這裏很重要哦,是爲了建立icdi2c 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;
}

下面我就mt9m001.c來分析一下image capture的probe函數

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驅動來實現。

.......
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章