[PATCH 4/5] media/i2c: max96717: add FSYNC support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 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





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux