diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 118 |
1 files changed, 70 insertions, 48 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 4a6d56c3fed9..71a69908ccf6 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -38,6 +38,8 @@ | |||
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/gpio.h> | ||
42 | #include <linux/regulator/consumer.h> | ||
41 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
42 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
43 | #include <sound/core.h> | 45 | #include <sound/core.h> |
@@ -47,16 +49,25 @@ | |||
47 | #include <sound/soc-dapm.h> | 49 | #include <sound/soc-dapm.h> |
48 | #include <sound/initval.h> | 50 | #include <sound/initval.h> |
49 | #include <sound/tlv.h> | 51 | #include <sound/tlv.h> |
52 | #include <sound/tlv320aic3x.h> | ||
50 | 53 | ||
51 | #include "tlv320aic3x.h" | 54 | #include "tlv320aic3x.h" |
52 | 55 | ||
53 | #define AIC3X_VERSION "0.2" | 56 | #define AIC3X_NUM_SUPPLIES 4 |
57 | static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { | ||
58 | "IOVDD", /* I/O Voltage */ | ||
59 | "DVDD", /* Digital Core Voltage */ | ||
60 | "AVDD", /* Analog DAC Voltage */ | ||
61 | "DRVDD", /* ADC Analog and Output Driver Voltage */ | ||
62 | }; | ||
54 | 63 | ||
55 | /* codec private data */ | 64 | /* codec private data */ |
56 | struct aic3x_priv { | 65 | struct aic3x_priv { |
57 | struct snd_soc_codec codec; | 66 | struct snd_soc_codec codec; |
67 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; | ||
58 | unsigned int sysclk; | 68 | unsigned int sysclk; |
59 | int master; | 69 | int master; |
70 | int gpio_reset; | ||
60 | }; | 71 | }; |
61 | 72 | ||
62 | /* | 73 | /* |
@@ -764,7 +775,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
764 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 775 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
765 | struct snd_soc_device *socdev = rtd->socdev; | 776 | struct snd_soc_device *socdev = rtd->socdev; |
766 | struct snd_soc_codec *codec = socdev->card->codec; | 777 | struct snd_soc_codec *codec = socdev->card->codec; |
767 | struct aic3x_priv *aic3x = codec->private_data; | 778 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
768 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; | 779 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
769 | u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; | 780 | u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
770 | u16 d, pll_d = 1; | 781 | u16 d, pll_d = 1; |
@@ -931,7 +942,7 @@ static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
931 | int clk_id, unsigned int freq, int dir) | 942 | int clk_id, unsigned int freq, int dir) |
932 | { | 943 | { |
933 | struct snd_soc_codec *codec = codec_dai->codec; | 944 | struct snd_soc_codec *codec = codec_dai->codec; |
934 | struct aic3x_priv *aic3x = codec->private_data; | 945 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
935 | 946 | ||
936 | aic3x->sysclk = freq; | 947 | aic3x->sysclk = freq; |
937 | return 0; | 948 | return 0; |
@@ -941,7 +952,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
941 | unsigned int fmt) | 952 | unsigned int fmt) |
942 | { | 953 | { |
943 | struct snd_soc_codec *codec = codec_dai->codec; | 954 | struct snd_soc_codec *codec = codec_dai->codec; |
944 | struct aic3x_priv *aic3x = codec->private_data; | 955 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
945 | u8 iface_areg, iface_breg; | 956 | u8 iface_areg, iface_breg; |
946 | int delay = 0; | 957 | int delay = 0; |
947 | 958 | ||
@@ -995,12 +1006,13 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
995 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, | 1006 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
996 | enum snd_soc_bias_level level) | 1007 | enum snd_soc_bias_level level) |
997 | { | 1008 | { |
998 | struct aic3x_priv *aic3x = codec->private_data; | 1009 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
999 | u8 reg; | 1010 | u8 reg; |
1000 | 1011 | ||
1001 | switch (level) { | 1012 | switch (level) { |
1002 | case SND_SOC_BIAS_ON: | 1013 | case SND_SOC_BIAS_ON: |
1003 | /* all power is driven by DAPM system */ | 1014 | break; |
1015 | case SND_SOC_BIAS_PREPARE: | ||
1004 | if (aic3x->master) { | 1016 | if (aic3x->master) { |
1005 | /* enable pll */ | 1017 | /* enable pll */ |
1006 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1018 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
@@ -1008,48 +1020,9 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1008 | reg | PLL_ENABLE); | 1020 | reg | PLL_ENABLE); |
1009 | } | 1021 | } |
1010 | break; | 1022 | break; |
1011 | case SND_SOC_BIAS_PREPARE: | ||
1012 | break; | ||
1013 | case SND_SOC_BIAS_STANDBY: | 1023 | case SND_SOC_BIAS_STANDBY: |
1014 | /* | 1024 | /* fall through and disable pll */ |
1015 | * all power is driven by DAPM system, | ||
1016 | * so output power is safe if bypass was set | ||
1017 | */ | ||
1018 | if (aic3x->master) { | ||
1019 | /* disable pll */ | ||
1020 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
1021 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | ||
1022 | reg & ~PLL_ENABLE); | ||
1023 | } | ||
1024 | break; | ||
1025 | case SND_SOC_BIAS_OFF: | 1025 | case SND_SOC_BIAS_OFF: |
1026 | /* force all power off */ | ||
1027 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | ||
1028 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | ||
1029 | reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL); | ||
1030 | aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON); | ||
1031 | |||
1032 | reg = aic3x_read_reg_cache(codec, DAC_PWR); | ||
1033 | aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON)); | ||
1034 | |||
1035 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | ||
1036 | aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON); | ||
1037 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | ||
1038 | aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON); | ||
1039 | |||
1040 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | ||
1041 | aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON); | ||
1042 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | ||
1043 | aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON); | ||
1044 | |||
1045 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | ||
1046 | aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON); | ||
1047 | |||
1048 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | ||
1049 | aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON); | ||
1050 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | ||
1051 | aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON); | ||
1052 | |||
1053 | if (aic3x->master) { | 1026 | if (aic3x->master) { |
1054 | /* disable pll */ | 1027 | /* disable pll */ |
1055 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1028 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
@@ -1171,7 +1144,7 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1171 | codec->hw_write(codec->control_data, data, 2); | 1144 | codec->hw_write(codec->control_data, data, 2); |
1172 | } | 1145 | } |
1173 | 1146 | ||
1174 | aic3x_set_bias_level(codec, codec->suspend_bias_level); | 1147 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1175 | 1148 | ||
1176 | return 0; | 1149 | return 0; |
1177 | } | 1150 | } |
@@ -1309,6 +1282,13 @@ static int aic3x_unregister(struct aic3x_priv *aic3x) | |||
1309 | snd_soc_unregister_dai(&aic3x_dai); | 1282 | snd_soc_unregister_dai(&aic3x_dai); |
1310 | snd_soc_unregister_codec(&aic3x->codec); | 1283 | snd_soc_unregister_codec(&aic3x->codec); |
1311 | 1284 | ||
1285 | if (aic3x->gpio_reset >= 0) { | ||
1286 | gpio_set_value(aic3x->gpio_reset, 0); | ||
1287 | gpio_free(aic3x->gpio_reset); | ||
1288 | } | ||
1289 | regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1290 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1291 | |||
1312 | kfree(aic3x); | 1292 | kfree(aic3x); |
1313 | aic3x_codec = NULL; | 1293 | aic3x_codec = NULL; |
1314 | 1294 | ||
@@ -1330,6 +1310,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1330 | { | 1310 | { |
1331 | struct snd_soc_codec *codec; | 1311 | struct snd_soc_codec *codec; |
1332 | struct aic3x_priv *aic3x; | 1312 | struct aic3x_priv *aic3x; |
1313 | struct aic3x_pdata *pdata = i2c->dev.platform_data; | ||
1314 | int ret, i; | ||
1333 | 1315 | ||
1334 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1316 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
1335 | if (aic3x == NULL) { | 1317 | if (aic3x == NULL) { |
@@ -1339,13 +1321,53 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1339 | 1321 | ||
1340 | codec = &aic3x->codec; | 1322 | codec = &aic3x->codec; |
1341 | codec->dev = &i2c->dev; | 1323 | codec->dev = &i2c->dev; |
1342 | codec->private_data = aic3x; | 1324 | snd_soc_codec_set_drvdata(codec, aic3x); |
1343 | codec->control_data = i2c; | 1325 | codec->control_data = i2c; |
1344 | codec->hw_write = (hw_write_t) i2c_master_send; | 1326 | codec->hw_write = (hw_write_t) i2c_master_send; |
1345 | 1327 | ||
1346 | i2c_set_clientdata(i2c, aic3x); | 1328 | i2c_set_clientdata(i2c, aic3x); |
1347 | 1329 | ||
1330 | aic3x->gpio_reset = -1; | ||
1331 | if (pdata && pdata->gpio_reset >= 0) { | ||
1332 | ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset"); | ||
1333 | if (ret != 0) | ||
1334 | goto err_gpio; | ||
1335 | aic3x->gpio_reset = pdata->gpio_reset; | ||
1336 | gpio_direction_output(aic3x->gpio_reset, 0); | ||
1337 | } | ||
1338 | |||
1339 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | ||
1340 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | ||
1341 | |||
1342 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), | ||
1343 | aic3x->supplies); | ||
1344 | if (ret != 0) { | ||
1345 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1346 | goto err_get; | ||
1347 | } | ||
1348 | |||
1349 | ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), | ||
1350 | aic3x->supplies); | ||
1351 | if (ret != 0) { | ||
1352 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1353 | goto err_enable; | ||
1354 | } | ||
1355 | |||
1356 | if (aic3x->gpio_reset >= 0) { | ||
1357 | udelay(1); | ||
1358 | gpio_set_value(aic3x->gpio_reset, 1); | ||
1359 | } | ||
1360 | |||
1348 | return aic3x_register(codec); | 1361 | return aic3x_register(codec); |
1362 | |||
1363 | err_enable: | ||
1364 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1365 | err_get: | ||
1366 | if (aic3x->gpio_reset >= 0) | ||
1367 | gpio_free(aic3x->gpio_reset); | ||
1368 | err_gpio: | ||
1369 | kfree(aic3x); | ||
1370 | return ret; | ||
1349 | } | 1371 | } |
1350 | 1372 | ||
1351 | static int aic3x_i2c_remove(struct i2c_client *client) | 1373 | static int aic3x_i2c_remove(struct i2c_client *client) |