From b3bbef45e97526e8c56fd542d75e505776eecc01 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 20 Mar 2017 10:13:52 +0100 Subject: ASoC: wm8903: add regulator handling The WM8903 has four different voltage inputs: AVDD, CPVDD, DBVDD and DCVDD. On the Qualcomm APQ8060 Dragonboard these are all supplied from proper regulators and thus need activating and binding. This is a quick-and-dirty solution just grabbing and enabling the regulator supplies on probe() and disabling them on remove() and the errorpath. More elaborate power management is likely possible. I assume the nVidia designs using this codec have some hard-wired always-on power and will be happy with using the dummy regulators for this. But someone from the nVidia camp should probably check whether they can bind these to proper regulators instead. We also amend the DT binding document. A small change like this does not warrant a separate patch for augmenting these. Cc: devicetree@vger.kernel.org Cc: Mark Brown Cc: Liam Girdwood Cc: Stephen Warren Cc: Charles Keepax Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 6e887c2c42b1..237eeb9a8b97 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -115,10 +116,19 @@ static const struct reg_default wm8903_reg_defaults[] = { { 172, 0x0000 }, /* R172 - Analogue Output Bias 0 */ }; +#define WM8903_NUM_SUPPLIES 4 +static const char *wm8903_supply_names[WM8903_NUM_SUPPLIES] = { + "AVDD", + "CPVDD", + "DBVDD", + "DCVDD", +}; + struct wm8903_priv { struct wm8903_platform_data *pdata; struct device *dev; struct regmap *regmap; + struct regulator_bulk_data supplies[WM8903_NUM_SUPPLIES]; int sysclk; int irq; @@ -2030,6 +2040,23 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, pdata = wm8903->pdata; + for (i = 0; i < ARRAY_SIZE(wm8903->supplies); i++) + wm8903->supplies[i].supply = wm8903_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); if (ret != 0) { dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); @@ -2160,6 +2187,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, return 0; err: + regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); return ret; } @@ -2167,6 +2196,8 @@ static int wm8903_i2c_remove(struct i2c_client *client) { struct wm8903_priv *wm8903 = i2c_get_clientdata(client); + regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); if (client->irq) free_irq(client->irq, wm8903); wm8903_free_gpio(wm8903); -- cgit