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 @@
#include <linux/slab.h>
#include <linux/smiapp.h>
#include <linux/v4l2-mediabus.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <uapi/linux/ccs.h>
#include "ccs.h"
......@@ -98,7 +99,7 @@ static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit,
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
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))
return -EINVAL;
......@@ -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",
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,
......@@ -138,7 +139,7 @@ u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
if (ret)
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):
val = *(u8 *)ptr;
break;
......@@ -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++) {
u32 reg = ccs_limits[i].reg;
unsigned int width = ccs_reg_width(reg);
unsigned int width = CCI_REG_WIDTH_BYTES(reg);
unsigned int j;
if (l == CCS_L_LAST) {
......@@ -2725,66 +2726,54 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
rval = ccs_read(sensor, MODULE_MANUFACTURER_ID,
&minfo->mipi_manufacturer_id);
if (!rval && !minfo->mipi_manufacturer_id)
rval = ccs_read_addr_8only(sensor,
SMIAPP_REG_U8_MANUFACTURER_ID,
&minfo->smia_manufacturer_id);
rval = ccs_read_addr(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
&minfo->smia_manufacturer_id);
if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID,
&minfo->model_id);
rval = ccs_read(sensor, MODULE_MODEL_ID, &minfo->model_id);
if (!rval)
rval = ccs_read_addr_8only(sensor,
CCS_R_MODULE_REVISION_NUMBER_MAJOR,
&rev);
rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MAJOR, &rev);
if (!rval) {
rval = ccs_read_addr_8only(sensor,
CCS_R_MODULE_REVISION_NUMBER_MINOR,
&minfo->revision_number);
rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MINOR,
&minfo->revision_number);
minfo->revision_number |= rev << 8;
}
if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR,
&minfo->module_year);
rval = ccs_read(sensor, MODULE_DATE_YEAR, &minfo->module_year);
if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH,
&minfo->module_month);
rval = ccs_read(sensor, MODULE_DATE_MONTH,
&minfo->module_month);
if (!rval)
rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY,
&minfo->module_day);
rval = ccs_read(sensor, MODULE_DATE_DAY, &minfo->module_day);
/* Sensor info */
if (!rval)
rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
&minfo->sensor_mipi_manufacturer_id);
if (!rval && !minfo->sensor_mipi_manufacturer_id)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_MANUFACTURER_ID,
&minfo->sensor_smia_manufacturer_id);
rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
&minfo->sensor_smia_manufacturer_id);
if (!rval)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_MODEL_ID,
&minfo->sensor_model_id);
rval = ccs_read(sensor, SENSOR_MODEL_ID,
&minfo->sensor_model_id);
if (!rval)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_REVISION_NUMBER,
&minfo->sensor_revision_number);
rval = ccs_read(sensor, SENSOR_REVISION_NUMBER,
&minfo->sensor_revision_number);
if (!rval && !minfo->sensor_revision_number)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_REVISION_NUMBER_16,
&minfo->sensor_revision_number);
rval = ccs_read(sensor, SENSOR_REVISION_NUMBER_16,
&minfo->sensor_revision_number);
if (!rval)
rval = ccs_read_addr_8only(sensor,
CCS_R_SENSOR_FIRMWARE_VERSION,
&minfo->sensor_firmware_version);
rval = ccs_read(sensor, SENSOR_FIRMWARE_VERSION,
&minfo->sensor_firmware_version);
/* SMIA */
if (!rval)
rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version);
if (!rval && !minfo->ccs_version)
rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
&minfo->smia_version);
rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIA_VERSION,
&minfo->smia_version);
if (!rval && !minfo->ccs_version)
rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
&minfo->smiapp_version);
rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
&minfo->smiapp_version);
if (rval) {
dev_err(&client->dev, "sensor detection failed\n");
......@@ -3318,6 +3307,13 @@ static int ccs_probe(struct i2c_client *client)
if (IS_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);
if (rval < 0)
return rval;
......@@ -3648,12 +3644,16 @@ static int ccs_module_init(void)
{
unsigned int i, l;
CCS_BUILD_BUG;
for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) {
if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) {
ccs_limit_offsets[l + 1].lim =
ALIGN(ccs_limit_offsets[l].lim +
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;
l++;
} else {
......
......@@ -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)
{
if (val >> 10 > U32_MAX / 15625) {
......@@ -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,
bool only8, bool conv)
{
unsigned int len = ccs_reg_width(reg);
u64 __val;
int rval;
if (!only8)
rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val);
else
rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len,
val);
rval = cci_read(sensor->regmap, reg, &__val, NULL);
if (rval < 0)
return rval;
if (!conv)
return 0;
*val = ccs_reg_conv(sensor, reg, *val);
*val = conv ? ccs_reg_conv(sensor, reg, __val) : __val;
return 0;
}
......@@ -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,
u32 reg, u32 *val)
{
unsigned int width = ccs_reg_width(reg);
unsigned int width = CCI_REG_WIDTH_BYTES(reg);
size_t i;
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)
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.
* Returns zero if successful, or non-zero otherwise.
*/
int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
{
unsigned int retries = 10;
int rval;
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)
if (rval < 0)
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
......@@ -374,40 +234,38 @@ 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;
int len;
for (j = 0; j < regs->len;
j += msg.len - 2, regdata += msg.len - 2) {
for (j = 0; j < regs->len; j += len, regdata += len) {
char printbuf[(MAX_WRITE_LEN << 1) +
1 /* \0 */] = { 0 };
unsigned int retries = 10;
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,
"writing msr reg 0x%4.4x value 0x%s\n",
regs->addr + j, printbuf);
put_unaligned_be16(regs->addr + j, buf);
memcpy(buf + 2, regdata, msg.len);
msg.len += 2;
do {
rval = regmap_bulk_write(sensor->regmap,
regs->addr + j,
regdata, len);
if (rval)
fsleep(1000);
} while (rval && --retries);
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);
len, regs->addr + j);
return rval;
}
}
......
This diff is collapsed.
......@@ -13,6 +13,7 @@
#define __CCS_H__
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
......@@ -211,6 +212,7 @@ struct ccs_sensor {
struct clk *ext_clk;
struct gpio_desc *xshutdown;
struct gpio_desc *reset;
struct regmap *regmap;
void *ccs_limits;
u8 nbinning_subtypes;
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