diff options
author | Ilkka Koskinen <ilkka.koskinen@nokia.com> | 2009-12-09 05:05:50 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-12-16 12:31:04 -0500 |
commit | 7c4e6492205b677a5786b85bcf72ce7c8f4adf15 (patch) | |
tree | 80c318cd3a918f408f86843937505bc3af1b8fe9 | |
parent | 0fe692292a26f57b6522fe859cc8b2549ec0cd97 (diff) |
ASoC: tpa6130a2: Add support for regulator framework
Take the regulator framework in use for managing the power sources
Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Eduardo Valentin <eduardo.valentin@nokia.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/tpa6130a2.c | 87 |
1 files changed, 70 insertions, 17 deletions
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6b650c1aa3d1..0eb33d49942e 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/regulator/consumer.h> | ||
28 | #include <sound/tpa6130a2-plat.h> | 29 | #include <sound/tpa6130a2-plat.h> |
29 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
30 | #include <sound/soc-dapm.h> | 31 | #include <sound/soc-dapm.h> |
@@ -34,10 +35,17 @@ | |||
34 | 35 | ||
35 | static struct i2c_client *tpa6130a2_client; | 36 | static struct i2c_client *tpa6130a2_client; |
36 | 37 | ||
38 | #define TPA6130A2_NUM_SUPPLIES 2 | ||
39 | static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = { | ||
40 | "CPVSS", | ||
41 | "Vdd", | ||
42 | }; | ||
43 | |||
37 | /* This struct is used to save the context */ | 44 | /* This struct is used to save the context */ |
38 | struct tpa6130a2_data { | 45 | struct tpa6130a2_data { |
39 | struct mutex mutex; | 46 | struct mutex mutex; |
40 | unsigned char regs[TPA6130A2_CACHEREGNUM]; | 47 | unsigned char regs[TPA6130A2_CACHEREGNUM]; |
48 | struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; | ||
41 | int power_gpio; | 49 | int power_gpio; |
42 | unsigned char power_state; | 50 | unsigned char power_state; |
43 | }; | 51 | }; |
@@ -106,10 +114,11 @@ static void tpa6130a2_initialize(void) | |||
106 | tpa6130a2_i2c_write(i, data->regs[i]); | 114 | tpa6130a2_i2c_write(i, data->regs[i]); |
107 | } | 115 | } |
108 | 116 | ||
109 | static void tpa6130a2_power(int power) | 117 | static int tpa6130a2_power(int power) |
110 | { | 118 | { |
111 | struct tpa6130a2_data *data; | 119 | struct tpa6130a2_data *data; |
112 | u8 val; | 120 | u8 val; |
121 | int ret; | ||
113 | 122 | ||
114 | BUG_ON(tpa6130a2_client == NULL); | 123 | BUG_ON(tpa6130a2_client == NULL); |
115 | data = i2c_get_clientdata(tpa6130a2_client); | 124 | data = i2c_get_clientdata(tpa6130a2_client); |
@@ -117,11 +126,20 @@ static void tpa6130a2_power(int power) | |||
117 | mutex_lock(&data->mutex); | 126 | mutex_lock(&data->mutex); |
118 | if (power) { | 127 | if (power) { |
119 | /* Power on */ | 128 | /* Power on */ |
120 | if (data->power_gpio >= 0) { | 129 | if (data->power_gpio >= 0) |
121 | gpio_set_value(data->power_gpio, 1); | 130 | gpio_set_value(data->power_gpio, 1); |
122 | data->power_state = 1; | 131 | |
123 | tpa6130a2_initialize(); | 132 | ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), |
133 | data->supplies); | ||
134 | if (ret != 0) { | ||
135 | dev_err(&tpa6130a2_client->dev, | ||
136 | "Failed to enable supplies: %d\n", ret); | ||
137 | goto exit; | ||
124 | } | 138 | } |
139 | |||
140 | data->power_state = 1; | ||
141 | tpa6130a2_initialize(); | ||
142 | |||
125 | /* Clear SWS */ | 143 | /* Clear SWS */ |
126 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | 144 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); |
127 | val &= ~TPA6130A2_SWS; | 145 | val &= ~TPA6130A2_SWS; |
@@ -131,13 +149,25 @@ static void tpa6130a2_power(int power) | |||
131 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | 149 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); |
132 | val |= TPA6130A2_SWS; | 150 | val |= TPA6130A2_SWS; |
133 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); | 151 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); |
152 | |||
134 | /* Power off */ | 153 | /* Power off */ |
135 | if (data->power_gpio >= 0) { | 154 | if (data->power_gpio >= 0) |
136 | gpio_set_value(data->power_gpio, 0); | 155 | gpio_set_value(data->power_gpio, 0); |
137 | data->power_state = 0; | 156 | |
157 | ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies), | ||
158 | data->supplies); | ||
159 | if (ret != 0) { | ||
160 | dev_err(&tpa6130a2_client->dev, | ||
161 | "Failed to disable supplies: %d\n", ret); | ||
162 | goto exit; | ||
138 | } | 163 | } |
164 | |||
165 | data->power_state = 0; | ||
139 | } | 166 | } |
167 | |||
168 | exit: | ||
140 | mutex_unlock(&data->mutex); | 169 | mutex_unlock(&data->mutex); |
170 | return ret; | ||
141 | } | 171 | } |
142 | 172 | ||
143 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, | 173 | static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, |
@@ -299,15 +329,17 @@ static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w, | |||
299 | static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, | 329 | static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, |
300 | struct snd_kcontrol *kcontrol, int event) | 330 | struct snd_kcontrol *kcontrol, int event) |
301 | { | 331 | { |
332 | int ret = 0; | ||
333 | |||
302 | switch (event) { | 334 | switch (event) { |
303 | case SND_SOC_DAPM_POST_PMU: | 335 | case SND_SOC_DAPM_POST_PMU: |
304 | tpa6130a2_power(1); | 336 | ret = tpa6130a2_power(1); |
305 | break; | 337 | break; |
306 | case SND_SOC_DAPM_POST_PMD: | 338 | case SND_SOC_DAPM_POST_PMD: |
307 | tpa6130a2_power(0); | 339 | ret = tpa6130a2_power(0); |
308 | break; | 340 | break; |
309 | } | 341 | } |
310 | return 0; | 342 | return ret; |
311 | } | 343 | } |
312 | 344 | ||
313 | static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { | 345 | static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { |
@@ -352,7 +384,7 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
352 | struct device *dev; | 384 | struct device *dev; |
353 | struct tpa6130a2_data *data; | 385 | struct tpa6130a2_data *data; |
354 | struct tpa6130a2_platform_data *pdata; | 386 | struct tpa6130a2_platform_data *pdata; |
355 | int ret; | 387 | int i, ret; |
356 | 388 | ||
357 | dev = &client->dev; | 389 | dev = &client->dev; |
358 | 390 | ||
@@ -387,15 +419,25 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
387 | if (ret < 0) { | 419 | if (ret < 0) { |
388 | dev_err(dev, "Failed to request power GPIO (%d)\n", | 420 | dev_err(dev, "Failed to request power GPIO (%d)\n", |
389 | data->power_gpio); | 421 | data->power_gpio); |
390 | goto fail; | 422 | goto err_gpio; |
391 | } | 423 | } |
392 | gpio_direction_output(data->power_gpio, 0); | 424 | gpio_direction_output(data->power_gpio, 0); |
393 | } else { | ||
394 | data->power_state = 1; | ||
395 | tpa6130a2_initialize(); | ||
396 | } | 425 | } |
397 | 426 | ||
398 | tpa6130a2_power(1); | 427 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) |
428 | data->supplies[i].supply = tpa6130a2_supply_names[i]; | ||
429 | |||
430 | ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | ||
431 | data->supplies); | ||
432 | if (ret != 0) { | ||
433 | dev_err(dev, "Failed to request supplies: %d\n", ret); | ||
434 | goto err_regulator; | ||
435 | } | ||
436 | |||
437 | ret = tpa6130a2_power(1); | ||
438 | if (ret != 0) | ||
439 | goto err_power; | ||
440 | |||
399 | 441 | ||
400 | /* Read version */ | 442 | /* Read version */ |
401 | ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & | 443 | ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & |
@@ -404,10 +446,18 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
404 | dev_warn(dev, "UNTESTED version detected (%d)\n", ret); | 446 | dev_warn(dev, "UNTESTED version detected (%d)\n", ret); |
405 | 447 | ||
406 | /* Disable the chip */ | 448 | /* Disable the chip */ |
407 | tpa6130a2_power(0); | 449 | ret = tpa6130a2_power(0); |
450 | if (ret != 0) | ||
451 | goto err_power; | ||
408 | 452 | ||
409 | return 0; | 453 | return 0; |
410 | fail: | 454 | |
455 | err_power: | ||
456 | regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); | ||
457 | err_regulator: | ||
458 | if (data->power_gpio >= 0) | ||
459 | gpio_free(data->power_gpio); | ||
460 | err_gpio: | ||
411 | kfree(data); | 461 | kfree(data); |
412 | i2c_set_clientdata(tpa6130a2_client, NULL); | 462 | i2c_set_clientdata(tpa6130a2_client, NULL); |
413 | tpa6130a2_client = NULL; | 463 | tpa6130a2_client = NULL; |
@@ -423,6 +473,9 @@ static int tpa6130a2_remove(struct i2c_client *client) | |||
423 | 473 | ||
424 | if (data->power_gpio >= 0) | 474 | if (data->power_gpio >= 0) |
425 | gpio_free(data->power_gpio); | 475 | gpio_free(data->power_gpio); |
476 | |||
477 | regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies); | ||
478 | |||
426 | kfree(data); | 479 | kfree(data); |
427 | tpa6130a2_client = NULL; | 480 | tpa6130a2_client = NULL; |
428 | 481 | ||