xref: /linux/sound/soc/amd/acp/acp-i2s.c (revision 6c8c1406)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2021 Advanced Micro Devices, Inc.
7 //
8 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
9 //
10 
11 /*
12  * Generic Hardware interface for ACP Audio I2S controller
13  */
14 
15 #include <linux/platform_device.h>
16 #include <linux/module.h>
17 #include <linux/err.h>
18 #include <linux/io.h>
19 #include <sound/pcm_params.h>
20 #include <sound/soc.h>
21 #include <sound/soc-dai.h>
22 #include <linux/dma-mapping.h>
23 
24 #include "amd.h"
25 
26 #define DRV_NAME "acp_i2s_playcap"
27 
28 static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
29 			   unsigned int fmt)
30 {
31 	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
32 	int mode;
33 
34 	mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
35 	switch (mode) {
36 	case SND_SOC_DAIFMT_I2S:
37 		adata->tdm_mode = TDM_DISABLE;
38 		break;
39 	case SND_SOC_DAIFMT_DSP_A:
40 		adata->tdm_mode = TDM_ENABLE;
41 		break;
42 	default:
43 		return -EINVAL;
44 	}
45 	return 0;
46 }
47 
48 static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,
49 				int slots, int slot_width)
50 {
51 	struct device *dev = dai->component->dev;
52 	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
53 	struct acp_stream *stream;
54 	int slot_len;
55 
56 	switch (slot_width) {
57 	case SLOT_WIDTH_8:
58 		slot_len = 8;
59 		break;
60 	case SLOT_WIDTH_16:
61 		slot_len = 16;
62 		break;
63 	case SLOT_WIDTH_24:
64 		slot_len = 24;
65 		break;
66 	case SLOT_WIDTH_32:
67 		slot_len = 0;
68 		break;
69 	default:
70 		dev_err(dev, "Unsupported bitdepth %d\n", slot_width);
71 		return -EINVAL;
72 	}
73 
74 	spin_lock_irq(&adata->acp_lock);
75 	list_for_each_entry(stream, &adata->stream_list, list) {
76 		if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
77 			adata->tdm_tx_fmt[stream->dai_id - 1] =
78 					FRM_LEN | (slots << 15) | (slot_len << 18);
79 		else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
80 			adata->tdm_rx_fmt[stream->dai_id - 1] =
81 					FRM_LEN | (slots << 15) | (slot_len << 18);
82 	}
83 	spin_unlock_irq(&adata->acp_lock);
84 	return 0;
85 }
86 
87 static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
88 			    struct snd_soc_dai *dai)
89 {
90 	struct device *dev = dai->component->dev;
91 	struct acp_dev_data *adata;
92 	struct acp_resource *rsrc;
93 	u32 val;
94 	u32 xfer_resolution;
95 	u32 reg_val, fmt_reg, tdm_fmt;
96 	u32 lrclk_div_val, bclk_div_val;
97 
98 	adata = snd_soc_dai_get_drvdata(dai);
99 	rsrc = adata->rsrc;
100 
101 	/* These values are as per Hardware Spec */
102 	switch (params_format(params)) {
103 	case SNDRV_PCM_FORMAT_U8:
104 	case SNDRV_PCM_FORMAT_S8:
105 		xfer_resolution = 0x0;
106 		break;
107 	case SNDRV_PCM_FORMAT_S16_LE:
108 		xfer_resolution = 0x02;
109 		break;
110 	case SNDRV_PCM_FORMAT_S24_LE:
111 		xfer_resolution = 0x04;
112 		break;
113 	case SNDRV_PCM_FORMAT_S32_LE:
114 		xfer_resolution = 0x05;
115 		break;
116 	default:
117 		return -EINVAL;
118 	}
119 
120 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
121 		switch (dai->driver->id) {
122 		case I2S_BT_INSTANCE:
123 			reg_val = ACP_BTTDM_ITER;
124 			fmt_reg = ACP_BTTDM_TXFRMT;
125 			break;
126 		case I2S_SP_INSTANCE:
127 			reg_val = ACP_I2STDM_ITER;
128 			fmt_reg = ACP_I2STDM_TXFRMT;
129 			break;
130 		case I2S_HS_INSTANCE:
131 			reg_val = ACP_HSTDM_ITER;
132 			fmt_reg = ACP_HSTDM_TXFRMT;
133 			break;
134 		default:
135 			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
136 			return -EINVAL;
137 		}
138 	} else {
139 		switch (dai->driver->id) {
140 		case I2S_BT_INSTANCE:
141 			reg_val = ACP_BTTDM_IRER;
142 			fmt_reg = ACP_BTTDM_RXFRMT;
143 			break;
144 		case I2S_SP_INSTANCE:
145 			reg_val = ACP_I2STDM_IRER;
146 			fmt_reg = ACP_I2STDM_RXFRMT;
147 			break;
148 		case I2S_HS_INSTANCE:
149 			reg_val = ACP_HSTDM_IRER;
150 			fmt_reg = ACP_HSTDM_RXFRMT;
151 			break;
152 		default:
153 			dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
154 			return -EINVAL;
155 		}
156 	}
157 
158 	val = readl(adata->acp_base + reg_val);
159 	val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
160 	val = val | (xfer_resolution  << 3);
161 	writel(val, adata->acp_base + reg_val);
162 
163 	if (adata->tdm_mode) {
164 		val = readl(adata->acp_base + reg_val);
165 		writel(val | BIT(1), adata->acp_base + reg_val);
166 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
167 			tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];
168 		else
169 			tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];
170 		writel(tdm_fmt, adata->acp_base + fmt_reg);
171 	}
172 
173 	if (rsrc->soc_mclk) {
174 		switch (params_format(params)) {
175 		case SNDRV_PCM_FORMAT_S16_LE:
176 			switch (params_rate(params)) {
177 			case 8000:
178 				bclk_div_val = 768;
179 				break;
180 			case 16000:
181 				bclk_div_val = 384;
182 				break;
183 			case 24000:
184 				bclk_div_val = 256;
185 				break;
186 			case 32000:
187 				bclk_div_val = 192;
188 				break;
189 			case 44100:
190 			case 48000:
191 				bclk_div_val = 128;
192 				break;
193 			case 88200:
194 			case 96000:
195 				bclk_div_val = 64;
196 				break;
197 			case 192000:
198 				bclk_div_val = 32;
199 				break;
200 			default:
201 				return -EINVAL;
202 			}
203 			lrclk_div_val = 32;
204 			break;
205 		case SNDRV_PCM_FORMAT_S32_LE:
206 			switch (params_rate(params)) {
207 			case 8000:
208 				bclk_div_val = 384;
209 				break;
210 			case 16000:
211 				bclk_div_val = 192;
212 				break;
213 			case 24000:
214 				bclk_div_val = 128;
215 				break;
216 			case 32000:
217 				bclk_div_val = 96;
218 				break;
219 			case 44100:
220 			case 48000:
221 				bclk_div_val = 64;
222 				break;
223 			case 88200:
224 			case 96000:
225 				bclk_div_val = 32;
226 				break;
227 			case 192000:
228 				bclk_div_val = 16;
229 				break;
230 			default:
231 				return -EINVAL;
232 			}
233 			lrclk_div_val = 64;
234 			break;
235 		default:
236 			return -EINVAL;
237 		}
238 		adata->lrclk_div = lrclk_div_val;
239 		adata->bclk_div = bclk_div_val;
240 	}
241 	return 0;
242 }
243 
244 static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
245 {
246 	struct acp_stream *stream = substream->runtime->private_data;
247 	struct device *dev = dai->component->dev;
248 	struct acp_dev_data *adata = dev_get_drvdata(dev);
249 	struct acp_resource *rsrc = adata->rsrc;
250 	u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
251 
252 	period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
253 	buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);
254 
255 	switch (cmd) {
256 	case SNDRV_PCM_TRIGGER_START:
257 	case SNDRV_PCM_TRIGGER_RESUME:
258 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
259 		stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
260 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
261 			switch (dai->driver->id) {
262 			case I2S_BT_INSTANCE:
263 				water_val = ACP_BT_TX_INTR_WATERMARK_SIZE;
264 				reg_val = ACP_BTTDM_ITER;
265 				ier_val = ACP_BTTDM_IER;
266 				buf_reg = ACP_BT_TX_RINGBUFSIZE;
267 				break;
268 			case I2S_SP_INSTANCE:
269 				water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
270 				reg_val = ACP_I2STDM_ITER;
271 				ier_val = ACP_I2STDM_IER;
272 				buf_reg = ACP_I2S_TX_RINGBUFSIZE;
273 				break;
274 			case I2S_HS_INSTANCE:
275 				water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
276 				reg_val = ACP_HSTDM_ITER;
277 				ier_val = ACP_HSTDM_IER;
278 				buf_reg = ACP_HS_TX_RINGBUFSIZE;
279 				break;
280 			default:
281 				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
282 				return -EINVAL;
283 			}
284 		} else {
285 			switch (dai->driver->id) {
286 			case I2S_BT_INSTANCE:
287 				water_val = ACP_BT_RX_INTR_WATERMARK_SIZE;
288 				reg_val = ACP_BTTDM_IRER;
289 				ier_val = ACP_BTTDM_IER;
290 				buf_reg = ACP_BT_RX_RINGBUFSIZE;
291 				break;
292 			case I2S_SP_INSTANCE:
293 				water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
294 				reg_val = ACP_I2STDM_IRER;
295 				ier_val = ACP_I2STDM_IER;
296 				buf_reg = ACP_I2S_RX_RINGBUFSIZE;
297 				break;
298 			case I2S_HS_INSTANCE:
299 				water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
300 				reg_val = ACP_HSTDM_IRER;
301 				ier_val = ACP_HSTDM_IER;
302 				buf_reg = ACP_HS_RX_RINGBUFSIZE;
303 				break;
304 			default:
305 				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
306 				return -EINVAL;
307 			}
308 		}
309 		writel(period_bytes, adata->acp_base + water_val);
310 		writel(buf_size, adata->acp_base + buf_reg);
311 		val = readl(adata->acp_base + reg_val);
312 		val = val | BIT(0);
313 		writel(val, adata->acp_base + reg_val);
314 		writel(1, adata->acp_base + ier_val);
315 		if (rsrc->soc_mclk)
316 			acp_set_i2s_clk(adata, dai->driver->id);
317 		return 0;
318 	case SNDRV_PCM_TRIGGER_STOP:
319 	case SNDRV_PCM_TRIGGER_SUSPEND:
320 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
321 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
322 			switch (dai->driver->id) {
323 			case I2S_BT_INSTANCE:
324 				reg_val = ACP_BTTDM_ITER;
325 				break;
326 			case I2S_SP_INSTANCE:
327 				reg_val = ACP_I2STDM_ITER;
328 				break;
329 			case I2S_HS_INSTANCE:
330 				reg_val = ACP_HSTDM_ITER;
331 				break;
332 			default:
333 				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
334 				return -EINVAL;
335 			}
336 
337 		} else {
338 			switch (dai->driver->id) {
339 			case I2S_BT_INSTANCE:
340 				reg_val = ACP_BTTDM_IRER;
341 				break;
342 			case I2S_SP_INSTANCE:
343 				reg_val = ACP_I2STDM_IRER;
344 				break;
345 			case I2S_HS_INSTANCE:
346 				reg_val = ACP_HSTDM_IRER;
347 				break;
348 			default:
349 				dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
350 				return -EINVAL;
351 			}
352 		}
353 		val = readl(adata->acp_base + reg_val);
354 		val = val & ~BIT(0);
355 		writel(val, adata->acp_base + reg_val);
356 
357 		if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
358 		    !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
359 			writel(0, adata->acp_base + ACP_BTTDM_IER);
360 		if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
361 		    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
362 			writel(0, adata->acp_base + ACP_I2STDM_IER);
363 		if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
364 		    !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
365 			writel(0, adata->acp_base + ACP_HSTDM_IER);
366 		return 0;
367 	default:
368 		return -EINVAL;
369 	}
370 
371 	return 0;
372 }
373 
374 static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
375 {
376 	struct device *dev = dai->component->dev;
377 	struct acp_dev_data *adata = dev_get_drvdata(dev);
378 	struct acp_resource *rsrc = adata->rsrc;
379 	struct acp_stream *stream = substream->runtime->private_data;
380 	u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
381 	u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
382 	unsigned int dir = substream->stream;
383 
384 	switch (dai->driver->id) {
385 	case I2S_SP_INSTANCE:
386 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
387 			reg_dma_size = ACP_I2S_TX_DMA_SIZE;
388 			acp_fifo_addr = rsrc->sram_pte_offset +
389 						SP_PB_FIFO_ADDR_OFFSET;
390 			reg_fifo_addr =	ACP_I2S_TX_FIFOADDR;
391 			reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
392 
393 			phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
394 			writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
395 		} else {
396 			reg_dma_size = ACP_I2S_RX_DMA_SIZE;
397 			acp_fifo_addr = rsrc->sram_pte_offset +
398 						SP_CAPT_FIFO_ADDR_OFFSET;
399 			reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
400 			reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
401 			phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
402 			writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
403 		}
404 		break;
405 	case I2S_BT_INSTANCE:
406 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
407 			reg_dma_size = ACP_BT_TX_DMA_SIZE;
408 			acp_fifo_addr = rsrc->sram_pte_offset +
409 						BT_PB_FIFO_ADDR_OFFSET;
410 			reg_fifo_addr = ACP_BT_TX_FIFOADDR;
411 			reg_fifo_size = ACP_BT_TX_FIFOSIZE;
412 
413 			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
414 			writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
415 		} else {
416 			reg_dma_size = ACP_BT_RX_DMA_SIZE;
417 			acp_fifo_addr = rsrc->sram_pte_offset +
418 						BT_CAPT_FIFO_ADDR_OFFSET;
419 			reg_fifo_addr = ACP_BT_RX_FIFOADDR;
420 			reg_fifo_size = ACP_BT_RX_FIFOSIZE;
421 
422 			phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
423 			writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
424 		}
425 		break;
426 	case I2S_HS_INSTANCE:
427 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
428 			reg_dma_size = ACP_HS_TX_DMA_SIZE;
429 			acp_fifo_addr = rsrc->sram_pte_offset +
430 				HS_PB_FIFO_ADDR_OFFSET;
431 			reg_fifo_addr = ACP_HS_TX_FIFOADDR;
432 			reg_fifo_size = ACP_HS_TX_FIFOSIZE;
433 
434 			phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
435 			writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
436 		} else {
437 			reg_dma_size = ACP_HS_RX_DMA_SIZE;
438 			acp_fifo_addr = rsrc->sram_pte_offset +
439 					HS_CAPT_FIFO_ADDR_OFFSET;
440 			reg_fifo_addr = ACP_HS_RX_FIFOADDR;
441 			reg_fifo_size = ACP_HS_RX_FIFOSIZE;
442 
443 			phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
444 			writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
445 		}
446 		break;
447 	default:
448 		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
449 		return -EINVAL;
450 	}
451 
452 	writel(DMA_SIZE, adata->acp_base + reg_dma_size);
453 	writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
454 	writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
455 
456 	ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
457 	ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
458 			BIT(BT_RX_THRESHOLD(rsrc->offset)) |
459 			BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
460 			BIT(BT_TX_THRESHOLD(rsrc->offset)) |
461 			BIT(HS_RX_THRESHOLD(rsrc->offset)) |
462 			BIT(HS_TX_THRESHOLD(rsrc->offset));
463 
464 	writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
465 
466 	return 0;
467 }
468 
469 static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
470 {
471 	struct acp_stream *stream = substream->runtime->private_data;
472 	struct device *dev = dai->component->dev;
473 	struct acp_dev_data *adata = dev_get_drvdata(dev);
474 	struct acp_resource *rsrc = adata->rsrc;
475 	unsigned int dir = substream->stream;
476 	unsigned int irq_bit = 0;
477 
478 	switch (dai->driver->id) {
479 	case I2S_SP_INSTANCE:
480 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
481 			irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
482 			stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
483 			stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
484 		} else {
485 			irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
486 			stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
487 			stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
488 		}
489 		break;
490 	case I2S_BT_INSTANCE:
491 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
492 			irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
493 			stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
494 			stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
495 		} else {
496 			irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
497 			stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
498 			stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
499 		}
500 		break;
501 	case I2S_HS_INSTANCE:
502 		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
503 			irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
504 			stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
505 			stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
506 		} else {
507 			irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
508 			stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
509 			stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
510 		}
511 		break;
512 	default:
513 		dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
514 		return -EINVAL;
515 	}
516 
517 	/* Save runtime dai configuration in stream */
518 	stream->id = dai->driver->id + dir;
519 	stream->dai_id = dai->driver->id;
520 	stream->irq_bit = irq_bit;
521 	stream->dir = substream->stream;
522 
523 	return 0;
524 }
525 
526 const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
527 	.startup = acp_i2s_startup,
528 	.hw_params = acp_i2s_hwparams,
529 	.prepare = acp_i2s_prepare,
530 	.trigger = acp_i2s_trigger,
531 	.set_fmt = acp_i2s_set_fmt,
532 	.set_tdm_slot = acp_i2s_set_tdm_slot,
533 };
534 EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
535 
536 int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
537 {
538 	struct device *dev = dai->component->dev;
539 	struct acp_dev_data *adata = dev_get_drvdata(dev);
540 	struct acp_resource *rsrc = adata->rsrc;
541 	unsigned int val;
542 
543 	if (!adata->acp_base) {
544 		dev_err(dev, "I2S base is NULL\n");
545 		return -EINVAL;
546 	}
547 
548 	val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset);
549 	if (val != rsrc->i2s_mode) {
550 		dev_err(dev, "I2S Mode not supported val %x\n", val);
551 		return -EINVAL;
552 	}
553 
554 	return 0;
555 }
556 EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
557 
558 MODULE_LICENSE("Dual BSD/GPL");
559 MODULE_ALIAS(DRV_NAME);
560