diff options
Diffstat (limited to 'sound/soc/codecs/adau1701.c')
-rw-r--r-- | sound/soc/codecs/adau1701.c | 126 |
1 files changed, 110 insertions, 16 deletions
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index d4e219b6b98f..ff7f846e3b76 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> @@ -101,6 +102,10 @@ #define ADAU1701_FIRMWARE "adau1701.bin" +static const char * const supply_names[] = { + "dvdd", "avdd" +}; + struct adau1701 { int gpio_nreset; int gpio_pll_mode[2]; @@ -112,6 +117,7 @@ struct adau1701 { u8 pin_config[12]; struct sigmadsp *sigmadsp; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; }; static const struct snd_kcontrol_new adau1701_controls[] = { @@ -565,7 +571,6 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec, break; } - codec->dapm.bias_level = level; return 0; } @@ -669,6 +674,13 @@ static int adau1701_probe(struct snd_soc_codec *codec) if (ret) return ret; + ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), + adau1701->supplies); + if (ret < 0) { + dev_err(codec->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + /* * Let the pll_clkdiv variable default to something that won't happen * at runtime. That way, we can postpone the firmware download from @@ -680,7 +692,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) /* initalize with pre-configured pll mode settings */ ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); if (ret < 0) - return ret; + goto exit_regulators_disable; /* set up pin config */ val = 0; @@ -696,10 +708,60 @@ static int adau1701_probe(struct snd_soc_codec *codec) regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); return 0; + +exit_regulators_disable: + + regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); + return ret; } +static int adau1701_remove(struct snd_soc_codec *codec) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(adau1701->gpio_nreset)) + gpio_set_value_cansleep(adau1701->gpio_nreset, 0); + + regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); + + return 0; +} + +#ifdef CONFIG_PM +static int adau1701_suspend(struct snd_soc_codec *codec) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + + regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), + adau1701->supplies); + + return 0; +} + +static int adau1701_resume(struct snd_soc_codec *codec) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), + adau1701->supplies); + if (ret < 0) { + dev_err(codec->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + return adau1701_reset(codec, adau1701->pll_clkdiv, 0); +} +#else +#define adau1701_resume NULL +#define adau1701_suspend NULL +#endif /* CONFIG_PM */ + static struct snd_soc_codec_driver adau1701_codec_drv = { .probe = adau1701_probe, + .remove = adau1701_remove, + .resume = adau1701_resume, + .suspend = adau1701_suspend, .set_bias_level = adau1701_set_bias_level, .idle_bias_off = true, @@ -730,32 +792,58 @@ static int adau1701_i2c_probe(struct i2c_client *client, struct device *dev = &client->dev; int gpio_nreset = -EINVAL; int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; - int ret; + int ret, i; adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); if (!adau1701) return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + adau1701->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies), + adau1701->supplies); + if (ret < 0) { + dev_err(dev, "Failed to get regulators: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies), + adau1701->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + adau1701->client = client; adau1701->regmap = devm_regmap_init(dev, NULL, client, &adau1701_regmap); - if (IS_ERR(adau1701->regmap)) - return PTR_ERR(adau1701->regmap); + if (IS_ERR(adau1701->regmap)) { + ret = PTR_ERR(adau1701->regmap); + goto exit_regulators_disable; + } + if (dev->of_node) { gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); - if (gpio_nreset < 0 && gpio_nreset != -ENOENT) - return gpio_nreset; + if (gpio_nreset < 0 && gpio_nreset != -ENOENT) { + ret = gpio_nreset; + goto exit_regulators_disable; + } gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, "adi,pll-mode-gpios", 0); - if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) - return gpio_pll_mode[0]; + if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) { + ret = gpio_pll_mode[0]; + goto exit_regulators_disable; + } gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, "adi,pll-mode-gpios", 1); - if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) - return gpio_pll_mode[1]; + if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) { + ret = gpio_pll_mode[1]; + goto exit_regulators_disable; + } of_property_read_u32(dev->of_node, "adi,pll-clkdiv", &adau1701->pll_clkdiv); @@ -769,7 +857,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, "ADAU1701 Reset"); if (ret < 0) - return ret; + goto exit_regulators_disable; } if (gpio_is_valid(gpio_pll_mode[0]) && @@ -778,13 +866,13 @@ static int adau1701_i2c_probe(struct i2c_client *client, GPIOF_OUT_INIT_LOW, "ADAU1701 PLL mode 0"); if (ret < 0) - return ret; + goto exit_regulators_disable; ret = devm_gpio_request_one(dev, gpio_pll_mode[1], GPIOF_OUT_INIT_LOW, "ADAU1701 PLL mode 1"); if (ret < 0) - return ret; + goto exit_regulators_disable; } adau1701->gpio_nreset = gpio_nreset; @@ -795,11 +883,17 @@ static int adau1701_i2c_probe(struct i2c_client *client, adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); - if (IS_ERR(adau1701->sigmadsp)) - return PTR_ERR(adau1701->sigmadsp); + if (IS_ERR(adau1701->sigmadsp)) { + ret = PTR_ERR(adau1701->sigmadsp); + goto exit_regulators_disable; + } ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, &adau1701_dai, 1); + +exit_regulators_disable: + + regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies); return ret; } |