All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Tony Lindgren <tony@atomide.com>, Mark Brown <broonie@kernel.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>,
	linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 3/3] ASoC: tlv320aic3x: switch to using gpiod API
Date: Wed,  2 Nov 2022 16:20:04 -0700	[thread overview]
Message-ID: <20221102232004.1721864-3-dmitry.torokhov@gmail.com> (raw)
In-Reply-To: <20221102232004.1721864-1-dmitry.torokhov@gmail.com>

Switch the driver from legacy gpio API that is deprecated to the newer
gpiod API that respects line polarities described in ACPI/DT.

The driver still tries to support shared reset lines, by first trying to
allocate the reset GPIO normally, and then non-exclusively, although the
utility of such support is questionable, toggling reset line from one
driver/instance will result in all chips being reset, potentially at an
inopportune moment.

Note that this change depends on commit fbbbcd177a27 ("gpiolib: of: add
quirk for locating reset lines with legacy bindings") to translate
request for "reset" GPIO to the legacy name "gpio-reset" in case when
proper name is not used.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 sound/soc/codecs/tlv320aic3x.c | 108 ++++++++++++---------------------
 1 file changed, 39 insertions(+), 69 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 9b2bb99cc165..56e795a00e22 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -32,12 +32,12 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -56,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
 	"DRVDD",	/* ADC Analog and Output Driver Voltage */
 };
 
-static LIST_HEAD(reset_list);
-
 struct aic3x_priv;
 
 struct aic3x_disable_nb {
@@ -80,9 +78,9 @@ struct aic3x_priv {
 	unsigned int dai_fmt;
 	unsigned int tdm_delay;
 	unsigned int slot_width;
-	struct list_head list;
 	int master;
-	int gpio_reset;
+	struct gpio_desc *gpio_reset;
+	bool shared_reset;
 	int power;
 	u16 model;
 
@@ -1369,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb,
 		 * Put codec to reset and require cache sync as at least one
 		 * of the supplies was disabled
 		 */
-		if (gpio_is_valid(aic3x->gpio_reset))
-			gpio_set_value(aic3x->gpio_reset, 0);
+		if (aic3x->gpio_reset)
+			gpiod_set_value(aic3x->gpio_reset, 1);
 		regcache_mark_dirty(aic3x->regmap);
 	}
 
@@ -1390,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
 			goto out;
 		aic3x->power = 1;
 
-		if (gpio_is_valid(aic3x->gpio_reset)) {
+		if (aic3x->gpio_reset) {
 			udelay(1);
-			gpio_set_value(aic3x->gpio_reset, 1);
+			gpiod_set_value(aic3x->gpio_reset, 0);
 		}
 
 		/* Sync reg_cache with the hardware */
@@ -1598,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component)
 	return 0;
 }
 
-static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
-{
-	struct aic3x_priv *a;
-
-	list_for_each_entry(a, &reset_list, list) {
-		if (gpio_is_valid(aic3x->gpio_reset) &&
-		    aic3x->gpio_reset == a->gpio_reset)
-			return true;
-	}
-
-	return false;
-}
-
 static int aic3x_component_probe(struct snd_soc_component *component)
 {
 	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
@@ -1775,19 +1760,6 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		if (!ai3x_setup)
 			return -ENOMEM;
 
-		ret = of_get_named_gpio(np, "reset-gpios", 0);
-		if (ret >= 0) {
-			aic3x->gpio_reset = ret;
-		} else {
-			ret = of_get_named_gpio(np, "gpio-reset", 0);
-			if (ret > 0) {
-				dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
-				aic3x->gpio_reset = ret;
-			} else {
-				aic3x->gpio_reset = -1;
-			}
-		}
-
 		if (of_property_read_u32_array(np, "ai3x-gpio-func",
 					ai3x_setup->gpio_func, 2) >= 0) {
 			aic3x->setup = ai3x_setup;
@@ -1812,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		} else {
 			aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
 		}
-
-	} else {
-		aic3x->gpio_reset = -1;
 	}
 
 	aic3x->model = driver_data;
 
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x)) {
-		ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
-		if (ret != 0)
-			goto err;
-		gpio_direction_output(aic3x->gpio_reset, 0);
+	aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
+						    GPIOD_OUT_HIGH);
+	ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+	if (ret) {
+		if (ret != -EBUSY)
+			return ret;
+
+		/*
+		 * Apparently there are setups where the codec is sharing
+		 * its reset line. Try to get it non-exclusively, although
+		 * the utility of this is unclear: how do we make sure that
+		 * resetting one chip will not disturb the others that share
+		 * the same line?
+		 */
+		aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
+				GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+		ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+		if (ret)
+			return ret;
+
+		aic3x->shared_reset = true;
 	}
 
+	gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
+
 	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
 		aic3x->supplies[i].supply = aic3x_supply_names[i];
 
 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
 				      aic3x->supplies);
-	if (ret != 0) {
+	if (ret) {
 		dev_err(dev, "Failed to request supplies: %d\n", ret);
-		goto err_gpio;
+		return ret;
 	}
 
 	aic3x_configure_ocmv(dev, aic3x);
@@ -1843,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
 					    ARRAY_SIZE(aic3007_class_d));
 		if (ret != 0)
-			dev_err(dev, "Failed to init class D: %d\n",
-				ret);
+			dev_err(dev, "Failed to init class D: %d\n", ret);
 	}
 
 	ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
-
-	if (ret != 0)
-		goto err_gpio;
-
-	INIT_LIST_HEAD(&aic3x->list);
-	list_add(&aic3x->list, &reset_list);
+	if (ret)
+		return ret;
 
 	return 0;
-
-err_gpio:
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x))
-		gpio_free(aic3x->gpio_reset);
-err:
-	return ret;
 }
 EXPORT_SYMBOL(aic3x_probe);
 
@@ -1870,13 +1844,9 @@ void aic3x_remove(struct device *dev)
 {
 	struct aic3x_priv *aic3x = dev_get_drvdata(dev);
 
-	list_del(&aic3x->list);
-
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x)) {
-		gpio_set_value(aic3x->gpio_reset, 0);
-		gpio_free(aic3x->gpio_reset);
-	}
+	/* Leave the codec in reset state */
+	if (aic3x->gpio_reset && !aic3x->shared_reset)
+		gpiod_set_value(aic3x->gpio_reset, 1);
 }
 EXPORT_SYMBOL(aic3x_remove);
 
-- 
2.38.1.273.g43a17bfeac-goog


WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Tony Lindgren <tony@atomide.com>, Mark Brown <broonie@kernel.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>,
	linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 3/3] ASoC: tlv320aic3x: switch to using gpiod API
Date: Wed,  2 Nov 2022 16:20:04 -0700	[thread overview]
Message-ID: <20221102232004.1721864-3-dmitry.torokhov@gmail.com> (raw)
In-Reply-To: <20221102232004.1721864-1-dmitry.torokhov@gmail.com>

Switch the driver from legacy gpio API that is deprecated to the newer
gpiod API that respects line polarities described in ACPI/DT.

The driver still tries to support shared reset lines, by first trying to
allocate the reset GPIO normally, and then non-exclusively, although the
utility of such support is questionable, toggling reset line from one
driver/instance will result in all chips being reset, potentially at an
inopportune moment.

Note that this change depends on commit fbbbcd177a27 ("gpiolib: of: add
quirk for locating reset lines with legacy bindings") to translate
request for "reset" GPIO to the legacy name "gpio-reset" in case when
proper name is not used.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 sound/soc/codecs/tlv320aic3x.c | 108 ++++++++++++---------------------
 1 file changed, 39 insertions(+), 69 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 9b2bb99cc165..56e795a00e22 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -32,12 +32,12 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -56,8 +56,6 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
 	"DRVDD",	/* ADC Analog and Output Driver Voltage */
 };
 
-static LIST_HEAD(reset_list);
-
 struct aic3x_priv;
 
 struct aic3x_disable_nb {
@@ -80,9 +78,9 @@ struct aic3x_priv {
 	unsigned int dai_fmt;
 	unsigned int tdm_delay;
 	unsigned int slot_width;
-	struct list_head list;
 	int master;
-	int gpio_reset;
+	struct gpio_desc *gpio_reset;
+	bool shared_reset;
 	int power;
 	u16 model;
 
@@ -1369,8 +1367,8 @@ static int aic3x_regulator_event(struct notifier_block *nb,
 		 * Put codec to reset and require cache sync as at least one
 		 * of the supplies was disabled
 		 */
-		if (gpio_is_valid(aic3x->gpio_reset))
-			gpio_set_value(aic3x->gpio_reset, 0);
+		if (aic3x->gpio_reset)
+			gpiod_set_value(aic3x->gpio_reset, 1);
 		regcache_mark_dirty(aic3x->regmap);
 	}
 
@@ -1390,9 +1388,9 @@ static int aic3x_set_power(struct snd_soc_component *component, int power)
 			goto out;
 		aic3x->power = 1;
 
-		if (gpio_is_valid(aic3x->gpio_reset)) {
+		if (aic3x->gpio_reset) {
 			udelay(1);
-			gpio_set_value(aic3x->gpio_reset, 1);
+			gpiod_set_value(aic3x->gpio_reset, 0);
 		}
 
 		/* Sync reg_cache with the hardware */
@@ -1598,19 +1596,6 @@ static int aic3x_init(struct snd_soc_component *component)
 	return 0;
 }
 
-static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
-{
-	struct aic3x_priv *a;
-
-	list_for_each_entry(a, &reset_list, list) {
-		if (gpio_is_valid(aic3x->gpio_reset) &&
-		    aic3x->gpio_reset == a->gpio_reset)
-			return true;
-	}
-
-	return false;
-}
-
 static int aic3x_component_probe(struct snd_soc_component *component)
 {
 	struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
@@ -1775,19 +1760,6 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		if (!ai3x_setup)
 			return -ENOMEM;
 
-		ret = of_get_named_gpio(np, "reset-gpios", 0);
-		if (ret >= 0) {
-			aic3x->gpio_reset = ret;
-		} else {
-			ret = of_get_named_gpio(np, "gpio-reset", 0);
-			if (ret > 0) {
-				dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT");
-				aic3x->gpio_reset = ret;
-			} else {
-				aic3x->gpio_reset = -1;
-			}
-		}
-
 		if (of_property_read_u32_array(np, "ai3x-gpio-func",
 					ai3x_setup->gpio_func, 2) >= 0) {
 			aic3x->setup = ai3x_setup;
@@ -1812,29 +1784,43 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		} else {
 			aic3x->micbias_vg = AIC3X_MICBIAS_OFF;
 		}
-
-	} else {
-		aic3x->gpio_reset = -1;
 	}
 
 	aic3x->model = driver_data;
 
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x)) {
-		ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
-		if (ret != 0)
-			goto err;
-		gpio_direction_output(aic3x->gpio_reset, 0);
+	aic3x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
+						    GPIOD_OUT_HIGH);
+	ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+	if (ret) {
+		if (ret != -EBUSY)
+			return ret;
+
+		/*
+		 * Apparently there are setups where the codec is sharing
+		 * its reset line. Try to get it non-exclusively, although
+		 * the utility of this is unclear: how do we make sure that
+		 * resetting one chip will not disturb the others that share
+		 * the same line?
+		 */
+		aic3x->gpio_reset = devm_gpiod_get(dev, "reset",
+				GPIOD_ASIS | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+		ret = PTR_ERR_OR_ZERO(aic3x->gpio_reset);
+		if (ret)
+			return ret;
+
+		aic3x->shared_reset = true;
 	}
 
+	gpiod_set_consumer_name(aic3x->gpio_reset, "tlv320aic3x reset");
+
 	for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
 		aic3x->supplies[i].supply = aic3x_supply_names[i];
 
 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies),
 				      aic3x->supplies);
-	if (ret != 0) {
+	if (ret) {
 		dev_err(dev, "Failed to request supplies: %d\n", ret);
-		goto err_gpio;
+		return ret;
 	}
 
 	aic3x_configure_ocmv(dev, aic3x);
@@ -1843,26 +1829,14 @@ int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver
 		ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
 					    ARRAY_SIZE(aic3007_class_d));
 		if (ret != 0)
-			dev_err(dev, "Failed to init class D: %d\n",
-				ret);
+			dev_err(dev, "Failed to init class D: %d\n", ret);
 	}
 
 	ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1);
-
-	if (ret != 0)
-		goto err_gpio;
-
-	INIT_LIST_HEAD(&aic3x->list);
-	list_add(&aic3x->list, &reset_list);
+	if (ret)
+		return ret;
 
 	return 0;
-
-err_gpio:
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x))
-		gpio_free(aic3x->gpio_reset);
-err:
-	return ret;
 }
 EXPORT_SYMBOL(aic3x_probe);
 
@@ -1870,13 +1844,9 @@ void aic3x_remove(struct device *dev)
 {
 	struct aic3x_priv *aic3x = dev_get_drvdata(dev);
 
-	list_del(&aic3x->list);
-
-	if (gpio_is_valid(aic3x->gpio_reset) &&
-	    !aic3x_is_shared_reset(aic3x)) {
-		gpio_set_value(aic3x->gpio_reset, 0);
-		gpio_free(aic3x->gpio_reset);
-	}
+	/* Leave the codec in reset state */
+	if (aic3x->gpio_reset && !aic3x->shared_reset)
+		gpiod_set_value(aic3x->gpio_reset, 1);
 }
 EXPORT_SYMBOL(aic3x_remove);
 
-- 
2.38.1.273.g43a17bfeac-goog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-11-02 23:25 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-02 23:20 [PATCH 1/3] arm: omap2: n8x0: stop instantiating codec platform data Dmitry Torokhov
2022-11-02 23:20 ` Dmitry Torokhov
2022-11-02 23:20 ` [PATCH 2/3] ASoC: tlv320aic3x: remove support for " Dmitry Torokhov
2022-11-02 23:20   ` Dmitry Torokhov
2022-11-02 23:20 ` Dmitry Torokhov [this message]
2022-11-02 23:20   ` [PATCH 3/3] ASoC: tlv320aic3x: switch to using gpiod API Dmitry Torokhov
2022-11-03 12:15 ` [PATCH 1/3] arm: omap2: n8x0: stop instantiating codec platform data Mark Brown
2022-11-03 12:15   ` Mark Brown
2022-11-03 12:46   ` Tony Lindgren
2022-11-03 12:46     ` Tony Lindgren
2022-11-03 12:45 ` Tony Lindgren
2022-11-03 12:45   ` Tony Lindgren
2022-11-03 16:35 ` Mark Brown
2022-11-03 16:35   ` Mark Brown

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=20221102232004.1721864-3-dmitry.torokhov@gmail.com \
    --to=dmitry.torokhov@gmail.com \
    --cc=broonie@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=tony@atomide.com \
    /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.