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