All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
To: Geert Uytterhoeven <geert+renesas@glider.be>,
	Magnus Damm <magnus.damm@gmail.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Kieran Bingham <kieran.bingham@ideasonboard.com>,
	Rob Herring <robh+dt@kernel.org>
Cc: Jacopo Mondi <jacopo+renesas@jmondi.org>,
	linux-renesas-soc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH v4 3/7] media: i2c: max9286: Use "maxim,gpio-poc" property
Date: Thu, 15 Apr 2021 14:25:58 +0200	[thread overview]
Message-ID: <20210415122602.87697-4-jacopo+renesas@jmondi.org> (raw)
In-Reply-To: <20210415122602.87697-1-jacopo+renesas@jmondi.org>

The 'maxim,gpio-poc' property is used when the remote camera
power-over-coax is controlled by one of the MAX9286 gpio lines,
to instruct the driver about which line to use and what the line
polarity is.

Add to the max9286 driver support for parsing the newly introduced
property and use it if available in place of the usual supply, as it is
not possible to establish one as consumer of the max9286 gpio
controller.

If the new property is present, no gpio controller is registered and
'poc-supply' is ignored.

In order to maximize code re-use, break out the max9286 gpio handling
function so that they can be used by the gpio controller through the
gpio-consumer API, or directly by the driver code.

Wrap the power up and power down routines to their own function to
be able to use either the gpio line directly or the supply. This will
make it easier to control the remote camera power at run time.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 drivers/media/i2c/max9286.c | 119 ++++++++++++++++++++++++++++--------
 1 file changed, 93 insertions(+), 26 deletions(-)

diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 6fd4d59fcc72..a8b37783d2ef 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -15,6 +15,7 @@
 #include <linux/fwnode.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/module.h>
@@ -165,6 +166,9 @@ struct max9286_priv {
 
 	u32 reverse_channel_mv;
 
+	u32 gpio_poc;
+	u32 gpio_poc_flags;
+
 	struct v4l2_ctrl_handler ctrls;
 	struct v4l2_ctrl *pixelrate;
 
@@ -1022,8 +1026,19 @@ static int max9286_setup(struct max9286_priv *priv)
 	return 0;
 }
 
-static void max9286_gpio_set(struct gpio_chip *chip,
-			     unsigned int offset, int value)
+static int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset,
+			    int value)
+{
+	int ret = max9286_read(priv, 0x0f);
+	if (ret < 0)
+		return ret;
+
+	ret = value ? (ret & 0x3) | BIT(offset) : (ret & 0x3) & ~BIT(offset);
+	return max9286_write(priv, 0x0f, MAX9286_0X0F_RESERVED | ret);
+}
+
+static void max9286_gpiochip_set(struct gpio_chip *chip,
+				 unsigned int offset, int value)
 {
 	struct max9286_priv *priv = gpiochip_get_data(chip);
 
@@ -1035,7 +1050,7 @@ static void max9286_gpio_set(struct gpio_chip *chip,
 	max9286_write(priv, 0x0f, MAX9286_0X0F_RESERVED | priv->gpio_state);
 }
 
-static int max9286_gpio_get(struct gpio_chip *chip, unsigned int offset)
+static int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset)
 {
 	struct max9286_priv *priv = gpiochip_get_data(chip);
 
@@ -1055,8 +1070,8 @@ static int max9286_register_gpio(struct max9286_priv *priv)
 	gpio->of_node = dev->of_node;
 	gpio->ngpio = 2;
 	gpio->base = -1;
-	gpio->set = max9286_gpio_set;
-	gpio->get = max9286_gpio_get;
+	gpio->set = max9286_gpiochip_set;
+	gpio->get = max9286_gpiochip_get;
 	gpio->can_sleep = true;
 
 	/* GPIO values default to high */
@@ -1069,6 +1084,71 @@ static int max9286_register_gpio(struct max9286_priv *priv)
 	return ret;
 }
 
+static int max9286_parse_gpios(struct max9286_priv *priv)
+{
+	struct device *dev = &priv->client->dev;
+	u32 gpio_poc[2];
+	int ret;
+
+	/*
+	 * Parse the "gpio-poc" vendor property. If the camera power is
+	 * controlled by one of the MAX9286 gpio lines, do not register
+	 * the gpio controller and ignore 'poc-supply'.
+	 */
+	ret = of_property_read_u32_array(dev->of_node,
+					 "maxim,gpio-poc", gpio_poc, 2);
+	if (!ret) {
+		priv->gpio_poc = gpio_poc[0];
+		priv->gpio_poc_flags = gpio_poc[1];
+		if (priv->gpio_poc > 1 ||
+		    (priv->gpio_poc_flags != GPIO_ACTIVE_HIGH &&
+		     priv->gpio_poc_flags != GPIO_ACTIVE_LOW)) {
+			dev_err(dev, "Invalid 'gpio-poc': (%u %u)\n",
+				priv->gpio_poc, priv->gpio_poc_flags);
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	ret = max9286_register_gpio(priv);
+	if (ret)
+		return ret;
+
+	priv->regulator = devm_regulator_get(dev, "poc");
+	if (IS_ERR(priv->regulator)) {
+		if (PTR_ERR(priv->regulator) != -EPROBE_DEFER)
+			dev_err(dev, "Unable to get PoC regulator (%ld)\n",
+				PTR_ERR(priv->regulator));
+		return PTR_ERR(priv->regulator);
+	}
+
+	return 0;
+}
+
+static int max9286_poc_enable(struct max9286_priv *priv, bool enable)
+{
+	int ret;
+
+	/* If "poc-gpio" is used, toggle the line and do not use regulator. */
+	if (enable)
+		ret = priv->regulator
+		    ? regulator_enable(priv->regulator)
+		    : max9286_gpio_set(priv, priv->gpio_poc,
+				       enable ^ priv->gpio_poc_flags);
+	else
+		ret = priv->regulator
+		    ? regulator_disable(priv->regulator)
+		    : max9286_gpio_set(priv, priv->gpio_poc,
+				       enable ^ priv->gpio_poc_flags);
+
+	if (ret < 0)
+		dev_err(&priv->client->dev, "Unable to turn PoC %s\n",
+			enable ? "on" : "off");
+
+	return ret;
+}
+
 static int max9286_init(struct device *dev)
 {
 	struct max9286_priv *priv;
@@ -1078,17 +1158,14 @@ static int max9286_init(struct device *dev)
 	client = to_i2c_client(dev);
 	priv = i2c_get_clientdata(client);
 
-	/* Enable the bus power. */
-	ret = regulator_enable(priv->regulator);
-	if (ret < 0) {
-		dev_err(&client->dev, "Unable to turn PoC on\n");
+	ret = max9286_poc_enable(priv, true);
+	if (ret)
 		return ret;
-	}
 
 	ret = max9286_setup(priv);
 	if (ret) {
 		dev_err(dev, "Unable to setup max9286\n");
-		goto err_regulator;
+		goto err_poc_disable;
 	}
 
 	/*
@@ -1098,7 +1175,7 @@ static int max9286_init(struct device *dev)
 	ret = max9286_v4l2_register(priv);
 	if (ret) {
 		dev_err(dev, "Failed to register with V4L2\n");
-		goto err_regulator;
+		goto err_poc_disable;
 	}
 
 	ret = max9286_i2c_mux_init(priv);
@@ -1114,8 +1191,8 @@ static int max9286_init(struct device *dev)
 
 err_v4l2_register:
 	max9286_v4l2_unregister(priv);
-err_regulator:
-	regulator_disable(priv->regulator);
+err_poc_disable:
+	max9286_poc_enable(priv, false);
 
 	return ret;
 }
@@ -1286,20 +1363,10 @@ static int max9286_probe(struct i2c_client *client)
 	 */
 	max9286_configure_i2c(priv, false);
 
-	ret = max9286_register_gpio(priv);
+	ret = max9286_parse_gpios(priv);
 	if (ret)
 		goto err_powerdown;
 
-	priv->regulator = devm_regulator_get(&client->dev, "poc");
-	if (IS_ERR(priv->regulator)) {
-		if (PTR_ERR(priv->regulator) != -EPROBE_DEFER)
-			dev_err(&client->dev,
-				"Unable to get PoC regulator (%ld)\n",
-				PTR_ERR(priv->regulator));
-		ret = PTR_ERR(priv->regulator);
-		goto err_powerdown;
-	}
-
 	ret = max9286_parse_dt(priv);
 	if (ret)
 		goto err_powerdown;
@@ -1326,7 +1393,7 @@ static int max9286_remove(struct i2c_client *client)
 
 	max9286_v4l2_unregister(priv);
 
-	regulator_disable(priv->regulator);
+	max9286_poc_enable(priv, false);
 
 	gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
 
-- 
2.31.1


  parent reply	other threads:[~2021-04-15 12:25 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-15 12:25 [PATCH v4 0/7] arm64: dts: renesas: Enable GMSL on R8A77970 V3M Eagle Jacopo Mondi
2021-04-15 12:25 ` [PATCH v4 1/7] dt-bindings: media: max9286: Re-indent example Jacopo Mondi
2021-04-15 14:42   ` Laurent Pinchart
2021-04-15 16:40   ` Rob Herring
2021-04-15 12:25 ` [PATCH v4 2/7] dt-bindings: media: max9286: Define 'maxim,gpio-poc' Jacopo Mondi
2021-04-15 16:53   ` Rob Herring
2021-04-15 12:25 ` Jacopo Mondi [this message]
2021-04-15 19:19   ` [PATCH v4 3/7] media: i2c: max9286: Use "maxim,gpio-poc" property Laurent Pinchart
2021-04-18 15:01     ` Jacopo Mondi
2021-04-15 12:25 ` [PATCH v4 4/7] arm64: dts: renesas: r8a77970: Add csi40 port@0 Jacopo Mondi
2021-04-15 14:47   ` Laurent Pinchart
2021-04-15 16:47     ` Geert Uytterhoeven
2021-04-15 19:09       ` Laurent Pinchart
2021-04-15 12:26 ` [PATCH v4 5/7] arm64: dts: renesas: eagle: Enable MAX9286 Jacopo Mondi
2021-04-15 12:26 ` [PATCH v4 6/7] arm64: dts: renesas: eagle: Add GMSL .dtsi Jacopo Mondi
2021-04-15 12:26 ` [PATCH v4 7/7] DNI: arm64: dts: renesas: eagle: Include eagle-gmsl Jacopo Mondi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210415122602.87697-4-jacopo+renesas@jmondi.org \
    --to=jacopo+renesas@jmondi.org \
    --cc=devicetree@vger.kernel.org \
    --cc=geert+renesas@glider.be \
    --cc=kieran.bingham@ideasonboard.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-renesas-soc@vger.kernel.org \
    --cc=magnus.damm@gmail.com \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.