| .. | .. |
|---|
| 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); |
|---|
| .. | .. |
|---|
| 780 | 778 | } |
|---|
| 781 | 779 | |
|---|
| 782 | 780 | /* 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) |
|---|
| 781 | +static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, |
|---|
| 782 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 785 | 783 | { |
|---|
| 786 | 784 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
|---|
| 787 | 785 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
|---|
| .. | .. |
|---|
| 791 | 789 | regmap_read(regmap, REG_SPDIF_SIS, &val); |
|---|
| 792 | 790 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; |
|---|
| 793 | 791 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); |
|---|
| 792 | + |
|---|
| 793 | + return 0; |
|---|
| 794 | +} |
|---|
| 795 | + |
|---|
| 796 | +static int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol, |
|---|
| 797 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 798 | +{ |
|---|
| 799 | + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
|---|
| 800 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
|---|
| 801 | + struct regmap *regmap = spdif_priv->regmap; |
|---|
| 802 | + u32 val; |
|---|
| 803 | + |
|---|
| 804 | + regmap_read(regmap, REG_SPDIF_SCR, &val); |
|---|
| 805 | + val = (val & SCR_VAL_MASK) >> SCR_VAL_OFFSET; |
|---|
| 806 | + val = 1 - val; |
|---|
| 807 | + ucontrol->value.integer.value[0] = val; |
|---|
| 808 | + |
|---|
| 809 | + return 0; |
|---|
| 810 | +} |
|---|
| 811 | + |
|---|
| 812 | +static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, |
|---|
| 813 | + struct snd_ctl_elem_value *ucontrol) |
|---|
| 814 | +{ |
|---|
| 815 | + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
|---|
| 816 | + struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); |
|---|
| 817 | + struct regmap *regmap = spdif_priv->regmap; |
|---|
| 818 | + u32 val = (1 - ucontrol->value.integer.value[0]) << SCR_VAL_OFFSET; |
|---|
| 819 | + |
|---|
| 820 | + regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_VAL_MASK, val); |
|---|
| 794 | 821 | |
|---|
| 795 | 822 | return 0; |
|---|
| 796 | 823 | } |
|---|
| .. | .. |
|---|
| 952 | 979 | /* Valid bit error controller */ |
|---|
| 953 | 980 | { |
|---|
| 954 | 981 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
|---|
| 955 | | - .name = "IEC958 V-Bit Errors", |
|---|
| 982 | + .name = "IEC958 RX V-Bit Errors", |
|---|
| 956 | 983 | .access = SNDRV_CTL_ELEM_ACCESS_READ | |
|---|
| 957 | 984 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
|---|
| 958 | 985 | .info = fsl_spdif_vbit_info, |
|---|
| 959 | | - .get = fsl_spdif_vbit_get, |
|---|
| 986 | + .get = fsl_spdif_rx_vbit_get, |
|---|
| 987 | + }, |
|---|
| 988 | + { |
|---|
| 989 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
|---|
| 990 | + .name = "IEC958 TX V-Bit", |
|---|
| 991 | + .access = SNDRV_CTL_ELEM_ACCESS_READ | |
|---|
| 992 | + SNDRV_CTL_ELEM_ACCESS_WRITE | |
|---|
| 993 | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
|---|
| 994 | + .info = fsl_spdif_vbit_info, |
|---|
| 995 | + .get = fsl_spdif_tx_vbit_get, |
|---|
| 996 | + .put = fsl_spdif_tx_vbit_put, |
|---|
| 960 | 997 | }, |
|---|
| 961 | 998 | /* DPLL lock info get controller */ |
|---|
| 962 | 999 | { |
|---|
| .. | .. |
|---|
| 988 | 1025 | &spdif_private->dma_params_rx); |
|---|
| 989 | 1026 | |
|---|
| 990 | 1027 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); |
|---|
| 1028 | + |
|---|
| 1029 | + /*Clear the val bit for Tx*/ |
|---|
| 1030 | + regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, |
|---|
| 1031 | + SCR_VAL_MASK, SCR_VAL_CLEAR); |
|---|
| 991 | 1032 | |
|---|
| 992 | 1033 | return 0; |
|---|
| 993 | 1034 | } |
|---|
| .. | .. |
|---|
| 1109 | 1150 | static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
|---|
| 1110 | 1151 | bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); |
|---|
| 1111 | 1152 | u64 rate_ideal, rate_actual, sub; |
|---|
| 1112 | | - u32 sysclk_dfmin, sysclk_dfmax; |
|---|
| 1113 | | - u32 txclk_df, sysclk_df, arate; |
|---|
| 1153 | + u32 arate; |
|---|
| 1154 | + u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; |
|---|
| 1155 | + u8 txclk_df; |
|---|
| 1114 | 1156 | |
|---|
| 1115 | 1157 | /* The sysclk has an extra divisor [2, 512] */ |
|---|
| 1116 | 1158 | sysclk_dfmin = is_sysclk ? 2 : 1; |
|---|
| .. | .. |
|---|
| 1184 | 1226 | continue; |
|---|
| 1185 | 1227 | |
|---|
| 1186 | 1228 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, |
|---|
| 1187 | | - i == STC_TXCLK_SPDIF_ROOT); |
|---|
| 1229 | + fsl_spdif_can_set_clk_rate(spdif_priv, i)); |
|---|
| 1188 | 1230 | if (savesub == ret) |
|---|
| 1189 | 1231 | continue; |
|---|
| 1190 | 1232 | |
|---|
| .. | .. |
|---|
| 1212 | 1254 | |
|---|
| 1213 | 1255 | static int fsl_spdif_probe(struct platform_device *pdev) |
|---|
| 1214 | 1256 | { |
|---|
| 1215 | | - struct device_node *np = pdev->dev.of_node; |
|---|
| 1216 | 1257 | struct fsl_spdif_priv *spdif_priv; |
|---|
| 1217 | 1258 | struct spdif_mixer_control *ctrl; |
|---|
| 1218 | 1259 | struct resource *res; |
|---|
| 1219 | 1260 | void __iomem *regs; |
|---|
| 1220 | 1261 | int irq, ret, i; |
|---|
| 1221 | 1262 | |
|---|
| 1222 | | - if (!np) |
|---|
| 1223 | | - return -ENODEV; |
|---|
| 1224 | | - |
|---|
| 1225 | 1263 | spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); |
|---|
| 1226 | 1264 | if (!spdif_priv) |
|---|
| 1227 | 1265 | return -ENOMEM; |
|---|
| 1228 | 1266 | |
|---|
| 1229 | 1267 | spdif_priv->pdev = pdev; |
|---|
| 1268 | + |
|---|
| 1269 | + spdif_priv->soc = of_device_get_match_data(&pdev->dev); |
|---|
| 1270 | + if (!spdif_priv->soc) { |
|---|
| 1271 | + dev_err(&pdev->dev, "failed to get soc data\n"); |
|---|
| 1272 | + return -ENODEV; |
|---|
| 1273 | + } |
|---|
| 1230 | 1274 | |
|---|
| 1231 | 1275 | /* Initialize this copy of the CPU DAI driver structure */ |
|---|
| 1232 | 1276 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); |
|---|
| .. | .. |
|---|
| 1246 | 1290 | } |
|---|
| 1247 | 1291 | |
|---|
| 1248 | 1292 | irq = platform_get_irq(pdev, 0); |
|---|
| 1249 | | - if (irq < 0) { |
|---|
| 1250 | | - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); |
|---|
| 1293 | + if (irq < 0) |
|---|
| 1251 | 1294 | return irq; |
|---|
| 1252 | | - } |
|---|
| 1253 | 1295 | |
|---|
| 1254 | 1296 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, |
|---|
| 1255 | 1297 | dev_name(&pdev->dev), spdif_priv); |
|---|
| .. | .. |
|---|
| 1311 | 1353 | |
|---|
| 1312 | 1354 | /* Register with ASoC */ |
|---|
| 1313 | 1355 | dev_set_drvdata(&pdev->dev, spdif_priv); |
|---|
| 1356 | + pm_runtime_enable(&pdev->dev); |
|---|
| 1357 | + regcache_cache_only(spdif_priv->regmap, true); |
|---|
| 1314 | 1358 | |
|---|
| 1315 | 1359 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, |
|---|
| 1316 | 1360 | &spdif_priv->cpu_dai_drv, 1); |
|---|
| 1317 | 1361 | if (ret) { |
|---|
| 1318 | 1362 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); |
|---|
| 1319 | | - return ret; |
|---|
| 1363 | + goto err_pm_disable; |
|---|
| 1320 | 1364 | } |
|---|
| 1321 | 1365 | |
|---|
| 1322 | 1366 | 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); |
|---|
| 1367 | + if (ret) { |
|---|
| 1368 | + dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n"); |
|---|
| 1369 | + goto err_pm_disable; |
|---|
| 1370 | + } |
|---|
| 1325 | 1371 | |
|---|
| 1372 | + return ret; |
|---|
| 1373 | + |
|---|
| 1374 | +err_pm_disable: |
|---|
| 1375 | + pm_runtime_disable(&pdev->dev); |
|---|
| 1326 | 1376 | return ret; |
|---|
| 1327 | 1377 | } |
|---|
| 1328 | 1378 | |
|---|
| 1329 | | -#ifdef CONFIG_PM_SLEEP |
|---|
| 1330 | | -static int fsl_spdif_suspend(struct device *dev) |
|---|
| 1379 | +static int fsl_spdif_remove(struct platform_device *pdev) |
|---|
| 1331 | 1380 | { |
|---|
| 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); |
|---|
| 1381 | + pm_runtime_disable(&pdev->dev); |
|---|
| 1339 | 1382 | |
|---|
| 1340 | 1383 | return 0; |
|---|
| 1341 | 1384 | } |
|---|
| 1342 | 1385 | |
|---|
| 1343 | | -static int fsl_spdif_resume(struct device *dev) |
|---|
| 1386 | +#ifdef CONFIG_PM |
|---|
| 1387 | +static int fsl_spdif_runtime_suspend(struct device *dev) |
|---|
| 1344 | 1388 | { |
|---|
| 1345 | 1389 | struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); |
|---|
| 1390 | + int i; |
|---|
| 1391 | + |
|---|
| 1392 | + /* Disable all the interrupts */ |
|---|
| 1393 | + regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0); |
|---|
| 1394 | + |
|---|
| 1395 | + regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, |
|---|
| 1396 | + &spdif_priv->regcache_srpc); |
|---|
| 1397 | + regcache_cache_only(spdif_priv->regmap, true); |
|---|
| 1398 | + |
|---|
| 1399 | + clk_disable_unprepare(spdif_priv->rxclk); |
|---|
| 1400 | + |
|---|
| 1401 | + for (i = 0; i < SPDIF_TXRATE_MAX; i++) |
|---|
| 1402 | + clk_disable_unprepare(spdif_priv->txclk[i]); |
|---|
| 1403 | + |
|---|
| 1404 | + if (!IS_ERR(spdif_priv->spbaclk)) |
|---|
| 1405 | + clk_disable_unprepare(spdif_priv->spbaclk); |
|---|
| 1406 | + clk_disable_unprepare(spdif_priv->coreclk); |
|---|
| 1407 | + |
|---|
| 1408 | + return 0; |
|---|
| 1409 | +} |
|---|
| 1410 | + |
|---|
| 1411 | +static int fsl_spdif_runtime_resume(struct device *dev) |
|---|
| 1412 | +{ |
|---|
| 1413 | + struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); |
|---|
| 1414 | + int ret; |
|---|
| 1415 | + int i; |
|---|
| 1416 | + |
|---|
| 1417 | + ret = clk_prepare_enable(spdif_priv->coreclk); |
|---|
| 1418 | + if (ret) { |
|---|
| 1419 | + dev_err(dev, "failed to enable core clock\n"); |
|---|
| 1420 | + return ret; |
|---|
| 1421 | + } |
|---|
| 1422 | + |
|---|
| 1423 | + if (!IS_ERR(spdif_priv->spbaclk)) { |
|---|
| 1424 | + ret = clk_prepare_enable(spdif_priv->spbaclk); |
|---|
| 1425 | + if (ret) { |
|---|
| 1426 | + dev_err(dev, "failed to enable spba clock\n"); |
|---|
| 1427 | + goto disable_core_clk; |
|---|
| 1428 | + } |
|---|
| 1429 | + } |
|---|
| 1430 | + |
|---|
| 1431 | + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { |
|---|
| 1432 | + ret = clk_prepare_enable(spdif_priv->txclk[i]); |
|---|
| 1433 | + if (ret) |
|---|
| 1434 | + goto disable_tx_clk; |
|---|
| 1435 | + } |
|---|
| 1436 | + |
|---|
| 1437 | + ret = clk_prepare_enable(spdif_priv->rxclk); |
|---|
| 1438 | + if (ret) |
|---|
| 1439 | + goto disable_tx_clk; |
|---|
| 1346 | 1440 | |
|---|
| 1347 | 1441 | regcache_cache_only(spdif_priv->regmap, false); |
|---|
| 1442 | + regcache_mark_dirty(spdif_priv->regmap); |
|---|
| 1348 | 1443 | |
|---|
| 1349 | 1444 | regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, |
|---|
| 1350 | 1445 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, |
|---|
| 1351 | 1446 | spdif_priv->regcache_srpc); |
|---|
| 1352 | 1447 | |
|---|
| 1353 | | - return regcache_sync(spdif_priv->regmap); |
|---|
| 1448 | + ret = regcache_sync(spdif_priv->regmap); |
|---|
| 1449 | + if (ret) |
|---|
| 1450 | + goto disable_rx_clk; |
|---|
| 1451 | + |
|---|
| 1452 | + return 0; |
|---|
| 1453 | + |
|---|
| 1454 | +disable_rx_clk: |
|---|
| 1455 | + clk_disable_unprepare(spdif_priv->rxclk); |
|---|
| 1456 | +disable_tx_clk: |
|---|
| 1457 | + for (i--; i >= 0; i--) |
|---|
| 1458 | + clk_disable_unprepare(spdif_priv->txclk[i]); |
|---|
| 1459 | + if (!IS_ERR(spdif_priv->spbaclk)) |
|---|
| 1460 | + clk_disable_unprepare(spdif_priv->spbaclk); |
|---|
| 1461 | +disable_core_clk: |
|---|
| 1462 | + clk_disable_unprepare(spdif_priv->coreclk); |
|---|
| 1463 | + |
|---|
| 1464 | + return ret; |
|---|
| 1354 | 1465 | } |
|---|
| 1355 | | -#endif /* CONFIG_PM_SLEEP */ |
|---|
| 1466 | +#endif /* CONFIG_PM */ |
|---|
| 1356 | 1467 | |
|---|
| 1357 | 1468 | static const struct dev_pm_ops fsl_spdif_pm = { |
|---|
| 1358 | | - SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume) |
|---|
| 1469 | + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
|---|
| 1470 | + pm_runtime_force_resume) |
|---|
| 1471 | + SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, |
|---|
| 1472 | + NULL) |
|---|
| 1359 | 1473 | }; |
|---|
| 1360 | 1474 | |
|---|
| 1361 | 1475 | static const struct of_device_id fsl_spdif_dt_ids[] = { |
|---|
| 1362 | | - { .compatible = "fsl,imx35-spdif", }, |
|---|
| 1363 | | - { .compatible = "fsl,vf610-spdif", }, |
|---|
| 1476 | + { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, }, |
|---|
| 1477 | + { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, |
|---|
| 1478 | + { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, |
|---|
| 1364 | 1479 | {} |
|---|
| 1365 | 1480 | }; |
|---|
| 1366 | 1481 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); |
|---|
| .. | .. |
|---|
| 1372 | 1487 | .pm = &fsl_spdif_pm, |
|---|
| 1373 | 1488 | }, |
|---|
| 1374 | 1489 | .probe = fsl_spdif_probe, |
|---|
| 1490 | + .remove = fsl_spdif_remove, |
|---|
| 1375 | 1491 | }; |
|---|
| 1376 | 1492 | |
|---|
| 1377 | 1493 | module_platform_driver(fsl_spdif_driver); |
|---|