diff options
author | Peter Ujfalusi <peter.ujfalusi@nokia.com> | 2009-04-23 07:36:49 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-04-23 11:11:17 -0400 |
commit | 8a1f936acdfd53cb0a981f3f80483863dcd84fa9 (patch) | |
tree | 598b788262d3ad53b219dd0bf457c959dfb9c75b /sound/soc/codecs/twl4030.c | |
parent | 31a00c6b7c0c4f01be49f02660de920c8b82b613 (diff) |
ASoC: TWL4030: Add 4 channel TDM support
Support for 4 channel TDM (SND_SOC_DAIFMT_DSP_A) for twl4030
codec.
The channel allocations are:
Playback:
TDM i2s TWL RX
Channel 1 Left SDRL2
Channel 3 Right SDRR2
Channel 2 -- SDRL1
Channel 4 -- SDRR1
Capture:
TDM i2s TWL TX
Channel 1 Left TXL1
Channel 3 Right TXR1
Channel 2 -- TXL2
Channel 4 -- TXR2
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index fdf88dfbcff9..e23c20c42f19 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -1251,6 +1251,28 @@ static void twl4030_constraints(struct twl4030_priv *twl4030, | |||
1251 | twl4030->channels); | 1251 | twl4030->channels); |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | /* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for | ||
1255 | * capture has to be enabled/disabled. */ | ||
1256 | static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, | ||
1257 | int enable) | ||
1258 | { | ||
1259 | u8 reg, mask; | ||
1260 | |||
1261 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); | ||
1262 | |||
1263 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) | ||
1264 | mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN; | ||
1265 | else | ||
1266 | mask = TWL4030_ATXL2_VTXL_EN | TWL4030_ATXR2_VTXR_EN; | ||
1267 | |||
1268 | if (enable) | ||
1269 | reg |= mask; | ||
1270 | else | ||
1271 | reg &= ~mask; | ||
1272 | |||
1273 | twl4030_write(codec, TWL4030_REG_OPTION, reg); | ||
1274 | } | ||
1275 | |||
1254 | static int twl4030_startup(struct snd_pcm_substream *substream, | 1276 | static int twl4030_startup(struct snd_pcm_substream *substream, |
1255 | struct snd_soc_dai *dai) | 1277 | struct snd_soc_dai *dai) |
1256 | { | 1278 | { |
@@ -1267,6 +1289,15 @@ static int twl4030_startup(struct snd_pcm_substream *substream, | |||
1267 | if (twl4030->configured) | 1289 | if (twl4030->configured) |
1268 | twl4030_constraints(twl4030, twl4030->master_substream); | 1290 | twl4030_constraints(twl4030, twl4030->master_substream); |
1269 | } else { | 1291 | } else { |
1292 | if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & | ||
1293 | TWL4030_OPTION_1)) { | ||
1294 | /* In option2 4 channel is not supported, set the | ||
1295 | * constraint for the first stream for channels, the | ||
1296 | * second stream will 'inherit' this cosntraint */ | ||
1297 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1298 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1299 | 2, 2); | ||
1300 | } | ||
1270 | twl4030->master_substream = substream; | 1301 | twl4030->master_substream = substream; |
1271 | } | 1302 | } |
1272 | 1303 | ||
@@ -1292,6 +1323,10 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, | |||
1292 | twl4030->configured = 0; | 1323 | twl4030->configured = 0; |
1293 | else if (!twl4030->master_substream->runtime->channels) | 1324 | else if (!twl4030->master_substream->runtime->channels) |
1294 | twl4030->configured = 0; | 1325 | twl4030->configured = 0; |
1326 | |||
1327 | /* If the closing substream had 4 channel, do the necessary cleanup */ | ||
1328 | if (substream->runtime->channels == 4) | ||
1329 | twl4030_tdm_enable(codec, substream->stream, 0); | ||
1295 | } | 1330 | } |
1296 | 1331 | ||
1297 | static int twl4030_hw_params(struct snd_pcm_substream *substream, | 1332 | static int twl4030_hw_params(struct snd_pcm_substream *substream, |
@@ -1304,6 +1339,16 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1304 | struct twl4030_priv *twl4030 = codec->private_data; | 1339 | struct twl4030_priv *twl4030 = codec->private_data; |
1305 | u8 mode, old_mode, format, old_format; | 1340 | u8 mode, old_mode, format, old_format; |
1306 | 1341 | ||
1342 | /* If the substream has 4 channel, do the necessary setup */ | ||
1343 | if (params_channels(params) == 4) { | ||
1344 | /* Safety check: are we in the correct operating mode? */ | ||
1345 | if ((twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & | ||
1346 | TWL4030_OPTION_1)) | ||
1347 | twl4030_tdm_enable(codec, substream->stream, 1); | ||
1348 | else | ||
1349 | return -EINVAL; | ||
1350 | } | ||
1351 | |||
1307 | if (twl4030->configured) | 1352 | if (twl4030->configured) |
1308 | /* Ignoring hw_params for already configured DAI */ | 1353 | /* Ignoring hw_params for already configured DAI */ |
1309 | return 0; | 1354 | return 0; |
@@ -1461,6 +1506,9 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1461 | case SND_SOC_DAIFMT_I2S: | 1506 | case SND_SOC_DAIFMT_I2S: |
1462 | format |= TWL4030_AIF_FORMAT_CODEC; | 1507 | format |= TWL4030_AIF_FORMAT_CODEC; |
1463 | break; | 1508 | break; |
1509 | case SND_SOC_DAIFMT_DSP_A: | ||
1510 | format |= TWL4030_AIF_FORMAT_TDM; | ||
1511 | break; | ||
1464 | default: | 1512 | default: |
1465 | return -EINVAL; | 1513 | return -EINVAL; |
1466 | } | 1514 | } |
@@ -1642,13 +1690,13 @@ struct snd_soc_dai twl4030_dai[] = { | |||
1642 | .playback = { | 1690 | .playback = { |
1643 | .stream_name = "Playback", | 1691 | .stream_name = "Playback", |
1644 | .channels_min = 2, | 1692 | .channels_min = 2, |
1645 | .channels_max = 2, | 1693 | .channels_max = 4, |
1646 | .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, | 1694 | .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, |
1647 | .formats = TWL4030_FORMATS,}, | 1695 | .formats = TWL4030_FORMATS,}, |
1648 | .capture = { | 1696 | .capture = { |
1649 | .stream_name = "Capture", | 1697 | .stream_name = "Capture", |
1650 | .channels_min = 2, | 1698 | .channels_min = 2, |
1651 | .channels_max = 2, | 1699 | .channels_max = 4, |
1652 | .rates = TWL4030_RATES, | 1700 | .rates = TWL4030_RATES, |
1653 | .formats = TWL4030_FORMATS,}, | 1701 | .formats = TWL4030_FORMATS,}, |
1654 | .ops = &twl4030_dai_ops, | 1702 | .ops = &twl4030_dai_ops, |