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/clk.h>
9 #include <linux/io.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_device.h>
13 #include <sound/pcm.h>
14 #include <sound/pcm_params.h>
15 #include <sound/soc.h>
16 #include "kmb_platform.h"
17
18 #define PERIODS_MIN 2
19 #define PERIODS_MAX 48
20 #define PERIOD_BYTES_MIN 4096
21 #define BUFFER_BYTES_MAX (PERIODS_MAX * PERIOD_BYTES_MIN)
22 #define TDM_OPERATION 5
23 #define I2S_OPERATION 0
24 #define DATA_WIDTH_CONFIG_BIT 6
25 #define TDM_CHANNEL_CONFIG_BIT 3
26
27 static const struct snd_pcm_hardware kmb_pcm_hardware = {
28 .info = SNDRV_PCM_INFO_INTERLEAVED |
29 SNDRV_PCM_INFO_MMAP |
30 SNDRV_PCM_INFO_MMAP_VALID |
31 SNDRV_PCM_INFO_BATCH |
32 SNDRV_PCM_INFO_BLOCK_TRANSFER,
33 .rates = SNDRV_PCM_RATE_8000 |
34 SNDRV_PCM_RATE_16000 |
35 SNDRV_PCM_RATE_48000,
36 .rate_min = 8000,
37 .rate_max = 48000,
38 .formats = SNDRV_PCM_FMTBIT_S16_LE |
39 SNDRV_PCM_FMTBIT_S24_LE |
40 SNDRV_PCM_FMTBIT_S32_LE,
41 .channels_min = 2,
42 .channels_max = 2,
43 .buffer_bytes_max = BUFFER_BYTES_MAX,
44 .period_bytes_min = PERIOD_BYTES_MIN,
45 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
46 .periods_min = PERIODS_MIN,
47 .periods_max = PERIODS_MAX,
48 .fifo_size = 16,
49 };
50
kmb_pcm_tx_fn(struct kmb_i2s_info * kmb_i2s,struct snd_pcm_runtime * runtime,unsigned int tx_ptr,bool * period_elapsed)51 static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s,
52 struct snd_pcm_runtime *runtime,
53 unsigned int tx_ptr, bool *period_elapsed)
54 {
55 unsigned int period_pos = tx_ptr % runtime->period_size;
56 void __iomem *i2s_base = kmb_i2s->i2s_base;
57 void *buf = runtime->dma_area;
58 int i;
59
60 /* KMB i2s uses two separate L/R FIFO */
61 for (i = 0; i < kmb_i2s->fifo_th; i++) {
62 if (kmb_i2s->config.data_width == 16) {
63 writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
64 writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
65 } else {
66 writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
67 writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
68 }
69
70 period_pos++;
71
72 if (++tx_ptr >= runtime->buffer_size)
73 tx_ptr = 0;
74 }
75
76 *period_elapsed = period_pos >= runtime->period_size;
77
78 return tx_ptr;
79 }
80
kmb_pcm_rx_fn(struct kmb_i2s_info * kmb_i2s,struct snd_pcm_runtime * runtime,unsigned int rx_ptr,bool * period_elapsed)81 static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s,
82 struct snd_pcm_runtime *runtime,
83 unsigned int rx_ptr, bool *period_elapsed)
84 {
85 unsigned int period_pos = rx_ptr % runtime->period_size;
86 void __iomem *i2s_base = kmb_i2s->i2s_base;
87 int chan = kmb_i2s->config.chan_nr;
88 void *buf = runtime->dma_area;
89 int i, j;
90
91 /* KMB i2s uses two separate L/R FIFO */
92 for (i = 0; i < kmb_i2s->fifo_th; i++) {
93 for (j = 0; j < chan / 2; j++) {
94 if (kmb_i2s->config.data_width == 16) {
95 ((u16 *)buf)[rx_ptr * chan + (j * 2)] =
96 readl(i2s_base + LRBR_LTHR(j));
97 ((u16 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
98 readl(i2s_base + RRBR_RTHR(j));
99 } else {
100 ((u32 *)buf)[rx_ptr * chan + (j * 2)] =
101 readl(i2s_base + LRBR_LTHR(j));
102 ((u32 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
103 readl(i2s_base + RRBR_RTHR(j));
104 }
105 }
106 period_pos++;
107
108 if (++rx_ptr >= runtime->buffer_size)
109 rx_ptr = 0;
110 }
111
112 *period_elapsed = period_pos >= runtime->period_size;
113
114 return rx_ptr;
115 }
116
kmb_i2s_disable_channels(struct kmb_i2s_info * kmb_i2s,u32 stream)117 static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s,
118 u32 stream)
119 {
120 u32 i;
121
122 /* Disable all channels regardless of configuration*/
123 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
124 for (i = 0; i < MAX_ISR; i++)
125 writel(0, kmb_i2s->i2s_base + TER(i));
126 } else {
127 for (i = 0; i < MAX_ISR; i++)
128 writel(0, kmb_i2s->i2s_base + RER(i));
129 }
130 }
131
kmb_i2s_clear_irqs(struct kmb_i2s_info * kmb_i2s,u32 stream)132 static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream)
133 {
134 struct i2s_clk_config_data *config = &kmb_i2s->config;
135 u32 i;
136
137 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
138 for (i = 0; i < config->chan_nr / 2; i++)
139 readl(kmb_i2s->i2s_base + TOR(i));
140 } else {
141 for (i = 0; i < config->chan_nr / 2; i++)
142 readl(kmb_i2s->i2s_base + ROR(i));
143 }
144 }
145
kmb_i2s_irq_trigger(struct kmb_i2s_info * kmb_i2s,u32 stream,int chan_nr,bool trigger)146 static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s,
147 u32 stream, int chan_nr, bool trigger)
148 {
149 u32 i, irq;
150 u32 flag;
151
152 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
153 flag = TX_INT_FLAG;
154 else
155 flag = RX_INT_FLAG;
156
157 for (i = 0; i < chan_nr / 2; i++) {
158 irq = readl(kmb_i2s->i2s_base + IMR(i));
159
160 if (trigger)
161 irq = irq & ~flag;
162 else
163 irq = irq | flag;
164
165 writel(irq, kmb_i2s->i2s_base + IMR(i));
166 }
167 }
168
kmb_pcm_operation(struct kmb_i2s_info * kmb_i2s,bool playback)169 static void kmb_pcm_operation(struct kmb_i2s_info *kmb_i2s, bool playback)
170 {
171 struct snd_pcm_substream *substream;
172 bool period_elapsed;
173 unsigned int new_ptr;
174 unsigned int ptr;
175
176 if (playback)
177 substream = kmb_i2s->tx_substream;
178 else
179 substream = kmb_i2s->rx_substream;
180
181 if (!substream || !snd_pcm_running(substream))
182 return;
183
184 if (playback) {
185 ptr = kmb_i2s->tx_ptr;
186 new_ptr = kmb_pcm_tx_fn(kmb_i2s, substream->runtime,
187 ptr, &period_elapsed);
188 cmpxchg(&kmb_i2s->tx_ptr, ptr, new_ptr);
189 } else {
190 ptr = kmb_i2s->rx_ptr;
191 new_ptr = kmb_pcm_rx_fn(kmb_i2s, substream->runtime,
192 ptr, &period_elapsed);
193 cmpxchg(&kmb_i2s->rx_ptr, ptr, new_ptr);
194 }
195
196 if (period_elapsed)
197 snd_pcm_period_elapsed(substream);
198 }
199
kmb_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)200 static int kmb_pcm_open(struct snd_soc_component *component,
201 struct snd_pcm_substream *substream)
202 {
203 struct snd_pcm_runtime *runtime = substream->runtime;
204 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
205 struct kmb_i2s_info *kmb_i2s;
206
207 kmb_i2s = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
208 snd_soc_set_runtime_hwparams(substream, &kmb_pcm_hardware);
209 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
210 runtime->private_data = kmb_i2s;
211
212 return 0;
213 }
214
kmb_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)215 static int kmb_pcm_trigger(struct snd_soc_component *component,
216 struct snd_pcm_substream *substream, int cmd)
217 {
218 struct snd_pcm_runtime *runtime = substream->runtime;
219 struct kmb_i2s_info *kmb_i2s = runtime->private_data;
220
221 switch (cmd) {
222 case SNDRV_PCM_TRIGGER_START:
223 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
224 kmb_i2s->tx_ptr = 0;
225 kmb_i2s->tx_substream = substream;
226 } else {
227 kmb_i2s->rx_ptr = 0;
228 kmb_i2s->rx_substream = substream;
229 }
230 break;
231 case SNDRV_PCM_TRIGGER_STOP:
232 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
233 kmb_i2s->tx_substream = NULL;
234 else
235 kmb_i2s->rx_substream = NULL;
236 break;
237 default:
238 return -EINVAL;
239 }
240
241 return 0;
242 }
243
kmb_i2s_irq_handler(int irq,void * dev_id)244 static irqreturn_t kmb_i2s_irq_handler(int irq, void *dev_id)
245 {
246 struct kmb_i2s_info *kmb_i2s = dev_id;
247 struct i2s_clk_config_data *config = &kmb_i2s->config;
248 irqreturn_t ret = IRQ_NONE;
249 u32 tx_enabled = 0;
250 u32 isr[4];
251 int i;
252
253 for (i = 0; i < config->chan_nr / 2; i++)
254 isr[i] = readl(kmb_i2s->i2s_base + ISR(i));
255
256 kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
257 kmb_i2s_clear_irqs(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
258 /* Only check TX interrupt if TX is active */
259 tx_enabled = readl(kmb_i2s->i2s_base + ITER);
260
261 /*
262 * Data available. Retrieve samples from FIFO
263 */
264
265 /*
266 * 8 channel audio will have isr[0..2] triggered,
267 * reading the specific isr based on the audio configuration,
268 * to avoid reading the buffers too early.
269 */
270 switch (config->chan_nr) {
271 case 2:
272 if (isr[0] & ISR_RXDA)
273 kmb_pcm_operation(kmb_i2s, false);
274 ret = IRQ_HANDLED;
275 break;
276 case 4:
277 if (isr[1] & ISR_RXDA)
278 kmb_pcm_operation(kmb_i2s, false);
279 ret = IRQ_HANDLED;
280 break;
281 case 8:
282 if (isr[3] & ISR_RXDA)
283 kmb_pcm_operation(kmb_i2s, false);
284 ret = IRQ_HANDLED;
285 break;
286 }
287
288 for (i = 0; i < config->chan_nr / 2; i++) {
289 /*
290 * Check if TX fifo is empty. If empty fill FIFO with samples
291 */
292 if ((isr[i] & ISR_TXFE) && tx_enabled) {
293 kmb_pcm_operation(kmb_i2s, true);
294 ret = IRQ_HANDLED;
295 }
296
297 /* Error Handling: TX */
298 if (isr[i] & ISR_TXFO) {
299 dev_dbg(kmb_i2s->dev, "TX overrun (ch_id=%d)\n", i);
300 ret = IRQ_HANDLED;
301 }
302 /* Error Handling: RX */
303 if (isr[i] & ISR_RXFO) {
304 dev_dbg(kmb_i2s->dev, "RX overrun (ch_id=%d)\n", i);
305 ret = IRQ_HANDLED;
306 }
307 }
308
309 return ret;
310 }
311
kmb_platform_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * soc_runtime)312 static int kmb_platform_pcm_new(struct snd_soc_component *component,
313 struct snd_soc_pcm_runtime *soc_runtime)
314 {
315 size_t size = kmb_pcm_hardware.buffer_bytes_max;
316 /* Use SNDRV_DMA_TYPE_CONTINUOUS as KMB doesn't use PCI sg buffer */
317 snd_pcm_set_managed_buffer_all(soc_runtime->pcm,
318 SNDRV_DMA_TYPE_CONTINUOUS,
319 NULL, size, size);
320 return 0;
321 }
322
kmb_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)323 static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
324 struct snd_pcm_substream *substream)
325 {
326 struct snd_pcm_runtime *runtime = substream->runtime;
327 struct kmb_i2s_info *kmb_i2s = runtime->private_data;
328 snd_pcm_uframes_t pos;
329
330 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
331 pos = kmb_i2s->tx_ptr;
332 else
333 pos = kmb_i2s->rx_ptr;
334
335 return pos < runtime->buffer_size ? pos : 0;
336 }
337
338 static const struct snd_soc_component_driver kmb_component = {
339 .name = "kmb",
340 .pcm_construct = kmb_platform_pcm_new,
341 .open = kmb_pcm_open,
342 .trigger = kmb_pcm_trigger,
343 .pointer = kmb_pcm_pointer,
344 };
345
kmb_i2s_start(struct kmb_i2s_info * kmb_i2s,struct snd_pcm_substream * substream)346 static void kmb_i2s_start(struct kmb_i2s_info *kmb_i2s,
347 struct snd_pcm_substream *substream)
348 {
349 struct i2s_clk_config_data *config = &kmb_i2s->config;
350
351 /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
352 writel(1, kmb_i2s->i2s_base + IER);
353
354 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
355 writel(1, kmb_i2s->i2s_base + ITER);
356 else
357 writel(1, kmb_i2s->i2s_base + IRER);
358
359 kmb_i2s_irq_trigger(kmb_i2s, substream->stream, config->chan_nr, true);
360
361 if (kmb_i2s->master)
362 writel(1, kmb_i2s->i2s_base + CER);
363 else
364 writel(0, kmb_i2s->i2s_base + CER);
365 }
366
kmb_i2s_stop(struct kmb_i2s_info * kmb_i2s,struct snd_pcm_substream * substream)367 static void kmb_i2s_stop(struct kmb_i2s_info *kmb_i2s,
368 struct snd_pcm_substream *substream)
369 {
370 /* I2S Programming sequence in Keem_Bay_VPU_DB_v1.1 */
371 kmb_i2s_clear_irqs(kmb_i2s, substream->stream);
372
373 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
374 writel(0, kmb_i2s->i2s_base + ITER);
375 else
376 writel(0, kmb_i2s->i2s_base + IRER);
377
378 kmb_i2s_irq_trigger(kmb_i2s, substream->stream, 8, false);
379
380 if (!kmb_i2s->active) {
381 writel(0, kmb_i2s->i2s_base + CER);
382 writel(0, kmb_i2s->i2s_base + IER);
383 }
384 }
385
kmb_disable_clk(void * clk)386 static void kmb_disable_clk(void *clk)
387 {
388 clk_disable_unprepare(clk);
389 }
390
kmb_set_dai_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)391 static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
392 {
393 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
394 int ret;
395
396 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
397 case SND_SOC_DAIFMT_CBM_CFM:
398 kmb_i2s->master = false;
399 ret = 0;
400 break;
401 case SND_SOC_DAIFMT_CBS_CFS:
402 writel(MASTER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
403
404 ret = clk_prepare_enable(kmb_i2s->clk_i2s);
405 if (ret < 0)
406 return ret;
407
408 ret = devm_add_action_or_reset(kmb_i2s->dev, kmb_disable_clk,
409 kmb_i2s->clk_i2s);
410 if (ret)
411 return ret;
412
413 kmb_i2s->master = true;
414 break;
415 default:
416 return -EINVAL;
417 }
418
419 return ret;
420 }
421
kmb_dai_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * cpu_dai)422 static int kmb_dai_trigger(struct snd_pcm_substream *substream,
423 int cmd, struct snd_soc_dai *cpu_dai)
424 {
425 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
426
427 switch (cmd) {
428 case SNDRV_PCM_TRIGGER_START:
429 /* Keep track of i2s activity before turn off
430 * the i2s interface
431 */
432 kmb_i2s->active++;
433 kmb_i2s_start(kmb_i2s, substream);
434 break;
435 case SNDRV_PCM_TRIGGER_STOP:
436 kmb_i2s->active--;
437 kmb_i2s_stop(kmb_i2s, substream);
438 break;
439 default:
440 return -EINVAL;
441 }
442
443 return 0;
444 }
445
kmb_i2s_config(struct kmb_i2s_info * kmb_i2s,int stream)446 static void kmb_i2s_config(struct kmb_i2s_info *kmb_i2s, int stream)
447 {
448 struct i2s_clk_config_data *config = &kmb_i2s->config;
449 u32 ch_reg;
450
451 kmb_i2s_disable_channels(kmb_i2s, stream);
452
453 for (ch_reg = 0; ch_reg < config->chan_nr / 2; ch_reg++) {
454 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
455 writel(kmb_i2s->xfer_resolution,
456 kmb_i2s->i2s_base + TCR(ch_reg));
457
458 writel(kmb_i2s->fifo_th - 1,
459 kmb_i2s->i2s_base + TFCR(ch_reg));
460
461 writel(1, kmb_i2s->i2s_base + TER(ch_reg));
462 } else {
463 writel(kmb_i2s->xfer_resolution,
464 kmb_i2s->i2s_base + RCR(ch_reg));
465
466 writel(kmb_i2s->fifo_th - 1,
467 kmb_i2s->i2s_base + RFCR(ch_reg));
468
469 writel(1, kmb_i2s->i2s_base + RER(ch_reg));
470 }
471 }
472 }
473
kmb_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params,struct snd_soc_dai * cpu_dai)474 static int kmb_dai_hw_params(struct snd_pcm_substream *substream,
475 struct snd_pcm_hw_params *hw_params,
476 struct snd_soc_dai *cpu_dai)
477 {
478 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
479 struct i2s_clk_config_data *config = &kmb_i2s->config;
480 u32 write_val;
481 int ret;
482
483 switch (params_format(hw_params)) {
484 case SNDRV_PCM_FORMAT_S16_LE:
485 config->data_width = 16;
486 kmb_i2s->ccr = 0x00;
487 kmb_i2s->xfer_resolution = 0x02;
488 break;
489 case SNDRV_PCM_FORMAT_S24_LE:
490 config->data_width = 32;
491 kmb_i2s->ccr = 0x14;
492 kmb_i2s->xfer_resolution = 0x05;
493 break;
494 case SNDRV_PCM_FORMAT_S32_LE:
495 config->data_width = 32;
496 kmb_i2s->ccr = 0x10;
497 kmb_i2s->xfer_resolution = 0x05;
498 break;
499 default:
500 dev_err(kmb_i2s->dev, "kmb: unsupported PCM fmt");
501 return -EINVAL;
502 }
503
504 config->chan_nr = params_channels(hw_params);
505
506 switch (config->chan_nr) {
507 case 8:
508 case 4:
509 /*
510 * Platform is not capable of providing clocks for
511 * multi channel audio
512 */
513 if (kmb_i2s->master)
514 return -EINVAL;
515
516 write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
517 (config->data_width << DATA_WIDTH_CONFIG_BIT) |
518 TDM_OPERATION;
519
520 writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
521 break;
522 case 2:
523 /*
524 * Platform is only capable of providing clocks need for
525 * 2 channel master mode
526 */
527 if (!(kmb_i2s->master))
528 return -EINVAL;
529
530 write_val = ((config->chan_nr / 2) << TDM_CHANNEL_CONFIG_BIT) |
531 (config->data_width << DATA_WIDTH_CONFIG_BIT) |
532 MASTER_MODE | I2S_OPERATION;
533
534 writel(write_val, kmb_i2s->pss_base + I2S_GEN_CFG_0);
535 break;
536 default:
537 dev_dbg(kmb_i2s->dev, "channel not supported\n");
538 return -EINVAL;
539 }
540
541 kmb_i2s_config(kmb_i2s, substream->stream);
542
543 writel(kmb_i2s->ccr, kmb_i2s->i2s_base + CCR);
544
545 config->sample_rate = params_rate(hw_params);
546
547 if (kmb_i2s->master) {
548 /* Only 2 ch supported in Master mode */
549 u32 bitclk = config->sample_rate * config->data_width * 2;
550
551 ret = clk_set_rate(kmb_i2s->clk_i2s, bitclk);
552 if (ret) {
553 dev_err(kmb_i2s->dev,
554 "Can't set I2S clock rate: %d\n", ret);
555 return ret;
556 }
557 }
558
559 return 0;
560 }
561
kmb_dai_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)562 static int kmb_dai_prepare(struct snd_pcm_substream *substream,
563 struct snd_soc_dai *cpu_dai)
564 {
565 struct kmb_i2s_info *kmb_i2s = snd_soc_dai_get_drvdata(cpu_dai);
566
567 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
568 writel(1, kmb_i2s->i2s_base + TXFFR);
569 else
570 writel(1, kmb_i2s->i2s_base + RXFFR);
571
572 return 0;
573 }
574
575 static struct snd_soc_dai_ops kmb_dai_ops = {
576 .trigger = kmb_dai_trigger,
577 .hw_params = kmb_dai_hw_params,
578 .prepare = kmb_dai_prepare,
579 .set_fmt = kmb_set_dai_fmt,
580 };
581
582 static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
583 {
584 .name = "intel_kmb_i2s",
585 .playback = {
586 .channels_min = 2,
587 .channels_max = 2,
588 .rates = SNDRV_PCM_RATE_8000 |
589 SNDRV_PCM_RATE_16000 |
590 SNDRV_PCM_RATE_48000,
591 .rate_min = 8000,
592 .rate_max = 48000,
593 .formats = (SNDRV_PCM_FMTBIT_S32_LE |
594 SNDRV_PCM_FMTBIT_S24_LE |
595 SNDRV_PCM_FMTBIT_S16_LE),
596 },
597 .capture = {
598 .channels_min = 2,
599 .channels_max = 2,
600 .rates = SNDRV_PCM_RATE_8000 |
601 SNDRV_PCM_RATE_16000 |
602 SNDRV_PCM_RATE_48000,
603 .rate_min = 8000,
604 .rate_max = 48000,
605 .formats = (SNDRV_PCM_FMTBIT_S32_LE |
606 SNDRV_PCM_FMTBIT_S24_LE |
607 SNDRV_PCM_FMTBIT_S16_LE),
608 },
609 .ops = &kmb_dai_ops,
610 },
611 };
612
613 static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
614 {
615 .name = "intel_kmb_tdm",
616 .capture = {
617 .channels_min = 4,
618 .channels_max = 8,
619 .rates = SNDRV_PCM_RATE_8000 |
620 SNDRV_PCM_RATE_16000 |
621 SNDRV_PCM_RATE_48000,
622 .rate_min = 8000,
623 .rate_max = 48000,
624 .formats = (SNDRV_PCM_FMTBIT_S32_LE |
625 SNDRV_PCM_FMTBIT_S24_LE |
626 SNDRV_PCM_FMTBIT_S16_LE),
627 },
628 .ops = &kmb_dai_ops,
629 },
630 };
631
632 static const struct of_device_id kmb_plat_of_match[] = {
633 { .compatible = "intel,keembay-i2s", .data = &intel_kmb_i2s_dai},
634 { .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai},
635 {}
636 };
637
kmb_plat_dai_probe(struct platform_device * pdev)638 static int kmb_plat_dai_probe(struct platform_device *pdev)
639 {
640 struct snd_soc_dai_driver *kmb_i2s_dai;
641 const struct of_device_id *match;
642 struct device *dev = &pdev->dev;
643 struct kmb_i2s_info *kmb_i2s;
644 int ret, irq;
645 u32 comp1_reg;
646
647 kmb_i2s = devm_kzalloc(dev, sizeof(*kmb_i2s), GFP_KERNEL);
648 if (!kmb_i2s)
649 return -ENOMEM;
650
651 kmb_i2s_dai = devm_kzalloc(dev, sizeof(*kmb_i2s_dai), GFP_KERNEL);
652 if (!kmb_i2s_dai)
653 return -ENOMEM;
654
655 match = of_match_device(kmb_plat_of_match, &pdev->dev);
656 if (!match) {
657 dev_err(&pdev->dev, "Error: No device match found\n");
658 return -ENODEV;
659 }
660 kmb_i2s_dai = (struct snd_soc_dai_driver *) match->data;
661
662 /* Prepare the related clocks */
663 kmb_i2s->clk_apb = devm_clk_get(dev, "apb_clk");
664 if (IS_ERR(kmb_i2s->clk_apb)) {
665 dev_err(dev, "Failed to get apb clock\n");
666 return PTR_ERR(kmb_i2s->clk_apb);
667 }
668
669 ret = clk_prepare_enable(kmb_i2s->clk_apb);
670 if (ret < 0)
671 return ret;
672
673 ret = devm_add_action_or_reset(dev, kmb_disable_clk, kmb_i2s->clk_apb);
674 if (ret) {
675 dev_err(dev, "Failed to add clk_apb reset action\n");
676 return ret;
677 }
678
679 kmb_i2s->clk_i2s = devm_clk_get(dev, "osc");
680 if (IS_ERR(kmb_i2s->clk_i2s)) {
681 dev_err(dev, "Failed to get osc clock\n");
682 return PTR_ERR(kmb_i2s->clk_i2s);
683 }
684
685 kmb_i2s->i2s_base = devm_platform_ioremap_resource(pdev, 0);
686 if (IS_ERR(kmb_i2s->i2s_base))
687 return PTR_ERR(kmb_i2s->i2s_base);
688
689 kmb_i2s->pss_base = devm_platform_ioremap_resource(pdev, 1);
690 if (IS_ERR(kmb_i2s->pss_base))
691 return PTR_ERR(kmb_i2s->pss_base);
692
693 kmb_i2s->dev = &pdev->dev;
694
695 irq = platform_get_irq_optional(pdev, 0);
696 if (irq > 0) {
697 ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
698 pdev->name, kmb_i2s);
699 if (ret < 0) {
700 dev_err(dev, "failed to request irq\n");
701 return ret;
702 }
703 }
704
705 comp1_reg = readl(kmb_i2s->i2s_base + I2S_COMP_PARAM_1);
706
707 kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
708
709 ret = devm_snd_soc_register_component(dev, &kmb_component,
710 kmb_i2s_dai, 1);
711 if (ret) {
712 dev_err(dev, "not able to register dai\n");
713 return ret;
714 }
715
716 /* To ensure none of the channels are enabled at boot up */
717 kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_PLAYBACK);
718 kmb_i2s_disable_channels(kmb_i2s, SNDRV_PCM_STREAM_CAPTURE);
719
720 dev_set_drvdata(dev, kmb_i2s);
721
722 return ret;
723 }
724
725 static struct platform_driver kmb_plat_dai_driver = {
726 .driver = {
727 .name = "kmb-plat-dai",
728 .of_match_table = kmb_plat_of_match,
729 },
730 .probe = kmb_plat_dai_probe,
731 };
732
733 module_platform_driver(kmb_plat_dai_driver);
734
735 MODULE_DESCRIPTION("ASoC Intel KeemBay Platform driver");
736 MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>");
737 MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>");
738 MODULE_LICENSE("GPL v2");
739 MODULE_ALIAS("platform:kmb_platform");
740