Re: [PATCH 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,

Thanks for the patch.

On Fri, Nov 06, 2020 at 02:40:43PM +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 | 63 +++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 48 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
> index 64ecb6917dd3..716c26c13c97 100644
> --- a/drivers/media/i2c/ov2740.c
> +++ b/drivers/media/i2c/ov2740.c
> @@ -71,9 +71,11 @@
>  #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;
> +	bool ready;
>  };
>  
>  enum {
> @@ -335,6 +337,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,8 +935,9 @@ 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;
> @@ -967,7 +973,7 @@ static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm)
>  	ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
>  			       OV2740_MODE_STREAMING);
>  	if (ret) {
> -		dev_err(&client->dev, "failed to start streaming\n");
> +		dev_err(&client->dev, "failed to set streaming mode\n");
>  		goto exit;
>  	}
>  
> @@ -997,20 +1003,48 @@ 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);
> +	if (!nvm->ready) {
> +		if (ov2740->streaming) {
> +			ret = -EBUSY;
> +			goto exit;
> +		}
>  
> -	return 0;

If you also moved memory allocation here, you could omit the ready field. I
think it'd be cleaner that way as well.

> +		ret = pm_runtime_get_sync(dev);
> +		if (ret < 0) {
> +			pm_runtime_put_noidle(dev);
> +			goto exit;
> +		}
> +		ret = ov2740_load_otp_data(nvm);
> +		if (!ret)
> +			nvm->ready = true;
> +		pm_runtime_put(dev);
> +	}
> +
> +exit:
> +	mutex_unlock(&ov2740->mutex);
> +
> +	if (!ret)
> +		memcpy(val, nvm->nvm_buffer + off, count);
> +
> +	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)
> @@ -1028,12 +1062,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 +1080,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 +1136,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);
>  

-- 
Regards,

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