.. | .. |
---|
16 | 16 | #include <linux/of_device.h> |
---|
17 | 17 | #include <linux/of_irq.h> |
---|
18 | 18 | #include <linux/regmap.h> |
---|
| 19 | +#include <linux/pm_runtime.h> |
---|
19 | 20 | |
---|
20 | 21 | #include <sound/asoundef.h> |
---|
21 | 22 | #include <sound/dmaengine_pcm.h> |
---|
.. | .. |
---|
41 | 42 | #define SRPC_NODPLL_START2 0xc |
---|
42 | 43 | |
---|
43 | 44 | #define DEFAULT_RXCLK_SRC 1 |
---|
| 45 | + |
---|
| 46 | +/** |
---|
| 47 | + * struct fsl_spdif_soc_data: soc specific data |
---|
| 48 | + * |
---|
| 49 | + * @imx: for imx platform |
---|
| 50 | + * @shared_root_clock: flag of sharing a clock source with others; |
---|
| 51 | + * so the driver shouldn't set root clock rate |
---|
| 52 | + */ |
---|
| 53 | +struct fsl_spdif_soc_data { |
---|
| 54 | + bool imx; |
---|
| 55 | + bool shared_root_clock; |
---|
| 56 | +}; |
---|
44 | 57 | |
---|
45 | 58 | /* |
---|
46 | 59 | * SPDIF control structure |
---|
.. | .. |
---|
68 | 81 | }; |
---|
69 | 82 | |
---|
70 | 83 | /** |
---|
71 | | - * fsl_spdif_priv: Freescale SPDIF private data |
---|
72 | | - * |
---|
| 84 | + * struct fsl_spdif_priv - Freescale SPDIF private data |
---|
| 85 | + * @soc: SPDIF soc data |
---|
73 | 86 | * @fsl_spdif_control: SPDIF control data |
---|
74 | 87 | * @cpu_dai_drv: cpu dai driver |
---|
75 | 88 | * @pdev: platform device pointer |
---|
.. | .. |
---|
87 | 100 | * @spbaclk: SPBA clock (optional, depending on SoC design) |
---|
88 | 101 | * @dma_params_tx: DMA parameters for transmit channel |
---|
89 | 102 | * @dma_params_rx: DMA parameters for receive channel |
---|
| 103 | + * @regcache_srpc: regcache for SRPC |
---|
90 | 104 | */ |
---|
91 | 105 | struct fsl_spdif_priv { |
---|
| 106 | + const struct fsl_spdif_soc_data *soc; |
---|
92 | 107 | struct spdif_mixer_control fsl_spdif_control; |
---|
93 | 108 | struct snd_soc_dai_driver cpu_dai_drv; |
---|
94 | 109 | struct platform_device *pdev; |
---|
.. | .. |
---|
96 | 111 | bool dpll_locked; |
---|
97 | 112 | u32 txrate[SPDIF_TXRATE_MAX]; |
---|
98 | 113 | u8 txclk_df[SPDIF_TXRATE_MAX]; |
---|
99 | | - u8 sysclk_df[SPDIF_TXRATE_MAX]; |
---|
| 114 | + u16 sysclk_df[SPDIF_TXRATE_MAX]; |
---|
100 | 115 | u8 txclk_src[SPDIF_TXRATE_MAX]; |
---|
101 | 116 | u8 rxclk_src; |
---|
102 | 117 | struct clk *txclk[SPDIF_TXRATE_MAX]; |
---|
.. | .. |
---|
109 | 124 | /* regcache for SRPC */ |
---|
110 | 125 | u32 regcache_srpc; |
---|
111 | 126 | }; |
---|
| 127 | + |
---|
| 128 | +static struct fsl_spdif_soc_data fsl_spdif_vf610 = { |
---|
| 129 | + .imx = false, |
---|
| 130 | + .shared_root_clock = false, |
---|
| 131 | +}; |
---|
| 132 | + |
---|
| 133 | +static struct fsl_spdif_soc_data fsl_spdif_imx35 = { |
---|
| 134 | + .imx = true, |
---|
| 135 | + .shared_root_clock = false, |
---|
| 136 | +}; |
---|
| 137 | + |
---|
| 138 | +static struct fsl_spdif_soc_data fsl_spdif_imx6sx = { |
---|
| 139 | + .imx = true, |
---|
| 140 | + .shared_root_clock = true, |
---|
| 141 | +}; |
---|
| 142 | + |
---|
| 143 | +/* Check if clk is a root clock that does not share clock source with others */ |
---|
| 144 | +static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk) |
---|
| 145 | +{ |
---|
| 146 | + return (clk == STC_TXCLK_SPDIF_ROOT) && !spdif->soc->shared_root_clock; |
---|
| 147 | +} |
---|
112 | 148 | |
---|
113 | 149 | /* DPLL locked and lock loss interrupt handler */ |
---|
114 | 150 | static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) |
---|
.. | .. |
---|
369 | 405 | static int spdif_set_sample_rate(struct snd_pcm_substream *substream, |
---|
370 | 406 | int sample_rate) |
---|
371 | 407 | { |
---|
372 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
373 | | - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 408 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 409 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
374 | 410 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; |
---|
375 | 411 | struct regmap *regmap = spdif_priv->regmap; |
---|
376 | 412 | struct platform_device *pdev = spdif_priv->pdev; |
---|
377 | 413 | unsigned long csfs = 0; |
---|
378 | 414 | u32 stc, mask, rate; |
---|
379 | | - u8 clk, txclk_df, sysclk_df; |
---|
| 415 | + u16 sysclk_df; |
---|
| 416 | + u8 clk, txclk_df; |
---|
380 | 417 | int ret; |
---|
381 | 418 | |
---|
382 | 419 | switch (sample_rate) { |
---|
.. | .. |
---|
419 | 456 | |
---|
420 | 457 | sysclk_df = spdif_priv->sysclk_df[rate]; |
---|
421 | 458 | |
---|
422 | | - /* Don't mess up the clocks from other modules */ |
---|
423 | | - if (clk != STC_TXCLK_SPDIF_ROOT) |
---|
| 459 | + if (!fsl_spdif_can_set_clk_rate(spdif_priv, clk)) |
---|
424 | 460 | goto clk_set_bypass; |
---|
425 | 461 | |
---|
426 | 462 | /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ |
---|
.. | .. |
---|
456 | 492 | static int fsl_spdif_startup(struct snd_pcm_substream *substream, |
---|
457 | 493 | struct snd_soc_dai *cpu_dai) |
---|
458 | 494 | { |
---|
459 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
460 | | - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 495 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 496 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
461 | 497 | struct platform_device *pdev = spdif_priv->pdev; |
---|
462 | 498 | struct regmap *regmap = spdif_priv->regmap; |
---|
463 | 499 | u32 scr, mask; |
---|
464 | | - int i; |
---|
465 | 500 | int ret; |
---|
466 | 501 | |
---|
467 | 502 | /* Reset module and interrupts only for first initialization */ |
---|
468 | | - if (!cpu_dai->active) { |
---|
469 | | - ret = clk_prepare_enable(spdif_priv->coreclk); |
---|
470 | | - if (ret) { |
---|
471 | | - dev_err(&pdev->dev, "failed to enable core clock\n"); |
---|
472 | | - return ret; |
---|
473 | | - } |
---|
474 | | - |
---|
475 | | - if (!IS_ERR(spdif_priv->spbaclk)) { |
---|
476 | | - ret = clk_prepare_enable(spdif_priv->spbaclk); |
---|
477 | | - if (ret) { |
---|
478 | | - dev_err(&pdev->dev, "failed to enable spba clock\n"); |
---|
479 | | - goto err_spbaclk; |
---|
480 | | - } |
---|
481 | | - } |
---|
482 | | - |
---|
| 503 | + if (!snd_soc_dai_active(cpu_dai)) { |
---|
483 | 504 | ret = spdif_softreset(spdif_priv); |
---|
484 | 505 | if (ret) { |
---|
485 | 506 | dev_err(&pdev->dev, "failed to soft reset\n"); |
---|
486 | | - goto err; |
---|
| 507 | + return ret; |
---|
487 | 508 | } |
---|
488 | 509 | |
---|
489 | 510 | /* Disable all the interrupts */ |
---|
.. | .. |
---|
497 | 518 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | |
---|
498 | 519 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | |
---|
499 | 520 | SCR_TXFIFO_FSEL_MASK; |
---|
500 | | - for (i = 0; i < SPDIF_TXRATE_MAX; i++) { |
---|
501 | | - ret = clk_prepare_enable(spdif_priv->txclk[i]); |
---|
502 | | - if (ret) |
---|
503 | | - goto disable_txclk; |
---|
504 | | - } |
---|
505 | 521 | } else { |
---|
506 | 522 | scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; |
---|
507 | 523 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| |
---|
508 | 524 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; |
---|
509 | | - ret = clk_prepare_enable(spdif_priv->rxclk); |
---|
510 | | - if (ret) |
---|
511 | | - goto err; |
---|
512 | 525 | } |
---|
513 | 526 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); |
---|
514 | 527 | |
---|
.. | .. |
---|
516 | 529 | regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); |
---|
517 | 530 | |
---|
518 | 531 | return 0; |
---|
519 | | - |
---|
520 | | -disable_txclk: |
---|
521 | | - for (i--; i >= 0; i--) |
---|
522 | | - clk_disable_unprepare(spdif_priv->txclk[i]); |
---|
523 | | -err: |
---|
524 | | - if (!IS_ERR(spdif_priv->spbaclk)) |
---|
525 | | - clk_disable_unprepare(spdif_priv->spbaclk); |
---|
526 | | -err_spbaclk: |
---|
527 | | - clk_disable_unprepare(spdif_priv->coreclk); |
---|
528 | | - |
---|
529 | | - return ret; |
---|
530 | 532 | } |
---|
531 | 533 | |
---|
532 | 534 | static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, |
---|
533 | 535 | struct snd_soc_dai *cpu_dai) |
---|
534 | 536 | { |
---|
535 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
536 | | - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 537 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 538 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
537 | 539 | struct regmap *regmap = spdif_priv->regmap; |
---|
538 | | - u32 scr, mask, i; |
---|
| 540 | + u32 scr, mask; |
---|
539 | 541 | |
---|
540 | 542 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
541 | 543 | scr = 0; |
---|
542 | 544 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | |
---|
543 | 545 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | |
---|
544 | 546 | SCR_TXFIFO_FSEL_MASK; |
---|
545 | | - for (i = 0; i < SPDIF_TXRATE_MAX; i++) |
---|
546 | | - clk_disable_unprepare(spdif_priv->txclk[i]); |
---|
| 547 | + /* Disable TX clock */ |
---|
| 548 | + regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0); |
---|
547 | 549 | } else { |
---|
548 | 550 | scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; |
---|
549 | 551 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| |
---|
550 | 552 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; |
---|
551 | | - clk_disable_unprepare(spdif_priv->rxclk); |
---|
552 | 553 | } |
---|
553 | 554 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); |
---|
554 | 555 | |
---|
555 | 556 | /* Power down SPDIF module only if tx&rx are both inactive */ |
---|
556 | | - if (!cpu_dai->active) { |
---|
| 557 | + if (!snd_soc_dai_active(cpu_dai)) { |
---|
557 | 558 | spdif_intr_status_clear(spdif_priv); |
---|
558 | 559 | regmap_update_bits(regmap, REG_SPDIF_SCR, |
---|
559 | 560 | SCR_LOW_POWER, SCR_LOW_POWER); |
---|
560 | | - if (!IS_ERR(spdif_priv->spbaclk)) |
---|
561 | | - clk_disable_unprepare(spdif_priv->spbaclk); |
---|
562 | | - clk_disable_unprepare(spdif_priv->coreclk); |
---|
563 | 561 | } |
---|
564 | 562 | } |
---|
565 | 563 | |
---|
.. | .. |
---|
567 | 565 | struct snd_pcm_hw_params *params, |
---|
568 | 566 | struct snd_soc_dai *dai) |
---|
569 | 567 | { |
---|
570 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
571 | | - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 568 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 569 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
572 | 570 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; |
---|
573 | 571 | struct platform_device *pdev = spdif_priv->pdev; |
---|
574 | 572 | u32 sample_rate = params_rate(params); |
---|
.. | .. |
---|
595 | 593 | static int fsl_spdif_trigger(struct snd_pcm_substream *substream, |
---|
596 | 594 | int cmd, struct snd_soc_dai *dai) |
---|
597 | 595 | { |
---|
598 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
599 | | - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 596 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 597 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
600 | 598 | struct regmap *regmap = spdif_priv->regmap; |
---|
601 | 599 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
---|
602 | 600 | u32 intr = SIE_INTR_FOR(tx); |
---|
.. | .. |
---|
614 | 612 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
---|
615 | 613 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0); |
---|
616 | 614 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0); |
---|
| 615 | + regmap_write(regmap, REG_SPDIF_STL, 0x0); |
---|
| 616 | + regmap_write(regmap, REG_SPDIF_STR, 0x0); |
---|
617 | 617 | break; |
---|
618 | 618 | default: |
---|
619 | 619 | return -EINVAL; |
---|
.. | .. |
---|
780 | 780 | } |
---|
781 | 781 | |
---|
782 | 782 | /* Get valid good bit from interrupt status register */ |
---|
783 | | -static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, |
---|
784 | | - struct snd_ctl_elem_value *ucontrol) |
---|
| 783 | +static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, |
---|
| 784 | + struct snd_ctl_elem_value *ucontrol) |
---|
785 | 785 | { |
---|
786 | 786 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
---|
787 | 787 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
---|
.. | .. |
---|
791 | 791 | regmap_read(regmap, REG_SPDIF_SIS, &val); |
---|
792 | 792 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; |
---|
793 | 793 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); |
---|
| 794 | + |
---|
| 795 | + return 0; |
---|
| 796 | +} |
---|
| 797 | + |
---|
| 798 | +static int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol, |
---|
| 799 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 800 | +{ |
---|
| 801 | + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
---|
| 802 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
---|
| 803 | + struct regmap *regmap = spdif_priv->regmap; |
---|
| 804 | + u32 val; |
---|
| 805 | + |
---|
| 806 | + regmap_read(regmap, REG_SPDIF_SCR, &val); |
---|
| 807 | + val = (val & SCR_VAL_MASK) >> SCR_VAL_OFFSET; |
---|
| 808 | + val = 1 - val; |
---|
| 809 | + ucontrol->value.integer.value[0] = val; |
---|
| 810 | + |
---|
| 811 | + return 0; |
---|
| 812 | +} |
---|
| 813 | + |
---|
| 814 | +static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, |
---|
| 815 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 816 | +{ |
---|
| 817 | + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
---|
| 818 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
---|
| 819 | + struct regmap *regmap = spdif_priv->regmap; |
---|
| 820 | + u32 val = (1 - ucontrol->value.integer.value[0]) << SCR_VAL_OFFSET; |
---|
| 821 | + |
---|
| 822 | + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_VAL_MASK, val); |
---|
794 | 823 | |
---|
795 | 824 | return 0; |
---|
796 | 825 | } |
---|
.. | .. |
---|
952 | 981 | /* Valid bit error controller */ |
---|
953 | 982 | { |
---|
954 | 983 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
---|
955 | | - .name = "IEC958 V-Bit Errors", |
---|
| 984 | + .name = "IEC958 RX V-Bit Errors", |
---|
956 | 985 | .access = SNDRV_CTL_ELEM_ACCESS_READ | |
---|
957 | 986 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
---|
958 | 987 | .info = fsl_spdif_vbit_info, |
---|
959 | | - .get = fsl_spdif_vbit_get, |
---|
| 988 | + .get = fsl_spdif_rx_vbit_get, |
---|
| 989 | + }, |
---|
| 990 | + { |
---|
| 991 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
---|
| 992 | + .name = "IEC958 TX V-Bit", |
---|
| 993 | + .access = SNDRV_CTL_ELEM_ACCESS_READ | |
---|
| 994 | + SNDRV_CTL_ELEM_ACCESS_WRITE | |
---|
| 995 | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
---|
| 996 | + .info = fsl_spdif_vbit_info, |
---|
| 997 | + .get = fsl_spdif_tx_vbit_get, |
---|
| 998 | + .put = fsl_spdif_tx_vbit_put, |
---|
960 | 999 | }, |
---|
961 | 1000 | /* DPLL lock info get controller */ |
---|
962 | 1001 | { |
---|
.. | .. |
---|
988 | 1027 | &spdif_private->dma_params_rx); |
---|
989 | 1028 | |
---|
990 | 1029 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); |
---|
| 1030 | + |
---|
| 1031 | + /*Clear the val bit for Tx*/ |
---|
| 1032 | + regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, |
---|
| 1033 | + SCR_VAL_MASK, SCR_VAL_CLEAR); |
---|
991 | 1034 | |
---|
992 | 1035 | return 0; |
---|
993 | 1036 | } |
---|
.. | .. |
---|
1109 | 1152 | static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
---|
1110 | 1153 | bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); |
---|
1111 | 1154 | u64 rate_ideal, rate_actual, sub; |
---|
1112 | | - u32 sysclk_dfmin, sysclk_dfmax; |
---|
1113 | | - u32 txclk_df, sysclk_df, arate; |
---|
| 1155 | + u32 arate; |
---|
| 1156 | + u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; |
---|
| 1157 | + u8 txclk_df; |
---|
1114 | 1158 | |
---|
1115 | 1159 | /* The sysclk has an extra divisor [2, 512] */ |
---|
1116 | 1160 | sysclk_dfmin = is_sysclk ? 2 : 1; |
---|
.. | .. |
---|
1184 | 1228 | continue; |
---|
1185 | 1229 | |
---|
1186 | 1230 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, |
---|
1187 | | - i == STC_TXCLK_SPDIF_ROOT); |
---|
| 1231 | + fsl_spdif_can_set_clk_rate(spdif_priv, i)); |
---|
1188 | 1232 | if (savesub == ret) |
---|
1189 | 1233 | continue; |
---|
1190 | 1234 | |
---|
.. | .. |
---|
1212 | 1256 | |
---|
1213 | 1257 | static int fsl_spdif_probe(struct platform_device *pdev) |
---|
1214 | 1258 | { |
---|
1215 | | - struct device_node *np = pdev->dev.of_node; |
---|
1216 | 1259 | struct fsl_spdif_priv *spdif_priv; |
---|
1217 | 1260 | struct spdif_mixer_control *ctrl; |
---|
1218 | 1261 | struct resource *res; |
---|
1219 | 1262 | void __iomem *regs; |
---|
1220 | 1263 | int irq, ret, i; |
---|
1221 | 1264 | |
---|
1222 | | - if (!np) |
---|
1223 | | - return -ENODEV; |
---|
1224 | | - |
---|
1225 | 1265 | spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); |
---|
1226 | 1266 | if (!spdif_priv) |
---|
1227 | 1267 | return -ENOMEM; |
---|
1228 | 1268 | |
---|
1229 | 1269 | spdif_priv->pdev = pdev; |
---|
| 1270 | + |
---|
| 1271 | + spdif_priv->soc = of_device_get_match_data(&pdev->dev); |
---|
| 1272 | + if (!spdif_priv->soc) { |
---|
| 1273 | + dev_err(&pdev->dev, "failed to get soc data\n"); |
---|
| 1274 | + return -ENODEV; |
---|
| 1275 | + } |
---|
1230 | 1276 | |
---|
1231 | 1277 | /* Initialize this copy of the CPU DAI driver structure */ |
---|
1232 | 1278 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); |
---|
.. | .. |
---|
1246 | 1292 | } |
---|
1247 | 1293 | |
---|
1248 | 1294 | irq = platform_get_irq(pdev, 0); |
---|
1249 | | - if (irq < 0) { |
---|
1250 | | - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); |
---|
| 1295 | + if (irq < 0) |
---|
1251 | 1296 | return irq; |
---|
1252 | | - } |
---|
1253 | 1297 | |
---|
1254 | 1298 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, |
---|
1255 | 1299 | dev_name(&pdev->dev), spdif_priv); |
---|
.. | .. |
---|
1311 | 1355 | |
---|
1312 | 1356 | /* Register with ASoC */ |
---|
1313 | 1357 | dev_set_drvdata(&pdev->dev, spdif_priv); |
---|
| 1358 | + pm_runtime_enable(&pdev->dev); |
---|
| 1359 | + regcache_cache_only(spdif_priv->regmap, true); |
---|
1314 | 1360 | |
---|
1315 | 1361 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, |
---|
1316 | 1362 | &spdif_priv->cpu_dai_drv, 1); |
---|
1317 | 1363 | if (ret) { |
---|
1318 | 1364 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); |
---|
1319 | | - return ret; |
---|
| 1365 | + goto err_pm_disable; |
---|
1320 | 1366 | } |
---|
1321 | 1367 | |
---|
1322 | 1368 | ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); |
---|
1323 | | - if (ret) |
---|
1324 | | - dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); |
---|
| 1369 | + if (ret) { |
---|
| 1370 | + dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n"); |
---|
| 1371 | + goto err_pm_disable; |
---|
| 1372 | + } |
---|
1325 | 1373 | |
---|
| 1374 | + return ret; |
---|
| 1375 | + |
---|
| 1376 | +err_pm_disable: |
---|
| 1377 | + pm_runtime_disable(&pdev->dev); |
---|
1326 | 1378 | return ret; |
---|
1327 | 1379 | } |
---|
1328 | 1380 | |
---|
1329 | | -#ifdef CONFIG_PM_SLEEP |
---|
1330 | | -static int fsl_spdif_suspend(struct device *dev) |
---|
| 1381 | +static int fsl_spdif_remove(struct platform_device *pdev) |
---|
1331 | 1382 | { |
---|
1332 | | - struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); |
---|
1333 | | - |
---|
1334 | | - regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, |
---|
1335 | | - &spdif_priv->regcache_srpc); |
---|
1336 | | - |
---|
1337 | | - regcache_cache_only(spdif_priv->regmap, true); |
---|
1338 | | - regcache_mark_dirty(spdif_priv->regmap); |
---|
| 1383 | + pm_runtime_disable(&pdev->dev); |
---|
1339 | 1384 | |
---|
1340 | 1385 | return 0; |
---|
1341 | 1386 | } |
---|
1342 | 1387 | |
---|
1343 | | -static int fsl_spdif_resume(struct device *dev) |
---|
| 1388 | +#ifdef CONFIG_PM |
---|
| 1389 | +static int fsl_spdif_runtime_suspend(struct device *dev) |
---|
1344 | 1390 | { |
---|
1345 | 1391 | struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); |
---|
| 1392 | + int i; |
---|
| 1393 | + |
---|
| 1394 | + /* Disable all the interrupts */ |
---|
| 1395 | + regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0); |
---|
| 1396 | + |
---|
| 1397 | + regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, |
---|
| 1398 | + &spdif_priv->regcache_srpc); |
---|
| 1399 | + regcache_cache_only(spdif_priv->regmap, true); |
---|
| 1400 | + |
---|
| 1401 | + clk_disable_unprepare(spdif_priv->rxclk); |
---|
| 1402 | + |
---|
| 1403 | + for (i = 0; i < SPDIF_TXRATE_MAX; i++) |
---|
| 1404 | + clk_disable_unprepare(spdif_priv->txclk[i]); |
---|
| 1405 | + |
---|
| 1406 | + if (!IS_ERR(spdif_priv->spbaclk)) |
---|
| 1407 | + clk_disable_unprepare(spdif_priv->spbaclk); |
---|
| 1408 | + clk_disable_unprepare(spdif_priv->coreclk); |
---|
| 1409 | + |
---|
| 1410 | + return 0; |
---|
| 1411 | +} |
---|
| 1412 | + |
---|
| 1413 | +static int fsl_spdif_runtime_resume(struct device *dev) |
---|
| 1414 | +{ |
---|
| 1415 | + struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); |
---|
| 1416 | + int ret; |
---|
| 1417 | + int i; |
---|
| 1418 | + |
---|
| 1419 | + ret = clk_prepare_enable(spdif_priv->coreclk); |
---|
| 1420 | + if (ret) { |
---|
| 1421 | + dev_err(dev, "failed to enable core clock\n"); |
---|
| 1422 | + return ret; |
---|
| 1423 | + } |
---|
| 1424 | + |
---|
| 1425 | + if (!IS_ERR(spdif_priv->spbaclk)) { |
---|
| 1426 | + ret = clk_prepare_enable(spdif_priv->spbaclk); |
---|
| 1427 | + if (ret) { |
---|
| 1428 | + dev_err(dev, "failed to enable spba clock\n"); |
---|
| 1429 | + goto disable_core_clk; |
---|
| 1430 | + } |
---|
| 1431 | + } |
---|
| 1432 | + |
---|
| 1433 | + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { |
---|
| 1434 | + ret = clk_prepare_enable(spdif_priv->txclk[i]); |
---|
| 1435 | + if (ret) |
---|
| 1436 | + goto disable_tx_clk; |
---|
| 1437 | + } |
---|
| 1438 | + |
---|
| 1439 | + ret = clk_prepare_enable(spdif_priv->rxclk); |
---|
| 1440 | + if (ret) |
---|
| 1441 | + goto disable_tx_clk; |
---|
1346 | 1442 | |
---|
1347 | 1443 | regcache_cache_only(spdif_priv->regmap, false); |
---|
| 1444 | + regcache_mark_dirty(spdif_priv->regmap); |
---|
1348 | 1445 | |
---|
1349 | 1446 | regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, |
---|
1350 | 1447 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, |
---|
1351 | 1448 | spdif_priv->regcache_srpc); |
---|
1352 | 1449 | |
---|
1353 | | - return regcache_sync(spdif_priv->regmap); |
---|
| 1450 | + ret = regcache_sync(spdif_priv->regmap); |
---|
| 1451 | + if (ret) |
---|
| 1452 | + goto disable_rx_clk; |
---|
| 1453 | + |
---|
| 1454 | + return 0; |
---|
| 1455 | + |
---|
| 1456 | +disable_rx_clk: |
---|
| 1457 | + clk_disable_unprepare(spdif_priv->rxclk); |
---|
| 1458 | +disable_tx_clk: |
---|
| 1459 | + for (i--; i >= 0; i--) |
---|
| 1460 | + clk_disable_unprepare(spdif_priv->txclk[i]); |
---|
| 1461 | + if (!IS_ERR(spdif_priv->spbaclk)) |
---|
| 1462 | + clk_disable_unprepare(spdif_priv->spbaclk); |
---|
| 1463 | +disable_core_clk: |
---|
| 1464 | + clk_disable_unprepare(spdif_priv->coreclk); |
---|
| 1465 | + |
---|
| 1466 | + return ret; |
---|
1354 | 1467 | } |
---|
1355 | | -#endif /* CONFIG_PM_SLEEP */ |
---|
| 1468 | +#endif /* CONFIG_PM */ |
---|
1356 | 1469 | |
---|
1357 | 1470 | static const struct dev_pm_ops fsl_spdif_pm = { |
---|
1358 | | - SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume) |
---|
| 1471 | + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
---|
| 1472 | + pm_runtime_force_resume) |
---|
| 1473 | + SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, |
---|
| 1474 | + NULL) |
---|
1359 | 1475 | }; |
---|
1360 | 1476 | |
---|
1361 | 1477 | static const struct of_device_id fsl_spdif_dt_ids[] = { |
---|
1362 | | - { .compatible = "fsl,imx35-spdif", }, |
---|
1363 | | - { .compatible = "fsl,vf610-spdif", }, |
---|
| 1478 | + { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, }, |
---|
| 1479 | + { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, |
---|
| 1480 | + { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, |
---|
1364 | 1481 | {} |
---|
1365 | 1482 | }; |
---|
1366 | 1483 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); |
---|
.. | .. |
---|
1372 | 1489 | .pm = &fsl_spdif_pm, |
---|
1373 | 1490 | }, |
---|
1374 | 1491 | .probe = fsl_spdif_probe, |
---|
| 1492 | + .remove = fsl_spdif_remove, |
---|
1375 | 1493 | }; |
---|
1376 | 1494 | |
---|
1377 | 1495 | module_platform_driver(fsl_spdif_driver); |
---|