Merge tag 'arm-fixes-6.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-block.git] / sound / soc / kirkwood / kirkwood-i2s.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
f9b95980 2/*
3 * kirkwood-i2s.c
4 *
5 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
69737897 6 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
f9b95980 7 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/io.h>
13#include <linux/slab.h>
14#include <linux/mbus.h>
15#include <linux/delay.h>
e919c716 16#include <linux/clk.h>
f9b95980 17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
c02cecb9 20#include <linux/platform_data/asoc-kirkwood.h>
eb632318
JFM
21#include <linux/of.h>
22
f9b95980 23#include "kirkwood.h"
24
f9b95980 25#define KIRKWOOD_I2S_FORMATS \
26 (SNDRV_PCM_FMTBIT_S16_LE | \
27 SNDRV_PCM_FMTBIT_S24_LE | \
28 SNDRV_PCM_FMTBIT_S32_LE)
29
1c195ddb
JFM
30#define KIRKWOOD_SPDIF_FORMATS \
31 (SNDRV_PCM_FMTBIT_S16_LE | \
32 SNDRV_PCM_FMTBIT_S24_LE)
33
2adfc688
MW
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
f9b95980 150static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
151 unsigned int fmt)
152{
f0fba2ad 153 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
f9b95980 154 unsigned long mask;
155 unsigned long value;
156
157 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
158 case SND_SOC_DAIFMT_RIGHT_J:
159 mask = KIRKWOOD_I2S_CTL_RJ;
160 break;
161 case SND_SOC_DAIFMT_LEFT_J:
162 mask = KIRKWOOD_I2S_CTL_LJ;
163 break;
164 case SND_SOC_DAIFMT_I2S:
165 mask = KIRKWOOD_I2S_CTL_I2S;
166 break;
167 default:
168 return -EINVAL;
169 }
170
171 /*
172 * Set same format for playback and record
173 * This avoids some troubles.
174 */
175 value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
176 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
177 value |= mask;
178 writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
179
180 value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
181 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
182 value |= mask;
183 writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
184
185 return 0;
186}
187
188static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
189{
190 unsigned long value;
191
192 value = KIRKWOOD_DCO_CTL_OFFSET_0;
193 switch (rate) {
194 default:
195 case 44100:
196 value |= KIRKWOOD_DCO_CTL_FREQ_11;
197 break;
198 case 48000:
199 value |= KIRKWOOD_DCO_CTL_FREQ_12;
200 break;
201 case 96000:
202 value |= KIRKWOOD_DCO_CTL_FREQ_24;
203 break;
204 }
205 writel(value, io + KIRKWOOD_DCO_CTL);
206
207 /* wait for dco locked */
208 do {
209 cpu_relax();
210 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
2424d458 211 value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
f9b95980 212 } while (value == 0);
213}
214
363589bf
RK
215static void kirkwood_set_rate(struct snd_soc_dai *dai,
216 struct kirkwood_dma_data *priv, unsigned long rate)
217{
218 uint32_t clks_ctrl;
219
1f1b6579 220 if (IS_ERR(priv->extclk)) {
8a537f85
JFM
221 /* use internal dco for the supported rates
222 * defined in kirkwood_i2s_dai */
363589bf
RK
223 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
224 __func__, rate);
2adfc688
MW
225 if (priv->pll_config)
226 armada_38x_set_pll(priv->pll_config, rate);
227 else
228 kirkwood_set_dco(priv->io, rate);
363589bf
RK
229
230 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
8a537f85
JFM
231 } else {
232 /* use the external clock for the other rates
233 * defined in kirkwood_i2s_dai_extclk */
363589bf
RK
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);
237
238 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
239 }
240 writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
241}
242
f0fba2ad
LG
243static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
244 struct snd_soc_dai *dai)
245{
246 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
247
248 snd_soc_dai_set_dma_data(dai, substream, priv);
249 return 0;
250}
251
f9b95980 252static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
253 struct snd_pcm_hw_params *params,
254 struct snd_soc_dai *dai)
255{
f0fba2ad 256 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
d8d11ba5
RK
257 uint32_t ctl_play, ctl_rec;
258 unsigned int i2s_reg;
259 unsigned long i2s_value;
f9b95980 260
261 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
262 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
f9b95980 263 } else {
264 i2s_reg = KIRKWOOD_I2S_RECCTL;
f9b95980 265 }
266
363589bf 267 kirkwood_set_rate(dai, priv, params_rate(params));
f9b95980 268
269 i2s_value = readl(priv->io+i2s_reg);
270 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
271
f9b95980 272 /*
273 * Size settings in play/rec i2s control regs and play/rec control
274 * regs must be the same.
275 */
276 switch (params_format(params)) {
277 case SNDRV_PCM_FORMAT_S16_LE:
278 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
d8d11ba5 279 ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
75b9b65e
JFM
280 KIRKWOOD_PLAYCTL_I2S_EN |
281 KIRKWOOD_PLAYCTL_SPDIF_EN;
d8d11ba5 282 ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
75b9b65e
JFM
283 KIRKWOOD_RECCTL_I2S_EN |
284 KIRKWOOD_RECCTL_SPDIF_EN;
f9b95980 285 break;
286 /*
287 * doesn't work... S20_3LE != kirkwood 20bit format ?
288 *
289 case SNDRV_PCM_FORMAT_S20_3LE:
290 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
d8d11ba5
RK
291 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
292 KIRKWOOD_PLAYCTL_I2S_EN;
293 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
294 KIRKWOOD_RECCTL_I2S_EN;
f9b95980 295 break;
296 */
297 case SNDRV_PCM_FORMAT_S24_LE:
298 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
d8d11ba5 299 ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
75b9b65e
JFM
300 KIRKWOOD_PLAYCTL_I2S_EN |
301 KIRKWOOD_PLAYCTL_SPDIF_EN;
d8d11ba5 302 ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
75b9b65e
JFM
303 KIRKWOOD_RECCTL_I2S_EN |
304 KIRKWOOD_RECCTL_SPDIF_EN;
f9b95980 305 break;
306 case SNDRV_PCM_FORMAT_S32_LE:
307 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
d8d11ba5
RK
308 ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
309 KIRKWOOD_PLAYCTL_I2S_EN;
310 ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
311 KIRKWOOD_RECCTL_I2S_EN;
f9b95980 312 break;
313 default:
314 return -EINVAL;
315 }
dfe4c936 316
317 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dfe4c936 318 if (params_channels(params) == 1)
d8d11ba5 319 ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
dfe4c936 320 else
d8d11ba5
RK
321 ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
322
323 priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
db43b16f 324 KIRKWOOD_PLAYCTL_ENABLE_MASK |
d8d11ba5
RK
325 KIRKWOOD_PLAYCTL_SIZE_MASK);
326 priv->ctl_play |= ctl_play;
327 } else {
67721906
RK
328 priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
329 KIRKWOOD_RECCTL_SIZE_MASK);
d8d11ba5 330 priv->ctl_rec |= ctl_rec;
dfe4c936 331 }
332
f9b95980 333 writel(i2s_value, priv->io+i2s_reg);
f9b95980 334
335 return 0;
336}
337
2fbc3821
RK
338static unsigned kirkwood_i2s_play_mute(unsigned ctl)
339{
340 if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN))
341 ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE;
342 if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN))
343 ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE;
344 return ctl;
345}
346
f9b95980 347static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
348 int cmd, struct snd_soc_dai *dai)
349{
920ec4e5 350 struct snd_pcm_runtime *runtime = substream->runtime;
f0fba2ad 351 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
982b604b
RK
352 uint32_t ctl, value;
353
354 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
4d2097e5 355 if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
982b604b
RK
356 unsigned timeout = 5000;
357 /*
358 * The Armada510 spec says that if we enter pause mode, the
359 * busy bit must be read back as clear _twice_. Make sure
360 * we respect that otherwise we get DMA underruns.
361 */
362 do {
363 value = ctl;
364 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
365 if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
366 break;
367 udelay(1);
368 } while (timeout--);
369
370 if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
371 dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
372 ctl);
373 }
f9b95980 374
375 switch (cmd) {
376 case SNDRV_PCM_TRIGGER_START:
d8d11ba5
RK
377 /* configure */
378 ctl = priv->ctl_play;
4f6f1478
JFM
379 if (dai->id == 0)
380 ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
381 else
382 ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
2fbc3821 383 ctl = kirkwood_i2s_play_mute(ctl);
db43b16f 384 value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
d8d11ba5
RK
385 writel(value, priv->io + KIRKWOOD_PLAYCTL);
386
387 /* enable interrupts */
920ec4e5
RK
388 if (!runtime->no_period_wakeup) {
389 value = readl(priv->io + KIRKWOOD_INT_MASK);
390 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
391 writel(value, priv->io + KIRKWOOD_INT_MASK);
392 }
f9b95980 393
d8d11ba5 394 /* enable playback */
982b604b 395 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
f9b95980 396 break;
397
398 case SNDRV_PCM_TRIGGER_STOP:
399 /* stop audio, disable interrupts */
75b9b65e
JFM
400 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
401 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
982b604b 402 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
f9b95980 403
404 value = readl(priv->io + KIRKWOOD_INT_MASK);
405 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
406 writel(value, priv->io + KIRKWOOD_INT_MASK);
407
408 /* disable all playbacks */
db43b16f 409 ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
982b604b 410 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
f9b95980 411 break;
412
413 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
414 case SNDRV_PCM_TRIGGER_SUSPEND:
75b9b65e
JFM
415 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
416 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
982b604b 417 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
f9b95980 418 break;
419
420 case SNDRV_PCM_TRIGGER_RESUME:
421 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
75b9b65e
JFM
422 ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
423 KIRKWOOD_PLAYCTL_SPDIF_MUTE);
2fbc3821 424 ctl = kirkwood_i2s_play_mute(ctl);
982b604b 425 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
f9b95980 426 break;
427
428 default:
429 return -EINVAL;
430 }
431
432 return 0;
433}
434
435static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
436 int cmd, struct snd_soc_dai *dai)
437{
f0fba2ad 438 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
d8d11ba5 439 uint32_t ctl, value;
f9b95980 440
441 value = readl(priv->io + KIRKWOOD_RECCTL);
442
443 switch (cmd) {
444 case SNDRV_PCM_TRIGGER_START:
d8d11ba5
RK
445 /* configure */
446 ctl = priv->ctl_rec;
75b9b65e
JFM
447 if (dai->id == 0)
448 ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
449 else
450 ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
451
52b896cf 452 value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
d8d11ba5
RK
453 writel(value, priv->io + KIRKWOOD_RECCTL);
454
455 /* enable interrupts */
f9b95980 456 value = readl(priv->io + KIRKWOOD_INT_MASK);
457 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
458 writel(value, priv->io + KIRKWOOD_INT_MASK);
459
d8d11ba5
RK
460 /* enable record */
461 writel(ctl, priv->io + KIRKWOOD_RECCTL);
f9b95980 462 break;
463
464 case SNDRV_PCM_TRIGGER_STOP:
465 /* stop audio, disable interrupts */
466 value = readl(priv->io + KIRKWOOD_RECCTL);
b424ec95 467 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
f9b95980 468 writel(value, priv->io + KIRKWOOD_RECCTL);
469
470 value = readl(priv->io + KIRKWOOD_INT_MASK);
471 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
472 writel(value, priv->io + KIRKWOOD_INT_MASK);
473
474 /* disable all records */
475 value = readl(priv->io + KIRKWOOD_RECCTL);
52b896cf 476 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
f9b95980 477 writel(value, priv->io + KIRKWOOD_RECCTL);
478 break;
479
480 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
481 case SNDRV_PCM_TRIGGER_SUSPEND:
482 value = readl(priv->io + KIRKWOOD_RECCTL);
b424ec95 483 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
f9b95980 484 writel(value, priv->io + KIRKWOOD_RECCTL);
485 break;
486
487 case SNDRV_PCM_TRIGGER_RESUME:
488 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
489 value = readl(priv->io + KIRKWOOD_RECCTL);
b424ec95 490 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
f9b95980 491 writel(value, priv->io + KIRKWOOD_RECCTL);
492 break;
493
494 default:
495 return -EINVAL;
f9b95980 496 }
497
498 return 0;
499}
500
501static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
502 struct snd_soc_dai *dai)
503{
504 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
505 return kirkwood_i2s_play_trigger(substream, cmd, dai);
506 else
507 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
508
509 return 0;
510}
511
75b9b65e 512static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
f9b95980 513{
514 unsigned long value;
515 unsigned int reg_data;
516
517 /* put system in a "safe" state : */
518 /* disable audio interrupts */
519 writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
520 writel(0, priv->io + KIRKWOOD_INT_MASK);
521
522 reg_data = readl(priv->io + 0x1200);
523 reg_data &= (~(0x333FF8));
524 reg_data |= 0x111D18;
525 writel(reg_data, priv->io + 0x1200);
526
527 msleep(500);
528
529 reg_data = readl(priv->io + 0x1200);
530 reg_data &= (~(0x333FF8));
531 reg_data |= 0x111D18;
532 writel(reg_data, priv->io + 0x1200);
533
534 /* disable playback/record */
535 value = readl(priv->io + KIRKWOOD_PLAYCTL);
db43b16f 536 value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
f9b95980 537 writel(value, priv->io + KIRKWOOD_PLAYCTL);
538
539 value = readl(priv->io + KIRKWOOD_RECCTL);
52b896cf 540 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
f9b95980 541 writel(value, priv->io + KIRKWOOD_RECCTL);
542
543 return 0;
544
545}
546
85e7652d 547static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
f0fba2ad 548 .startup = kirkwood_i2s_startup,
f9b95980 549 .trigger = kirkwood_i2s_trigger,
550 .hw_params = kirkwood_i2s_hw_params,
551 .set_fmt = kirkwood_i2s_set_fmt,
552};
553
75b9b65e
JFM
554static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
555 {
556 .name = "i2s",
557 .id = 0,
558 .playback = {
559 .channels_min = 1,
560 .channels_max = 2,
561 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
562 SNDRV_PCM_RATE_96000,
563 .formats = KIRKWOOD_I2S_FORMATS,
564 },
565 .capture = {
566 .channels_min = 1,
567 .channels_max = 2,
568 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
569 SNDRV_PCM_RATE_96000,
570 .formats = KIRKWOOD_I2S_FORMATS,
571 },
572 .ops = &kirkwood_i2s_dai_ops,
573 },
574 {
575 .name = "spdif",
576 .id = 1,
f9b95980 577 .playback = {
578 .channels_min = 1,
579 .channels_max = 2,
9e12cbd9
MB
580 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
581 SNDRV_PCM_RATE_96000,
1c195ddb 582 .formats = KIRKWOOD_SPDIF_FORMATS,
363589bf 583 },
f9b95980 584 .capture = {
585 .channels_min = 1,
586 .channels_max = 2,
9e12cbd9
MB
587 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
588 SNDRV_PCM_RATE_96000,
1c195ddb 589 .formats = KIRKWOOD_SPDIF_FORMATS,
363589bf
RK
590 },
591 .ops = &kirkwood_i2s_dai_ops,
75b9b65e 592 },
363589bf
RK
593};
594
75b9b65e
JFM
595static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
596 {
597 .name = "i2s",
598 .id = 0,
599 .playback = {
600 .channels_min = 1,
601 .channels_max = 2,
02fc17c1
JFM
602 .rates = SNDRV_PCM_RATE_CONTINUOUS,
603 .rate_min = 5512,
604 .rate_max = 192000,
75b9b65e
JFM
605 .formats = KIRKWOOD_I2S_FORMATS,
606 },
607 .capture = {
608 .channels_min = 1,
609 .channels_max = 2,
02fc17c1
JFM
610 .rates = SNDRV_PCM_RATE_CONTINUOUS,
611 .rate_min = 5512,
612 .rate_max = 192000,
75b9b65e
JFM
613 .formats = KIRKWOOD_I2S_FORMATS,
614 },
615 .ops = &kirkwood_i2s_dai_ops,
616 },
617 {
618 .name = "spdif",
619 .id = 1,
363589bf
RK
620 .playback = {
621 .channels_min = 1,
622 .channels_max = 2,
02fc17c1
JFM
623 .rates = SNDRV_PCM_RATE_CONTINUOUS,
624 .rate_min = 5512,
625 .rate_max = 192000,
1c195ddb 626 .formats = KIRKWOOD_SPDIF_FORMATS,
363589bf
RK
627 },
628 .capture = {
629 .channels_min = 1,
630 .channels_max = 2,
02fc17c1
JFM
631 .rates = SNDRV_PCM_RATE_CONTINUOUS,
632 .rate_min = 5512,
633 .rate_max = 192000,
1c195ddb 634 .formats = KIRKWOOD_SPDIF_FORMATS,
363589bf 635 },
f9b95980 636 .ops = &kirkwood_i2s_dai_ops,
75b9b65e 637 },
f9b95980 638};
f9b95980 639
34e15fbd 640static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
f9b95980 641{
363589bf 642 struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
75b9b65e 643 struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
f0fba2ad 644 struct kirkwood_dma_data *priv;
eb632318 645 struct device_node *np = pdev->dev.of_node;
f9b95980 646 int err;
647
dbc517bf 648 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
c7591edc 649 if (!priv)
dbc517bf 650 return -ENOMEM;
c7591edc 651
f0fba2ad 652 dev_set_drvdata(&pdev->dev, priv);
f9b95980 653
2adfc688
MW
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);
b25b5aa0
TR
658 if (IS_ERR(priv->io))
659 return PTR_ERR(priv->io);
f9b95980 660
661 priv->irq = platform_get_irq(pdev, 0);
cf9441ad 662 if (priv->irq < 0)
e7b2e30a 663 return priv->irq;
f9b95980 664
2adfc688
MW
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
eb632318
JFM
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");
dbc517bf 679 return -EINVAL;
f9b95980 680 }
681
eb632318 682 priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
e919c716
AL
683 if (IS_ERR(priv->clk)) {
684 dev_err(&pdev->dev, "no clock\n");
dbc517bf 685 return PTR_ERR(priv->clk);
e919c716 686 }
dbc517bf 687
4734dc96 688 priv->extclk = devm_clk_get(&pdev->dev, "extclk");
84aac6c7
JFM
689 if (IS_ERR(priv->extclk)) {
690 if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
691 return -EPROBE_DEFER;
692 } else {
aaa6d062 693 if (clk_is_match(priv->extclk, priv->clk)) {
af64d734 694 devm_clk_put(&pdev->dev, priv->extclk);
d8d11ba5
RK
695 priv->extclk = ERR_PTR(-EINVAL);
696 } else {
697 dev_info(&pdev->dev, "found external clock\n");
698 clk_prepare_enable(priv->extclk);
99d8d3ba 699 soc_dai = kirkwood_i2s_dai_extclk;
d8d11ba5
RK
700 }
701 }
702
4523817d
RK
703 err = clk_prepare_enable(priv->clk);
704 if (err < 0)
705 return err;
706
d8d11ba5
RK
707 /* Some sensible defaults - this reflects the powerup values */
708 priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
709 priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
710
711 /* Select the burst size */
eb632318 712 if (priv->burst == 32) {
d8d11ba5
RK
713 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
714 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
715 } else {
716 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
717 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
718 }
719
dc39596a 720 err = snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
75b9b65e 721 soc_dai, 2);
64ddf1f8
RK
722 if (err) {
723 dev_err(&pdev->dev, "snd_soc_register_component failed\n");
724 goto err_component;
725 }
baffab28 726
75b9b65e
JFM
727 kirkwood_i2s_init(priv);
728
64ddf1f8 729 return 0;
f98fc0f8 730
64ddf1f8 731 err_component:
4734dc96 732 if (!IS_ERR(priv->extclk))
363589bf 733 clk_disable_unprepare(priv->extclk);
baffab28 734 clk_disable_unprepare(priv->clk);
dbc517bf 735
f9b95980 736 return err;
737}
738
8c078706 739static void kirkwood_i2s_dev_remove(struct platform_device *pdev)
f9b95980 740{
f0fba2ad
LG
741 struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
742
dc39596a 743 snd_soc_unregister_component(&pdev->dev);
4734dc96 744 if (!IS_ERR(priv->extclk))
363589bf 745 clk_disable_unprepare(priv->extclk);
e919c716 746 clk_disable_unprepare(priv->clk);
f9b95980 747}
748
eb632318 749#ifdef CONFIG_OF
7f2c52af 750static const struct of_device_id mvebu_audio_of_match[] = {
d098b2f0
TP
751 { .compatible = "marvell,kirkwood-audio" },
752 { .compatible = "marvell,dove-audio" },
9a0d5113 753 { .compatible = "marvell,armada370-audio" },
2adfc688 754 { .compatible = "marvell,armada-380-audio" },
eb632318
JFM
755 { }
756};
757MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
758#endif
759
f9b95980 760static struct platform_driver kirkwood_i2s_driver = {
761 .probe = kirkwood_i2s_dev_probe,
8c078706 762 .remove_new = kirkwood_i2s_dev_remove,
f9b95980 763 .driver = {
764 .name = DRV_NAME,
eb632318 765 .of_match_table = of_match_ptr(mvebu_audio_of_match),
f9b95980 766 },
767};
768
41b10225 769module_platform_driver(kirkwood_i2s_driver);
f9b95980 770
771/* Module information */
69737897 772MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
f9b95980 773MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
774MODULE_LICENSE("GPL");
64ddf1f8 775MODULE_ALIAS("platform:mvebu-audio");