diff options
Diffstat (limited to 'sound/soc/codecs/wm9713.c')
-rw-r--r-- | sound/soc/codecs/wm9713.c | 96 |
1 files changed, 45 insertions, 51 deletions
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f3ca8aaf0139..523bad077fa0 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | struct wm9713_priv { | 33 | struct wm9713_priv { |
34 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | u32 pll_out; /* PLL output frequency */ | ||
36 | }; | 35 | }; |
37 | 36 | ||
38 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 37 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -190,21 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0), | |||
190 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), | 189 | SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1), |
191 | }; | 190 | }; |
192 | 191 | ||
193 | /* add non dapm controls */ | ||
194 | static int wm9713_add_controls(struct snd_soc_codec *codec) | ||
195 | { | ||
196 | int err, i; | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) { | ||
199 | err = snd_ctl_add(codec->card, | ||
200 | snd_soc_cnew(&wm9713_snd_ac97_controls[i], | ||
201 | codec, NULL)); | ||
202 | if (err < 0) | ||
203 | return err; | ||
204 | } | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* We have to create a fake left and right HP mixers because | 192 | /* We have to create a fake left and right HP mixers because |
209 | * the codec only has a single control that is shared by both channels. | 193 | * the codec only has a single control that is shared by both channels. |
210 | * This makes it impossible to determine the audio path using the current | 194 | * This makes it impossible to determine the audio path using the current |
@@ -636,7 +620,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
636 | else { | 620 | else { |
637 | reg = reg >> 1; | 621 | reg = reg >> 1; |
638 | 622 | ||
639 | if (reg > (ARRAY_SIZE(wm9713_reg))) | 623 | if (reg >= (ARRAY_SIZE(wm9713_reg))) |
640 | return -EIO; | 624 | return -EIO; |
641 | 625 | ||
642 | return cache[reg]; | 626 | return cache[reg]; |
@@ -650,7 +634,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
650 | if (reg < 0x7c) | 634 | if (reg < 0x7c) |
651 | soc_ac97_ops.write(codec->ac97, reg, val); | 635 | soc_ac97_ops.write(codec->ac97, reg, val); |
652 | reg = reg >> 1; | 636 | reg = reg >> 1; |
653 | if (reg <= (ARRAY_SIZE(wm9713_reg))) | 637 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
654 | cache[reg] = val; | 638 | cache[reg] = val; |
655 | 639 | ||
656 | return 0; | 640 | return 0; |
@@ -738,13 +722,13 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
738 | struct _pll_div pll_div; | 722 | struct _pll_div pll_div; |
739 | 723 | ||
740 | /* turn PLL off ? */ | 724 | /* turn PLL off ? */ |
741 | if (freq_in == 0 || freq_out == 0) { | 725 | if (freq_in == 0) { |
742 | /* disable PLL power and select ext source */ | 726 | /* disable PLL power and select ext source */ |
743 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 727 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
744 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); | 728 | ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); |
745 | reg = ac97_read(codec, AC97_EXTENDED_MID); | 729 | reg = ac97_read(codec, AC97_EXTENDED_MID); |
746 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); | 730 | ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); |
747 | wm9713->pll_out = 0; | 731 | wm9713->pll_in = 0; |
748 | return 0; | 732 | return 0; |
749 | } | 733 | } |
750 | 734 | ||
@@ -788,7 +772,6 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
788 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); | 772 | ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); |
789 | reg = ac97_read(codec, AC97_HANDSET_RATE); | 773 | reg = ac97_read(codec, AC97_HANDSET_RATE); |
790 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); | 774 | ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); |
791 | wm9713->pll_out = freq_out; | ||
792 | wm9713->pll_in = freq_in; | 775 | wm9713->pll_in = freq_in; |
793 | 776 | ||
794 | /* wait 10ms AC97 link frames for the link to stabilise */ | 777 | /* wait 10ms AC97 link frames for the link to stabilise */ |
@@ -957,13 +940,14 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, | |||
957 | struct snd_soc_dai *dai) | 940 | struct snd_soc_dai *dai) |
958 | { | 941 | { |
959 | struct snd_soc_codec *codec = dai->codec; | 942 | struct snd_soc_codec *codec = dai->codec; |
960 | u16 status; | 943 | u16 status, rate; |
961 | 944 | ||
962 | /* Gracefully shut down the voice interface. */ | 945 | /* Gracefully shut down the voice interface. */ |
963 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; | 946 | status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; |
964 | ac97_write(codec, AC97_HANDSET_RATE, 0x0280); | 947 | rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; |
948 | ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); | ||
965 | schedule_timeout_interruptible(msecs_to_jiffies(1)); | 949 | schedule_timeout_interruptible(msecs_to_jiffies(1)); |
966 | ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); | 950 | ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); |
967 | ac97_write(codec, AC97_EXTENDED_MID, status); | 951 | ac97_write(codec, AC97_EXTENDED_MID, status); |
968 | } | 952 | } |
969 | 953 | ||
@@ -1021,6 +1005,27 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, | |||
1021 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1005 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
1022 | SNDRV_PCM_FORMAT_S24_LE) | 1006 | SNDRV_PCM_FORMAT_S24_LE) |
1023 | 1007 | ||
1008 | static struct snd_soc_dai_ops wm9713_dai_ops_hifi = { | ||
1009 | .prepare = ac97_hifi_prepare, | ||
1010 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1011 | .set_pll = wm9713_set_dai_pll, | ||
1012 | }; | ||
1013 | |||
1014 | static struct snd_soc_dai_ops wm9713_dai_ops_aux = { | ||
1015 | .prepare = ac97_aux_prepare, | ||
1016 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1017 | .set_pll = wm9713_set_dai_pll, | ||
1018 | }; | ||
1019 | |||
1020 | static struct snd_soc_dai_ops wm9713_dai_ops_voice = { | ||
1021 | .hw_params = wm9713_pcm_hw_params, | ||
1022 | .shutdown = wm9713_voiceshutdown, | ||
1023 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1024 | .set_pll = wm9713_set_dai_pll, | ||
1025 | .set_fmt = wm9713_set_dai_fmt, | ||
1026 | .set_tristate = wm9713_set_dai_tristate, | ||
1027 | }; | ||
1028 | |||
1024 | struct snd_soc_dai wm9713_dai[] = { | 1029 | struct snd_soc_dai wm9713_dai[] = { |
1025 | { | 1030 | { |
1026 | .name = "AC97 HiFi", | 1031 | .name = "AC97 HiFi", |
@@ -1037,10 +1042,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1037 | .channels_max = 2, | 1042 | .channels_max = 2, |
1038 | .rates = WM9713_RATES, | 1043 | .rates = WM9713_RATES, |
1039 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 1044 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
1040 | .ops = { | 1045 | .ops = &wm9713_dai_ops_hifi, |
1041 | .prepare = ac97_hifi_prepare, | ||
1042 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1043 | .set_pll = wm9713_set_dai_pll,}, | ||
1044 | }, | 1046 | }, |
1045 | { | 1047 | { |
1046 | .name = "AC97 Aux", | 1048 | .name = "AC97 Aux", |
@@ -1050,10 +1052,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1050 | .channels_max = 1, | 1052 | .channels_max = 1, |
1051 | .rates = WM9713_RATES, | 1053 | .rates = WM9713_RATES, |
1052 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 1054 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
1053 | .ops = { | 1055 | .ops = &wm9713_dai_ops_aux, |
1054 | .prepare = ac97_aux_prepare, | ||
1055 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1056 | .set_pll = wm9713_set_dai_pll,}, | ||
1057 | }, | 1056 | }, |
1058 | { | 1057 | { |
1059 | .name = "WM9713 Voice", | 1058 | .name = "WM9713 Voice", |
@@ -1069,14 +1068,7 @@ struct snd_soc_dai wm9713_dai[] = { | |||
1069 | .channels_max = 2, | 1068 | .channels_max = 2, |
1070 | .rates = WM9713_PCM_RATES, | 1069 | .rates = WM9713_PCM_RATES, |
1071 | .formats = WM9713_PCM_FORMATS,}, | 1070 | .formats = WM9713_PCM_FORMATS,}, |
1072 | .ops = { | 1071 | .ops = &wm9713_dai_ops_voice, |
1073 | .hw_params = wm9713_pcm_hw_params, | ||
1074 | .shutdown = wm9713_voiceshutdown, | ||
1075 | .set_clkdiv = wm9713_set_dai_clkdiv, | ||
1076 | .set_pll = wm9713_set_dai_pll, | ||
1077 | .set_fmt = wm9713_set_dai_fmt, | ||
1078 | .set_tristate = wm9713_set_dai_tristate, | ||
1079 | }, | ||
1080 | }, | 1072 | }, |
1081 | }; | 1073 | }; |
1082 | EXPORT_SYMBOL_GPL(wm9713_dai); | 1074 | EXPORT_SYMBOL_GPL(wm9713_dai); |
@@ -1132,7 +1124,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev, | |||
1132 | pm_message_t state) | 1124 | pm_message_t state) |
1133 | { | 1125 | { |
1134 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1126 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1135 | struct snd_soc_codec *codec = socdev->codec; | 1127 | struct snd_soc_codec *codec = socdev->card->codec; |
1136 | u16 reg; | 1128 | u16 reg; |
1137 | 1129 | ||
1138 | /* Disable everything except touchpanel - that will be handled | 1130 | /* Disable everything except touchpanel - that will be handled |
@@ -1150,7 +1142,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev, | |||
1150 | static int wm9713_soc_resume(struct platform_device *pdev) | 1142 | static int wm9713_soc_resume(struct platform_device *pdev) |
1151 | { | 1143 | { |
1152 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1144 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1153 | struct snd_soc_codec *codec = socdev->codec; | 1145 | struct snd_soc_codec *codec = socdev->card->codec; |
1154 | struct wm9713_priv *wm9713 = codec->private_data; | 1146 | struct wm9713_priv *wm9713 = codec->private_data; |
1155 | int i, ret; | 1147 | int i, ret; |
1156 | u16 *cache = codec->reg_cache; | 1148 | u16 *cache = codec->reg_cache; |
@@ -1164,8 +1156,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1164 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1156 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1165 | 1157 | ||
1166 | /* do we need to re-start the PLL ? */ | 1158 | /* do we need to re-start the PLL ? */ |
1167 | if (wm9713->pll_out) | 1159 | if (wm9713->pll_in) |
1168 | wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out); | 1160 | wm9713_set_pll(codec, 0, wm9713->pll_in, 0); |
1169 | 1161 | ||
1170 | /* only synchronise the codec if warm reset failed */ | 1162 | /* only synchronise the codec if warm reset failed */ |
1171 | if (ret == 0) { | 1163 | if (ret == 0) { |
@@ -1191,10 +1183,11 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1191 | 1183 | ||
1192 | printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); | 1184 | printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION); |
1193 | 1185 | ||
1194 | socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1186 | socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), |
1195 | if (socdev->codec == NULL) | 1187 | GFP_KERNEL); |
1188 | if (socdev->card->codec == NULL) | ||
1196 | return -ENOMEM; | 1189 | return -ENOMEM; |
1197 | codec = socdev->codec; | 1190 | codec = socdev->card->codec; |
1198 | mutex_init(&codec->mutex); | 1191 | mutex_init(&codec->mutex); |
1199 | 1192 | ||
1200 | codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL); | 1193 | codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL); |
@@ -1245,7 +1238,8 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1245 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1238 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1246 | ac97_write(codec, AC97_CD, reg); | 1239 | ac97_write(codec, AC97_CD, reg); |
1247 | 1240 | ||
1248 | wm9713_add_controls(codec); | 1241 | snd_soc_add_controls(codec, wm9713_snd_ac97_controls, |
1242 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1249 | wm9713_add_widgets(codec); | 1243 | wm9713_add_widgets(codec); |
1250 | ret = snd_soc_init_card(socdev); | 1244 | ret = snd_soc_init_card(socdev); |
1251 | if (ret < 0) | 1245 | if (ret < 0) |
@@ -1265,15 +1259,15 @@ priv_err: | |||
1265 | kfree(codec->reg_cache); | 1259 | kfree(codec->reg_cache); |
1266 | 1260 | ||
1267 | cache_err: | 1261 | cache_err: |
1268 | kfree(socdev->codec); | 1262 | kfree(socdev->card->codec); |
1269 | socdev->codec = NULL; | 1263 | socdev->card->codec = NULL; |
1270 | return ret; | 1264 | return ret; |
1271 | } | 1265 | } |
1272 | 1266 | ||
1273 | static int wm9713_soc_remove(struct platform_device *pdev) | 1267 | static int wm9713_soc_remove(struct platform_device *pdev) |
1274 | { | 1268 | { |
1275 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1269 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1276 | struct snd_soc_codec *codec = socdev->codec; | 1270 | struct snd_soc_codec *codec = socdev->card->codec; |
1277 | 1271 | ||
1278 | if (codec == NULL) | 1272 | if (codec == NULL) |
1279 | return 0; | 1273 | return 0; |