[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251009155251.102472-19-balamanikandan.gunasundar@microchip.com>
Date: Thu, 9 Oct 2025 21:22:51 +0530
From: Balamanikandan Gunasundar <balamanikandan.gunasundar@...rochip.com>
To: Mauro Carvalho Chehab <mchehab@...nel.org>
CC: Eugen Hristev <eugen.hristev@...aro.org>, Chas Williams
<3chas3@...il.com>, Nicolas Ferre <nicolas.ferre@...rochip.com>, "Alexandre
Belloni" <alexandre.belloni@...tlin.com>, Claudiu Beznea
<claudiu.beznea@...on.dev>, Balakrishnan Sambath
<balakrishnan.s@...rochip.com>, Hans Verkuil <hverkuil@...nel.org>, "Ricardo
Ribalda" <ribalda@...omium.org>, Laurent Pinchart
<laurent.pinchart+renesas@...asonboard.com>, Jacopo Mondi
<jacopo.mondi@...asonboard.com>, Daniel Scally
<dan.scally+renesas@...asonboard.com>, Tomi Valkeinen
<tomi.valkeinen@...asonboard.com>, <linux-kernel@...r.kernel.org>,
<linux-media@...r.kernel.org>, <linux-atm-general@...ts.sourceforge.net>,
<netdev@...r.kernel.org>, <linux-arm-kernel@...ts.infradead.org>,
Balamanikandan Gunasundar <balamanikandan.gunasundar@...rochip.com>
Subject: [PATCH 18/18] media: microchip-isc: expose color correction registers as v4l2 controls
Enable the Color correction registers as v4l2 controls. Applications such
as libcamera can read and write the elements of color correction matrix
through the standard v4l2 control API.
Signed-off-by: Balamanikandan Gunasundar <balamanikandan.gunasundar@...rochip.com>
---
.../platform/microchip/microchip-isc-base.c | 175 +++++++++++++++++-
.../media/platform/microchip/microchip-isc.h | 12 ++
include/linux/atmel-isc-media.h | 13 ++
3 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 6c937a20fce0..e679dc02dc9f 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,7 +32,7 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-#define ISC_IS_FORMAT_RAW(mbus_code) \
+#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
#define ISC_IS_FORMAT_GREY(mbus_code) \
@@ -1677,6 +1677,165 @@ static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int isc_cc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_update_bits(regmap, ISC_CC_RR_RG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_update_bits(regmap, ISC_CC_RB_OR, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_update_bits(regmap, ISC_CC_GR_GG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_update_bits(regmap, ISC_CC_GB_OG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_update_bits(regmap, ISC_CC_BR_BG, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(11, 0), ctrl->val);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_update_bits(regmap, ISC_CC_BB_OB, GENMASK(27, 16),
+ (ctrl->val & GENMASK(11, 0)) << 16);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int isc_cc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct isc_device *isc = container_of(ctrl->handler,
+ struct isc_device, ctrls.handler);
+ struct regmap *regmap = isc->regmap;
+ unsigned int reg;
+
+ switch (ctrl->id) {
+ case ISC_CID_CC_RR:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_RG:
+ regmap_read(regmap, ISC_CC_RR_RG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_RB:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OR:
+ regmap_read(regmap, ISC_CC_RB_OR, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GR:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_GG:
+ regmap_read(regmap, ISC_CC_GR_GG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_GB:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OG:
+ regmap_read(regmap, ISC_CC_GB_OG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BR:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_BG:
+ regmap_read(regmap, ISC_CC_BR_BG, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ case ISC_CID_CC_BB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32(reg & GENMASK(11, 0), 11);
+ break;
+ case ISC_CID_CC_OB:
+ regmap_read(regmap, ISC_CC_BB_OB, ®);
+ ctrl->val = sign_extend32((reg & GENMASK(27, 16)) >> 16, 11);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(isc->dev, "id = 0x%x; val = 0x%x", ctrl->id, ctrl->val);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_cc_ops = {
+ .s_ctrl = isc_cc_s_ctrl,
+ .g_volatile_ctrl = isc_cc_g_volatile_ctrl,
+};
+
+#define ISC_CTRL_CC(_name, _id, _name_str) \
+ static const struct v4l2_ctrl_config _name = { \
+ .ops = &isc_cc_ops, \
+ .id = _id, \
+ .name = _name_str, \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .flags = V4L2_CTRL_FLAG_SLIDER, \
+ .min = -2048, \
+ .max = 2047, \
+ .step = 1, \
+ .def = 0, \
+ }
+
+ISC_CTRL_CC(isc_cc_rr_ctrl, ISC_CID_CC_RR, "CC RR");
+ISC_CTRL_CC(isc_cc_rg_ctrl, ISC_CID_CC_RG, "CC RG");
+
+ISC_CTRL_CC(isc_cc_rb_ctrl, ISC_CID_CC_RB, "CC RB");
+ISC_CTRL_CC(isc_cc_or_ctrl, ISC_CID_CC_OR, "CC OR");
+
+ISC_CTRL_CC(isc_cc_gr_ctrl, ISC_CID_CC_GR, "CC GR");
+ISC_CTRL_CC(isc_cc_gg_ctrl, ISC_CID_CC_GG, "CC GG");
+
+ISC_CTRL_CC(isc_cc_gb_ctrl, ISC_CID_CC_GB, "CC GB");
+ISC_CTRL_CC(isc_cc_og_ctrl, ISC_CID_CC_OG, "CC OG");
+
+ISC_CTRL_CC(isc_cc_br_ctrl, ISC_CID_CC_BR, "CC BR");
+ISC_CTRL_CC(isc_cc_bg_ctrl, ISC_CID_CC_BG, "CC BG");
+
+ISC_CTRL_CC(isc_cc_bb_ctrl, ISC_CID_CC_BB, "CC BB");
+ISC_CTRL_CC(isc_cc_ob_ctrl, ISC_CID_CC_OB, "CC OB");
+
static const struct v4l2_ctrl_ops isc_awb_ops = {
.s_ctrl = isc_s_awb_ctrl,
.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
@@ -1767,6 +1926,20 @@ static int isc_ctrl_init(struct isc_device *isc)
isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+ /* Color correction control */
+ isc->cc_rr = v4l2_ctrl_new_custom(hdl, &isc_cc_rr_ctrl, NULL);
+ isc->cc_rg = v4l2_ctrl_new_custom(hdl, &isc_cc_rg_ctrl, NULL);
+ isc->cc_rb = v4l2_ctrl_new_custom(hdl, &isc_cc_rb_ctrl, NULL);
+ isc->cc_or = v4l2_ctrl_new_custom(hdl, &isc_cc_or_ctrl, NULL);
+ isc->cc_gr = v4l2_ctrl_new_custom(hdl, &isc_cc_gr_ctrl, NULL);
+ isc->cc_gg = v4l2_ctrl_new_custom(hdl, &isc_cc_gg_ctrl, NULL);
+ isc->cc_gb = v4l2_ctrl_new_custom(hdl, &isc_cc_gb_ctrl, NULL);
+ isc->cc_og = v4l2_ctrl_new_custom(hdl, &isc_cc_og_ctrl, NULL);
+ isc->cc_br = v4l2_ctrl_new_custom(hdl, &isc_cc_br_ctrl, NULL);
+ isc->cc_bg = v4l2_ctrl_new_custom(hdl, &isc_cc_bg_ctrl, NULL);
+ isc->cc_bb = v4l2_ctrl_new_custom(hdl, &isc_cc_bb_ctrl, NULL);
+ isc->cc_ob = v4l2_ctrl_new_custom(hdl, &isc_cc_ob_ctrl, NULL);
+
/*
* The cluster is in auto mode with autowhitebalance enabled
* and manual mode otherwise.
diff --git a/drivers/media/platform/microchip/microchip-isc.h b/drivers/media/platform/microchip/microchip-isc.h
index fcb20669ef69..aaa6c4b653d4 100644
--- a/drivers/media/platform/microchip/microchip-isc.h
+++ b/drivers/media/platform/microchip/microchip-isc.h
@@ -357,6 +357,18 @@ struct isc_device {
struct v4l2_ctrl *b_off_ctrl;
struct v4l2_ctrl *gr_off_ctrl;
struct v4l2_ctrl *gb_off_ctrl;
+ struct v4l2_ctrl *cc_rr;
+ struct v4l2_ctrl *cc_rg;
+ struct v4l2_ctrl *cc_rb;
+ struct v4l2_ctrl *cc_or;
+ struct v4l2_ctrl *cc_gr;
+ struct v4l2_ctrl *cc_gg;
+ struct v4l2_ctrl *cc_gb;
+ struct v4l2_ctrl *cc_og;
+ struct v4l2_ctrl *cc_br;
+ struct v4l2_ctrl *cc_bg;
+ struct v4l2_ctrl *cc_bb;
+ struct v4l2_ctrl *cc_ob;
};
/* Statistics device */
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
index 79a320fb724e..028d34c8de81 100644
--- a/include/linux/atmel-isc-media.h
+++ b/include/linux/atmel-isc-media.h
@@ -53,6 +53,19 @@ enum atmel_isc_ctrl_id {
ISC_CID_GR_OFFSET,
/* Green Blue component offset control */
ISC_CID_GB_OFFSET,
+ /* Color correction registers */
+ ISC_CID_CC_RR,
+ ISC_CID_CC_RG,
+ ISC_CID_CC_RB,
+ ISC_CID_CC_OR,
+ ISC_CID_CC_GR,
+ ISC_CID_CC_GG,
+ ISC_CID_CC_GB,
+ ISC_CID_CC_OG,
+ ISC_CID_CC_BR,
+ ISC_CID_CC_BG,
+ ISC_CID_CC_BB,
+ ISC_CID_CC_OB,
};
#endif
--
2.34.1
Powered by blists - more mailing lists