summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/pcm3168a.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2019-11-13 15:47:34 +0300
committerMark Brown <broonie@kernel.org>2019-11-18 16:09:22 +0300
commit79f6c108c87b470aacf25fc25a86f48694d03ae8 (patch)
tree777a8765ae31c63aab7de14c5a97538c4e883f30 /sound/soc/codecs/pcm3168a.c
parentcdacc761dae1cbd6475ac79f0e732f2b1ca021e0 (diff)
downloadlinux-79f6c108c87b470aacf25fc25a86f48694d03ae8.tar.xz
ASoC: pcm3168a: Add support for optional RST gpio handling
In case the RST line is connected to a GPIO line it needs to be pulled high when the driver probes to be able to use the codec. Add support also for cases when more than one codec is is controlled by the same GPIO line by requesting the gpio with GPIOD_FLAGS_BIT_NONEXCLUSIVE. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Link: https://lore.kernel.org/r/20191113124734.27984-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/pcm3168a.c')
-rw-r--r--sound/soc/codecs/pcm3168a.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 313500ab36df..f3475134b519 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -9,7 +9,9 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -59,6 +61,7 @@ struct pcm3168a_priv {
struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES];
struct regmap *regmap;
struct clk *scki;
+ struct gpio_desc *gpio_rst;
unsigned long sysclk;
struct pcm3168a_io_params io_params[2];
@@ -643,6 +646,7 @@ static bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case PCM3168A_RST_SMODE:
case PCM3168A_DAC_ZERO:
case PCM3168A_ADC_OV:
return true;
@@ -702,6 +706,21 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
dev_set_drvdata(dev, pcm3168a);
+ /*
+ * Request the RST gpio line as non exclusive as the same reset line
+ * might be connected to multiple pcm3168a codec
+ */
+ pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "rst",
+ GPIOD_OUT_HIGH |
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ if (IS_ERR(pcm3168a->gpio_rst)) {
+ ret = PTR_ERR(pcm3168a->gpio_rst);
+ if (ret != -EPROBE_DEFER )
+ dev_err(dev, "failed to acquire RST gpio: %d\n", ret);
+
+ return ret;
+ }
+
pcm3168a->scki = devm_clk_get(dev, "scki");
if (IS_ERR(pcm3168a->scki)) {
ret = PTR_ERR(pcm3168a->scki);
@@ -743,10 +762,18 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
goto err_regulator;
}
- ret = pcm3168a_reset(pcm3168a);
- if (ret) {
- dev_err(dev, "Failed to reset device: %d\n", ret);
- goto err_regulator;
+ if (pcm3168a->gpio_rst) {
+ /*
+ * The device is taken out from reset via GPIO line, wait for
+ * 3846 SCKI clock cycles for the internal reset de-assertion
+ */
+ msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
+ } else {
+ ret = pcm3168a_reset(pcm3168a);
+ if (ret) {
+ dev_err(dev, "Failed to reset device: %d\n", ret);
+ goto err_regulator;
+ }
}
pm_runtime_set_active(dev);
@@ -785,6 +812,9 @@ static void pcm3168a_disable(struct device *dev)
void pcm3168a_remove(struct device *dev)
{
+ struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
+
+ gpiod_set_value_cansleep(pcm3168a->gpio_rst, 0);
pm_runtime_disable(dev);
#ifndef CONFIG_PM
pcm3168a_disable(dev);