Re: [PATCH v3 1/2] media: ov2740: only do OTP data read on demand from user

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Bingbu,

On Wed, Nov 11, 2020 at 02:39:56PM +0800, Bingbu Cao wrote:
> OTP data access of ov2740 in probe need power up, it may cause
> the camera flash LED blink during probe if the LED use same power
> rail with camera, this patch move the OTP data access out of
> probe, it will only occur on demand from user by nvmem sysfs.
> 
> Signed-off-by: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> Signed-off-by: Qingwu Zhang <qingwu.zhang@xxxxxxxxx>
> ---
>  drivers/media/i2c/ov2740.c | 111 ++++++++++++++++++++++++++++++++-------------
>  1 file changed, 79 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
> index 64ecb6917dd3..41c17df46f47 100644
> --- a/drivers/media/i2c/ov2740.c
> +++ b/drivers/media/i2c/ov2740.c
> @@ -71,9 +71,10 @@
>  #define OV2740_REG_OTP_CUSTOMER		0x7010
>  
>  struct nvm_data {
> -	char *nvm_buffer;
> +	struct i2c_client *client;
>  	struct nvmem_device *nvmem;
>  	struct regmap *regmap;
> +	char *nvm_buffer;
>  };
>  
>  enum {
> @@ -335,6 +336,9 @@ struct ov2740 {
>  
>  	/* Streaming on/off */
>  	bool streaming;
> +
> +	/* NVM data inforamtion */
> +	struct nvm_data *nvm;
>  };
>  
>  static inline struct ov2740 *to_ov2740(struct v4l2_subdev *subdev)
> @@ -930,45 +934,57 @@ static int ov2740_remove(struct i2c_client *client)
>  	return 0;
>  }
>  
> -static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm)
> +static int ov2740_load_otp_data(struct nvm_data *nvm)
>  {
> +	struct i2c_client *client = nvm->client;
>  	struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client));
>  	u32 isp_ctrl00 = 0;
>  	u32 isp_ctrl01 = 0;
>  	int ret;
>  
> +	if (!nvm)
> +		return -EINVAL;
> +
> +	if (nvm->nvm_buffer)
> +		return 0;
> +
> +	nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
> +	if (!nvm->nvm_buffer)
> +		return -ENOMEM;
> +
>  	ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00);
>  	if (ret) {
>  		dev_err(&client->dev, "failed to read ISP CTRL00\n");
> -		goto exit;
> +		goto err;
>  	}
> +
>  	ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01);
>  	if (ret) {
>  		dev_err(&client->dev, "failed to read ISP CTRL01\n");
> -		goto exit;
> +		goto err;
>  	}
>  
>  	/* Clear bit 5 of ISP CTRL00 */
>  	ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1,
>  			       isp_ctrl00 & ~BIT(5));
>  	if (ret) {
> -		dev_err(&client->dev, "failed to write ISP CTRL00\n");
> -		goto exit;
> +		dev_err(&client->dev, "failed to set ISP CTRL00\n");
> +		goto err;
>  	}
>  
>  	/* Clear bit 7 of ISP CTRL01 */
>  	ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1,
>  			       isp_ctrl01 & ~BIT(7));
>  	if (ret) {
> -		dev_err(&client->dev, "failed to write ISP CTRL01\n");
> -		goto exit;
> +		dev_err(&client->dev, "failed to set ISP CTRL01\n");
> +		goto err;
>  	}
>  
>  	ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
>  			       OV2740_MODE_STREAMING);
>  	if (ret) {
> -		dev_err(&client->dev, "failed to start streaming\n");
> -		goto exit;
> +		dev_err(&client->dev, "failed to set streaming mode\n");
> +		goto err;
>  	}
>  
>  	/*
> @@ -981,15 +997,33 @@ static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm)
>  			       nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE);
>  	if (ret) {
>  		dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret);
> -		goto exit;
> +		goto err;
>  	}
>  
> -	ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
> -			 OV2740_MODE_STANDBY);
> -	ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01);
> -	ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00);
> +	ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
> +			       OV2740_MODE_STANDBY);
> +	if (ret) {
> +		dev_err(&client->dev, "failed to set streaming mode\n");
> +		goto err;
> +	}
> +
> +	ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01);
> +	if (ret) {
> +		dev_err(&client->dev, "failed to set ISP CTRL01\n");
> +		goto err;
> +	}
> +
> +	ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00);
> +	if (ret) {
> +		dev_err(&client->dev, "failed to set ISP CTRL00\n");
> +		goto err;
> +	}
> +
> +	return 0;
> +err:
> +	kfree(nvm->nvm_buffer);
> +	nvm->nvm_buffer = NULL;
>  
> -exit:
>  	return ret;
>  }
>  
> @@ -997,29 +1031,43 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
>  			     size_t count)
>  {
>  	struct nvm_data *nvm = priv;
> +	struct v4l2_subdev *sd = i2c_get_clientdata(nvm->client);
> +	struct device *dev = &nvm->client->dev;
> +	struct ov2740 *ov2740 = to_ov2740(sd);
> +	int ret = 0;
> +
> +	mutex_lock(&ov2740->mutex);
>  
> -	memcpy(val, nvm->nvm_buffer + off, count);
> +	ret = pm_runtime_get_sync(dev);
> +	if (ret < 0) {
> +		pm_runtime_put_noidle(dev);
> +		goto exit;
> +	}
>  
> -	return 0;
> +	ret = ov2740_load_otp_data(nvm);

ov2740_load_otp_data() only needs to access the device on the first time.
Could you move resuming the device where it's really needed, please?

Can be a separate patch. Up to you.

> +	if (!ret)
> +		memcpy(val, nvm->nvm_buffer + off, count);
> +
> +	pm_runtime_put(dev);
> +exit:
> +	mutex_unlock(&ov2740->mutex);
> +	return ret;
>  }
>  
> -static int ov2740_register_nvmem(struct i2c_client *client)
> +static int ov2740_register_nvmem(struct i2c_client *client,
> +				 struct ov2740 *ov2740)
>  {
>  	struct nvm_data *nvm;
>  	struct regmap_config regmap_config = { };
>  	struct nvmem_config nvmem_config = { };
>  	struct regmap *regmap;
>  	struct device *dev = &client->dev;
> -	int ret = 0;
> +	int ret;
>  
>  	nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL);
>  	if (!nvm)
>  		return -ENOMEM;
>  
> -	nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
> -	if (!nvm->nvm_buffer)
> -		return -ENOMEM;
> -
>  	regmap_config.val_bits = 8;
>  	regmap_config.reg_bits = 16;
>  	regmap_config.disable_locking = true;
> @@ -1028,12 +1076,7 @@ static int ov2740_register_nvmem(struct i2c_client *client)
>  		return PTR_ERR(regmap);
>  
>  	nvm->regmap = regmap;
> -
> -	ret = ov2740_load_otp_data(client, nvm);
> -	if (ret) {
> -		dev_err(dev, "failed to load OTP data, ret %d\n", ret);
> -		return ret;
> -	}
> +	nvm->client = client;
>  
>  	nvmem_config.name = dev_name(dev);
>  	nvmem_config.dev = dev;
> @@ -1051,7 +1094,11 @@ static int ov2740_register_nvmem(struct i2c_client *client)
>  
>  	nvm->nvmem = devm_nvmem_register(dev, &nvmem_config);
>  
> -	return PTR_ERR_OR_ZERO(nvm->nvmem);
> +	ret = PTR_ERR_OR_ZERO(nvm->nvmem);
> +	if (!ret)
> +		ov2740->nvm = nvm;
> +
> +	return ret;
>  }
>  
>  static int ov2740_probe(struct i2c_client *client)
> @@ -1103,7 +1150,7 @@ static int ov2740_probe(struct i2c_client *client)
>  		goto probe_error_media_entity_cleanup;
>  	}
>  
> -	ret = ov2740_register_nvmem(client);
> +	ret = ov2740_register_nvmem(client, ov2740);
>  	if (ret)
>  		dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret);
>  
> -- 
> 2.7.4
> 

-- 
Sakari Ailus



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux