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