diff options
| author | Ilkka Koskinen <ilkka.koskinen@nokia.com> | 2009-12-04 06:49:10 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-12-04 07:35:08 -0500 |
| commit | 3a7aaed714bbe3c071000d720f0cce186d1897a4 (patch) | |
| tree | e817947015af4ce7cff7975153d4a140d257da8a /sound/soc/codecs/tlv320dac33.c | |
| parent | f1608cca9dd80231004e468b57a7a8eef80a9cd7 (diff) | |
ASoC: tlv320dac33: 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: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/tlv320dac33.c')
| -rw-r--r-- | sound/soc/codecs/tlv320dac33.c | 92 |
1 files changed, 79 insertions, 13 deletions
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 9c8903dbe647..5037454974b6 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
| 31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
| 32 | #include <linux/gpio.h> | 32 | #include <linux/gpio.h> |
| 33 | #include <linux/regulator/consumer.h> | ||
| 33 | #include <sound/core.h> | 34 | #include <sound/core.h> |
| 34 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
| 35 | #include <sound/pcm_params.h> | 36 | #include <sound/pcm_params.h> |
| @@ -58,11 +59,19 @@ enum dac33_state { | |||
| 58 | DAC33_FLUSH, | 59 | DAC33_FLUSH, |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 62 | #define DAC33_NUM_SUPPLIES 3 | ||
| 63 | static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = { | ||
| 64 | "AVDD", | ||
| 65 | "DVDD", | ||
| 66 | "IOVDD", | ||
| 67 | }; | ||
| 68 | |||
| 61 | struct tlv320dac33_priv { | 69 | struct tlv320dac33_priv { |
| 62 | struct mutex mutex; | 70 | struct mutex mutex; |
| 63 | struct workqueue_struct *dac33_wq; | 71 | struct workqueue_struct *dac33_wq; |
| 64 | struct work_struct work; | 72 | struct work_struct work; |
| 65 | struct snd_soc_codec codec; | 73 | struct snd_soc_codec codec; |
| 74 | struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES]; | ||
| 66 | int power_gpio; | 75 | int power_gpio; |
| 67 | int chip_power; | 76 | int chip_power; |
| 68 | int irq; | 77 | int irq; |
| @@ -297,28 +306,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) | |||
| 297 | dac33_write(codec, DAC33_PWR_CTRL, reg); | 306 | dac33_write(codec, DAC33_PWR_CTRL, reg); |
| 298 | } | 307 | } |
| 299 | 308 | ||
| 300 | static void dac33_hard_power(struct snd_soc_codec *codec, int power) | 309 | static int dac33_hard_power(struct snd_soc_codec *codec, int power) |
| 301 | { | 310 | { |
| 302 | struct tlv320dac33_priv *dac33 = codec->private_data; | 311 | struct tlv320dac33_priv *dac33 = codec->private_data; |
| 312 | int ret; | ||
| 303 | 313 | ||
| 304 | mutex_lock(&dac33->mutex); | 314 | mutex_lock(&dac33->mutex); |
| 305 | if (power) { | 315 | if (power) { |
| 306 | if (dac33->power_gpio >= 0) { | 316 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), |
| 307 | gpio_set_value(dac33->power_gpio, 1); | 317 | dac33->supplies); |
| 308 | dac33->chip_power = 1; | 318 | if (ret != 0) { |
| 309 | /* Restore registers */ | 319 | dev_err(codec->dev, |
| 310 | dac33_restore_regs(codec); | 320 | "Failed to enable supplies: %d\n", ret); |
| 321 | goto exit; | ||
| 311 | } | 322 | } |
| 323 | |||
| 324 | if (dac33->power_gpio >= 0) | ||
| 325 | gpio_set_value(dac33->power_gpio, 1); | ||
| 326 | |||
| 327 | dac33->chip_power = 1; | ||
| 328 | |||
| 329 | /* Restore registers */ | ||
| 330 | dac33_restore_regs(codec); | ||
| 331 | |||
| 312 | dac33_soft_power(codec, 1); | 332 | dac33_soft_power(codec, 1); |
| 313 | } else { | 333 | } else { |
| 314 | dac33_soft_power(codec, 0); | 334 | dac33_soft_power(codec, 0); |
| 315 | if (dac33->power_gpio >= 0) { | 335 | if (dac33->power_gpio >= 0) |
| 316 | gpio_set_value(dac33->power_gpio, 0); | 336 | gpio_set_value(dac33->power_gpio, 0); |
| 317 | dac33->chip_power = 0; | 337 | |
| 338 | ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), | ||
| 339 | dac33->supplies); | ||
| 340 | if (ret != 0) { | ||
| 341 | dev_err(codec->dev, | ||
| 342 | "Failed to disable supplies: %d\n", ret); | ||
| 343 | goto exit; | ||
| 318 | } | 344 | } |
| 345 | |||
| 346 | dac33->chip_power = 0; | ||
| 319 | } | 347 | } |
| 320 | mutex_unlock(&dac33->mutex); | ||
| 321 | 348 | ||
| 349 | exit: | ||
| 350 | mutex_unlock(&dac33->mutex); | ||
| 351 | return ret; | ||
| 322 | } | 352 | } |
| 323 | 353 | ||
| 324 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, | 354 | static int dac33_get_nsample(struct snd_kcontrol *kcontrol, |
| @@ -469,6 +499,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) | |||
| 469 | static int dac33_set_bias_level(struct snd_soc_codec *codec, | 499 | static int dac33_set_bias_level(struct snd_soc_codec *codec, |
| 470 | enum snd_soc_bias_level level) | 500 | enum snd_soc_bias_level level) |
| 471 | { | 501 | { |
| 502 | int ret; | ||
| 503 | |||
| 472 | switch (level) { | 504 | switch (level) { |
| 473 | case SND_SOC_BIAS_ON: | 505 | case SND_SOC_BIAS_ON: |
| 474 | dac33_soft_power(codec, 1); | 506 | dac33_soft_power(codec, 1); |
| @@ -476,12 +508,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec, | |||
| 476 | case SND_SOC_BIAS_PREPARE: | 508 | case SND_SOC_BIAS_PREPARE: |
| 477 | break; | 509 | break; |
| 478 | case SND_SOC_BIAS_STANDBY: | 510 | case SND_SOC_BIAS_STANDBY: |
| 479 | if (codec->bias_level == SND_SOC_BIAS_OFF) | 511 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
| 480 | dac33_hard_power(codec, 1); | 512 | ret = dac33_hard_power(codec, 1); |
| 513 | if (ret != 0) | ||
| 514 | return ret; | ||
| 515 | } | ||
| 516 | |||
| 481 | dac33_soft_power(codec, 0); | 517 | dac33_soft_power(codec, 0); |
| 482 | break; | 518 | break; |
| 483 | case SND_SOC_BIAS_OFF: | 519 | case SND_SOC_BIAS_OFF: |
| 484 | dac33_hard_power(codec, 0); | 520 | ret = dac33_hard_power(codec, 0); |
| 521 | if (ret != 0) | ||
| 522 | return ret; | ||
| 523 | |||
| 485 | break; | 524 | break; |
| 486 | } | 525 | } |
| 487 | codec->bias_level = level; | 526 | codec->bias_level = level; |
| @@ -959,6 +998,9 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
| 959 | /* power on device */ | 998 | /* power on device */ |
| 960 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 999 | dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 961 | 1000 | ||
| 1001 | /* Bias level configuration has enabled regulator an extra time */ | ||
| 1002 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1003 | |||
| 962 | return 0; | 1004 | return 0; |
| 963 | 1005 | ||
| 964 | pcm_err: | 1006 | pcm_err: |
| @@ -1039,7 +1081,7 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
| 1039 | struct tlv320dac33_platform_data *pdata; | 1081 | struct tlv320dac33_platform_data *pdata; |
| 1040 | struct tlv320dac33_priv *dac33; | 1082 | struct tlv320dac33_priv *dac33; |
| 1041 | struct snd_soc_codec *codec; | 1083 | struct snd_soc_codec *codec; |
| 1042 | int ret = 0; | 1084 | int ret, i; |
| 1043 | 1085 | ||
| 1044 | if (client->dev.platform_data == NULL) { | 1086 | if (client->dev.platform_data == NULL) { |
| 1045 | dev_err(&client->dev, "Platform data not set\n"); | 1087 | dev_err(&client->dev, "Platform data not set\n"); |
| @@ -1130,6 +1172,24 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
| 1130 | } | 1172 | } |
| 1131 | } | 1173 | } |
| 1132 | 1174 | ||
| 1175 | for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++) | ||
| 1176 | dac33->supplies[i].supply = dac33_supply_names[i]; | ||
| 1177 | |||
| 1178 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies), | ||
| 1179 | dac33->supplies); | ||
| 1180 | |||
| 1181 | if (ret != 0) { | ||
| 1182 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
| 1183 | goto err_get; | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), | ||
| 1187 | dac33->supplies); | ||
| 1188 | if (ret != 0) { | ||
| 1189 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
| 1190 | goto err_enable; | ||
| 1191 | } | ||
| 1192 | |||
| 1133 | ret = snd_soc_register_codec(codec); | 1193 | ret = snd_soc_register_codec(codec); |
| 1134 | if (ret != 0) { | 1194 | if (ret != 0) { |
| 1135 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1195 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
| @@ -1149,6 +1209,10 @@ static int dac33_i2c_probe(struct i2c_client *client, | |||
| 1149 | return ret; | 1209 | return ret; |
| 1150 | 1210 | ||
| 1151 | error_codec: | 1211 | error_codec: |
| 1212 | regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1213 | err_enable: | ||
| 1214 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1215 | err_get: | ||
| 1152 | if (dac33->irq >= 0) { | 1216 | if (dac33->irq >= 0) { |
| 1153 | free_irq(dac33->irq, &dac33->codec); | 1217 | free_irq(dac33->irq, &dac33->codec); |
| 1154 | destroy_workqueue(dac33->dac33_wq); | 1218 | destroy_workqueue(dac33->dac33_wq); |
| @@ -1177,6 +1241,8 @@ static int dac33_i2c_remove(struct i2c_client *client) | |||
| 1177 | if (dac33->irq >= 0) | 1241 | if (dac33->irq >= 0) |
| 1178 | free_irq(dac33->irq, &dac33->codec); | 1242 | free_irq(dac33->irq, &dac33->codec); |
| 1179 | 1243 | ||
| 1244 | regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies); | ||
| 1245 | |||
| 1180 | destroy_workqueue(dac33->dac33_wq); | 1246 | destroy_workqueue(dac33->dac33_wq); |
| 1181 | snd_soc_unregister_dai(&dac33_dai); | 1247 | snd_soc_unregister_dai(&dac33_dai); |
| 1182 | snd_soc_unregister_codec(&dac33->codec); | 1248 | snd_soc_unregister_codec(&dac33->codec); |
