diff options
author | Peter Rosin <peda@axentia.se> | 2015-01-28 09:16:09 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-01-28 14:28:53 -0500 |
commit | 8124930713f2fa37ad5347ddfcd2aae45a016aa5 (patch) | |
tree | 789b1bb9eeddc5cae3c2b89aafaaa4307cc1b003 /sound/soc/codecs/pcm512x.c | |
parent | 376dc4903eec7f64b9fd1dafe542c07ab63abb49 (diff) |
ASoC: pcm512x: Support mastering BCLK/LRCLK without using the PLL
Use register field names from the seemingly compatible PCM5242 datasheet,
as the PCM512x and PCM514x datasheets are severly lacking.
Signed-off-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/pcm512x.c')
-rw-r--r-- | sound/soc/codecs/pcm512x.c | 441 |
1 files changed, 425 insertions, 16 deletions
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 874723c36d65..526e6b30cdde 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | #include <sound/soc-dapm.h> | 25 | #include <sound/soc-dapm.h> |
26 | #include <sound/pcm_params.h> | ||
26 | #include <sound/tlv.h> | 27 | #include <sound/tlv.h> |
27 | 28 | ||
28 | #include "pcm512x.h" | 29 | #include "pcm512x.h" |
@@ -39,6 +40,7 @@ struct pcm512x_priv { | |||
39 | struct clk *sclk; | 40 | struct clk *sclk; |
40 | struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; | 41 | struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; |
41 | struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; | 42 | struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; |
43 | int fmt; | ||
42 | }; | 44 | }; |
43 | 45 | ||
44 | /* | 46 | /* |
@@ -69,6 +71,7 @@ static const struct reg_default pcm512x_reg_defaults[] = { | |||
69 | { PCM512x_MUTE, 0x00 }, | 71 | { PCM512x_MUTE, 0x00 }, |
70 | { PCM512x_DSP, 0x00 }, | 72 | { PCM512x_DSP, 0x00 }, |
71 | { PCM512x_PLL_REF, 0x00 }, | 73 | { PCM512x_PLL_REF, 0x00 }, |
74 | { PCM512x_DAC_REF, 0x00 }, | ||
72 | { PCM512x_DAC_ROUTING, 0x11 }, | 75 | { PCM512x_DAC_ROUTING, 0x11 }, |
73 | { PCM512x_DSP_PROGRAM, 0x01 }, | 76 | { PCM512x_DSP_PROGRAM, 0x01 }, |
74 | { PCM512x_CLKDET, 0x00 }, | 77 | { PCM512x_CLKDET, 0x00 }, |
@@ -87,6 +90,18 @@ static const struct reg_default pcm512x_reg_defaults[] = { | |||
87 | { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, | 90 | { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, |
88 | { PCM512x_VCOM_CTRL_1, 0x00 }, | 91 | { PCM512x_VCOM_CTRL_1, 0x00 }, |
89 | { PCM512x_VCOM_CTRL_2, 0x01 }, | 92 | { PCM512x_VCOM_CTRL_2, 0x01 }, |
93 | { PCM512x_BCLK_LRCLK_CFG, 0x00 }, | ||
94 | { PCM512x_MASTER_MODE, 0x7c }, | ||
95 | { PCM512x_SYNCHRONIZE, 0x10 }, | ||
96 | { PCM512x_DSP_CLKDIV, 0x00 }, | ||
97 | { PCM512x_DAC_CLKDIV, 0x00 }, | ||
98 | { PCM512x_NCP_CLKDIV, 0x00 }, | ||
99 | { PCM512x_OSR_CLKDIV, 0x00 }, | ||
100 | { PCM512x_MASTER_CLKDIV_1, 0x00 }, | ||
101 | { PCM512x_MASTER_CLKDIV_2, 0x00 }, | ||
102 | { PCM512x_FS_SPEED_MODE, 0x00 }, | ||
103 | { PCM512x_IDAC_1, 0x01 }, | ||
104 | { PCM512x_IDAC_2, 0x00 }, | ||
90 | }; | 105 | }; |
91 | 106 | ||
92 | static bool pcm512x_readable(struct device *dev, unsigned int reg) | 107 | static bool pcm512x_readable(struct device *dev, unsigned int reg) |
@@ -103,6 +118,8 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg) | |||
103 | case PCM512x_DSP_GPIO_INPUT: | 118 | case PCM512x_DSP_GPIO_INPUT: |
104 | case PCM512x_MASTER_MODE: | 119 | case PCM512x_MASTER_MODE: |
105 | case PCM512x_PLL_REF: | 120 | case PCM512x_PLL_REF: |
121 | case PCM512x_DAC_REF: | ||
122 | case PCM512x_SYNCHRONIZE: | ||
106 | case PCM512x_PLL_COEFF_0: | 123 | case PCM512x_PLL_COEFF_0: |
107 | case PCM512x_PLL_COEFF_1: | 124 | case PCM512x_PLL_COEFF_1: |
108 | case PCM512x_PLL_COEFF_2: | 125 | case PCM512x_PLL_COEFF_2: |
@@ -303,6 +320,94 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { | |||
303 | { "OUTR", NULL, "DACR" }, | 320 | { "OUTR", NULL, "DACR" }, |
304 | }; | 321 | }; |
305 | 322 | ||
323 | static const u32 pcm512x_dai_rates[] = { | ||
324 | 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, | ||
325 | 88200, 96000, 176400, 192000, 384000, | ||
326 | }; | ||
327 | |||
328 | static const struct snd_pcm_hw_constraint_list constraints_slave = { | ||
329 | .count = ARRAY_SIZE(pcm512x_dai_rates), | ||
330 | .list = pcm512x_dai_rates, | ||
331 | }; | ||
332 | |||
333 | static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream, | ||
334 | struct snd_soc_dai *dai) | ||
335 | { | ||
336 | struct snd_soc_codec *codec = dai->codec; | ||
337 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
338 | struct device *dev = dai->dev; | ||
339 | struct snd_pcm_hw_constraint_ratnums *constraints_no_pll; | ||
340 | struct snd_ratnum *rats_no_pll; | ||
341 | |||
342 | if (IS_ERR(pcm512x->sclk)) { | ||
343 | dev_err(dev, "Need SCLK for master mode: %ld\n", | ||
344 | PTR_ERR(pcm512x->sclk)); | ||
345 | return PTR_ERR(pcm512x->sclk); | ||
346 | } | ||
347 | |||
348 | constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll), | ||
349 | GFP_KERNEL); | ||
350 | if (!constraints_no_pll) | ||
351 | return -ENOMEM; | ||
352 | constraints_no_pll->nrats = 1; | ||
353 | rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL); | ||
354 | if (!rats_no_pll) | ||
355 | return -ENOMEM; | ||
356 | constraints_no_pll->rats = rats_no_pll; | ||
357 | rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; | ||
358 | rats_no_pll->den_min = 1; | ||
359 | rats_no_pll->den_max = 128; | ||
360 | rats_no_pll->den_step = 1; | ||
361 | |||
362 | return snd_pcm_hw_constraint_ratnums(substream->runtime, 0, | ||
363 | SNDRV_PCM_HW_PARAM_RATE, | ||
364 | constraints_no_pll); | ||
365 | } | ||
366 | |||
367 | static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream, | ||
368 | struct snd_soc_dai *dai) | ||
369 | { | ||
370 | struct snd_soc_codec *codec = dai->codec; | ||
371 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
372 | struct device *dev = dai->dev; | ||
373 | struct regmap *regmap = pcm512x->regmap; | ||
374 | |||
375 | if (IS_ERR(pcm512x->sclk)) { | ||
376 | dev_info(dev, "No SCLK, using BCLK: %ld\n", | ||
377 | PTR_ERR(pcm512x->sclk)); | ||
378 | |||
379 | /* Disable reporting of missing SCLK as an error */ | ||
380 | regmap_update_bits(regmap, PCM512x_ERROR_DETECT, | ||
381 | PCM512x_IDCH, PCM512x_IDCH); | ||
382 | |||
383 | /* Switch PLL input to BCLK */ | ||
384 | regmap_update_bits(regmap, PCM512x_PLL_REF, | ||
385 | PCM512x_SREF, PCM512x_SREF_BCK); | ||
386 | } | ||
387 | |||
388 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
389 | SNDRV_PCM_HW_PARAM_RATE, | ||
390 | &constraints_slave); | ||
391 | } | ||
392 | |||
393 | static int pcm512x_dai_startup(struct snd_pcm_substream *substream, | ||
394 | struct snd_soc_dai *dai) | ||
395 | { | ||
396 | struct snd_soc_codec *codec = dai->codec; | ||
397 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
398 | |||
399 | switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
400 | case SND_SOC_DAIFMT_CBM_CFM: | ||
401 | return pcm512x_dai_startup_master(substream, dai); | ||
402 | |||
403 | case SND_SOC_DAIFMT_CBS_CFS: | ||
404 | return pcm512x_dai_startup_slave(substream, dai); | ||
405 | |||
406 | default: | ||
407 | return -EINVAL; | ||
408 | } | ||
409 | } | ||
410 | |||
306 | static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | 411 | static int pcm512x_set_bias_level(struct snd_soc_codec *codec, |
307 | enum snd_soc_bias_level level) | 412 | enum snd_soc_bias_level level) |
308 | { | 413 | { |
@@ -340,17 +445,333 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | |||
340 | return 0; | 445 | return 0; |
341 | } | 446 | } |
342 | 447 | ||
448 | static int pcm512x_set_dividers(struct snd_soc_dai *dai, | ||
449 | struct snd_pcm_hw_params *params) | ||
450 | { | ||
451 | struct device *dev = dai->dev; | ||
452 | struct snd_soc_codec *codec = dai->codec; | ||
453 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
454 | unsigned long sck_rate; | ||
455 | unsigned long mck_rate; | ||
456 | unsigned long bclk_rate; | ||
457 | unsigned long sample_rate; | ||
458 | unsigned long osr_rate; | ||
459 | int bclk_div; | ||
460 | int lrclk_div; | ||
461 | int dsp_div; | ||
462 | int dac_div; | ||
463 | unsigned long dac_rate; | ||
464 | int ncp_div; | ||
465 | int osr_div; | ||
466 | unsigned long dac_mul; | ||
467 | unsigned long sck_mul; | ||
468 | int ret; | ||
469 | int idac; | ||
470 | int fssp; | ||
471 | |||
472 | lrclk_div = snd_soc_params_to_frame_size(params); | ||
473 | if (lrclk_div == 0) { | ||
474 | dev_err(dev, "No LRCLK?\n"); | ||
475 | return -EINVAL; | ||
476 | } | ||
477 | |||
478 | sck_rate = clk_get_rate(pcm512x->sclk); | ||
479 | bclk_div = params->rate_den * 64 / lrclk_div; | ||
480 | bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); | ||
481 | |||
482 | mck_rate = sck_rate; | ||
483 | |||
484 | if (bclk_div > 128) { | ||
485 | dev_err(dev, "Failed to find BCLK divider\n"); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | /* the actual rate */ | ||
490 | sample_rate = sck_rate / bclk_div / lrclk_div; | ||
491 | osr_rate = 16 * sample_rate; | ||
492 | |||
493 | /* run DSP no faster than 50 MHz */ | ||
494 | dsp_div = mck_rate > 50000000 ? 2 : 1; | ||
495 | |||
496 | /* run DAC no faster than 6144000 Hz */ | ||
497 | dac_mul = 6144000 / osr_rate; | ||
498 | sck_mul = sck_rate / osr_rate; | ||
499 | for (; dac_mul; dac_mul--) { | ||
500 | if (!(sck_mul % dac_mul)) | ||
501 | break; | ||
502 | } | ||
503 | if (!dac_mul) { | ||
504 | dev_err(dev, "Failed to find DAC rate\n"); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | dac_rate = dac_mul * osr_rate; | ||
509 | dev_dbg(dev, "dac_rate %lu sample_rate %lu\n", dac_rate, sample_rate); | ||
510 | |||
511 | dac_div = DIV_ROUND_CLOSEST(sck_rate, dac_rate); | ||
512 | if (dac_div > 128) { | ||
513 | dev_err(dev, "Failed to find DAC divider\n"); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | ncp_div = DIV_ROUND_CLOSEST(sck_rate / dac_div, 1536000); | ||
518 | if (ncp_div > 128 || sck_rate / dac_div / ncp_div > 2048000) { | ||
519 | /* run NCP no faster than 2048000 Hz, but why? */ | ||
520 | ncp_div = DIV_ROUND_UP(sck_rate / dac_div, 2048000); | ||
521 | if (ncp_div > 128) { | ||
522 | dev_err(dev, "Failed to find NCP divider\n"); | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate); | ||
528 | if (osr_div > 128) { | ||
529 | dev_err(dev, "Failed to find OSR divider\n"); | ||
530 | return -EINVAL; | ||
531 | } | ||
532 | |||
533 | idac = mck_rate / (dsp_div * sample_rate); | ||
534 | |||
535 | ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1); | ||
536 | if (ret != 0) { | ||
537 | dev_err(dev, "Failed to write DSP divider: %d\n", ret); | ||
538 | return ret; | ||
539 | } | ||
540 | |||
541 | ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1); | ||
542 | if (ret != 0) { | ||
543 | dev_err(dev, "Failed to write DAC divider: %d\n", ret); | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1); | ||
548 | if (ret != 0) { | ||
549 | dev_err(dev, "Failed to write NCP divider: %d\n", ret); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1); | ||
554 | if (ret != 0) { | ||
555 | dev_err(dev, "Failed to write OSR divider: %d\n", ret); | ||
556 | return ret; | ||
557 | } | ||
558 | |||
559 | ret = regmap_write(pcm512x->regmap, | ||
560 | PCM512x_MASTER_CLKDIV_1, bclk_div - 1); | ||
561 | if (ret != 0) { | ||
562 | dev_err(dev, "Failed to write BCLK divider: %d\n", ret); | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | ret = regmap_write(pcm512x->regmap, | ||
567 | PCM512x_MASTER_CLKDIV_2, lrclk_div - 1); | ||
568 | if (ret != 0) { | ||
569 | dev_err(dev, "Failed to write LRCLK divider: %d\n", ret); | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8); | ||
574 | if (ret != 0) { | ||
575 | dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff); | ||
580 | if (ret != 0) { | ||
581 | dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | if (sample_rate <= 48000) | ||
586 | fssp = PCM512x_FSSP_48KHZ; | ||
587 | else if (sample_rate <= 96000) | ||
588 | fssp = PCM512x_FSSP_96KHZ; | ||
589 | else if (sample_rate <= 192000) | ||
590 | fssp = PCM512x_FSSP_192KHZ; | ||
591 | else | ||
592 | fssp = PCM512x_FSSP_384KHZ; | ||
593 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE, | ||
594 | PCM512x_FSSP, fssp); | ||
595 | if (ret != 0) { | ||
596 | dev_err(codec->dev, "Failed to set fs speed: %d\n", ret); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | dev_dbg(codec->dev, "DSP divider %d\n", dsp_div); | ||
601 | dev_dbg(codec->dev, "DAC divider %d\n", dac_div); | ||
602 | dev_dbg(codec->dev, "NCP divider %d\n", ncp_div); | ||
603 | dev_dbg(codec->dev, "OSR divider %d\n", osr_div); | ||
604 | dev_dbg(codec->dev, "BCK divider %d\n", bclk_div); | ||
605 | dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div); | ||
606 | dev_dbg(codec->dev, "IDAC %d\n", idac); | ||
607 | dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp); | ||
608 | |||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int pcm512x_hw_params(struct snd_pcm_substream *substream, | ||
613 | struct snd_pcm_hw_params *params, | ||
614 | struct snd_soc_dai *dai) | ||
615 | { | ||
616 | struct snd_soc_codec *codec = dai->codec; | ||
617 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
618 | int alen; | ||
619 | int ret; | ||
620 | |||
621 | dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n", | ||
622 | params_rate(params), | ||
623 | params_channels(params)); | ||
624 | |||
625 | switch (snd_pcm_format_width(params_format(params))) { | ||
626 | case 16: | ||
627 | alen = PCM512x_ALEN_16; | ||
628 | break; | ||
629 | case 20: | ||
630 | alen = PCM512x_ALEN_20; | ||
631 | break; | ||
632 | case 24: | ||
633 | alen = PCM512x_ALEN_24; | ||
634 | break; | ||
635 | case 32: | ||
636 | alen = PCM512x_ALEN_32; | ||
637 | break; | ||
638 | default: | ||
639 | dev_err(codec->dev, "Bad frame size: %d\n", | ||
640 | snd_pcm_format_width(params_format(params))); | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
645 | case SND_SOC_DAIFMT_CBS_CFS: | ||
646 | ret = regmap_update_bits(pcm512x->regmap, | ||
647 | PCM512x_BCLK_LRCLK_CFG, | ||
648 | PCM512x_BCKP | ||
649 | | PCM512x_BCKO | PCM512x_LRKO, | ||
650 | 0); | ||
651 | if (ret != 0) { | ||
652 | dev_err(codec->dev, | ||
653 | "Failed to enable slave mode: %d\n", ret); | ||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, | ||
658 | PCM512x_DCAS, 0); | ||
659 | if (ret != 0) { | ||
660 | dev_err(codec->dev, | ||
661 | "Failed to enable clock divider autoset: %d\n", | ||
662 | ret); | ||
663 | return ret; | ||
664 | } | ||
665 | return 0; | ||
666 | case SND_SOC_DAIFMT_CBM_CFM: | ||
667 | break; | ||
668 | default: | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1, | ||
673 | PCM512x_ALEN, alen); | ||
674 | if (ret != 0) { | ||
675 | dev_err(codec->dev, "Failed to set frame size: %d\n", ret); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT, | ||
680 | PCM512x_IDFS | PCM512x_IDBK | ||
681 | | PCM512x_IDSK | PCM512x_IDCH | ||
682 | | PCM512x_IDCM | PCM512x_DCAS | ||
683 | | PCM512x_IPLK, | ||
684 | PCM512x_IDFS | PCM512x_IDBK | ||
685 | | PCM512x_IDSK | PCM512x_IDCH | ||
686 | | PCM512x_DCAS | PCM512x_IPLK); | ||
687 | if (ret != 0) { | ||
688 | dev_err(codec->dev, | ||
689 | "Failed to ignore auto-clock failures: %d\n", | ||
690 | ret); | ||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN, | ||
695 | PCM512x_PLLE, 0); | ||
696 | if (ret != 0) { | ||
697 | dev_err(codec->dev, "Failed to disable pll: %d\n", ret); | ||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | ret = pcm512x_set_dividers(dai, params); | ||
702 | if (ret != 0) | ||
703 | return ret; | ||
704 | |||
705 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF, | ||
706 | PCM512x_SDAC, PCM512x_SDAC_SCK); | ||
707 | if (ret != 0) { | ||
708 | dev_err(codec->dev, "Failed to set sck as dacref: %d\n", ret); | ||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG, | ||
713 | PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO, | ||
714 | PCM512x_BCKO | PCM512x_LRKO); | ||
715 | if (ret != 0) { | ||
716 | dev_err(codec->dev, "Failed to enable clock output: %d\n", ret); | ||
717 | return ret; | ||
718 | } | ||
719 | |||
720 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE, | ||
721 | PCM512x_RLRK | PCM512x_RBCK, | ||
722 | PCM512x_RLRK | PCM512x_RBCK); | ||
723 | if (ret != 0) { | ||
724 | dev_err(codec->dev, "Failed to enable master mode: %d\n", ret); | ||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, | ||
729 | PCM512x_RQSY, PCM512x_RQSY_HALT); | ||
730 | if (ret != 0) { | ||
731 | dev_err(codec->dev, "Failed to halt clocks: %d\n", ret); | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE, | ||
736 | PCM512x_RQSY, PCM512x_RQSY_RESUME); | ||
737 | if (ret != 0) { | ||
738 | dev_err(codec->dev, "Failed to resume clocks: %d\n", ret); | ||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
746 | { | ||
747 | struct snd_soc_codec *codec = dai->codec; | ||
748 | struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec); | ||
749 | |||
750 | pcm512x->fmt = fmt; | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static const struct snd_soc_dai_ops pcm512x_dai_ops = { | ||
756 | .startup = pcm512x_dai_startup, | ||
757 | .hw_params = pcm512x_hw_params, | ||
758 | .set_fmt = pcm512x_set_fmt, | ||
759 | }; | ||
760 | |||
343 | static struct snd_soc_dai_driver pcm512x_dai = { | 761 | static struct snd_soc_dai_driver pcm512x_dai = { |
344 | .name = "pcm512x-hifi", | 762 | .name = "pcm512x-hifi", |
345 | .playback = { | 763 | .playback = { |
346 | .stream_name = "Playback", | 764 | .stream_name = "Playback", |
347 | .channels_min = 2, | 765 | .channels_min = 2, |
348 | .channels_max = 2, | 766 | .channels_max = 2, |
349 | .rates = SNDRV_PCM_RATE_8000_192000, | 767 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
768 | .rate_min = 8000, | ||
769 | .rate_max = 384000, | ||
350 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 770 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
351 | SNDRV_PCM_FMTBIT_S24_LE | | 771 | SNDRV_PCM_FMTBIT_S24_LE | |
352 | SNDRV_PCM_FMTBIT_S32_LE | 772 | SNDRV_PCM_FMTBIT_S32_LE |
353 | }, | 773 | }, |
774 | .ops = &pcm512x_dai_ops, | ||
354 | }; | 775 | }; |
355 | 776 | ||
356 | static struct snd_soc_codec_driver pcm512x_codec_driver = { | 777 | static struct snd_soc_codec_driver pcm512x_codec_driver = { |
@@ -448,21 +869,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) | |||
448 | } | 869 | } |
449 | 870 | ||
450 | pcm512x->sclk = devm_clk_get(dev, NULL); | 871 | pcm512x->sclk = devm_clk_get(dev, NULL); |
451 | if (IS_ERR(pcm512x->sclk)) { | 872 | if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) |
452 | if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) | 873 | return -EPROBE_DEFER; |
453 | return -EPROBE_DEFER; | 874 | if (!IS_ERR(pcm512x->sclk)) { |
454 | |||
455 | dev_info(dev, "No SCLK, using BCLK: %ld\n", | ||
456 | PTR_ERR(pcm512x->sclk)); | ||
457 | |||
458 | /* Disable reporting of missing SCLK as an error */ | ||
459 | regmap_update_bits(regmap, PCM512x_ERROR_DETECT, | ||
460 | PCM512x_IDCH, PCM512x_IDCH); | ||
461 | |||
462 | /* Switch PLL input to BCLK */ | ||
463 | regmap_update_bits(regmap, PCM512x_PLL_REF, | ||
464 | PCM512x_SREF, PCM512x_SREF); | ||
465 | } else { | ||
466 | ret = clk_prepare_enable(pcm512x->sclk); | 875 | ret = clk_prepare_enable(pcm512x->sclk); |
467 | if (ret != 0) { | 876 | if (ret != 0) { |
468 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | 877 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); |