On 11/11/20 6:36 PM, Sakari Ailus wrote: > 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. Good point, will address in v4. ...... mutex_lock(&ov2740->mutex); + if (nvm->nvm_buffer) { + memcpy(val, nvm->nvm_buffer + off, count); + goto exit; + } + ret = pm_runtime_get_sync(dev); if (ret < 0) { pm_runtime_put_noidle(dev); .... > >> + 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 >> > -- Best regards, Bingbu Cao