[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250207112958.2571600-5-laurentiu.palcu@oss.nxp.com>
Date: Fri, 7 Feb 2025 13:29:56 +0200
From: Laurentiu Palcu <laurentiu.palcu@....nxp.com>
To: Julien Massot <julien.massot@...labora.com>,
Mauro Carvalho Chehab <mchehab@...nel.org>
Cc: Laurentiu Palcu <laurentiu.palcu@....nxp.com>,
linux-kernel@...r.kernel.org,
linux-media@...r.kernel.org
Subject: [PATCH 4/5] media/i2c: max96717: add FSYNC support
According to specs:
"""
Frame synchronization (FSYNC) is used to align images sent from multiple
sources in surround-view applications and is required for concatenation.
In FSYNC mode, the GMSL2 CSI-2 quad deserializer sends a sync signal to
each serializer; the serializers then send the signal to the connected
sensor.
"""
Since max96717 can be used in multi-sensor setups, we need FSYNC
support. For that, I added a DT property("maxim,fsync-config") that will
be used to configure the frame sync output pin and the RX ID of the
GPIO as sent by the deserializer chip.
Also, add the .request() callback for the gpiochip so that we can use
'gpio-reserved-ranges' in DT to exclude the pins that are used for
FSYNC from being used as GPIOs.
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@....nxp.com>
---
drivers/media/i2c/max96717.c | 87 ++++++++++++++++++++++++++++++++----
1 file changed, 79 insertions(+), 8 deletions(-)
diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c
index 6a668a004c717..47a3be195a971 100644
--- a/drivers/media/i2c/max96717.c
+++ b/drivers/media/i2c/max96717.c
@@ -70,13 +70,28 @@
#define MAX96717_VTX_CHKB_ALT CCI_REG8(0x275)
/* GPIO */
-#define MAX96717_NUM_GPIO 11
-#define MAX96717_GPIO_REG_A(gpio) CCI_REG8(0x2be + (gpio) * 3)
-#define MAX96717_GPIO_OUT BIT(4)
-#define MAX96717_GPIO_IN BIT(3)
-#define MAX96717_GPIO_RX_EN BIT(2)
-#define MAX96717_GPIO_TX_EN BIT(1)
-#define MAX96717_GPIO_OUT_DIS BIT(0)
+#define MAX96717_NUM_GPIO 11
+#define MAX96717_GPIO_REG_A(gpio) CCI_REG8(0x2be + (gpio) * 3)
+#define MAX96717_GPIO_OUT BIT(4)
+#define MAX96717_GPIO_IN BIT(3)
+#define MAX96717_GPIO_RX_EN BIT(2)
+#define MAX96717_GPIO_TX_EN BIT(1)
+#define MAX96717_GPIO_OUT_DIS BIT(0)
+#define MAX96717_GPIO_REG_B(gpio) CCI_REG8(0x2bf + (gpio) * 3)
+#define MAX96717_GPIO_TX_ID_MASK GENMASK(4, 0)
+#define MAX96717_GPIO_TX_ID_SHIFT 0
+#define MAX96717_OUT_TYPE BIT(5)
+#define MAX96717_OUT_TYPE_PUSH_PULL BIT(5)
+#define MAX96717_OUT_TYPE_OPEN_DRAIN 0
+#define MAX96717_PULL_UPDN_SEL_MASK GENMASK(7, 6)
+#define MAX96717_PULL_UPDN_SEL_SHIFT 6
+#define MAX96717_GPIO_NO_PULL 0
+#define MAX96717_GPIO_PULL_UP 1
+#define MAX96717_GPIO_PULL_DOWN 2
+#define MAX96717_GPIO_REG_C(gpio) CCI_REG8(0x2c0 + (gpio) * 3)
+#define MAX96717_GPIO_RX_ID_MASK GENMASK(4, 0)
+#define MAX96717_GPIO_RX_ID_SHIFT 0
+#define MAX96717_OVR_RES_CFG BIT(7)
/* CMU */
#define MAX96717_CMU_CMU2 CCI_REG8(0x0302)
@@ -125,6 +140,11 @@ enum max96717_vpg_mode {
MAX96717_VPG_GRADIENT = 2,
};
+struct max96717_fsync_desc {
+ int pin;
+ int rx_id;
+};
+
struct max96717_priv {
struct i2c_client *client;
struct regmap *regmap;
@@ -141,6 +161,7 @@ struct max96717_priv {
struct clk_hw clk_hw;
struct gpio_chip gpio_chip;
enum max96717_vpg_mode pattern;
+ struct max96717_fsync_desc fsync;
};
static inline struct max96717_priv *sd_to_max96717(struct v4l2_subdev *sd)
@@ -364,6 +385,7 @@ static int max96717_gpiochip_probe(struct max96717_priv *priv)
gc->get_direction = max96717_gpio_get_direction;
gc->direction_input = max96717_gpio_direction_in;
gc->direction_output = max96717_gpio_direction_out;
+ gc->request = gpiochip_generic_request;
gc->set = max96717_gpiochip_set;
gc->get = max96717_gpiochip_get;
gc->of_gpio_n_cells = 2;
@@ -386,6 +408,26 @@ static int max96717_gpiochip_probe(struct max96717_priv *priv)
return 0;
}
+static int max96717_fsync_setup(struct max96717_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->fsync.pin == -1)
+ return 0;
+
+ cci_update_bits(priv->regmap, MAX96717_GPIO_REG_C(priv->fsync.pin),
+ MAX96717_GPIO_RX_ID_MASK,
+ priv->fsync.rx_id << MAX96717_GPIO_RX_ID_SHIFT, &ret);
+
+ cci_update_bits(priv->regmap, MAX96717_GPIO_REG_B(priv->fsync.pin),
+ MAX96717_PULL_UPDN_SEL_MASK,
+ 1 << MAX96717_PULL_UPDN_SEL_SHIFT, &ret);
+
+ return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(priv->fsync.pin),
+ MAX96717_GPIO_RX_EN | MAX96717_GPIO_OUT_DIS,
+ MAX96717_GPIO_RX_EN, &ret);
+}
+
static int _max96717_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_krouting *routing)
@@ -1037,7 +1079,8 @@ static int max96717_parse_dt(struct max96717_priv *priv)
struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
struct fwnode_handle *ep_fwnode;
unsigned char num_data_lanes;
- int ret;
+ int ret, count;
+ u32 dt_val[2];
ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
MAX96717_PAD_SINK, 0, 0);
@@ -1058,6 +1101,30 @@ static int max96717_parse_dt(struct max96717_priv *priv)
priv->mipi_csi2 = vep.bus.mipi_csi2;
+ priv->fsync.pin = -1;
+ count = fwnode_property_present(dev_fwnode(dev), "maxim,fsync-config");
+ if (count > 0) {
+ ret = fwnode_property_read_u32_array(dev_fwnode(dev), "maxim,fsync-config",
+ dt_val, count);
+ if (ret) {
+ dev_err(dev, "Unable to read FSYNC config from DT.\n");
+ return ret;
+ }
+
+ priv->fsync.rx_id = dt_val[0];
+ if (priv->fsync.rx_id > 31) {
+ dev_err(dev, "Wrong GPIO RX ID. Allowed: 0 -> 31\n");
+ return -EINVAL;
+ }
+
+ priv->fsync.pin = dt_val[1];
+ if (priv->fsync.pin >= MAX96717_NUM_GPIO) {
+ dev_err(dev, "Wrong GPIO pin used for FSYNC. Allowed: 0 -> %d\n",
+ MAX96717_NUM_GPIO - 1);
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -1092,6 +1159,10 @@ static int max96717_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, ret,
"Failed to init gpiochip\n");
+ ret = max96717_fsync_setup(priv);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Failed to setup FSYNC\n");
+
ret = max96717_register_clkout(priv);
if (ret)
return dev_err_probe(dev, ret, "Failed to register clkout\n");
--
2.34.1
Powered by blists - more mailing lists