Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/keembay/kmb_platform.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Copyright (C) 2020 Intel Corporation.
4
//
5
// Intel KeemBay Platform driver.
6
//
7
8
#include <linux/bitrev.h>
9
#include <linux/clk.h>
10
#include <linux/dma-mapping.h>
11
#include <linux/io.h>
12
#include <linux/module.h>
13
#include <linux/of.h>
14
#include <sound/dmaengine_pcm.h>
15
#include <sound/pcm.h>
16
#include <sound/pcm_params.h>
17
#include <sound/soc.h>
18
#include "kmb_platform.h"
19
20
#define PERIODS_MIN 2
21
#define PERIODS_MAX 48
22
#define PERIOD_BYTES_MIN 4096
23
#define BUFFER_BYTES_MAX (PERIODS_MAX * PERIOD_BYTES_MIN)
24
#define TDM_OPERATION 5
25
#define I2S_OPERATION 0
26
#define DATA_WIDTH_CONFIG_BIT 6
27
#define TDM_CHANNEL_CONFIG_BIT 3
28
29
static const struct snd_pcm_hardware kmb_pcm_hardware = {
30
.info = SNDRV_PCM_INFO_INTERLEAVED |
31
SNDRV_PCM_INFO_MMAP |
32
SNDRV_PCM_INFO_MMAP_VALID |
33
SNDRV_PCM_INFO_BATCH |
34
SNDRV_PCM_INFO_BLOCK_TRANSFER,
35
.rates = SNDRV_PCM_RATE_8000 |
36
SNDRV_PCM_RATE_16000 |
37
SNDRV_PCM_RATE_48000,
38
.rate_min = 8000,
39
.rate_max = 48000,
40
.formats = SNDRV_PCM_FMTBIT_S16_LE |
41
SNDRV_PCM_FMTBIT_S24_LE |
42
SNDRV_PCM_FMTBIT_S32_LE |
43
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
44
.channels_min = 2,
45
.channels_max = 2,
46
.buffer_bytes_max = BUFFER_BYTES_MAX,
47
.period_bytes_min = PERIOD_BYTES_MIN,
48
.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
49
.periods_min = PERIODS_MIN,
50
.periods_max = PERIODS_MAX,
51
.fifo_size = 16,
52
};
53
54
/*
55
* Convert to ADV7511 HDMI hardware format.
56
* ADV7511 HDMI chip need parity bit replaced by block start bit and
57
* with the preamble bits left out.
58
* ALSA IEC958 subframe format:
59
* bit 0-3 = preamble (0x8 = block start)
60
* 4-7 = AUX (=0)
61
* 8-27 = audio data (without AUX if 24bit sample)
62
* 28 = validity
63
* 29 = user data
64
* 30 = channel status
65
* 31 = parity
66
*
67
* ADV7511 IEC958 subframe format:
68
* bit 0-23 = audio data
69
* 24 = validity
70
* 25 = user data
71
* 26 = channel status
72
* 27 = block start
73
* 28-31 = 0
74
* MSB to LSB bit reverse by software as hardware not supporting it.
75
*/
76
static void hdmi_reformat_iec958(struct snd_pcm_runtime *runtime,
77
struct kmb_i2s_info *kmb_i2s,
78
unsigned int tx_ptr)
79
{
80
u32(*buf)[2] = (void *)runtime->dma_area;
81
unsigned long temp;
82
u32 i, j, sample;
83
84
for (i = 0; i < kmb_i2s->fifo_th; i++) {
85
j = 0;
86
do {
87
temp = buf[tx_ptr][j];
88
/* Replace parity with block start*/
89
assign_bit(31, &temp, (BIT(3) & temp));
90
sample = bitrev32(temp);
91
buf[tx_ptr][j] = sample << 4;
92
j++;
93
} while (j < 2);
94
tx_ptr++;
95
}
96
}
97
98
static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
99
struct snd_pcm_runtime *runtime,
100
unsigned int tx_ptr, bool *period_elapsed)
101
{
102
unsigned int period_pos = tx_ptr % runtime->period_size;
103
void __iomem *i2s_base = kmb_i2s->i2s_base;
104
void *buf = runtime->dma_area;
105
int i;
106
107
if (kmb_i2s->iec958_fmt)
108
hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr);
109
110
/* KMB i2s uses two separate L/R FIFO */
111
for (i = 0; i < kmb_i2s->fifo_th; i++) {
112
if (kmb_i2s->config.data_width == 16) {
113
writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
114
writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
115
} else {
116
writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
117
writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
118
}
119
120
period_pos++;
121
122
if (++tx_ptr >= runtime->buffer_size)
123
tx_ptr = 0;
124
}
125
126
*period_elapsed = period_pos >= runtime->period_size;
127
128
return tx_ptr;
129
}
130
131
static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s,
132
struct snd_pcm_runtime *runtime,
133
unsigned int rx_ptr, bool *period_elapsed)
134
{
135
unsigned int period_pos = rx_ptr % runtime->period_size;
136
void __iomem *i2s_base = kmb_i2s->i2s_base;
137
int chan = kmb_i2s->config.chan_nr;
138
void *buf = runtime->dma_area;
139
int i, j;
140
141
/* KMB i2s uses two separate L/R FIFO */
142
for (i = 0; i < kmb_i2s->fifo_th; i++) {
143
for (j = 0; j < chan / 2; j++) {
144
if (kmb_i2s->config.data_width == 16) {
145
((u16 *)buf)[rx_ptr * chan + (j * 2)] =
146
readl(i2s_base + LRBR_LTHR(j));
147
((u16 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
148
readl(i2s_base + RRBR_RTHR(j));
149
} else {
150
((u32 *)buf)[rx_ptr * chan + (j * 2)] =
151
readl(i2s_base + LRBR_LTHR(j));
152
((u32 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
153
readl(i2s_base + RRBR_RTHR(j));
154
}
155
}
156
period_pos++;
157
158
if (++rx_ptr >= runtime->buffer_size)
159
rx_ptr = 0;
160
}
161
162
*period_elapsed = period_pos >= runtime->period_size;
163
164
return rx_ptr;
165
}
166
167
static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s,
168
u32 stream)
169
{
170
u32 i;
171
172
/* Disable all channels regardless of configuration*/
173
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
174
for (i = 0; i < MAX_ISR; i++)
175
writel(0, kmb_i2s->i2s_base + TER(i));
176
} else {
177
for (i = 0; i < MAX_ISR; i++)
178
writel(0, kmb_i2s->i2s_base + RER(i));
179
}
180
}
181
182
static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream)
183
{
184
struct i2s_clk_config_data *config = &kmb_i2s->config;
185
u32 i;
186
187
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
188
for (i = 0; i < config->chan_nr / 2; i++)
189
readl(kmb_i2s->i2s_base + TOR(i));
190
} else {
191
for (i = 0; i < config->chan_nr / 2; i++)
192
readl(kmb_i2s->i2s_base + ROR(i));
193
}
194
}
195
196
static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s,
197
u32 stream, int chan_nr, bool trigger)
198
{
199
u32 i, irq;
200
u32 flag;
201
202
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
203
flag = TX_INT_FLAG;
204
else
205
flag = RX_INT_FLAG;
206
207
for (i = 0; i < chan_nr / 2; i++) {
208
irq = readl(kmb_i2s->i2s_base + IMR(i));
209
210
if (trigger)
211
irq = irq & ~flag;
212
else
213
irq = irq | flag;
214
215
writel(irq, kmb_i2s->i2s_base + IMR(i));
216
}
217
}
218
219
static void kmb_pcm_operation(struct kmb_i2s_info *kmb_i2s, bool playback)
220
{
221
struct snd_pcm_substream *substream;
222
bool period_elapsed;
223
unsigned int new_ptr;
224
unsigned int ptr;
225
226
if (playback)
227
substream = kmb_i2s->tx_substream;
228
else
229
substream = kmb_i2s->rx_substream;
230
231
if (!substream || !snd_pcm_running(substream))
232
return;
233
234
if (playback) {
235
ptr = kmb_i2s->tx_ptr;
236
new_ptr = kmb_pcm_tx_fn(kmb_i2s, substream->runtime,
237
ptr, &period_elapsed);
238
cmpxchg(&kmb_i2s->tx_ptr, ptr, new_ptr);
239
} else {
240
ptr = kmb_i2s->rx_ptr;
241
new_ptr = kmb_pcm_rx_fn(kmb_i2s, substream->runtime,
242
ptr, &period_elapsed);
243
cmpxchg(&kmb_i2s->rx_ptr, ptr, new_ptr);
244
}
245
246
if (period_elapsed)
247
snd_pcm_period_elapsed(substream);
248
}
249
250
static int kmb_pcm_open(struct snd_soc_component *component,
251
struct snd_pcm_substream *substream)
252
{
253
struct snd_pcm_runtime *runtime = substream->runtime;
254
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
255
struct kmb_i2s_info *kmb_i2s;
256
257
kmb_i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
258
snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware);
259
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
260
runtime->private_data = kmb_i2s;
261
262
return 0;
263
}
264
265
static int kmb_pcm_trigger(struct snd_soc_component *component,
266
struct snd_pcm_substream *substream, int cmd)
267
{
268
struct snd_pcm_runtime *runtime = substream->runtime;
269
struct kmb_i2s_info *kmb_i2s = runtime->private_data;
270
271
switch (cmd) {
272
case SNDRV_PCM_TRIGGER_START:
273
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
274
kmb_i2s->tx_ptr = 0;
275
kmb_i2s->tx_substream = substream;
276
} else {
277
kmb_i2s->rx_ptr = 0;
278
kmb_i2s->rx_substream = substream;
279
}
280
break;
281
case SNDRV_PCM_TRIGGER_STOP:
282
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
283
kmb_i2s->tx_substream = NULL;
284
else
285
kmb_i2s->rx_substream = NULL;
286
kmb_i2s->iec958_fmt = false;
287
break;
288
default:
289
return -EINVAL;
290
}
291
292
return 0;
293
}
294
295
static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id)
296
{
297
struct kmb_i2s_info *kmb_i2s = dev_id;
298
struct i2s_clk_config_data *config = &kmb_i2s->config;
299
irqreturn_t ret = IRQ_NONE;
300
u32 tx_enabled = 0;
301
u32 isr[4];
302
int i;
303
304
for (i = 0; i < config->chan_nr / 2; i++)
305
isr[i] = readl(kmb_i2s->i2s_base + ISR(i));
306
307
kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
308
kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
309
/* Only check TX interrupt if TX is active */
310
tx_enabled = readl(kmb_i2s->i2s_base + ITER);
311
312
/*
313
* Data available. Retrieve samples from FIFO
314
*/
315
316
/*
317
* 8 channel audio will have isr[0..2] triggered,
318
* reading the specific isr based on the audio configuration,
319
* to avoid reading the buffers too early.
320
*/
321
switch (config->chan_nr) {
322
case 2:
323
if (isr[0] & ISR_RXDA)
324
kmb_pcm_operation(kmb_i2s, false);
325
ret = IRQ_HANDLED;
326
break;
327
case 4:
328
if (isr[1] & ISR_RXDA)
329
kmb_pcm_operation(kmb_i2s, false);
330
ret = IRQ_HANDLED;
331
break;
332
case 8:
333
if (isr[3] & ISR_RXDA)
334
kmb_pcm_operation(kmb_i2s, false);
335
ret = IRQ_HANDLED;
336
break;
337
}
338
339
for (i = 0; i < config->chan_nr / 2; i++) {
340
/*
341
* Check if TX fifo is empty. If empty fill FIFO with samples
342
*/
343
if ((isr[i] & ISR_TXFE) && tx_enabled) {
344
kmb_pcm_operation(kmb_i2s, true);
345
ret = IRQ_HANDLED;
346
}
347
348
/* Error Handling: TX */
349
if (isr[i] & ISR_TXFO) {
350
dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i);
351
ret = IRQ_HANDLED;
352
}
353
/* Error Handling: RX */
354
if (isr[i] & ISR_RXFO) {
355
dev_dbg(kmb_i2s->dev, "RX overrun (ch_id=%d)\n", i);
356
ret = IRQ_HANDLED;
357
}
358
}
359
360
return ret;
361
}
362
363
static int kmb_platform_pcm_new(struct snd_soc_component *component,
364
struct snd_soc_pcm_runtime *soc_runtime)
365
{
366
size_t size = kmb_pcm_hardware.buffer_bytes_max;
367
/* Use SNDRV_DMA_TYPE_CONTINUOUS as KMB doesn't use PCI sg buffer */
368
snd_pcm_set_managed_buffer_all(soc_runtime->pcm,
369
SNDRV_DMA_TYPE_CONTINUOUS,
370
NULL, size, size);
371
return 0;
372
}
373
374
static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
375
struct snd_pcm_substream *substream)
376
{
377
struct snd_pcm_runtime *runtime = substream->runtime;
378
struct kmb_i2s_info *kmb_i2s = runtime->private_data;
379
snd_pcm_uframes_t pos;
380
381
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
382
pos = kmb_i2s->tx_ptr;
383
else
384
pos = kmb_i2s->rx_ptr;
385
386
return pos < runtime->buffer_size ? pos : 0;
387
}
388
389
static const struct snd_soc_component_driver kmb_component = {
390
.name = "kmb",
391
.pcm_construct = kmb_platform_pcm_new,
392
.open = kmb_pcm_open,
393
.trigger = kmb_pcm_trigger,
394
.pointer = kmb_pcm_pointer,
395
.legacy_dai_naming = 1,
396
};
397
398
static const struct snd_soc_component_driver kmb_component_dma = {
399
.name = "kmb",
400
.legacy_dai_naming = 1,
401
};
402
403
static int kmb_probe(struct snd_soc_dai *cpu_dai)
404
{
405
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
406
407
if (kmb_i2s->use_pio)
408
return 0;
409
410
snd_soc_dai_init_dma_data(cpu_dai, &kmb_i2s->play_dma_data,
411
&kmb_i2s->capture_dma_data);
412
413
return 0;
414
}
415
416
static inline void kmb_i2s_enable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
417
{
418
u32 dma_reg;
419
420
dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
421
/* Enable DMA handshake for stream */
422
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
423
dma_reg |= I2S_DMAEN_TXBLOCK;
424
else
425
dma_reg |= I2S_DMAEN_RXBLOCK;
426
427
writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
428
}
429
430
static inline void kmb_i2s_disable_dma(struct kmb_i2s_info *kmb_i2s, u32 stream)
431
{
432
u32 dma_reg;
433
434
dma_reg = readl(kmb_i2s->i2s_base + I2S_DMACR);
435
/* Disable DMA handshake for stream */
436
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
437
dma_reg &= ~I2S_DMAEN_TXBLOCK;
438
writel(1, kmb_i2s->i2s_base + I2S_RTXDMA);
439
} else {
440
dma_reg &= ~I2S_DMAEN_RXBLOCK;
441
writel(1, kmb_i2s->i2s_base + I2S_RRXDMA);
442
}
443
writel(dma_reg, kmb_i2s->i2s_base + I2S_DMACR);
444
}
445
446
static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
447
struct snd_pcm_substream *substream)
448
{
449
struct i2s_clk_config_data *config = &kmb_i2s->config;
450
451
/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
452
writel(1, kmb_i2s->i2s_base + IER);
453
454
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
455
writel(1, kmb_i2s->i2s_base + ITER);
456
else
457
writel(1, kmb_i2s->i2s_base + IRER);
458
459
if (kmb_i2s->use_pio)
460
kmb_i2s_irq_trigger(kmb_i2s, substream->stream,
461
config->chan_nr, true);
462
else
463
kmb_i2s_enable_dma(kmb_i2s, substream->stream);
464
465
if (kmb_i2s->clock_provider)
466
writel(1, kmb_i2s->i2s_base + CER);
467
else
468
writel(0, kmb_i2s->i2s_base + CER);
469
}
470
471
static void kmb_i2s_stop(struct kmb_i2s_info *kmb_i2s,
472
struct snd_pcm_substream *substream)
473
{
474
/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
475
kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
476
477
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
478
writel(0, kmb_i2s->i2s_base + ITER);
479
else
480
writel(0, kmb_i2s->i2s_base + IRER);
481
482
kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
483
484
if (!kmb_i2s->active) {
485
writel(0, kmb_i2s->i2s_base + CER);
486
writel(0, kmb_i2s->i2s_base + IER);
487
}
488
}
489
490
static void kmb_disable_clk(void *clk)
491
{
492
clk_disable_unprepare(clk);
493
}
494
495
static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
496
{
497
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
498
int ret;
499
500
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
501
case SND_SOC_DAIFMT_BC_FC:
502
kmb_i2s->clock_provider = false;
503
ret = 0;
504
break;
505
case SND_SOC_DAIFMT_BP_FP:
506
writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
507
508
ret = clk_prepare_enable(kmb_i2s->clk_i2s);
509
if (ret < 0)
510
return ret;
511
512
ret = devm_add_action_or_reset(kmb_i2s->dev, kmb_disable_clk,
513
kmb_i2s->clk_i2s);
514
if (ret)
515
return ret;
516
517
kmb_i2s->clock_provider = true;
518
break;
519
default:
520
return -EINVAL;
521
}
522
523
return ret;
524
}
525
526
static int kmb_dai_trigger(struct snd_pcm_substream *substream,
527
int cmd, struct snd_soc_dai *cpu_dai)
528
{
529
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
530
531
switch (cmd) {
532
case SNDRV_PCM_TRIGGER_START:
533
/* Keep track of i2s activity before turn off
534
* the i2s interface
535
*/
536
kmb_i2s->active++;
537
kmb_i2s_start(kmb_i2s, substream);
538
break;
539
case SNDRV_PCM_TRIGGER_STOP:
540
kmb_i2s->active--;
541
if (kmb_i2s->use_pio)
542
kmb_i2s_stop(kmb_i2s, substream);
543
break;
544
default:
545
return -EINVAL;
546
}
547
548
return 0;
549
}
550
551
static void kmb_i2s_config(struct kmb_i2s_info *kmb_i2s, int stream)
552
{
553
struct i2s_clk_config_data *config = &kmb_i2s->config;
554
u32 ch_reg;
555
556
kmb_i2s_disable_channels(kmb_i2s, stream);
557
558
for (ch_reg = 0; ch_reg < config->chan_nr / 2; ch_reg++) {
559
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
560
writel(kmb_i2s->xfer_resolution,
561
kmb_i2s->i2s_base + TCR(ch_reg));
562
563
writel(kmb_i2s->fifo_th - 1,
564
kmb_i2s->i2s_base + TFCR(ch_reg));
565
566
writel(1, kmb_i2s->i2s_base + TER(ch_reg));
567
} else {
568
writel(kmb_i2s->xfer_resolution,
569
kmb_i2s->i2s_base + RCR(ch_reg));
570
571
writel(kmb_i2s->fifo_th - 1,
572
kmb_i2s->i2s_base + RFCR(ch_reg));
573
574
writel(1, kmb_i2s->i2s_base + RER(ch_reg));
575
}
576
}
577
}
578
579
static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
580
struct snd_pcm_hw_params *hw_params,
581
struct snd_soc_dai *cpu_dai)
582
{
583
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
584
struct i2s_clk_config_data *config = &kmb_i2s->config;
585
u32 write_val;
586
int ret;
587
588
switch (params_format(hw_params)) {
589
case SNDRV_PCM_FORMAT_S16_LE:
590
config->data_width = 16;
591
kmb_i2s->ccr = 0x00;
592
kmb_i2s->xfer_resolution = 0x02;
593
kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
594
kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
595
break;
596
case SNDRV_PCM_FORMAT_S24_LE:
597
config->data_width = 32;
598
kmb_i2s->ccr = 0x14;
599
kmb_i2s->xfer_resolution = 0x05;
600
kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
601
kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
602
break;
603
case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
604
kmb_i2s->iec958_fmt = true;
605
fallthrough;
606
case SNDRV_PCM_FORMAT_S32_LE:
607
config->data_width = 32;
608
kmb_i2s->ccr = 0x10;
609
kmb_i2s->xfer_resolution = 0x05;
610
kmb_i2s->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
611
kmb_i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
612
break;
613
default:
614
dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt");
615
return -EINVAL;
616
}
617
618
config->chan_nr = params_channels(hw_params);
619
620
switch (config->chan_nr) {
621
case 8:
622
case 4:
623
/*
624
* Platform is not capable of providing clocks for
625
* multi channel audio
626
*/
627
if (kmb_i2s->clock_provider)
628
return -EINVAL;
629
630
write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
631
(config->data_width << DATA_WIDTH_CONFIG_BIT) |
632
TDM_OPERATION;
633
634
writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
635
break;
636
case 2:
637
/*
638
* Platform is only capable of providing clocks need for
639
* 2 channel master mode
640
*/
641
if (!(kmb_i2s->clock_provider))
642
return -EINVAL;
643
644
write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
645
(config->data_width << DATA_WIDTH_CONFIG_BIT) |
646
CLOCK_PROVIDER_MODE | I2S_OPERATION;
647
648
writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
649
break;
650
default:
651
dev_dbg(kmb_i2s->dev, "channel not supported\n");
652
return -EINVAL;
653
}
654
655
kmb_i2s_config(kmb_i2s, substream->stream);
656
657
writel(kmb_i2s->ccr, kmb_i2s->i2s_base + CCR);
658
659
config->sample_rate = params_rate(hw_params);
660
661
if (kmb_i2s->clock_provider) {
662
/* Only 2 ch supported in Master mode */
663
u32 bitclk = config->sample_rate * config->data_width * 2;
664
665
ret = clk_set_rate(kmb_i2s->clk_i2s, bitclk);
666
if (ret) {
667
dev_err(kmb_i2s->dev,
668
"Can't set I2S clock rate: %d\n", ret);
669
return ret;
670
}
671
}
672
673
return 0;
674
}
675
676
static int kmb_dai_prepare(struct snd_pcm_substream *substream,
677
struct snd_soc_dai *cpu_dai)
678
{
679
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
680
681
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
682
writel(1, kmb_i2s->i2s_base + TXFFR);
683
else
684
writel(1, kmb_i2s->i2s_base + RXFFR);
685
686
return 0;
687
}
688
689
static int kmb_dai_startup(struct snd_pcm_substream *substream,
690
struct snd_soc_dai *cpu_dai)
691
{
692
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
693
struct snd_dmaengine_dai_dma_data *dma_data;
694
695
if (kmb_i2s->use_pio)
696
return 0;
697
698
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
699
dma_data = &kmb_i2s->play_dma_data;
700
else
701
dma_data = &kmb_i2s->capture_dma_data;
702
703
snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
704
705
return 0;
706
}
707
708
static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
709
struct snd_soc_dai *cpu_dai)
710
{
711
struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
712
/* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
713
if (kmb_i2s->use_pio)
714
kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
715
716
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
717
writel(0, kmb_i2s->i2s_base + ITER);
718
else
719
writel(0, kmb_i2s->i2s_base + IRER);
720
721
if (kmb_i2s->use_pio)
722
kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
723
else
724
kmb_i2s_disable_dma(kmb_i2s, substream->stream);
725
726
if (!kmb_i2s->active) {
727
writel(0, kmb_i2s->i2s_base + CER);
728
writel(0, kmb_i2s->i2s_base + IER);
729
}
730
731
return 0;
732
}
733
734
static const struct snd_soc_dai_ops kmb_dai_ops = {
735
.probe = kmb_probe,
736
.startup = kmb_dai_startup,
737
.trigger = kmb_dai_trigger,
738
.hw_params = kmb_dai_hw_params,
739
.hw_free = kmb_dai_hw_free,
740
.prepare = kmb_dai_prepare,
741
.set_fmt = kmb_set_dai_fmt,
742
};
743
744
static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
745
{
746
.name = "intel_kmb_hdmi_i2s",
747
.playback = {
748
.channels_min = 2,
749
.channels_max = 2,
750
.rates = SNDRV_PCM_RATE_48000,
751
.rate_min = 48000,
752
.rate_max = 48000,
753
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
754
SNDRV_PCM_FMTBIT_S24_LE |
755
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
756
},
757
.ops = &kmb_dai_ops,
758
},
759
};
760
761
static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
762
{
763
.name = "intel_kmb_i2s",
764
.playback = {
765
.channels_min = 2,
766
.channels_max = 2,
767
.rates = SNDRV_PCM_RATE_8000 |
768
SNDRV_PCM_RATE_16000 |
769
SNDRV_PCM_RATE_48000,
770
.rate_min = 8000,
771
.rate_max = 48000,
772
.formats = (SNDRV_PCM_FMTBIT_S32_LE |
773
SNDRV_PCM_FMTBIT_S24_LE |
774
SNDRV_PCM_FMTBIT_S16_LE),
775
},
776
.capture = {
777
.channels_min = 2,
778
.channels_max = 2,
779
.rates = SNDRV_PCM_RATE_8000 |
780
SNDRV_PCM_RATE_16000 |
781
SNDRV_PCM_RATE_48000,
782
.rate_min = 8000,
783
.rate_max = 48000,
784
.formats = (SNDRV_PCM_FMTBIT_S32_LE |
785
SNDRV_PCM_FMTBIT_S24_LE |
786
SNDRV_PCM_FMTBIT_S16_LE),
787
},
788
.ops = &kmb_dai_ops,
789
},
790
};
791
792
static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
793
{
794
.name = "intel_kmb_tdm",
795
.capture = {
796
.channels_min = 4,
797
.channels_max = 8,
798
.rates = SNDRV_PCM_RATE_8000 |
799
SNDRV_PCM_RATE_16000 |
800
SNDRV_PCM_RATE_48000,
801
.rate_min = 8000,
802
.rate_max = 48000,
803
.formats = (SNDRV_PCM_FMTBIT_S32_LE |
804
SNDRV_PCM_FMTBIT_S24_LE |
805
SNDRV_PCM_FMTBIT_S16_LE),
806
},
807
.ops = &kmb_dai_ops,
808
},
809
};
810
811
static const struct of_device_id kmb_plat_of_match[] = {
812
{ .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai},
813
{ .compatible = "intel,keembay-hdmi-i2s", .data = &intel_kmb_hdmi_dai},
814
{ .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
815
{}
816
};
817
MODULE_DEVICE_TABLE(of, kmb_plat_of_match);
818
819
static int kmb_plat_dai_probe(struct platform_device *pdev)
820
{
821
struct device_node *np = pdev->dev.of_node;
822
struct snd_soc_dai_driver *kmb_i2s_dai;
823
struct device *dev = &pdev->dev;
824
struct kmb_i2s_info *kmb_i2s;
825
struct resource *res;
826
int ret, irq;
827
u32 comp1_reg;
828
829
kmb_i2s = devm_kzalloc(dev, sizeof(*kmb_i2s), GFP_KERNEL);
830
if (!kmb_i2s)
831
return -ENOMEM;
832
833
kmb_i2s_dai = (struct snd_soc_dai_driver *)device_get_match_data(&pdev->dev);
834
835
/* Prepare the related clocks */
836
kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk");
837
if (IS_ERR(kmb_i2s->clk_apb)) {
838
dev_err(dev, "Failed to get apb clock\n");
839
return PTR_ERR(kmb_i2s->clk_apb);
840
}
841
842
ret = clk_prepare_enable(kmb_i2s->clk_apb);
843
if (ret < 0)
844
return ret;
845
846
ret = devm_add_action_or_reset(dev, kmb_disable_clk, kmb_i2s->clk_apb);
847
if (ret) {
848
dev_err(dev, "Failed to add clk_apb reset action\n");
849
return ret;
850
}
851
852
kmb_i2s->clk_i2s = devm_clk_get(dev, "osc");
853
if (IS_ERR(kmb_i2s->clk_i2s)) {
854
dev_err(dev, "Failed to get osc clock\n");
855
return PTR_ERR(kmb_i2s->clk_i2s);
856
}
857
858
kmb_i2s->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
859
if (IS_ERR(kmb_i2s->i2s_base))
860
return PTR_ERR(kmb_i2s->i2s_base);
861
862
kmb_i2s->pss_base = devm_platform_ioremap_resource(pdev, 1);
863
if (IS_ERR(kmb_i2s->pss_base))
864
return PTR_ERR(kmb_i2s->pss_base);
865
866
kmb_i2s->dev = &pdev->dev;
867
868
comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1);
869
870
kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
871
872
kmb_i2s->use_pio = !of_property_present(np, "dmas");
873
874
if (kmb_i2s->use_pio) {
875
irq = platform_get_irq_optional(pdev, 0);
876
if (irq > 0) {
877
ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
878
pdev->name, kmb_i2s);
879
if (ret < 0) {
880
dev_err(dev, "failed to request irq\n");
881
return ret;
882
}
883
}
884
ret = devm_snd_soc_register_component(dev, &kmb_component,
885
kmb_i2s_dai, 1);
886
} else {
887
kmb_i2s->play_dma_data.addr = res->start + I2S_TXDMA;
888
kmb_i2s->capture_dma_data.addr = res->start + I2S_RXDMA;
889
ret = snd_dmaengine_pcm_register(&pdev->dev,
890
NULL, 0);
891
if (ret) {
892
dev_err(&pdev->dev, "could not register dmaengine: %d\n",
893
ret);
894
return ret;
895
}
896
ret = devm_snd_soc_register_component(dev, &kmb_component_dma,
897
kmb_i2s_dai, 1);
898
}
899
900
if (ret) {
901
dev_err(dev, "not able to register dai\n");
902
return ret;
903
}
904
905
/* To ensure none of the channels are enabled at boot up */
906
kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
907
kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
908
909
dev_set_drvdata(dev, kmb_i2s);
910
911
return ret;
912
}
913
914
static struct platform_driver kmb_plat_dai_driver = {
915
.driver = {
916
.name = "kmb-plat-dai",
917
.of_match_table = kmb_plat_of_match,
918
},
919
.probe = kmb_plat_dai_probe,
920
};
921
922
module_platform_driver(kmb_plat_dai_driver);
923
924
MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver");
925
MODULE_AUTHOR("Sia Jee Heng <[email protected]>");
926
MODULE_AUTHOR("Sit, Michael Wei Hong <[email protected]>");
927
MODULE_LICENSE("GPL v2");
928
MODULE_ALIAS("platform:kmb_platform");
929
930