diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 97738e2ece04..bfda7a88e825 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -122,6 +122,9 @@ struct twl4030_priv { | |||
122 | unsigned int bypass_state; | 122 | unsigned int bypass_state; |
123 | unsigned int codec_powered; | 123 | unsigned int codec_powered; |
124 | unsigned int codec_muted; | 124 | unsigned int codec_muted; |
125 | |||
126 | struct snd_pcm_substream *master_substream; | ||
127 | struct snd_pcm_substream *slave_substream; | ||
125 | }; | 128 | }; |
126 | 129 | ||
127 | /* | 130 | /* |
@@ -1217,6 +1220,50 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, | |||
1217 | return 0; | 1220 | return 0; |
1218 | } | 1221 | } |
1219 | 1222 | ||
1223 | static int twl4030_startup(struct snd_pcm_substream *substream) | ||
1224 | { | ||
1225 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1226 | struct snd_soc_device *socdev = rtd->socdev; | ||
1227 | struct snd_soc_codec *codec = socdev->codec; | ||
1228 | struct twl4030_priv *twl4030 = codec->private_data; | ||
1229 | |||
1230 | /* If we already have a playback or capture going then constrain | ||
1231 | * this substream to match it. | ||
1232 | */ | ||
1233 | if (twl4030->master_substream) { | ||
1234 | struct snd_pcm_runtime *master_runtime; | ||
1235 | master_runtime = twl4030->master_substream->runtime; | ||
1236 | |||
1237 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1238 | SNDRV_PCM_HW_PARAM_RATE, | ||
1239 | master_runtime->rate, | ||
1240 | master_runtime->rate); | ||
1241 | |||
1242 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
1243 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1244 | master_runtime->sample_bits, | ||
1245 | master_runtime->sample_bits); | ||
1246 | |||
1247 | twl4030->slave_substream = substream; | ||
1248 | } else | ||
1249 | twl4030->master_substream = substream; | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | static void twl4030_shutdown(struct snd_pcm_substream *substream) | ||
1255 | { | ||
1256 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1257 | struct snd_soc_device *socdev = rtd->socdev; | ||
1258 | struct snd_soc_codec *codec = socdev->codec; | ||
1259 | struct twl4030_priv *twl4030 = codec->private_data; | ||
1260 | |||
1261 | if (twl4030->master_substream == substream) | ||
1262 | twl4030->master_substream = twl4030->slave_substream; | ||
1263 | |||
1264 | twl4030->slave_substream = NULL; | ||
1265 | } | ||
1266 | |||
1220 | static int twl4030_hw_params(struct snd_pcm_substream *substream, | 1267 | static int twl4030_hw_params(struct snd_pcm_substream *substream, |
1221 | struct snd_pcm_hw_params *params, | 1268 | struct snd_pcm_hw_params *params, |
1222 | struct snd_soc_dai *dai) | 1269 | struct snd_soc_dai *dai) |
@@ -1224,8 +1271,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1271 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1225 | struct snd_soc_device *socdev = rtd->socdev; | 1272 | struct snd_soc_device *socdev = rtd->socdev; |
1226 | struct snd_soc_codec *codec = socdev->card->codec; | 1273 | struct snd_soc_codec *codec = socdev->card->codec; |
1274 | struct twl4030_priv *twl4030 = codec->private_data; | ||
1227 | u8 mode, old_mode, format, old_format; | 1275 | u8 mode, old_mode, format, old_format; |
1228 | 1276 | ||
1277 | if (substream == twl4030->slave_substream) | ||
1278 | /* Ignoring hw_params for slave substream */ | ||
1279 | return 0; | ||
1280 | |||
1229 | /* bit rate */ | 1281 | /* bit rate */ |
1230 | old_mode = twl4030_read_reg_cache(codec, | 1282 | old_mode = twl4030_read_reg_cache(codec, |
1231 | TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; | 1283 | TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; |
@@ -1259,6 +1311,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1259 | case 48000: | 1311 | case 48000: |
1260 | mode |= TWL4030_APLL_RATE_48000; | 1312 | mode |= TWL4030_APLL_RATE_48000; |
1261 | break; | 1313 | break; |
1314 | case 96000: | ||
1315 | mode |= TWL4030_APLL_RATE_96000; | ||
1316 | break; | ||
1262 | default: | 1317 | default: |
1263 | printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", | 1318 | printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", |
1264 | params_rate(params)); | 1319 | params_rate(params)); |
@@ -1384,6 +1439,8 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1384 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) | 1439 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) |
1385 | 1440 | ||
1386 | static struct snd_soc_dai_ops twl4030_dai_ops = { | 1441 | static struct snd_soc_dai_ops twl4030_dai_ops = { |
1442 | .startup = twl4030_startup, | ||
1443 | .shutdown = twl4030_shutdown, | ||
1387 | .hw_params = twl4030_hw_params, | 1444 | .hw_params = twl4030_hw_params, |
1388 | .set_sysclk = twl4030_set_dai_sysclk, | 1445 | .set_sysclk = twl4030_set_dai_sysclk, |
1389 | .set_fmt = twl4030_set_dai_fmt, | 1446 | .set_fmt = twl4030_set_dai_fmt, |
@@ -1395,7 +1452,7 @@ struct snd_soc_dai twl4030_dai = { | |||
1395 | .stream_name = "Playback", | 1452 | .stream_name = "Playback", |
1396 | .channels_min = 2, | 1453 | .channels_min = 2, |
1397 | .channels_max = 2, | 1454 | .channels_max = 2, |
1398 | .rates = TWL4030_RATES, | 1455 | .rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, |
1399 | .formats = TWL4030_FORMATS,}, | 1456 | .formats = TWL4030_FORMATS,}, |
1400 | .capture = { | 1457 | .capture = { |
1401 | .stream_name = "Capture", | 1458 | .stream_name = "Capture", |