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

source code of linux/sound/soc/amd/acp/acp-i2s.c