kirkwood-i2s.c (c95baf12f5077419db01313ab61c2aac007d40cd) kirkwood-i2s.c (2adfc688777e58f22f691d08728dd74d76177fd9)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * kirkwood-i2s.c
4 *
5 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
6 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
7 */
8

--- 17 unchanged lines hidden (view full) ---

26 (SNDRV_PCM_FMTBIT_S16_LE | \
27 SNDRV_PCM_FMTBIT_S24_LE | \
28 SNDRV_PCM_FMTBIT_S32_LE)
29
30#define KIRKWOOD_SPDIF_FORMATS \
31 (SNDRV_PCM_FMTBIT_S16_LE | \
32 SNDRV_PCM_FMTBIT_S24_LE)
33
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * kirkwood-i2s.c
4 *
5 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
6 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
7 */
8

--- 17 unchanged lines hidden (view full) ---

26 (SNDRV_PCM_FMTBIT_S16_LE | \
27 SNDRV_PCM_FMTBIT_S24_LE | \
28 SNDRV_PCM_FMTBIT_S32_LE)
29
30#define KIRKWOOD_SPDIF_FORMATS \
31 (SNDRV_PCM_FMTBIT_S16_LE | \
32 SNDRV_PCM_FMTBIT_S24_LE)
33
34/* These registers are relative to the second register region -
35 * audio pll configuration.
36 */
37#define A38X_PLL_CONF_REG0 0x0
38#define A38X_PLL_FB_CLK_DIV_OFFSET 10
39#define A38X_PLL_FB_CLK_DIV_MASK 0x7fc00
40#define A38X_PLL_CONF_REG1 0x4
41#define A38X_PLL_FREQ_OFFSET_MASK 0xffff
42#define A38X_PLL_FREQ_OFFSET_VALID BIT(16)
43#define A38X_PLL_SW_RESET BIT(31)
44#define A38X_PLL_CONF_REG2 0x8
45#define A38X_PLL_AUDIO_POSTDIV_MASK 0x7f
46
47/* Bit below belongs to SoC control register corresponding to the third
48 * register region.
49 */
50#define A38X_SPDIF_MODE_ENABLE BIT(27)
51
52static int armada_38x_i2s_init_quirk(struct platform_device *pdev,
53 struct kirkwood_dma_data *priv,
54 struct snd_soc_dai_driver *dai_drv)
55{
56 struct device_node *np = pdev->dev.of_node;
57 u32 reg_val;
58 int i;
59
60 priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
61 if (IS_ERR(priv->pll_config))
62 return -ENOMEM;
63
64 priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
65 if (IS_ERR(priv->soc_control))
66 return -ENOMEM;
67
68 /* Select one of exceptive modes: I2S or S/PDIF */
69 reg_val = readl(priv->soc_control);
70 if (of_property_read_bool(np, "spdif-mode")) {
71 reg_val |= A38X_SPDIF_MODE_ENABLE;
72 dev_info(&pdev->dev, "using S/PDIF mode\n");
73 } else {
74 reg_val &= ~A38X_SPDIF_MODE_ENABLE;
75 dev_info(&pdev->dev, "using I2S mode\n");
76 }
77 writel(reg_val, priv->soc_control);
78
79 /* Update available rates of mclk's fs */
80 for (i = 0; i < 2; i++) {
81 dai_drv[i].playback.rates |= SNDRV_PCM_RATE_192000;
82 dai_drv[i].capture.rates |= SNDRV_PCM_RATE_192000;
83 }
84
85 return 0;
86}
87
88static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
89{
90 u32 reg_val;
91 u16 freq_offset = 0x22b0;
92 u8 audio_postdiv, fb_clk_div = 0x1d;
93
94 /* Set frequency offset value to not valid and enable PLL reset */
95 reg_val = readl(base + A38X_PLL_CONF_REG1);
96 reg_val &= ~A38X_PLL_FREQ_OFFSET_VALID;
97 reg_val &= ~A38X_PLL_SW_RESET;
98 writel(reg_val, base + A38X_PLL_CONF_REG1);
99
100 udelay(1);
101
102 /* Update PLL parameters */
103 switch (rate) {
104 default:
105 case 44100:
106 freq_offset = 0x735;
107 fb_clk_div = 0x1b;
108 audio_postdiv = 0xc;
109 break;
110 case 48000:
111 audio_postdiv = 0xc;
112 break;
113 case 96000:
114 audio_postdiv = 0x6;
115 break;
116 case 192000:
117 audio_postdiv = 0x3;
118 break;
119 }
120
121 reg_val = readl(base + A38X_PLL_CONF_REG0);
122 reg_val &= ~A38X_PLL_FB_CLK_DIV_MASK;
123 reg_val |= (fb_clk_div << A38X_PLL_FB_CLK_DIV_OFFSET);
124 writel(reg_val, base + A38X_PLL_CONF_REG0);
125
126 reg_val = readl(base + A38X_PLL_CONF_REG2);
127 reg_val &= ~A38X_PLL_AUDIO_POSTDIV_MASK;
128 reg_val |= audio_postdiv;
129 writel(reg_val, base + A38X_PLL_CONF_REG2);
130
131 reg_val = readl(base + A38X_PLL_CONF_REG1);
132 reg_val &= ~A38X_PLL_FREQ_OFFSET_MASK;
133 reg_val |= freq_offset;
134 writel(reg_val, base + A38X_PLL_CONF_REG1);
135
136 udelay(1);
137
138 /* Disable reset */
139 reg_val |= A38X_PLL_SW_RESET;
140 writel(reg_val, base + A38X_PLL_CONF_REG1);
141
142 /* Wait 50us for PLL to lock */
143 udelay(50);
144
145 /* Restore frequency offset value validity */
146 reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
147 writel(reg_val, base + A38X_PLL_CONF_REG1);
148}
149
34static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
35 unsigned int fmt)
36{
37 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
38 unsigned long mask;
39 unsigned long value;
40
41 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {

--- 59 unchanged lines hidden (view full) ---

101{
102 uint32_t clks_ctrl;
103
104 if (IS_ERR(priv->extclk)) {
105 /* use internal dco for the supported rates
106 * defined in kirkwood_i2s_dai */
107 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
108 __func__, rate);
150static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
151 unsigned int fmt)
152{
153 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
154 unsigned long mask;
155 unsigned long value;
156
157 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {

--- 59 unchanged lines hidden (view full) ---

217{
218 uint32_t clks_ctrl;
219
220 if (IS_ERR(priv->extclk)) {
221 /* use internal dco for the supported rates
222 * defined in kirkwood_i2s_dai */
223 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
224 __func__, rate);
109 kirkwood_set_dco(priv->io, rate);
225 if (priv->pll_config)
226 armada_38x_set_pll(priv->pll_config, rate);
227 else
228 kirkwood_set_dco(priv->io, rate);
110
111 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
112 } else {
113 /* use the external clock for the other rates
114 * defined in kirkwood_i2s_dai_extclk */
115 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
116 __func__, rate, 256 * rate);
117 clk_set_rate(priv->extclk, 256 * rate);

--- 409 unchanged lines hidden (view full) ---

527 int err;
528
529 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
530 if (!priv)
531 return -ENOMEM;
532
533 dev_set_drvdata(&pdev->dev, priv);
534
229
230 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
231 } else {
232 /* use the external clock for the other rates
233 * defined in kirkwood_i2s_dai_extclk */
234 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
235 __func__, rate, 256 * rate);
236 clk_set_rate(priv->extclk, 256 * rate);

--- 409 unchanged lines hidden (view full) ---

646 int err;
647
648 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
649 if (!priv)
650 return -ENOMEM;
651
652 dev_set_drvdata(&pdev->dev, priv);
653
535 priv->io = devm_platform_ioremap_resource(pdev, 0);
654 if (of_device_is_compatible(np, "marvell,armada-380-audio"))
655 priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
656 else
657 priv->io = devm_platform_ioremap_resource(pdev, 0);
536 if (IS_ERR(priv->io))
537 return PTR_ERR(priv->io);
538
539 priv->irq = platform_get_irq(pdev, 0);
540 if (priv->irq < 0)
541 return priv->irq;
542
658 if (IS_ERR(priv->io))
659 return PTR_ERR(priv->io);
660
661 priv->irq = platform_get_irq(pdev, 0);
662 if (priv->irq < 0)
663 return priv->irq;
664
665 if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
666 err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
667 if (err < 0)
668 return err;
669 /* Set initial pll frequency */
670 armada_38x_set_pll(priv->pll_config, 44100);
671 }
672
543 if (np) {
544 priv->burst = 128; /* might be 32 or 128 */
545 } else if (data) {
546 priv->burst = data->burst;
547 } else {
548 dev_err(&pdev->dev, "no DT nor platform data ?!\n");
549 return -EINVAL;
550 }

--- 67 unchanged lines hidden (view full) ---

618 return 0;
619}
620
621#ifdef CONFIG_OF
622static const struct of_device_id mvebu_audio_of_match[] = {
623 { .compatible = "marvell,kirkwood-audio" },
624 { .compatible = "marvell,dove-audio" },
625 { .compatible = "marvell,armada370-audio" },
673 if (np) {
674 priv->burst = 128; /* might be 32 or 128 */
675 } else if (data) {
676 priv->burst = data->burst;
677 } else {
678 dev_err(&pdev->dev, "no DT nor platform data ?!\n");
679 return -EINVAL;
680 }

--- 67 unchanged lines hidden (view full) ---

748 return 0;
749}
750
751#ifdef CONFIG_OF
752static const struct of_device_id mvebu_audio_of_match[] = {
753 { .compatible = "marvell,kirkwood-audio" },
754 { .compatible = "marvell,dove-audio" },
755 { .compatible = "marvell,armada370-audio" },
756 { .compatible = "marvell,armada-380-audio" },
626 { }
627};
628MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
629#endif
630
631static struct platform_driver kirkwood_i2s_driver = {
632 .probe = kirkwood_i2s_dev_probe,
633 .remove = kirkwood_i2s_dev_remove,

--- 13 unchanged lines hidden ---
757 { }
758};
759MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
760#endif
761
762static struct platform_driver kirkwood_i2s_driver = {
763 .probe = kirkwood_i2s_dev_probe,
764 .remove = kirkwood_i2s_dev_remove,

--- 13 unchanged lines hidden ---