diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 81 |
1 files changed, 39 insertions, 42 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 556123b4059c..584bc1e67f76 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
41 | #include <linux/regulator/consumer.h> | ||
41 | #include <linux/platform_device.h> | 42 | #include <linux/platform_device.h> |
42 | #include <sound/core.h> | 43 | #include <sound/core.h> |
43 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
@@ -49,11 +50,18 @@ | |||
49 | 50 | ||
50 | #include "tlv320aic3x.h" | 51 | #include "tlv320aic3x.h" |
51 | 52 | ||
52 | #define AIC3X_VERSION "0.2" | 53 | #define AIC3X_NUM_SUPPLIES 4 |
54 | static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { | ||
55 | "IOVDD", /* I/O Voltage */ | ||
56 | "DVDD", /* Digital Core Voltage */ | ||
57 | "AVDD", /* Analog DAC Voltage */ | ||
58 | "DRVDD", /* ADC Analog and Output Driver Voltage */ | ||
59 | }; | ||
53 | 60 | ||
54 | /* codec private data */ | 61 | /* codec private data */ |
55 | struct aic3x_priv { | 62 | struct aic3x_priv { |
56 | struct snd_soc_codec codec; | 63 | struct snd_soc_codec codec; |
64 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; | ||
57 | unsigned int sysclk; | 65 | unsigned int sysclk; |
58 | int master; | 66 | int master; |
59 | }; | 67 | }; |
@@ -999,7 +1007,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
999 | 1007 | ||
1000 | switch (level) { | 1008 | switch (level) { |
1001 | case SND_SOC_BIAS_ON: | 1009 | case SND_SOC_BIAS_ON: |
1002 | /* all power is driven by DAPM system */ | 1010 | break; |
1011 | case SND_SOC_BIAS_PREPARE: | ||
1003 | if (aic3x->master) { | 1012 | if (aic3x->master) { |
1004 | /* enable pll */ | 1013 | /* enable pll */ |
1005 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1014 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
@@ -1007,48 +1016,9 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1007 | reg | PLL_ENABLE); | 1016 | reg | PLL_ENABLE); |
1008 | } | 1017 | } |
1009 | break; | 1018 | break; |
1010 | case SND_SOC_BIAS_PREPARE: | ||
1011 | break; | ||
1012 | case SND_SOC_BIAS_STANDBY: | 1019 | case SND_SOC_BIAS_STANDBY: |
1013 | /* | 1020 | /* fall through and disable pll */ |
1014 | * all power is driven by DAPM system, | ||
1015 | * so output power is safe if bypass was set | ||
1016 | */ | ||
1017 | if (aic3x->master) { | ||
1018 | /* disable pll */ | ||
1019 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
1020 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | ||
1021 | reg & ~PLL_ENABLE); | ||
1022 | } | ||
1023 | break; | ||
1024 | case SND_SOC_BIAS_OFF: | 1021 | case SND_SOC_BIAS_OFF: |
1025 | /* force all power off */ | ||
1026 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | ||
1027 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | ||
1028 | reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL); | ||
1029 | aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON); | ||
1030 | |||
1031 | reg = aic3x_read_reg_cache(codec, DAC_PWR); | ||
1032 | aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON)); | ||
1033 | |||
1034 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | ||
1035 | aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON); | ||
1036 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | ||
1037 | aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON); | ||
1038 | |||
1039 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | ||
1040 | aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON); | ||
1041 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | ||
1042 | aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON); | ||
1043 | |||
1044 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | ||
1045 | aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON); | ||
1046 | |||
1047 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | ||
1048 | aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON); | ||
1049 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | ||
1050 | aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON); | ||
1051 | |||
1052 | if (aic3x->master) { | 1022 | if (aic3x->master) { |
1053 | /* disable pll */ | 1023 | /* disable pll */ |
1054 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1024 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
@@ -1308,6 +1278,9 @@ static int aic3x_unregister(struct aic3x_priv *aic3x) | |||
1308 | snd_soc_unregister_dai(&aic3x_dai); | 1278 | snd_soc_unregister_dai(&aic3x_dai); |
1309 | snd_soc_unregister_codec(&aic3x->codec); | 1279 | snd_soc_unregister_codec(&aic3x->codec); |
1310 | 1280 | ||
1281 | regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1282 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1283 | |||
1311 | kfree(aic3x); | 1284 | kfree(aic3x); |
1312 | aic3x_codec = NULL; | 1285 | aic3x_codec = NULL; |
1313 | 1286 | ||
@@ -1329,6 +1302,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1329 | { | 1302 | { |
1330 | struct snd_soc_codec *codec; | 1303 | struct snd_soc_codec *codec; |
1331 | struct aic3x_priv *aic3x; | 1304 | struct aic3x_priv *aic3x; |
1305 | int ret, i; | ||
1332 | 1306 | ||
1333 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1307 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
1334 | if (aic3x == NULL) { | 1308 | if (aic3x == NULL) { |
@@ -1344,7 +1318,30 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1344 | 1318 | ||
1345 | i2c_set_clientdata(i2c, aic3x); | 1319 | i2c_set_clientdata(i2c, aic3x); |
1346 | 1320 | ||
1321 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | ||
1322 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | ||
1323 | |||
1324 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), | ||
1325 | aic3x->supplies); | ||
1326 | if (ret != 0) { | ||
1327 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1328 | goto err_get; | ||
1329 | } | ||
1330 | |||
1331 | ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), | ||
1332 | aic3x->supplies); | ||
1333 | if (ret != 0) { | ||
1334 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1335 | goto err_enable; | ||
1336 | } | ||
1337 | |||
1347 | return aic3x_register(codec); | 1338 | return aic3x_register(codec); |
1339 | |||
1340 | err_enable: | ||
1341 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1342 | err_get: | ||
1343 | kfree(aic3x); | ||
1344 | return ret; | ||
1348 | } | 1345 | } |
1349 | 1346 | ||
1350 | static int aic3x_i2c_remove(struct i2c_client *client) | 1347 | static int aic3x_i2c_remove(struct i2c_client *client) |