@@ -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;
+ }
+
+ 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,
- 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_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,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;
- 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 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 +1081,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 +1099,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 +1155,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);