Commit 52932211 authored by Sakari Ailus's avatar Sakari Ailus Committed by Hans Verkuil

media: ccs: Use V4L2 CCI for accessing sensor registers

Use V4L2 CCI for accessing device's registers. The 8-bit compatibility
read option is removed but this is supported by regmap through other
means.

Also the CCS register definitions are re-generated with V4L2 CCI
definitions. The older SMIA++ register definitions have been manually
converted.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent d180509c
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smiapp.h> #include <linux/smiapp.h>
#include <linux/v4l2-mediabus.h> #include <linux/v4l2-mediabus.h>
#include <media/v4l2-fwnode.h> #include <media/v4l2-cci.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <uapi/linux/ccs.h> #include <uapi/linux/ccs.h>
#include "ccs.h" #include "ccs.h"
...@@ -98,7 +99,7 @@ static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit, ...@@ -98,7 +99,7 @@ static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit,
linfo = &ccs_limits[ccs_limit_offsets[limit].info]; linfo = &ccs_limits[ccs_limit_offsets[limit].info];
if (WARN_ON(!sensor->ccs_limits) || if (WARN_ON(!sensor->ccs_limits) ||
WARN_ON(offset + ccs_reg_width(linfo->reg) > WARN_ON(offset + CCI_REG_WIDTH_BYTES(linfo->reg) >
ccs_limit_offsets[limit + 1].lim)) ccs_limit_offsets[limit + 1].lim))
return -EINVAL; return -EINVAL;
...@@ -124,7 +125,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor, ...@@ -124,7 +125,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor,
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n", dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n",
linfo->reg, linfo->name, offset, val, val); linfo->reg, linfo->name, offset, val, val);
ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); ccs_assign_limit(ptr, CCI_REG_WIDTH_BYTES(linfo->reg), val);
} }
u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
...@@ -138,7 +139,7 @@ u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, ...@@ -138,7 +139,7 @@ u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
if (ret) if (ret)
return 0; return 0;
switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { switch (CCI_REG_WIDTH_BYTES(ccs_limits[ccs_limit_offsets[limit].info].reg)) {
case sizeof(u8): case sizeof(u8):
val = *(u8 *)ptr; val = *(u8 *)ptr;
break; break;
...@@ -176,7 +177,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) ...@@ -176,7 +177,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor)
for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) {
u32 reg = ccs_limits[i].reg; u32 reg = ccs_limits[i].reg;
unsigned int width = ccs_reg_width(reg); unsigned int width = CCI_REG_WIDTH_BYTES(reg);
unsigned int j; unsigned int j;
if (l == CCS_L_LAST) { if (l == CCS_L_LAST) {
...@@ -2725,66 +2726,54 @@ static int ccs_identify_module(struct ccs_sensor *sensor) ...@@ -2725,66 +2726,54 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, rval = ccs_read(sensor, MODULE_MANUFACTURER_ID,
&minfo->mipi_manufacturer_id); &minfo->mipi_manufacturer_id);
if (!rval && !minfo->mipi_manufacturer_id) if (!rval && !minfo->mipi_manufacturer_id)
rval = ccs_read_addr_8only(sensor, rval = ccs_read_addr(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
SMIAPP_REG_U8_MANUFACTURER_ID, &minfo->smia_manufacturer_id);
&minfo->smia_manufacturer_id);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, rval = ccs_read(sensor, MODULE_MODEL_ID, &minfo->model_id);
&minfo->model_id);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MAJOR, &rev);
CCS_R_MODULE_REVISION_NUMBER_MAJOR,
&rev);
if (!rval) { if (!rval) {
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MINOR,
CCS_R_MODULE_REVISION_NUMBER_MINOR, &minfo->revision_number);
&minfo->revision_number);
minfo->revision_number |= rev << 8; minfo->revision_number |= rev << 8;
} }
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, rval = ccs_read(sensor, MODULE_DATE_YEAR, &minfo->module_year);
&minfo->module_year);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, rval = ccs_read(sensor, MODULE_DATE_MONTH,
&minfo->module_month); &minfo->module_month);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, rval = ccs_read(sensor, MODULE_DATE_DAY, &minfo->module_day);
&minfo->module_day);
/* Sensor info */ /* Sensor info */
if (!rval) if (!rval)
rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
&minfo->sensor_mipi_manufacturer_id); &minfo->sensor_mipi_manufacturer_id);
if (!rval && !minfo->sensor_mipi_manufacturer_id) if (!rval && !minfo->sensor_mipi_manufacturer_id)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
CCS_R_SENSOR_MANUFACTURER_ID, &minfo->sensor_smia_manufacturer_id);
&minfo->sensor_smia_manufacturer_id);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, SENSOR_MODEL_ID,
CCS_R_SENSOR_MODEL_ID, &minfo->sensor_model_id);
&minfo->sensor_model_id);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, SENSOR_REVISION_NUMBER,
CCS_R_SENSOR_REVISION_NUMBER, &minfo->sensor_revision_number);
&minfo->sensor_revision_number);
if (!rval && !minfo->sensor_revision_number) if (!rval && !minfo->sensor_revision_number)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, SENSOR_REVISION_NUMBER_16,
CCS_R_SENSOR_REVISION_NUMBER_16, &minfo->sensor_revision_number);
&minfo->sensor_revision_number);
if (!rval) if (!rval)
rval = ccs_read_addr_8only(sensor, rval = ccs_read(sensor, SENSOR_FIRMWARE_VERSION,
CCS_R_SENSOR_FIRMWARE_VERSION, &minfo->sensor_firmware_version);
&minfo->sensor_firmware_version);
/* SMIA */ /* SMIA */
if (!rval) if (!rval)
rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version);
if (!rval && !minfo->ccs_version) if (!rval && !minfo->ccs_version)
rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIA_VERSION,
&minfo->smia_version); &minfo->smia_version);
if (!rval && !minfo->ccs_version) if (!rval && !minfo->ccs_version)
rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
&minfo->smiapp_version); &minfo->smiapp_version);
if (rval) { if (rval) {
dev_err(&client->dev, "sensor detection failed\n"); dev_err(&client->dev, "sensor detection failed\n");
...@@ -3318,6 +3307,13 @@ static int ccs_probe(struct i2c_client *client) ...@@ -3318,6 +3307,13 @@ static int ccs_probe(struct i2c_client *client)
if (IS_ERR(sensor->xshutdown)) if (IS_ERR(sensor->xshutdown))
return PTR_ERR(sensor->xshutdown); return PTR_ERR(sensor->xshutdown);
sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(sensor->regmap)) {
dev_err(&client->dev, "can't initialise CCI (%ld)\n",
PTR_ERR(sensor->regmap));
return PTR_ERR(sensor->regmap);
}
rval = ccs_power_on(&client->dev); rval = ccs_power_on(&client->dev);
if (rval < 0) if (rval < 0)
return rval; return rval;
...@@ -3648,12 +3644,16 @@ static int ccs_module_init(void) ...@@ -3648,12 +3644,16 @@ static int ccs_module_init(void)
{ {
unsigned int i, l; unsigned int i, l;
CCS_BUILD_BUG;
for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) {
if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) {
ccs_limit_offsets[l + 1].lim = ccs_limit_offsets[l + 1].lim =
ALIGN(ccs_limit_offsets[l].lim + ALIGN(ccs_limit_offsets[l].lim +
ccs_limits[i].size, ccs_limits[i].size,
ccs_reg_width(ccs_limits[i + 1].reg)); ccs_limits[i + 1].reg ?
CCI_REG_WIDTH_BYTES(ccs_limits[i + 1].reg) :
1U);
ccs_limit_offsets[l].info = i; ccs_limit_offsets[l].info = i;
l++; l++;
} else { } else {
......
...@@ -62,87 +62,6 @@ static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat) ...@@ -62,87 +62,6 @@ static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat)
} }
/*
* Read a 8/16/32-bit i2c register. The value is returned in 'val'.
* Returns zero if successful, or non-zero otherwise.
*/
static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len,
u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct i2c_msg msg;
unsigned char data_buf[sizeof(u32)] = { 0 };
unsigned char offset_buf[sizeof(u16)];
int r;
if (len > sizeof(data_buf))
return -EINVAL;
msg.addr = client->addr;
msg.flags = 0;
msg.len = sizeof(offset_buf);
msg.buf = offset_buf;
put_unaligned_be16(reg, offset_buf);
r = i2c_transfer(client->adapter, &msg, 1);
if (r != 1) {
if (r >= 0)
r = -EBUSY;
goto err;
}
msg.len = len;
msg.flags = I2C_M_RD;
msg.buf = &data_buf[sizeof(data_buf) - len];
r = i2c_transfer(client->adapter, &msg, 1);
if (r != 1) {
if (r >= 0)
r = -EBUSY;
goto err;
}
*val = get_unaligned_be32(data_buf);
return 0;
err:
dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
return r;
}
/* Read a register using 8-bit access only. */
static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg,
u16 len, u32 *val)
{
unsigned int i;
int rval;
*val = 0;
for (i = 0; i < len; i++) {
u32 val8;
rval = ____ccs_read_addr(sensor, reg + i, 1, &val8);
if (rval < 0)
return rval;
*val |= val8 << ((len - i - 1) << 3);
}
return 0;
}
unsigned int ccs_reg_width(u32 reg)
{
if (reg & CCS_FL_16BIT)
return sizeof(u16);
if (reg & CCS_FL_32BIT)
return sizeof(u32);
return sizeof(u8);
}
static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val) static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
{ {
if (val >> 10 > U32_MAX / 15625) { if (val >> 10 > U32_MAX / 15625) {
...@@ -178,21 +97,14 @@ u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val) ...@@ -178,21 +97,14 @@ u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
bool only8, bool conv) bool only8, bool conv)
{ {
unsigned int len = ccs_reg_width(reg); u64 __val;
int rval; int rval;
if (!only8) rval = cci_read(sensor->regmap, reg, &__val, NULL);
rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val);
else
rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len,
val);
if (rval < 0) if (rval < 0)
return rval; return rval;
if (!conv) *val = conv ? ccs_reg_conv(sensor, reg, __val) : __val;
return 0;
*val = ccs_reg_conv(sensor, reg, *val);
return 0; return 0;
} }
...@@ -200,7 +112,7 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, ...@@ -200,7 +112,7 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs, static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs,
u32 reg, u32 *val) u32 reg, u32 *val)
{ {
unsigned int width = ccs_reg_width(reg); unsigned int width = CCI_REG_WIDTH_BYTES(reg);
size_t i; size_t i;
for (i = 0; i < num_regs; i++, regs++) { for (i = 0; i < num_regs; i++, regs++) {
...@@ -292,71 +204,13 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val) ...@@ -292,71 +204,13 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
return ccs_read_addr_raw(sensor, reg, val, false, true, false, true); return ccs_read_addr_raw(sensor, reg, val, false, true, false, true);
} }
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 len = ccs_reg_width(reg);
int r;
if (len > sizeof(data) - 2)
return -EINVAL;
msg.addr = client->addr;
msg.flags = 0; /* Write */
msg.len = 2 + len;
msg.buf = data;
put_unaligned_be16(CCS_REG_ADDR(reg), data);
put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
dev_dbg(&client->dev, "writing reg 0x%4.4x value 0x%*.*x (%u)\n",
CCS_REG_ADDR(reg), ccs_reg_width(reg) << 1,
ccs_reg_width(reg) << 1, val, val);
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);
return r;
}
/* /*
* Write to a 8/16-bit register. * Write to a 8/16-bit register.
* Returns zero if successful, or non-zero otherwise. * Returns zero if successful, or non-zero otherwise.
*/ */
int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
{ {
unsigned int retries = 10;
int rval; int rval;
rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val); rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val);
...@@ -365,7 +219,13 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) ...@@ -365,7 +219,13 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
if (rval < 0) if (rval < 0)
return rval; return rval;
return ccs_write_addr_no_quirk(sensor, reg, val); rval = 0;
do {
if (cci_write(sensor->regmap, reg, val, &rval))
fsleep(1000);
} while (rval && --retries);
return rval;
} }
#define MAX_WRITE_LEN 32U #define MAX_WRITE_LEN 32U
...@@ -374,40 +234,38 @@ int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs, ...@@ -374,40 +234,38 @@ int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
size_t num_regs) size_t num_regs)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); 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; size_t i;
for (i = 0; i < num_regs; i++, regs++) { for (i = 0; i < num_regs; i++, regs++) {
unsigned char *regdata = regs->value; unsigned char *regdata = regs->value;
unsigned int j; unsigned int j;
int len;
for (j = 0; j < regs->len; for (j = 0; j < regs->len; j += len, regdata += len) {
j += msg.len - 2, regdata += msg.len - 2) {
char printbuf[(MAX_WRITE_LEN << 1) + char printbuf[(MAX_WRITE_LEN << 1) +
1 /* \0 */] = { 0 }; 1 /* \0 */] = { 0 };
unsigned int retries = 10;
int rval; int rval;
msg.len = min(regs->len - j, MAX_WRITE_LEN); len = min(regs->len - j, MAX_WRITE_LEN);
bin2hex(printbuf, regdata, msg.len); bin2hex(printbuf, regdata, len);
dev_dbg(&client->dev, dev_dbg(&client->dev,
"writing msr reg 0x%4.4x value 0x%s\n", "writing msr reg 0x%4.4x value 0x%s\n",
regs->addr + j, printbuf); regs->addr + j, printbuf);
put_unaligned_be16(regs->addr + j, buf); do {
memcpy(buf + 2, regdata, msg.len); rval = regmap_bulk_write(sensor->regmap,
regs->addr + j,
msg.len += 2; regdata, len);
if (rval)
fsleep(1000);
} while (rval && --retries);
rval = ccs_write_retry(client, &msg);
if (rval) { if (rval) {
dev_err(&client->dev, dev_err(&client->dev,
"error writing %u octets to address 0x%4.4x\n", "error writing %u octets to address 0x%4.4x\n",
msg.len, regs->addr + j); len, regs->addr + j);
return rval; return rval;
} }
} }
......
This diff is collapsed.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define __CCS_H__ #define __CCS_H__
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/regmap.h>
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
...@@ -211,6 +212,7 @@ struct ccs_sensor { ...@@ -211,6 +212,7 @@ struct ccs_sensor {
struct clk *ext_clk; struct clk *ext_clk;
struct gpio_desc *xshutdown; struct gpio_desc *xshutdown;
struct gpio_desc *reset; struct gpio_desc *reset;
struct regmap *regmap;
void *ccs_limits; void *ccs_limits;
u8 nbinning_subtypes; u8 nbinning_subtypes;
struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1];
......
This diff is collapsed.
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