Commit 2538d322 authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab

media: ccs: Add support for manufacturer regs from sensor and module files

Write manufacturer specific registers (MSRs) from file to the sensor on
sensor power-on.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 2dd4b579
......@@ -1278,6 +1278,21 @@ static int ccs_setup_flash_strobe(struct ccs_sensor *sensor)
* Power management
*/
static int ccs_write_msr_regs(struct ccs_sensor *sensor)
{
int rval;
rval = ccs_write_data_regs(sensor,
sensor->sdata.sensor_manufacturer_regs,
sensor->sdata.num_sensor_manufacturer_regs);
if (rval)
return rval;
return ccs_write_data_regs(sensor,
sensor->mdata.module_manufacturer_regs,
sensor->mdata.num_module_manufacturer_regs);
}
static int ccs_power_on(struct device *dev)
{
struct v4l2_subdev *subdev = dev_get_drvdata(dev);
......@@ -1383,6 +1398,10 @@ static int ccs_power_on(struct device *dev)
if (rval < 0)
goto out_cci_addr_fail;
rval = ccs_write_msr_regs(sensor);
if (rval)
goto out_cci_addr_fail;
rval = ccs_call_quirk(sensor, post_poweron);
if (rval) {
dev_err(dev, "post_poweron quirks failed\n");
......@@ -3220,6 +3239,10 @@ static int ccs_probe(struct i2c_client *client)
if (rval < 0)
goto out_media_entity_cleanup;
rval = ccs_write_msr_regs(sensor);
if (rval)
goto out_media_entity_cleanup;
pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
pm_runtime_enable(&client->dev);
......
......@@ -236,12 +236,38 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
return ccs_read_addr_raw(sensor, reg, val, false, true, false);
}
static int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg)
{
unsigned int retries;
int r;
for (retries = 0; retries < 10; retries++) {
/*
* Due to unknown reason sensor stops responding. This
* loop is a temporaty solution until the root cause
* is found.
*/
r = i2c_transfer(client->adapter, msg, 1);
if (r != 1) {
usleep_range(1000, 2000);
continue;
}
if (retries)
dev_err(&client->dev,
"sensor i2c stall encountered. retries: %d\n",
retries);
return 0;
}
return r;
}
int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct i2c_msg msg;
unsigned char data[6];
unsigned int retries;
unsigned int len = ccs_reg_width(reg);
int r;
......@@ -256,24 +282,8 @@ int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val)
put_unaligned_be16(CCS_REG_ADDR(reg), data);
put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
for (retries = 0; retries < 10; retries++) {
/*
* Due to unknown reason sensor stops responding. This
* loop is a temporaty solution until the root cause
* is found.
*/
r = i2c_transfer(client->adapter, &msg, 1);
if (r == 1) {
if (retries)
dev_err(&client->dev,
"sensor i2c stall encountered. retries: %d\n",
retries);
return 0;
}
usleep_range(1000, 2000);
}
r = ccs_write_retry(client, &msg);
if (r)
dev_err(&client->dev,
"wrote 0x%x to offset 0x%x error %d\n", val,
CCS_REG_ADDR(reg), r);
......@@ -297,3 +307,43 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
return ccs_write_addr_no_quirk(sensor, reg, val);
}
#define MAX_WRITE_LEN 32U
int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
size_t num_regs)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
unsigned char buf[2 + MAX_WRITE_LEN];
struct i2c_msg msg = {
.addr = client->addr,
.buf = buf,
};
size_t i;
for (i = 0; i < num_regs; i++, regs++) {
unsigned char *regdata = regs->value;
unsigned int j;
for (j = 0; j < regs->len;
j += msg.len - 2, regdata += msg.len - 2) {
int rval;
msg.len = min(regs->len - j, MAX_WRITE_LEN);
put_unaligned_be16(regs->addr + j, buf);
memcpy(buf + 2, regdata, msg.len);
msg.len += 2;
rval = ccs_write_retry(client, &msg);
if (rval) {
dev_err(&client->dev,
"error writing %u octets to address 0x%4.4x\n",
msg.len, regs->addr + j);
return rval;
}
}
}
return 0;
}
......@@ -27,6 +27,8 @@ int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val);
int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val);
int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val);
int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val);
int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
size_t num_regs);
unsigned int ccs_reg_width(u32 reg);
u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val);
......
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