aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8993.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-17 13:52:47 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-17 13:53:50 -0400
commitd3c9e9a1390f8a34da8b69e09fa1afa90f5067f4 (patch)
treeefd1270eecad034c89aebe0b321dac247ffc3aa9 /sound/soc/codecs/wm8993.c
parent0182dcc52c759d005cc3e65deadee9f166cdd7d0 (diff)
ASoC: Implement TDM configuration for WM8993
Note that the number of slots used internally is specified in terms of stereo slots while the external API works with mono slots. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8993.c')
-rw-r--r--sound/soc/codecs/wm8993.c99
1 files changed, 81 insertions, 18 deletions
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index f9119a6e616e..13befa338247 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -218,6 +218,8 @@ struct wm8993_priv {
218 struct snd_soc_codec codec; 218 struct snd_soc_codec codec;
219 int master; 219 int master;
220 int sysclk_source; 220 int sysclk_source;
221 int tdm_slots;
222 int tdm_width;
221 unsigned int mclk_rate; 223 unsigned int mclk_rate;
222 unsigned int sysclk_rate; 224 unsigned int sysclk_rate;
223 unsigned int fs; 225 unsigned int fs;
@@ -1107,24 +1109,30 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
1107 /* What BCLK do we need? */ 1109 /* What BCLK do we need? */
1108 wm8993->fs = params_rate(params); 1110 wm8993->fs = params_rate(params);
1109 wm8993->bclk = 2 * wm8993->fs; 1111 wm8993->bclk = 2 * wm8993->fs;
1110 switch (params_format(params)) { 1112 if (wm8993->tdm_slots) {
1111 case SNDRV_PCM_FORMAT_S16_LE: 1113 dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
1112 wm8993->bclk *= 16; 1114 wm8993->tdm_slots, wm8993->tdm_width);
1113 break; 1115 wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
1114 case SNDRV_PCM_FORMAT_S20_3LE: 1116 } else {
1115 wm8993->bclk *= 20; 1117 switch (params_format(params)) {
1116 aif1 |= 0x8; 1118 case SNDRV_PCM_FORMAT_S16_LE:
1117 break; 1119 wm8993->bclk *= 16;
1118 case SNDRV_PCM_FORMAT_S24_LE: 1120 break;
1119 wm8993->bclk *= 24; 1121 case SNDRV_PCM_FORMAT_S20_3LE:
1120 aif1 |= 0x10; 1122 wm8993->bclk *= 20;
1121 break; 1123 aif1 |= 0x8;
1122 case SNDRV_PCM_FORMAT_S32_LE: 1124 break;
1123 wm8993->bclk *= 32; 1125 case SNDRV_PCM_FORMAT_S24_LE:
1124 aif1 |= 0x18; 1126 wm8993->bclk *= 24;
1125 break; 1127 aif1 |= 0x10;
1126 default: 1128 break;
1127 return -EINVAL; 1129 case SNDRV_PCM_FORMAT_S32_LE:
1130 wm8993->bclk *= 32;
1131 aif1 |= 0x18;
1132 break;
1133 default:
1134 return -EINVAL;
1135 }
1128 } 1136 }
1129 1137
1130 dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk); 1138 dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8993->bclk);
@@ -1243,12 +1251,67 @@ static int wm8993_digital_mute(struct snd_soc_dai *codec_dai, int mute)
1243 return 0; 1251 return 0;
1244} 1252}
1245 1253
1254static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1255 unsigned int rx_mask, int slots, int slot_width)
1256{
1257 struct snd_soc_codec *codec = dai->codec;
1258 struct wm8993_priv *wm8993 = codec->private_data;
1259 int aif1 = 0;
1260 int aif2 = 0;
1261
1262 /* Don't need to validate anything if we're turning off TDM */
1263 if (slots == 0) {
1264 wm8993->tdm_slots = 0;
1265 goto out;
1266 }
1267
1268 /* Note that we allow configurations we can't handle ourselves -
1269 * for example, we can generate clocks for slots 2 and up even if
1270 * we can't use those slots ourselves.
1271 */
1272 aif1 |= WM8993_AIFADC_TDM;
1273 aif2 |= WM8993_AIFDAC_TDM;
1274
1275 switch (rx_mask) {
1276 case 3:
1277 break;
1278 case 0xc:
1279 aif1 |= WM8993_AIFADC_TDM_CHAN;
1280 break;
1281 default:
1282 return -EINVAL;
1283 }
1284
1285
1286 switch (tx_mask) {
1287 case 3:
1288 break;
1289 case 0xc:
1290 aif2 |= WM8993_AIFDAC_TDM_CHAN;
1291 break;
1292 default:
1293 return -EINVAL;
1294 }
1295
1296out:
1297 wm8993->tdm_width = slot_width;
1298 wm8993->tdm_slots = slots / 2;
1299
1300 snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_1,
1301 WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1);
1302 snd_soc_update_bits(codec, WM8993_AUDIO_INTERFACE_2,
1303 WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2);
1304
1305 return 0;
1306}
1307
1246static struct snd_soc_dai_ops wm8993_ops = { 1308static struct snd_soc_dai_ops wm8993_ops = {
1247 .set_sysclk = wm8993_set_sysclk, 1309 .set_sysclk = wm8993_set_sysclk,
1248 .set_fmt = wm8993_set_dai_fmt, 1310 .set_fmt = wm8993_set_dai_fmt,
1249 .hw_params = wm8993_hw_params, 1311 .hw_params = wm8993_hw_params,
1250 .digital_mute = wm8993_digital_mute, 1312 .digital_mute = wm8993_digital_mute,
1251 .set_pll = wm8993_set_fll, 1313 .set_pll = wm8993_set_fll,
1314 .set_tdm_slot = wm8993_set_tdm_slot,
1252}; 1315};
1253 1316
1254#define WM8993_RATES SNDRV_PCM_RATE_8000_48000 1317#define WM8993_RATES SNDRV_PCM_RATE_8000_48000