diff options
Diffstat (limited to 'sound/soc/codecs/pcm3168a.c')
-rw-r--r-- | sound/soc/codecs/pcm3168a.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 313500ab36df..9711fab296eb 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,25 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, pcm3168a); + /* + * Request the reset (connected to RST pin) gpio line as non exclusive + * as the same reset line might be connected to multiple pcm3168a codec + * + * The RST is low active, we want the GPIO line to be high initially, so + * request the initial level to LOW which in practice means DEASSERTED: + * The deasserted level of GPIO_ACTIVE_LOW is HIGH. + */ + pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW | + 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 +766,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 +816,15 @@ static void pcm3168a_disable(struct device *dev) void pcm3168a_remove(struct device *dev) { + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + /* + * The RST is low active, we want the GPIO line to be low when the + * driver is removed, so set level to 1 which in practice means + * ASSERTED: + * The asserted level of GPIO_ACTIVE_LOW is LOW. + */ + gpiod_set_value_cansleep(pcm3168a->gpio_rst, 1); pm_runtime_disable(dev); #ifndef CONFIG_PM pcm3168a_disable(dev); |