aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl4030.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2009-04-23 07:36:49 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-04-23 11:11:17 -0400
commit8a1f936acdfd53cb0a981f3f80483863dcd84fa9 (patch)
tree598b788262d3ad53b219dd0bf457c959dfb9c75b /sound/soc/codecs/twl4030.c
parent31a00c6b7c0c4f01be49f02660de920c8b82b613 (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.c52
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. */
1256static 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
1254static int twl4030_startup(struct snd_pcm_substream *substream, 1276static 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
1297static int twl4030_hw_params(struct snd_pcm_substream *substream, 1332static 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,