aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ssm2602.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/ssm2602.c')
-rw-r--r--sound/soc/codecs/ssm2602.c57
1 files changed, 46 insertions, 11 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 44ef0dacd56..cac37361676 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -285,16 +285,23 @@ static inline int get_coeff(int mclk, int rate)
285} 285}
286 286
287static int ssm2602_hw_params(struct snd_pcm_substream *substream, 287static int ssm2602_hw_params(struct snd_pcm_substream *substream,
288 struct snd_pcm_hw_params *params) 288 struct snd_pcm_hw_params *params,
289 struct snd_soc_dai *dai)
289{ 290{
290 u16 srate; 291 u16 srate;
291 struct snd_soc_pcm_runtime *rtd = substream->private_data; 292 struct snd_soc_pcm_runtime *rtd = substream->private_data;
292 struct snd_soc_device *socdev = rtd->socdev; 293 struct snd_soc_device *socdev = rtd->socdev;
293 struct snd_soc_codec *codec = socdev->codec; 294 struct snd_soc_codec *codec = socdev->codec;
294 struct ssm2602_priv *ssm2602 = codec->private_data; 295 struct ssm2602_priv *ssm2602 = codec->private_data;
296 struct i2c_client *i2c = codec->control_data;
295 u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; 297 u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
296 int i = get_coeff(ssm2602->sysclk, params_rate(params)); 298 int i = get_coeff(ssm2602->sysclk, params_rate(params));
297 299
300 if (substream == ssm2602->slave_substream) {
301 dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
302 return 0;
303 }
304
298 /*no match is found*/ 305 /*no match is found*/
299 if (i == ARRAY_SIZE(coeff_div)) 306 if (i == ARRAY_SIZE(coeff_div))
300 return -EINVAL; 307 return -EINVAL;
@@ -324,19 +331,26 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
324 return 0; 331 return 0;
325} 332}
326 333
327static int ssm2602_startup(struct snd_pcm_substream *substream) 334static int ssm2602_startup(struct snd_pcm_substream *substream,
335 struct snd_soc_dai *dai)
328{ 336{
329 struct snd_soc_pcm_runtime *rtd = substream->private_data; 337 struct snd_soc_pcm_runtime *rtd = substream->private_data;
330 struct snd_soc_device *socdev = rtd->socdev; 338 struct snd_soc_device *socdev = rtd->socdev;
331 struct snd_soc_codec *codec = socdev->codec; 339 struct snd_soc_codec *codec = socdev->codec;
332 struct ssm2602_priv *ssm2602 = codec->private_data; 340 struct ssm2602_priv *ssm2602 = codec->private_data;
341 struct i2c_client *i2c = codec->control_data;
333 struct snd_pcm_runtime *master_runtime; 342 struct snd_pcm_runtime *master_runtime;
334 343
335 /* The DAI has shared clocks so if we already have a playback or 344 /* The DAI has shared clocks so if we already have a playback or
336 * capture going then constrain this substream to match it. 345 * capture going then constrain this substream to match it.
346 * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
337 */ 347 */
338 if (ssm2602->master_substream) { 348 if (ssm2602->master_substream) {
339 master_runtime = ssm2602->master_substream->runtime; 349 master_runtime = ssm2602->master_substream->runtime;
350 dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
351 master_runtime->sample_bits,
352 master_runtime->rate);
353
340 snd_pcm_hw_constraint_minmax(substream->runtime, 354 snd_pcm_hw_constraint_minmax(substream->runtime,
341 SNDRV_PCM_HW_PARAM_RATE, 355 SNDRV_PCM_HW_PARAM_RATE,
342 master_runtime->rate, 356 master_runtime->rate,
@@ -354,7 +368,8 @@ static int ssm2602_startup(struct snd_pcm_substream *substream)
354 return 0; 368 return 0;
355} 369}
356 370
357static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) 371static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
372 struct snd_soc_dai *dai)
358{ 373{
359 struct snd_soc_pcm_runtime *rtd = substream->private_data; 374 struct snd_soc_pcm_runtime *rtd = substream->private_data;
360 struct snd_soc_device *socdev = rtd->socdev; 375 struct snd_soc_device *socdev = rtd->socdev;
@@ -365,14 +380,21 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream)
365 return 0; 380 return 0;
366} 381}
367 382
368static void ssm2602_shutdown(struct snd_pcm_substream *substream) 383static void ssm2602_shutdown(struct snd_pcm_substream *substream,
384 struct snd_soc_dai *dai)
369{ 385{
370 struct snd_soc_pcm_runtime *rtd = substream->private_data; 386 struct snd_soc_pcm_runtime *rtd = substream->private_data;
371 struct snd_soc_device *socdev = rtd->socdev; 387 struct snd_soc_device *socdev = rtd->socdev;
372 struct snd_soc_codec *codec = socdev->codec; 388 struct snd_soc_codec *codec = socdev->codec;
389 struct ssm2602_priv *ssm2602 = codec->private_data;
373 /* deactivate */ 390 /* deactivate */
374 if (!codec->active) 391 if (!codec->active)
375 ssm2602_write(codec, SSM2602_ACTIVE, 0); 392 ssm2602_write(codec, SSM2602_ACTIVE, 0);
393
394 if (ssm2602->master_substream == substream)
395 ssm2602->master_substream = ssm2602->slave_substream;
396
397 ssm2602->slave_substream = NULL;
376} 398}
377 399
378static int ssm2602_mute(struct snd_soc_dai *dai, int mute) 400static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
@@ -432,10 +454,10 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
432 iface |= 0x0001; 454 iface |= 0x0001;
433 break; 455 break;
434 case SND_SOC_DAIFMT_DSP_A: 456 case SND_SOC_DAIFMT_DSP_A:
435 iface |= 0x0003; 457 iface |= 0x0013;
436 break; 458 break;
437 case SND_SOC_DAIFMT_DSP_B: 459 case SND_SOC_DAIFMT_DSP_B:
438 iface |= 0x0013; 460 iface |= 0x0003;
439 break; 461 break;
440 default: 462 default:
441 return -EINVAL; 463 return -EINVAL;
@@ -496,6 +518,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
496 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ 518 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
497 SNDRV_PCM_RATE_96000) 519 SNDRV_PCM_RATE_96000)
498 520
521#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
522 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
523
499struct snd_soc_dai ssm2602_dai = { 524struct snd_soc_dai ssm2602_dai = {
500 .name = "SSM2602", 525 .name = "SSM2602",
501 .playback = { 526 .playback = {
@@ -503,20 +528,18 @@ struct snd_soc_dai ssm2602_dai = {
503 .channels_min = 2, 528 .channels_min = 2,
504 .channels_max = 2, 529 .channels_max = 2,
505 .rates = SSM2602_RATES, 530 .rates = SSM2602_RATES,
506 .formats = SNDRV_PCM_FMTBIT_S32_LE,}, 531 .formats = SSM2602_FORMATS,},
507 .capture = { 532 .capture = {
508 .stream_name = "Capture", 533 .stream_name = "Capture",
509 .channels_min = 2, 534 .channels_min = 2,
510 .channels_max = 2, 535 .channels_max = 2,
511 .rates = SSM2602_RATES, 536 .rates = SSM2602_RATES,
512 .formats = SNDRV_PCM_FMTBIT_S32_LE,}, 537 .formats = SSM2602_FORMATS,},
513 .ops = { 538 .ops = {
514 .startup = ssm2602_startup, 539 .startup = ssm2602_startup,
515 .prepare = ssm2602_pcm_prepare, 540 .prepare = ssm2602_pcm_prepare,
516 .hw_params = ssm2602_hw_params, 541 .hw_params = ssm2602_hw_params,
517 .shutdown = ssm2602_shutdown, 542 .shutdown = ssm2602_shutdown,
518 },
519 .dai_ops = {
520 .digital_mute = ssm2602_mute, 543 .digital_mute = ssm2602_mute,
521 .set_sysclk = ssm2602_set_dai_sysclk, 544 .set_sysclk = ssm2602_set_dai_sysclk,
522 .set_fmt = ssm2602_set_dai_fmt, 545 .set_fmt = ssm2602_set_dai_fmt,
@@ -601,7 +624,7 @@ static int ssm2602_init(struct snd_soc_device *socdev)
601 624
602 ssm2602_add_controls(codec); 625 ssm2602_add_controls(codec);
603 ssm2602_add_widgets(codec); 626 ssm2602_add_widgets(codec);
604 ret = snd_soc_register_card(socdev); 627 ret = snd_soc_init_card(socdev);
605 if (ret < 0) { 628 if (ret < 0) {
606 pr_err("ssm2602: failed to register card\n"); 629 pr_err("ssm2602: failed to register card\n");
607 goto card_err; 630 goto card_err;
@@ -770,6 +793,18 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
770}; 793};
771EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); 794EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
772 795
796static int __init ssm2602_modinit(void)
797{
798 return snd_soc_register_dai(&ssm2602_dai);
799}
800module_init(ssm2602_modinit);
801
802static void __exit ssm2602_exit(void)
803{
804 snd_soc_unregister_dai(&ssm2602_dai);
805}
806module_exit(ssm2602_exit);
807
773MODULE_DESCRIPTION("ASoC ssm2602 driver"); 808MODULE_DESCRIPTION("ASoC ssm2602 driver");
774MODULE_AUTHOR("Cliff Cai"); 809MODULE_AUTHOR("Cliff Cai");
775MODULE_LICENSE("GPL"); 810MODULE_LICENSE("GPL");