Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/kirkwood/kirkwood-i2s.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* kirkwood-i2s.c
4
*
5
* (c) 2010 Arnaud Patard <[email protected]>
6
* (c) 2010 Arnaud Patard <[email protected]>
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>
16
#include <linux/clk.h>
17
#include <sound/pcm.h>
18
#include <sound/pcm_params.h>
19
#include <sound/soc.h>
20
#include <linux/platform_data/asoc-kirkwood.h>
21
#include <linux/of.h>
22
23
#include "kirkwood.h"
24
25
#define KIRKWOOD_I2S_FORMATS \
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
52
static 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
88
static 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
150
static 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) {
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
188
static 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);
211
value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
212
} while (value == 0);
213
}
214
215
static 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
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);
225
if (priv->pll_config)
226
armada_38x_set_pll(priv->pll_config, rate);
227
else
228
kirkwood_set_dco(priv->io, rate);
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);
237
238
clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
239
}
240
writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
241
}
242
243
static 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
252
static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
253
struct snd_pcm_hw_params *params,
254
struct snd_soc_dai *dai)
255
{
256
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
257
uint32_t ctl_play, ctl_rec;
258
unsigned int i2s_reg;
259
unsigned long i2s_value;
260
261
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
262
i2s_reg = KIRKWOOD_I2S_PLAYCTL;
263
} else {
264
i2s_reg = KIRKWOOD_I2S_RECCTL;
265
}
266
267
kirkwood_set_rate(dai, priv, params_rate(params));
268
269
i2s_value = readl(priv->io+i2s_reg);
270
i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
271
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;
279
ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
280
KIRKWOOD_PLAYCTL_I2S_EN |
281
KIRKWOOD_PLAYCTL_SPDIF_EN;
282
ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
283
KIRKWOOD_RECCTL_I2S_EN |
284
KIRKWOOD_RECCTL_SPDIF_EN;
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;
291
ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
292
KIRKWOOD_PLAYCTL_I2S_EN;
293
ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
294
KIRKWOOD_RECCTL_I2S_EN;
295
break;
296
*/
297
case SNDRV_PCM_FORMAT_S24_LE:
298
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
299
ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
300
KIRKWOOD_PLAYCTL_I2S_EN |
301
KIRKWOOD_PLAYCTL_SPDIF_EN;
302
ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
303
KIRKWOOD_RECCTL_I2S_EN |
304
KIRKWOOD_RECCTL_SPDIF_EN;
305
break;
306
case SNDRV_PCM_FORMAT_S32_LE:
307
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
308
ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
309
KIRKWOOD_PLAYCTL_I2S_EN;
310
ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
311
KIRKWOOD_RECCTL_I2S_EN;
312
break;
313
default:
314
return -EINVAL;
315
}
316
317
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
318
if (params_channels(params) == 1)
319
ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
320
else
321
ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
322
323
priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
324
KIRKWOOD_PLAYCTL_ENABLE_MASK |
325
KIRKWOOD_PLAYCTL_SIZE_MASK);
326
priv->ctl_play |= ctl_play;
327
} else {
328
priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
329
KIRKWOOD_RECCTL_SIZE_MASK);
330
priv->ctl_rec |= ctl_rec;
331
}
332
333
writel(i2s_value, priv->io+i2s_reg);
334
335
return 0;
336
}
337
338
static 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
347
static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
348
int cmd, struct snd_soc_dai *dai)
349
{
350
struct snd_pcm_runtime *runtime = substream->runtime;
351
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
352
uint32_t ctl, value;
353
354
ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
355
if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
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
}
374
375
switch (cmd) {
376
case SNDRV_PCM_TRIGGER_START:
377
/* configure */
378
ctl = priv->ctl_play;
379
if (dai->id == 0)
380
ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
381
else
382
ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
383
ctl = kirkwood_i2s_play_mute(ctl);
384
value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
385
writel(value, priv->io + KIRKWOOD_PLAYCTL);
386
387
/* enable interrupts */
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
}
393
394
/* enable playback */
395
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
396
break;
397
398
case SNDRV_PCM_TRIGGER_STOP:
399
/* stop audio, disable interrupts */
400
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
401
KIRKWOOD_PLAYCTL_SPDIF_MUTE;
402
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
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 */
409
ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
410
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
411
break;
412
413
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
414
case SNDRV_PCM_TRIGGER_SUSPEND:
415
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
416
KIRKWOOD_PLAYCTL_SPDIF_MUTE;
417
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
418
break;
419
420
case SNDRV_PCM_TRIGGER_RESUME:
421
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
422
ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
423
KIRKWOOD_PLAYCTL_SPDIF_MUTE);
424
ctl = kirkwood_i2s_play_mute(ctl);
425
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
426
break;
427
428
default:
429
return -EINVAL;
430
}
431
432
return 0;
433
}
434
435
static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
436
int cmd, struct snd_soc_dai *dai)
437
{
438
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
439
uint32_t ctl, value;
440
441
value = readl(priv->io + KIRKWOOD_RECCTL);
442
443
switch (cmd) {
444
case SNDRV_PCM_TRIGGER_START:
445
/* configure */
446
ctl = priv->ctl_rec;
447
if (dai->id == 0)
448
ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
449
else
450
ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
451
452
value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
453
writel(value, priv->io + KIRKWOOD_RECCTL);
454
455
/* enable interrupts */
456
value = readl(priv->io + KIRKWOOD_INT_MASK);
457
value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
458
writel(value, priv->io + KIRKWOOD_INT_MASK);
459
460
/* enable record */
461
writel(ctl, priv->io + KIRKWOOD_RECCTL);
462
break;
463
464
case SNDRV_PCM_TRIGGER_STOP:
465
/* stop audio, disable interrupts */
466
value = readl(priv->io + KIRKWOOD_RECCTL);
467
value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
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);
476
value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
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);
483
value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
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);
490
value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
491
writel(value, priv->io + KIRKWOOD_RECCTL);
492
break;
493
494
default:
495
return -EINVAL;
496
}
497
498
return 0;
499
}
500
501
static 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
512
static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
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);
536
value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
537
writel(value, priv->io + KIRKWOOD_PLAYCTL);
538
539
value = readl(priv->io + KIRKWOOD_RECCTL);
540
value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
541
writel(value, priv->io + KIRKWOOD_RECCTL);
542
543
return 0;
544
545
}
546
547
static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
548
.startup = kirkwood_i2s_startup,
549
.trigger = kirkwood_i2s_trigger,
550
.hw_params = kirkwood_i2s_hw_params,
551
.set_fmt = kirkwood_i2s_set_fmt,
552
};
553
554
static 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,
577
.playback = {
578
.channels_min = 1,
579
.channels_max = 2,
580
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
581
SNDRV_PCM_RATE_96000,
582
.formats = KIRKWOOD_SPDIF_FORMATS,
583
},
584
.capture = {
585
.channels_min = 1,
586
.channels_max = 2,
587
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
588
SNDRV_PCM_RATE_96000,
589
.formats = KIRKWOOD_SPDIF_FORMATS,
590
},
591
.ops = &kirkwood_i2s_dai_ops,
592
},
593
};
594
595
static 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,
602
.rates = SNDRV_PCM_RATE_CONTINUOUS,
603
.rate_min = 5512,
604
.rate_max = 192000,
605
.formats = KIRKWOOD_I2S_FORMATS,
606
},
607
.capture = {
608
.channels_min = 1,
609
.channels_max = 2,
610
.rates = SNDRV_PCM_RATE_CONTINUOUS,
611
.rate_min = 5512,
612
.rate_max = 192000,
613
.formats = KIRKWOOD_I2S_FORMATS,
614
},
615
.ops = &kirkwood_i2s_dai_ops,
616
},
617
{
618
.name = "spdif",
619
.id = 1,
620
.playback = {
621
.channels_min = 1,
622
.channels_max = 2,
623
.rates = SNDRV_PCM_RATE_CONTINUOUS,
624
.rate_min = 5512,
625
.rate_max = 192000,
626
.formats = KIRKWOOD_SPDIF_FORMATS,
627
},
628
.capture = {
629
.channels_min = 1,
630
.channels_max = 2,
631
.rates = SNDRV_PCM_RATE_CONTINUOUS,
632
.rate_min = 5512,
633
.rate_max = 192000,
634
.formats = KIRKWOOD_SPDIF_FORMATS,
635
},
636
.ops = &kirkwood_i2s_dai_ops,
637
},
638
};
639
640
static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
641
{
642
struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
643
struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
644
struct kirkwood_dma_data *priv;
645
struct device_node *np = pdev->dev.of_node;
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
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);
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
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
}
681
682
priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
683
if (IS_ERR(priv->clk)) {
684
dev_err(&pdev->dev, "no clock\n");
685
return PTR_ERR(priv->clk);
686
}
687
688
priv->extclk = devm_clk_get(&pdev->dev, "extclk");
689
if (IS_ERR(priv->extclk)) {
690
if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
691
return -EPROBE_DEFER;
692
} else {
693
if (clk_is_match(priv->extclk, priv->clk)) {
694
devm_clk_put(&pdev->dev, priv->extclk);
695
priv->extclk = ERR_PTR(-EINVAL);
696
} else {
697
dev_info(&pdev->dev, "found external clock\n");
698
clk_prepare_enable(priv->extclk);
699
soc_dai = kirkwood_i2s_dai_extclk;
700
}
701
}
702
703
err = clk_prepare_enable(priv->clk);
704
if (err < 0)
705
return err;
706
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 */
712
if (priv->burst == 32) {
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
720
err = snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
721
soc_dai, 2);
722
if (err) {
723
dev_err(&pdev->dev, "snd_soc_register_component failed\n");
724
goto err_component;
725
}
726
727
kirkwood_i2s_init(priv);
728
729
return 0;
730
731
err_component:
732
if (!IS_ERR(priv->extclk))
733
clk_disable_unprepare(priv->extclk);
734
clk_disable_unprepare(priv->clk);
735
736
return err;
737
}
738
739
static void kirkwood_i2s_dev_remove(struct platform_device *pdev)
740
{
741
struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
742
743
snd_soc_unregister_component(&pdev->dev);
744
if (!IS_ERR(priv->extclk))
745
clk_disable_unprepare(priv->extclk);
746
clk_disable_unprepare(priv->clk);
747
}
748
749
#ifdef CONFIG_OF
750
static const struct of_device_id mvebu_audio_of_match[] = {
751
{ .compatible = "marvell,kirkwood-audio" },
752
{ .compatible = "marvell,dove-audio" },
753
{ .compatible = "marvell,armada370-audio" },
754
{ .compatible = "marvell,armada-380-audio" },
755
{ }
756
};
757
MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
758
#endif
759
760
static struct platform_driver kirkwood_i2s_driver = {
761
.probe = kirkwood_i2s_dev_probe,
762
.remove = kirkwood_i2s_dev_remove,
763
.driver = {
764
.name = DRV_NAME,
765
.of_match_table = of_match_ptr(mvebu_audio_of_match),
766
},
767
};
768
769
module_platform_driver(kirkwood_i2s_driver);
770
771
/* Module information */
772
MODULE_AUTHOR("Arnaud Patard, <[email protected]>");
773
MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
774
MODULE_LICENSE("GPL");
775
MODULE_ALIAS("platform:mvebu-audio");
776
777