summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/ccs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/ccs')
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c318
-rw-r--r--drivers/media/i2c/ccs/ccs-data.c25
-rw-r--r--drivers/media/i2c/ccs/ccs-data.h2
-rw-r--r--drivers/media/i2c/ccs/ccs-reg-access.c29
-rw-r--r--drivers/media/i2c/ccs/ccs.h8
-rw-r--r--drivers/media/i2c/ccs/smiapp-reg-defs.h2
6 files changed, 321 insertions, 63 deletions
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index b39ae5f8446b..15afbb4f5b31 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -28,6 +28,7 @@
#include <linux/v4l2-mediabus.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-device.h>
+#include <uapi/linux/ccs.h>
#include "ccs.h"
@@ -382,15 +383,22 @@ static int ccs_pll_configure(struct ccs_sensor *sensor)
if (rval < 0)
return rval;
- /* Lane op clock ratio does not apply here. */
- rval = ccs_write(sensor, REQUESTED_LINK_RATE,
- DIV_ROUND_UP(pll->op_bk.sys_clk_freq_hz,
- 1000000 / 256 / 256) *
- (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
- sensor->pll.csi2.lanes : 1) <<
- (pll->flags & CCS_PLL_FLAG_OP_SYS_DDR ? 1 : 0));
- if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
- return rval;
+ if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY) &
+ CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL)) {
+ /* Lane op clock ratio does not apply here. */
+ rval = ccs_write(sensor, REQUESTED_LINK_RATE,
+ DIV_ROUND_UP(pll->op_bk.sys_clk_freq_hz,
+ 1000000 / 256 / 256) *
+ (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
+ sensor->pll.csi2.lanes : 1) <<
+ (pll->flags & CCS_PLL_FLAG_OP_SYS_DDR ?
+ 1 : 0));
+ if (rval < 0)
+ return rval;
+ }
+
+ if (sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
+ return 0;
rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op_bk.pix_clk_div);
if (rval < 0)
@@ -671,6 +679,49 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl)
rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val);
break;
+
+ case V4L2_CID_CCS_ANALOGUE_LINEAR_GAIN:
+ rval = ccs_write(sensor, ANALOG_LINEAR_GAIN_GLOBAL, ctrl->val);
+
+ break;
+
+ case V4L2_CID_CCS_ANALOGUE_EXPONENTIAL_GAIN:
+ rval = ccs_write(sensor, ANALOG_EXPONENTIAL_GAIN_GLOBAL,
+ ctrl->val);
+
+ break;
+
+ case V4L2_CID_DIGITAL_GAIN:
+ if (CCS_LIM(sensor, DIGITAL_GAIN_CAPABILITY) ==
+ CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL) {
+ rval = ccs_write(sensor, DIGITAL_GAIN_GLOBAL,
+ ctrl->val);
+ break;
+ }
+
+ rval = ccs_write_addr(sensor,
+ SMIAPP_REG_U16_DIGITAL_GAIN_GREENR,
+ ctrl->val);
+ if (rval)
+ break;
+
+ rval = ccs_write_addr(sensor,
+ SMIAPP_REG_U16_DIGITAL_GAIN_RED,
+ ctrl->val);
+ if (rval)
+ break;
+
+ rval = ccs_write_addr(sensor,
+ SMIAPP_REG_U16_DIGITAL_GAIN_BLUE,
+ ctrl->val);
+ if (rval)
+ break;
+
+ rval = ccs_write_addr(sensor,
+ SMIAPP_REG_U16_DIGITAL_GAIN_GREENB,
+ ctrl->val);
+
+ break;
case V4L2_CID_EXPOSURE:
rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val);
@@ -713,6 +764,19 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl)
rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val);
break;
+ case V4L2_CID_CCS_SHADING_CORRECTION:
+ rval = ccs_write(sensor, SHADING_CORRECTION_EN,
+ ctrl->val ? CCS_SHADING_CORRECTION_EN_ENABLE :
+ 0);
+
+ if (!rval && sensor->luminance_level)
+ v4l2_ctrl_activate(sensor->luminance_level, ctrl->val);
+
+ break;
+ case V4L2_CID_CCS_LUMINANCE_CORRECTION_LEVEL:
+ rval = ccs_write(sensor, LUMINANCE_CORRECTION_LEVEL, ctrl->val);
+
+ break;
case V4L2_CID_PIXEL_RATE:
/* For v4l2_ctrl_s_ctrl_int64() used internally. */
rval = 0;
@@ -739,19 +803,144 @@ static int ccs_init_controls(struct ccs_sensor *sensor)
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
int rval;
- rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
+ rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 17);
if (rval)
return rval;
sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
- sensor->analog_gain = v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops,
- V4L2_CID_ANALOGUE_GAIN,
- CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN),
- CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX),
- max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U),
- CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN));
+ switch (CCS_LIM(sensor, ANALOG_GAIN_CAPABILITY)) {
+ case CCS_ANALOG_GAIN_CAPABILITY_GLOBAL: {
+ struct {
+ const char *name;
+ u32 id;
+ s32 value;
+ } const gain_ctrls[] = {
+ { "Analogue Gain m0", V4L2_CID_CCS_ANALOGUE_GAIN_M0,
+ CCS_LIM(sensor, ANALOG_GAIN_M0), },
+ { "Analogue Gain c0", V4L2_CID_CCS_ANALOGUE_GAIN_C0,
+ CCS_LIM(sensor, ANALOG_GAIN_C0), },
+ { "Analogue Gain m1", V4L2_CID_CCS_ANALOGUE_GAIN_M1,
+ CCS_LIM(sensor, ANALOG_GAIN_M1), },
+ { "Analogue Gain c1", V4L2_CID_CCS_ANALOGUE_GAIN_C1,
+ CCS_LIM(sensor, ANALOG_GAIN_C1), },
+ };
+ struct v4l2_ctrl_config ctrl_cfg = {
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .ops = &ccs_ctrl_ops,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ .step = 1,
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gain_ctrls); i++) {
+ ctrl_cfg.name = gain_ctrls[i].name;
+ ctrl_cfg.id = gain_ctrls[i].id;
+ ctrl_cfg.min = ctrl_cfg.max = ctrl_cfg.def =
+ gain_ctrls[i].value;
+
+ v4l2_ctrl_new_custom(&sensor->pixel_array->ctrl_handler,
+ &ctrl_cfg, NULL);
+ }
+
+ v4l2_ctrl_new_std(&sensor->pixel_array->ctrl_handler,
+ &ccs_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN),
+ CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX),
+ max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP),
+ 1U),
+ CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN));
+ }
+ break;
+
+ case CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL: {
+ struct {
+ const char *name;
+ u32 id;
+ u16 min, max, step;
+ } const gain_ctrls[] = {
+ {
+ "Analogue Linear Gain",
+ V4L2_CID_CCS_ANALOGUE_LINEAR_GAIN,
+ CCS_LIM(sensor, ANALOG_LINEAR_GAIN_MIN),
+ CCS_LIM(sensor, ANALOG_LINEAR_GAIN_MAX),
+ max(CCS_LIM(sensor,
+ ANALOG_LINEAR_GAIN_STEP_SIZE),
+ 1U),
+ },
+ {
+ "Analogue Exponential Gain",
+ V4L2_CID_CCS_ANALOGUE_EXPONENTIAL_GAIN,
+ CCS_LIM(sensor, ANALOG_EXPONENTIAL_GAIN_MIN),
+ CCS_LIM(sensor, ANALOG_EXPONENTIAL_GAIN_MAX),
+ max(CCS_LIM(sensor,
+ ANALOG_EXPONENTIAL_GAIN_STEP_SIZE),
+ 1U),
+ },
+ };
+ struct v4l2_ctrl_config ctrl_cfg = {
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .ops = &ccs_ctrl_ops,
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gain_ctrls); i++) {
+ ctrl_cfg.name = gain_ctrls[i].name;
+ ctrl_cfg.min = ctrl_cfg.def = gain_ctrls[i].min;
+ ctrl_cfg.max = gain_ctrls[i].max;
+ ctrl_cfg.step = gain_ctrls[i].step;
+ ctrl_cfg.id = gain_ctrls[i].id;
+
+ v4l2_ctrl_new_custom(&sensor->pixel_array->ctrl_handler,
+ &ctrl_cfg, NULL);
+ }
+ }
+ }
+
+ if (CCS_LIM(sensor, SHADING_CORRECTION_CAPABILITY) &
+ (CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING |
+ CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION)) {
+ const struct v4l2_ctrl_config ctrl_cfg = {
+ .name = "Shading Correction",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .id = V4L2_CID_CCS_SHADING_CORRECTION,
+ .ops = &ccs_ctrl_ops,
+ .max = 1,
+ .step = 1,
+ };
+
+ v4l2_ctrl_new_custom(&sensor->pixel_array->ctrl_handler,
+ &ctrl_cfg, NULL);
+ }
+
+ if (CCS_LIM(sensor, SHADING_CORRECTION_CAPABILITY) &
+ CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION) {
+ const struct v4l2_ctrl_config ctrl_cfg = {
+ .name = "Luminance Correction Level",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .id = V4L2_CID_CCS_LUMINANCE_CORRECTION_LEVEL,
+ .ops = &ccs_ctrl_ops,
+ .max = 255,
+ .step = 1,
+ .def = 128,
+ };
+
+ sensor->luminance_level =
+ v4l2_ctrl_new_custom(&sensor->pixel_array->ctrl_handler,
+ &ctrl_cfg, NULL);
+ }
+
+ if (CCS_LIM(sensor, DIGITAL_GAIN_CAPABILITY) ==
+ CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL ||
+ CCS_LIM(sensor, DIGITAL_GAIN_CAPABILITY) ==
+ SMIAPP_DIGITAL_GAIN_CAPABILITY_PER_CHANNEL)
+ v4l2_ctrl_new_std(&sensor->pixel_array->ctrl_handler,
+ &ccs_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ CCS_LIM(sensor, DIGITAL_GAIN_MIN),
+ CCS_LIM(sensor, DIGITAL_GAIN_MAX),
+ max(CCS_LIM(sensor, DIGITAL_GAIN_STEP_SIZE),
+ 1U),
+ 0x100);
/* Exposure limits will be updated soon, use just something here. */
sensor->exposure = v4l2_ctrl_new_std(
@@ -1001,7 +1190,7 @@ static void ccs_update_blanking(struct ccs_sensor *sensor)
{
struct v4l2_ctrl *vblank = sensor->vblank;
struct v4l2_ctrl *hblank = sensor->hblank;
- uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp;
+ u16 min_fll, max_fll, min_llp, max_llp, min_lbp;
int min, max;
if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) {
@@ -1322,6 +1511,28 @@ static int ccs_write_msr_regs(struct ccs_sensor *sensor)
sensor->mdata.num_module_manufacturer_regs);
}
+static int ccs_update_phy_ctrl(struct ccs_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ u8 val;
+
+ if (!sensor->ccs_limits)
+ return 0;
+
+ if (CCS_LIM(sensor, PHY_CTRL_CAPABILITY) &
+ CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL) {
+ val = CCS_PHY_CTRL_AUTO;
+ } else if (CCS_LIM(sensor, PHY_CTRL_CAPABILITY) &
+ CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL) {
+ val = CCS_PHY_CTRL_UI;
+ } else {
+ dev_err(&client->dev, "manual PHY control not supported\n");
+ return -EINVAL;
+ }
+
+ return ccs_write(sensor, PHY_CTRL, val);
+}
+
static int ccs_power_on(struct device *dev)
{
struct v4l2_subdev *subdev = dev_get_drvdata(dev);
@@ -1333,7 +1544,6 @@ static int ccs_power_on(struct device *dev)
struct ccs_sensor *sensor =
container_of(ssd, struct ccs_sensor, ssds[0]);
const struct ccs_device *ccsdev = device_get_match_data(dev);
- unsigned int sleep;
int rval;
rval = regulator_bulk_enable(ARRAY_SIZE(ccs_regulators),
@@ -1343,21 +1553,25 @@ static int ccs_power_on(struct device *dev)
return rval;
}
- rval = clk_prepare_enable(sensor->ext_clk);
- if (rval < 0) {
- dev_dbg(dev, "failed to enable xclk\n");
- goto out_xclk_fail;
- }
+ if (sensor->reset || sensor->xshutdown || sensor->ext_clk) {
+ unsigned int sleep;
+
+ rval = clk_prepare_enable(sensor->ext_clk);
+ if (rval < 0) {
+ dev_dbg(dev, "failed to enable xclk\n");
+ goto out_xclk_fail;
+ }
- gpiod_set_value(sensor->reset, 0);
- gpiod_set_value(sensor->xshutdown, 1);
+ gpiod_set_value(sensor->reset, 0);
+ gpiod_set_value(sensor->xshutdown, 1);
- if (ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA)
- sleep = SMIAPP_RESET_DELAY(sensor->hwcfg.ext_clk);
- else
- sleep = 5000;
+ if (ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA)
+ sleep = SMIAPP_RESET_DELAY(sensor->hwcfg.ext_clk);
+ else
+ sleep = 5000;
- usleep_range(sleep, sleep);
+ usleep_range(sleep, sleep);
+ }
/*
* Failures to respond to the address change command have been noticed.
@@ -1370,18 +1584,27 @@ static int ccs_power_on(struct device *dev)
* is found.
*/
- if (sensor->hwcfg.i2c_addr_alt) {
- rval = ccs_change_cci_addr(sensor);
- if (rval) {
- dev_err(dev, "cci address change error\n");
+ if (!sensor->reset && !sensor->xshutdown) {
+ u8 retry = 100;
+ u32 reset;
+
+ rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON);
+ if (rval < 0) {
+ dev_err(dev, "software reset failed\n");
goto out_cci_addr_fail;
}
- }
- rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON);
- if (rval < 0) {
- dev_err(dev, "software reset failed\n");
- goto out_cci_addr_fail;
+ do {
+ rval = ccs_read(sensor, SOFTWARE_RESET, &reset);
+ reset = !rval && reset == CCS_SOFTWARE_RESET_OFF;
+ if (reset)
+ break;
+
+ usleep_range(1000, 2000);
+ } while (--retry);
+
+ if (!reset)
+ return -EIO;
}
if (sensor->hwcfg.i2c_addr_alt) {
@@ -1426,8 +1649,7 @@ static int ccs_power_on(struct device *dev)
goto out_cci_addr_fail;
}
- /* DPHY control done by sensor based on requested link rate */
- rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI);
+ rval = ccs_update_phy_ctrl(sensor);
if (rval < 0)
goto out_cci_addr_fail;
@@ -2908,7 +3130,8 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
int i;
int rval;
- ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
if (!ep)
return -ENODEV;
@@ -3080,6 +3303,11 @@ static int ccs_probe(struct i2c_client *client)
return -EINVAL;
}
+ if (!sensor->hwcfg.ext_clk) {
+ dev_err(&client->dev, "cannot work with xclk frequency 0\n");
+ return -EINVAL;
+ }
+
sensor->reset = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(sensor->reset))
@@ -3148,6 +3376,10 @@ static int ccs_probe(struct i2c_client *client)
goto out_free_ccs_limits;
}
+ rval = ccs_update_phy_ctrl(sensor);
+ if (rval < 0)
+ goto out_free_ccs_limits;
+
/*
* Handle Sensor Module orientation on the board.
*
diff --git a/drivers/media/i2c/ccs/ccs-data.c b/drivers/media/i2c/ccs/ccs-data.c
index 6555bd4b325a..45f2b2f55ec5 100644
--- a/drivers/media/i2c/ccs/ccs-data.c
+++ b/drivers/media/i2c/ccs/ccs-data.c
@@ -10,7 +10,6 @@
#include <linux/limits.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/types.h>
#include "ccs-data-defs.h"
@@ -215,7 +214,7 @@ static int ccs_data_parse_regs(struct bin_container *bin,
size_t *__num_regs, const void *payload,
const void *endp, struct device *dev)
{
- struct ccs_reg *regs_base, *regs;
+ struct ccs_reg *regs_base = NULL, *regs = NULL;
size_t num_regs = 0;
u16 addr = 0;
@@ -286,6 +285,9 @@ static int ccs_data_parse_regs(struct bin_container *bin,
if (!bin->base) {
bin_reserve(bin, len);
} else if (__regs) {
+ if (!regs)
+ return -EIO;
+
regs->addr = addr;
regs->len = len;
regs->value = bin_alloc(bin, len);
@@ -306,8 +308,12 @@ static int ccs_data_parse_regs(struct bin_container *bin,
if (__num_regs)
*__num_regs = num_regs;
- if (bin->base && __regs)
+ if (bin->base && __regs) {
+ if (!regs_base)
+ return -EIO;
+
*__regs = regs_base;
+ }
return 0;
}
@@ -426,7 +432,7 @@ static int ccs_data_parse_rules(struct bin_container *bin,
size_t *__num_rules, const void *payload,
const void *endp, struct device *dev)
{
- struct ccs_rule *rules_base, *rules = NULL, *next_rule;
+ struct ccs_rule *rules_base = NULL, *rules = NULL, *next_rule = NULL;
size_t num_rules = 0;
const void *__next_rule = payload;
int rval;
@@ -484,6 +490,9 @@ static int ccs_data_parse_rules(struct bin_container *bin,
} else {
unsigned int i;
+ if (!next_rule)
+ return -EIO;
+
rules = next_rule;
next_rule++;
@@ -556,6 +565,9 @@ static int ccs_data_parse_rules(struct bin_container *bin,
bin_reserve(bin, sizeof(*rules) * num_rules);
*__num_rules = num_rules;
} else {
+ if (!rules_base)
+ return -EIO;
+
*__rules = rules_base;
}
@@ -691,7 +703,7 @@ static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_lo
}
for (i = 0; i < max_block_type_id; i++) {
- struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup;
+ struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL;
unsigned int j;
if (!is_contained(__num_pixel_descs, endp))
@@ -722,6 +734,9 @@ static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_lo
if (!bin->base)
continue;
+ if (!pdgroup)
+ return -EIO;
+
pdesc = &pdgroup->descs[j];
pdesc->pixel_type = __pixel_desc->pixel_type;
pdesc->small_offset_x = __pixel_desc->small_offset_x;
diff --git a/drivers/media/i2c/ccs/ccs-data.h b/drivers/media/i2c/ccs/ccs-data.h
index 50d6508b24f3..c75d480c8792 100644
--- a/drivers/media/i2c/ccs/ccs-data.h
+++ b/drivers/media/i2c/ccs/ccs-data.h
@@ -10,6 +10,8 @@
#include <linux/types.h>
+struct device;
+
/**
* struct ccs_data_block_version - CCS static data version
* @version_major: Major version number
diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c
index b776af2a3c33..25993445f4fe 100644
--- a/drivers/media/i2c/ccs/ccs-reg-access.c
+++ b/drivers/media/i2c/ccs/ccs-reg-access.c
@@ -17,11 +17,10 @@
#include "ccs.h"
#include "ccs-limits.h"
-static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
- uint32_t phloat)
+static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat)
{
- int32_t exp;
- uint64_t man;
+ s32 exp;
+ u64 man;
if (phloat >= 0x80000000) {
dev_err(&client->dev, "this is a negative number\n");
@@ -137,11 +136,11 @@ static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg,
unsigned int ccs_reg_width(u32 reg)
{
if (reg & CCS_FL_16BIT)
- return sizeof(uint16_t);
+ return sizeof(u16);
if (reg & CCS_FL_32BIT)
- return sizeof(uint32_t);
+ return sizeof(u32);
- return sizeof(uint8_t);
+ return sizeof(u8);
}
static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
@@ -205,7 +204,7 @@ static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs,
size_t i;
for (i = 0; i < num_regs; i++, regs++) {
- uint8_t *data;
+ u8 *data;
if (regs->addr + regs->len < CCS_REG_ADDR(reg) + width)
continue;
@@ -216,13 +215,13 @@ static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs,
data = &regs->value[CCS_REG_ADDR(reg) - regs->addr];
switch (width) {
- case sizeof(uint8_t):
+ case sizeof(u8):
*val = *data;
break;
- case sizeof(uint16_t):
+ case sizeof(u16):
*val = get_unaligned_be16(data);
break;
- case sizeof(uint32_t):
+ case sizeof(u32):
*val = get_unaligned_be32(data);
break;
default:
@@ -387,12 +386,20 @@ int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
for (j = 0; j < regs->len;
j += msg.len - 2, regdata += msg.len - 2) {
+ char printbuf[(MAX_WRITE_LEN << 1) +
+ 1 /* \0 */] = { 0 };
int rval;
msg.len = min(regs->len - j, MAX_WRITE_LEN);
+ bin2hex(printbuf, regdata, msg.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;
rval = ccs_write_retry(client, &msg);
diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h
index 356b87c33405..6beac375cc48 100644
--- a/drivers/media/i2c/ccs/ccs.h
+++ b/drivers/media/i2c/ccs/ccs.h
@@ -84,11 +84,11 @@ struct ccs_hwconfig {
unsigned short i2c_addr_dfl; /* Default i2c addr */
unsigned short i2c_addr_alt; /* Alternate i2c addr */
- uint32_t ext_clk; /* sensor external clk */
+ u32 ext_clk; /* sensor external clk */
unsigned int lanes; /* Number of CSI-2 lanes */
- uint32_t csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */
- uint64_t *op_sys_clock;
+ u32 csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */
+ u64 *op_sys_clock;
enum ccs_module_board_orient module_board_orient;
@@ -262,13 +262,13 @@ struct ccs_sensor {
unsigned long *valid_link_freqs;
/* Pixel array controls */
- struct v4l2_ctrl *analog_gain;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *pixel_rate_parray;
+ struct v4l2_ctrl *luminance_level;
/* src controls */
struct v4l2_ctrl *link_freq;
struct v4l2_ctrl *pixel_rate_csi;
diff --git a/drivers/media/i2c/ccs/smiapp-reg-defs.h b/drivers/media/i2c/ccs/smiapp-reg-defs.h
index e80c110ebf3a..177e3e51207a 100644
--- a/drivers/media/i2c/ccs/smiapp-reg-defs.h
+++ b/drivers/media/i2c/ccs/smiapp-reg-defs.h
@@ -535,6 +535,8 @@
#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0
#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1
+#define SMIAPP_DIGITAL_GAIN_CAPABILITY_PER_CHANNEL 1
+
#define SMIAPP_BINNING_CAPABILITY_NO 0
#define SMIAPP_BINNING_CAPABILITY_YES 1