lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250131163408.2019144-11-laurentiu.palcu@oss.nxp.com>
Date: Fri, 31 Jan 2025 18:34:04 +0200
From: Laurentiu Palcu <laurentiu.palcu@....nxp.com>
To: Niklas Söderlund <niklas.soderlund@...natech.se>,
	Mauro Carvalho Chehab <mchehab@...nel.org>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Linus Walleij <linus.walleij@...aro.org>,
	Bartosz Golaszewski <brgl@...ev.pl>
Cc: Laurentiu Palcu <laurentiu.palcu@....nxp.com>,
	linux-gpio@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	linux-media@...r.kernel.org,
	linux-staging@...ts.linux.dev
Subject: [RFC 10/12] staging: media: max96712: add gpiochip functionality

The deserializer has GPIOs that can be used for various purposes. Add
support for gpiochip.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@....nxp.com>
---
 drivers/staging/media/max96712/max96712.c | 140 ++++++++++++++++++++++
 1 file changed, 140 insertions(+)

diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c
index ed1d46ea98cb9..307b2f1d3a6be 100644
--- a/drivers/staging/media/max96712/max96712.c
+++ b/drivers/staging/media/max96712/max96712.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/gpio/driver.h>
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/module.h>
@@ -108,6 +109,41 @@
 #define   CSI2_LANE_CNT_MASK				GENMASK(7, 6)
 #define   CSI2_LANE_CNT_SHIFT				6
 
+/* GPIO_A: 0 <= gpio < 11 */
+#define MAX96712_GPIO_A_A(gpio)				CCI_REG8(0x0300 + (gpio) * 0x03)
+#define   GPIO_OUT_DIS					BIT(0)
+#define   GPIO_TX_EN_A					BIT(1)
+#define   GPIO_RX_EN_A					BIT(2)
+#define   GPIO_IN					BIT(3)
+#define   GPIO_OUT					BIT(4)
+#define   TX_COMP_EN_A					BIT(5)
+#define   RES_CFG					BIT(7)
+#define MAX96712_GPIO_A_B(gpio)				CCI_REG8(0x0301 + (gpio) * 0x03)
+#define   GPIO_TX_ID_A_MASK				GENMASK(4, 0)
+#define   GPIO_TX_ID_A_SHIFT				0
+#define   OUT_TYPE					BIT(5)
+#define   PULL_UPDN_SEL_MASK				GENMASK(7, 6)
+#define   PULL_UPDN_SEL_SHIFT				6
+#define MAX96712_GPIO_A_C(gpio)				CCI_REG8(0x0302 + (gpio) * 0x03)
+#define   GPIO_RX_ID_A_MASK				GENMASK(4, 0)
+#define   GPIO_RX_ID_A_SHIFT				0
+#define   GPIO_RECVED_A					BIT(6)
+#define   OVR_RES_CFG					BIT(7)
+
+/* GPIO_B, GPIO_C, GPIO_D: 0 <= gpio < 11, link: 1, 2, 3 */
+#define MAX96712_GPIO_B(gpio)				CCI_REG8(0x0301 + (link) * 0x36 + \
+								 (gpio) * 0x03)
+#define   GPIO_TX_ID_MASK				GENMASK(4, 0)
+#define   GPIO_TX_ID_SHIFT				0
+#define   GPIO_TX_EN					BIT(5)
+#define   TX_COMP_EN					BIT(6)
+#define MAX96712_GPIO_C(gpio)				CCI_REG8(0x0302 + (link) * 0x36 + \
+								 (gpio) * 0x03)
+#define   GPIO_RX_ID_MASK				GENMASK(4, 0)
+#define   GPIO_RX_ID_SHIFT				0
+#define   GPIO_RX_EN					BIT(5)
+#define   GPIO_RECVED					BIT(6)
+
 /* VRX_PATGEN */
 #define MAX96712_VRX_PATGEN_0				CCI_REG8(0x1050)
 #define   VTG_MODE_MASK					GENMASK(1, 0)
@@ -160,6 +196,8 @@
 
 #define MHZ(f)						((f) * 1000000U)
 
+#define MAX96712_NUM_GPIO				12
+
 enum max96712_pattern {
 	MAX96712_PATTERN_CHECKERBOARD = 0,
 	MAX96712_PATTERN_GRADIENT,
@@ -179,6 +217,8 @@ struct max96712_priv {
 	struct regmap *regmap;
 	struct gpio_desc *gpiod_pwdn;
 
+	struct gpio_chip gpio_chip;
+
 	struct i2c_mux_core *mux;
 	int mux_chan;
 
@@ -830,6 +870,7 @@ static int max96712_v4l2_register(struct max96712_priv *priv)
 	return ret;
 }
 
+/* I2C Mux section */
 static int max96712_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
 {
 	struct max96712_priv *priv = i2c_mux_priv(muxc);
@@ -885,6 +926,101 @@ static int max96712_i2c_init(struct max96712_priv *priv)
 	return ret;
 }
 
+/* GPIO chip section */
+static int max96712_gpiochip_get(struct gpio_chip *gpiochip,
+				 unsigned int offset)
+{
+	struct max96712_priv *priv = gpiochip_get_data(gpiochip);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MAX96712_GPIO_A_A(offset), &val);
+	if (ret)
+		return ret;
+
+	if (val & GPIO_OUT_DIS)
+		return !!(val & GPIO_IN);
+	else
+		return !!(val & GPIO_OUT);
+}
+
+static void max96712_gpiochip_set(struct gpio_chip *gpiochip,
+				  unsigned int offset, int value)
+{
+	struct max96712_priv *priv = gpiochip_get_data(gpiochip);
+
+	regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset), GPIO_OUT,
+			   GPIO_OUT);
+}
+
+static int max96712_gpio_get_direction(struct gpio_chip *gpiochip,
+				       unsigned int offset)
+{
+	struct max96712_priv *priv = gpiochip_get_data(gpiochip);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MAX96712_GPIO_A_A(offset), &val);
+	if (ret < 0)
+		return ret;
+
+	return !!(val & GPIO_OUT_DIS);
+}
+
+static int max96712_gpio_direction_out(struct gpio_chip *gpiochip,
+				       unsigned int offset, int value)
+{
+	struct max96712_priv *priv = gpiochip_get_data(gpiochip);
+
+	return regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset),
+				  GPIO_OUT_DIS | GPIO_OUT,
+				  value ? GPIO_OUT : 0);
+}
+
+static int max96712_gpio_direction_in(struct gpio_chip *gpiochip,
+				      unsigned int offset)
+{
+	struct max96712_priv *priv = gpiochip_get_data(gpiochip);
+
+	return regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(offset),
+				  GPIO_OUT_DIS, GPIO_OUT_DIS);
+}
+
+static int max96712_gpiochip_probe(struct max96712_priv *priv)
+{
+	struct device *dev = &priv->client->dev;
+	struct gpio_chip *gc = &priv->gpio_chip;
+	int i, ret = 0;
+
+	gc->label = dev_name(dev);
+	gc->parent = dev;
+	gc->owner = THIS_MODULE;
+	gc->ngpio = MAX96712_NUM_GPIO;
+	gc->base = -1;
+	gc->can_sleep = true;
+	gc->get_direction = max96712_gpio_get_direction;
+	gc->direction_input = max96712_gpio_direction_in;
+	gc->direction_output = max96712_gpio_direction_out;
+	gc->request = gpiochip_generic_request;
+	gc->set = max96712_gpiochip_set;
+	gc->get = max96712_gpiochip_get;
+	gc->of_gpio_n_cells = 2;
+
+	/* Disable GPIO forwarding */
+	for (i = 0; i < gc->ngpio; i++)
+		regmap_update_bits(priv->regmap, MAX96712_GPIO_A_A(i),
+				   GPIO_RX_EN_A | GPIO_TX_EN_A, 0);
+
+	ret = devm_gpiochip_add_data(dev, gc, priv);
+	if (ret) {
+		dev_err(dev, "Unable to create gpio_chip\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/* DT parsing section */
 static int max96712_parse_rx_ports(struct max96712_priv *priv, struct device_node *node,
 				   struct of_endpoint *ep)
 {
@@ -1061,6 +1197,10 @@ static int max96712_probe(struct i2c_client *client)
 
 	max96712_mipi_configure(priv);
 
+	ret = max96712_gpiochip_probe(priv);
+	if (ret)
+		return ret;
+
 	ret = max96712_v4l2_register(priv);
 	if (ret)
 		return ret;
-- 
2.44.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ