Commit 798f1a6b authored by Bingbu Cao's avatar Bingbu Cao Committed by Mauro Carvalho Chehab

media: ov2740: only do OTP data read on demand from user

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: default avatarBingbu Cao <bingbu.cao@intel.com>
Signed-off-by: default avatarQingwu Zhang <qingwu.zhang@intel.com>
Reviewed-by: default avatarTomasz Figa <tfiga@chromium.org>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 3c80f6f8
...@@ -71,9 +71,10 @@ ...@@ -71,9 +71,10 @@
#define OV2740_REG_OTP_CUSTOMER 0x7010 #define OV2740_REG_OTP_CUSTOMER 0x7010
struct nvm_data { struct nvm_data {
char *nvm_buffer; struct i2c_client *client;
struct nvmem_device *nvmem; struct nvmem_device *nvmem;
struct regmap *regmap; struct regmap *regmap;
char *nvm_buffer;
}; };
enum { enum {
...@@ -335,6 +336,9 @@ struct ov2740 { ...@@ -335,6 +336,9 @@ struct ov2740 {
/* Streaming on/off */ /* Streaming on/off */
bool streaming; bool streaming;
/* NVM data inforamtion */
struct nvm_data *nvm;
}; };
static inline struct ov2740 *to_ov2740(struct v4l2_subdev *subdev) static inline struct ov2740 *to_ov2740(struct v4l2_subdev *subdev)
...@@ -930,45 +934,57 @@ static int ov2740_remove(struct i2c_client *client) ...@@ -930,45 +934,57 @@ static int ov2740_remove(struct i2c_client *client)
return 0; 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)); struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client));
u32 isp_ctrl00 = 0; u32 isp_ctrl00 = 0;
u32 isp_ctrl01 = 0; u32 isp_ctrl01 = 0;
int ret; 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); ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to read ISP CTRL00\n"); 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); ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to read ISP CTRL01\n"); dev_err(&client->dev, "failed to read ISP CTRL01\n");
goto exit; goto err;
} }
/* Clear bit 5 of ISP CTRL00 */ /* Clear bit 5 of ISP CTRL00 */
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1,
isp_ctrl00 & ~BIT(5)); isp_ctrl00 & ~BIT(5));
if (ret) { if (ret) {
dev_err(&client->dev, "failed to write ISP CTRL00\n"); dev_err(&client->dev, "failed to set ISP CTRL00\n");
goto exit; goto err;
} }
/* Clear bit 7 of ISP CTRL01 */ /* Clear bit 7 of ISP CTRL01 */
ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1,
isp_ctrl01 & ~BIT(7)); isp_ctrl01 & ~BIT(7));
if (ret) { if (ret) {
dev_err(&client->dev, "failed to write ISP CTRL01\n"); dev_err(&client->dev, "failed to set ISP CTRL01\n");
goto exit; goto err;
} }
ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1,
OV2740_MODE_STREAMING); OV2740_MODE_STREAMING);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to start streaming\n"); dev_err(&client->dev, "failed to set streaming mode\n");
goto exit; goto err;
} }
/* /*
...@@ -981,15 +997,33 @@ static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm) ...@@ -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); nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret); dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret);
goto exit; goto err;
}
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;
} }
ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01);
OV2740_MODE_STANDBY); if (ret) {
ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); dev_err(&client->dev, "failed to set ISP CTRL01\n");
ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); 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; return ret;
} }
...@@ -997,29 +1031,48 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, ...@@ -997,29 +1031,48 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val,
size_t count) size_t count)
{ {
struct nvm_data *nvm = priv; 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;
memcpy(val, nvm->nvm_buffer + off, count); mutex_lock(&ov2740->mutex);
return 0; 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);
goto exit;
}
ret = ov2740_load_otp_data(nvm);
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 nvm_data *nvm;
struct regmap_config regmap_config = { }; struct regmap_config regmap_config = { };
struct nvmem_config nvmem_config = { }; struct nvmem_config nvmem_config = { };
struct regmap *regmap; struct regmap *regmap;
struct device *dev = &client->dev; struct device *dev = &client->dev;
int ret = 0; int ret;
nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL);
if (!nvm) if (!nvm)
return -ENOMEM; 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.val_bits = 8;
regmap_config.reg_bits = 16; regmap_config.reg_bits = 16;
regmap_config.disable_locking = true; regmap_config.disable_locking = true;
...@@ -1028,12 +1081,7 @@ static int ov2740_register_nvmem(struct i2c_client *client) ...@@ -1028,12 +1081,7 @@ static int ov2740_register_nvmem(struct i2c_client *client)
return PTR_ERR(regmap); return PTR_ERR(regmap);
nvm->regmap = regmap; nvm->regmap = regmap;
nvm->client = client;
ret = ov2740_load_otp_data(client, nvm);
if (ret) {
dev_err(dev, "failed to load OTP data, ret %d\n", ret);
return ret;
}
nvmem_config.name = dev_name(dev); nvmem_config.name = dev_name(dev);
nvmem_config.dev = dev; nvmem_config.dev = dev;
...@@ -1051,7 +1099,11 @@ static int ov2740_register_nvmem(struct i2c_client *client) ...@@ -1051,7 +1099,11 @@ static int ov2740_register_nvmem(struct i2c_client *client)
nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); 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) static int ov2740_probe(struct i2c_client *client)
...@@ -1103,7 +1155,7 @@ static int ov2740_probe(struct i2c_client *client) ...@@ -1103,7 +1155,7 @@ static int ov2740_probe(struct i2c_client *client)
goto probe_error_media_entity_cleanup; goto probe_error_media_entity_cleanup;
} }
ret = ov2740_register_nvmem(client); ret = ov2740_register_nvmem(client, ov2740);
if (ret) if (ret)
dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment