aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/twl4030.c85
1 files changed, 66 insertions, 19 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 921b205de28a..a1b76d7fd130 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -125,6 +125,11 @@ struct twl4030_priv {
125 125
126 struct snd_pcm_substream *master_substream; 126 struct snd_pcm_substream *master_substream;
127 struct snd_pcm_substream *slave_substream; 127 struct snd_pcm_substream *slave_substream;
128
129 unsigned int configured;
130 unsigned int rate;
131 unsigned int sample_bits;
132 unsigned int channels;
128}; 133};
129 134
130/* 135/*
@@ -1220,6 +1225,36 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1220 return 0; 1225 return 0;
1221} 1226}
1222 1227
1228static void twl4030_constraints(struct twl4030_priv *twl4030,
1229 struct snd_pcm_substream *mst_substream)
1230{
1231 struct snd_pcm_substream *slv_substream;
1232
1233 /* Pick the stream, which need to be constrained */
1234 if (mst_substream == twl4030->master_substream)
1235 slv_substream = twl4030->slave_substream;
1236 else if (mst_substream == twl4030->slave_substream)
1237 slv_substream = twl4030->master_substream;
1238 else /* This should not happen.. */
1239 return;
1240
1241 /* Set the constraints according to the already configured stream */
1242 snd_pcm_hw_constraint_minmax(slv_substream->runtime,
1243 SNDRV_PCM_HW_PARAM_RATE,
1244 twl4030->rate,
1245 twl4030->rate);
1246
1247 snd_pcm_hw_constraint_minmax(slv_substream->runtime,
1248 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
1249 twl4030->sample_bits,
1250 twl4030->sample_bits);
1251
1252 snd_pcm_hw_constraint_minmax(slv_substream->runtime,
1253 SNDRV_PCM_HW_PARAM_CHANNELS,
1254 twl4030->channels,
1255 twl4030->channels);
1256}
1257
1223static int twl4030_startup(struct snd_pcm_substream *substream, 1258static int twl4030_startup(struct snd_pcm_substream *substream,
1224 struct snd_soc_dai *dai) 1259 struct snd_soc_dai *dai)
1225{ 1260{
@@ -1228,26 +1263,16 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
1228 struct snd_soc_codec *codec = socdev->card->codec; 1263 struct snd_soc_codec *codec = socdev->card->codec;
1229 struct twl4030_priv *twl4030 = codec->private_data; 1264 struct twl4030_priv *twl4030 = codec->private_data;
1230 1265
1231 /* If we already have a playback or capture going then constrain
1232 * this substream to match it.
1233 */
1234 if (twl4030->master_substream) { 1266 if (twl4030->master_substream) {
1235 struct snd_pcm_runtime *master_runtime;
1236 master_runtime = twl4030->master_substream->runtime;
1237
1238 snd_pcm_hw_constraint_minmax(substream->runtime,
1239 SNDRV_PCM_HW_PARAM_RATE,
1240 master_runtime->rate,
1241 master_runtime->rate);
1242
1243 snd_pcm_hw_constraint_minmax(substream->runtime,
1244 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
1245 master_runtime->sample_bits,
1246 master_runtime->sample_bits);
1247
1248 twl4030->slave_substream = substream; 1267 twl4030->slave_substream = substream;
1249 } else 1268 /* The DAI has one configuration for playback and capture, so
1269 * if the DAI has been already configured then constrain this
1270 * substream to match it. */
1271 if (twl4030->configured)
1272 twl4030_constraints(twl4030, twl4030->master_substream);
1273 } else {
1250 twl4030->master_substream = substream; 1274 twl4030->master_substream = substream;
1275 }
1251 1276
1252 return 0; 1277 return 0;
1253} 1278}
@@ -1264,6 +1289,13 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
1264 twl4030->master_substream = twl4030->slave_substream; 1289 twl4030->master_substream = twl4030->slave_substream;
1265 1290
1266 twl4030->slave_substream = NULL; 1291 twl4030->slave_substream = NULL;
1292
1293 /* If all streams are closed, or the remaining stream has not yet
1294 * been configured than set the DAI as not configured. */
1295 if (!twl4030->master_substream)
1296 twl4030->configured = 0;
1297 else if (!twl4030->master_substream->runtime->channels)
1298 twl4030->configured = 0;
1267} 1299}
1268 1300
1269static int twl4030_hw_params(struct snd_pcm_substream *substream, 1301static int twl4030_hw_params(struct snd_pcm_substream *substream,
@@ -1276,8 +1308,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1276 struct twl4030_priv *twl4030 = codec->private_data; 1308 struct twl4030_priv *twl4030 = codec->private_data;
1277 u8 mode, old_mode, format, old_format; 1309 u8 mode, old_mode, format, old_format;
1278 1310
1279 if (substream == twl4030->slave_substream) 1311 if (twl4030->configured)
1280 /* Ignoring hw_params for slave substream */ 1312 /* Ignoring hw_params for already configured DAI */
1281 return 0; 1313 return 0;
1282 1314
1283 /* bit rate */ 1315 /* bit rate */
@@ -1357,6 +1389,21 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1357 /* set CODECPDZ afterwards */ 1389 /* set CODECPDZ afterwards */
1358 twl4030_codec_enable(codec, 1); 1390 twl4030_codec_enable(codec, 1);
1359 } 1391 }
1392
1393 /* Store the important parameters for the DAI configuration and set
1394 * the DAI as configured */
1395 twl4030->configured = 1;
1396 twl4030->rate = params_rate(params);
1397 twl4030->sample_bits = hw_param_interval(params,
1398 SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
1399 twl4030->channels = params_channels(params);
1400
1401 /* If both playback and capture streams are open, and one of them
1402 * is setting the hw parameters right now (since we are here), set
1403 * constraints to the other stream to match the current one. */
1404 if (twl4030->slave_substream)
1405 twl4030_constraints(twl4030, substream);
1406
1360 return 0; 1407 return 0;
1361} 1408}
1362 1409