Merge tag 'dio_for_v5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack...
[linux-2.6-microblaze.git] / sound / soc / intel / keembay / kmb_platform.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
386 static void kmb_disable_clk(void *clk)
387 {
388         clk_disable_unprepare(clk);
389 }
390
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
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
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
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 = 24;
491                 kmb_i2s->ccr = 0x08;
492                 kmb_i2s->xfer_resolution = 0x04;
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
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
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");