1// SPDX-License-Identifier: GPL-2.0
2//
3// Xilinx ASoC audio formatter support
4//
5// Copyright (C) 2018 Xilinx, Inc.
6//
7// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
8
9#include <linux/clk.h>
10#include <linux/io.h>
11#include <linux/module.h>
12#include <linux/of_address.h>
13#include <linux/of_irq.h>
14#include <linux/sizes.h>
15
16#include <sound/asoundef.h>
17#include <sound/soc.h>
18#include <sound/pcm_params.h>
19
20#define DRV_NAME "xlnx_formatter_pcm"
21
22#define XLNX_S2MM_OFFSET 0
23#define XLNX_MM2S_OFFSET 0x100
24
25#define XLNX_AUD_CORE_CONFIG 0x4
26#define XLNX_AUD_CTRL 0x10
27#define XLNX_AUD_STS 0x14
28
29#define AUD_CTRL_RESET_MASK BIT(1)
30#define AUD_CFG_MM2S_MASK BIT(15)
31#define AUD_CFG_S2MM_MASK BIT(31)
32
33#define XLNX_AUD_FS_MULTIPLIER 0x18
34#define XLNX_AUD_PERIOD_CONFIG 0x1C
35#define XLNX_AUD_BUFF_ADDR_LSB 0x20
36#define XLNX_AUD_BUFF_ADDR_MSB 0x24
37#define XLNX_AUD_XFER_COUNT 0x28
38#define XLNX_AUD_CH_STS_START 0x2C
39#define XLNX_BYTES_PER_CH 0x44
40#define XLNX_AUD_ALIGN_BYTES 64
41
42#define AUD_STS_IOC_IRQ_MASK BIT(31)
43#define AUD_STS_CH_STS_MASK BIT(29)
44#define AUD_CTRL_IOC_IRQ_MASK BIT(13)
45#define AUD_CTRL_TOUT_IRQ_MASK BIT(14)
46#define AUD_CTRL_DMA_EN_MASK BIT(0)
47
48#define CFG_MM2S_CH_MASK GENMASK(11, 8)
49#define CFG_MM2S_CH_SHIFT 8
50#define CFG_MM2S_XFER_MASK GENMASK(14, 13)
51#define CFG_MM2S_XFER_SHIFT 13
52#define CFG_MM2S_PKG_MASK BIT(12)
53
54#define CFG_S2MM_CH_MASK GENMASK(27, 24)
55#define CFG_S2MM_CH_SHIFT 24
56#define CFG_S2MM_XFER_MASK GENMASK(30, 29)
57#define CFG_S2MM_XFER_SHIFT 29
58#define CFG_S2MM_PKG_MASK BIT(28)
59
60#define AUD_CTRL_DATA_WIDTH_SHIFT 16
61#define AUD_CTRL_ACTIVE_CH_SHIFT 19
62#define PERIOD_CFG_PERIODS_SHIFT 16
63
64#define PERIODS_MIN 2
65#define PERIODS_MAX 6
66#define PERIOD_BYTES_MIN 192
67#define PERIOD_BYTES_MAX (50 * 1024)
68#define XLNX_PARAM_UNKNOWN 0
69
70enum bit_depth {
71 BIT_DEPTH_8,
72 BIT_DEPTH_16,
73 BIT_DEPTH_20,
74 BIT_DEPTH_24,
75 BIT_DEPTH_32,
76};
77
78struct xlnx_pcm_drv_data {
79 void __iomem *mmio;
80 bool s2mm_presence;
81 bool mm2s_presence;
82 int s2mm_irq;
83 int mm2s_irq;
84 struct snd_pcm_substream *play_stream;
85 struct snd_pcm_substream *capture_stream;
86 struct clk *axi_clk;
87 unsigned int sysclk;
88};
89
90/*
91 * struct xlnx_pcm_stream_param - stream configuration
92 * @mmio: base address offset
93 * @interleaved: audio channels arrangement in buffer
94 * @xfer_mode: data formatting mode during transfer
95 * @ch_limit: Maximum channels supported
96 * @buffer_size: stream ring buffer size
97 */
98struct xlnx_pcm_stream_param {
99 void __iomem *mmio;
100 bool interleaved;
101 u32 xfer_mode;
102 u32 ch_limit;
103 u64 buffer_size;
104};
105
106static const struct snd_pcm_hardware xlnx_pcm_hardware = {
107 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
108 SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_PAUSE |
109 SNDRV_PCM_INFO_RESUME,
110 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
111 SNDRV_PCM_FMTBIT_S24_LE,
112 .channels_min = 2,
113 .channels_max = 2,
114 .rates = SNDRV_PCM_RATE_8000_192000,
115 .rate_min = 8000,
116 .rate_max = 192000,
117 .buffer_bytes_max = PERIODS_MAX * PERIOD_BYTES_MAX,
118 .period_bytes_min = PERIOD_BYTES_MIN,
119 .period_bytes_max = PERIOD_BYTES_MAX,
120 .periods_min = PERIODS_MIN,
121 .periods_max = PERIODS_MAX,
122};
123
124enum {
125 AES_TO_AES,
126 AES_TO_PCM,
127 PCM_TO_PCM,
128 PCM_TO_AES
129};
130
131static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val,
132 struct device *dev)
133{
134 u32 padded, srate, bit_depth, status[2];
135
136 if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) {
137 status[0] = chsts_reg1_val & 0xff;
138 status[1] = (chsts_reg1_val >> 16) & 0xff;
139
140 switch (status[0] & IEC958_AES0_PRO_FS) {
141 case IEC958_AES0_PRO_FS_44100:
142 srate = 44100;
143 break;
144 case IEC958_AES0_PRO_FS_48000:
145 srate = 48000;
146 break;
147 case IEC958_AES0_PRO_FS_32000:
148 srate = 32000;
149 break;
150 case IEC958_AES0_PRO_FS_NOTID:
151 default:
152 srate = XLNX_PARAM_UNKNOWN;
153 break;
154 }
155
156 switch (status[1] & IEC958_AES2_PRO_SBITS) {
157 case IEC958_AES2_PRO_WORDLEN_NOTID:
158 case IEC958_AES2_PRO_SBITS_20:
159 padded = 0;
160 break;
161 case IEC958_AES2_PRO_SBITS_24:
162 padded = 4;
163 break;
164 default:
165 bit_depth = XLNX_PARAM_UNKNOWN;
166 goto log_params;
167 }
168
169 switch (status[1] & IEC958_AES2_PRO_WORDLEN) {
170 case IEC958_AES2_PRO_WORDLEN_20_16:
171 bit_depth = 16 + padded;
172 break;
173 case IEC958_AES2_PRO_WORDLEN_22_18:
174 bit_depth = 18 + padded;
175 break;
176 case IEC958_AES2_PRO_WORDLEN_23_19:
177 bit_depth = 19 + padded;
178 break;
179 case IEC958_AES2_PRO_WORDLEN_24_20:
180 bit_depth = 20 + padded;
181 break;
182 case IEC958_AES2_PRO_WORDLEN_NOTID:
183 default:
184 bit_depth = XLNX_PARAM_UNKNOWN;
185 break;
186 }
187
188 } else {
189 status[0] = (chsts_reg1_val >> 24) & 0xff;
190 status[1] = chsts_reg2_val & 0xff;
191
192 switch (status[0] & IEC958_AES3_CON_FS) {
193 case IEC958_AES3_CON_FS_44100:
194 srate = 44100;
195 break;
196 case IEC958_AES3_CON_FS_48000:
197 srate = 48000;
198 break;
199 case IEC958_AES3_CON_FS_32000:
200 srate = 32000;
201 break;
202 default:
203 srate = XLNX_PARAM_UNKNOWN;
204 break;
205 }
206
207 if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24)
208 padded = 4;
209 else
210 padded = 0;
211
212 switch (status[1] & IEC958_AES4_CON_WORDLEN) {
213 case IEC958_AES4_CON_WORDLEN_20_16:
214 bit_depth = 16 + padded;
215 break;
216 case IEC958_AES4_CON_WORDLEN_22_18:
217 bit_depth = 18 + padded;
218 break;
219 case IEC958_AES4_CON_WORDLEN_23_19:
220 bit_depth = 19 + padded;
221 break;
222 case IEC958_AES4_CON_WORDLEN_24_20:
223 bit_depth = 20 + padded;
224 break;
225 case IEC958_AES4_CON_WORDLEN_21_17:
226 bit_depth = 17 + padded;
227 break;
228 case IEC958_AES4_CON_WORDLEN_NOTID:
229 default:
230 bit_depth = XLNX_PARAM_UNKNOWN;
231 break;
232 }
233 }
234
235log_params:
236 if (srate != XLNX_PARAM_UNKNOWN)
237 dev_info(dev, "sample rate = %d\n", srate);
238 else
239 dev_info(dev, "sample rate = unknown\n");
240
241 if (bit_depth != XLNX_PARAM_UNKNOWN)
242 dev_info(dev, "bit_depth = %d\n", bit_depth);
243 else
244 dev_info(dev, "bit_depth = unknown\n");
245}
246
247static int xlnx_formatter_pcm_reset(void __iomem *mmio_base)
248{
249 u32 val, retries = 0;
250
251 val = readl(addr: mmio_base + XLNX_AUD_CTRL);
252 val |= AUD_CTRL_RESET_MASK;
253 writel(val, addr: mmio_base + XLNX_AUD_CTRL);
254
255 val = readl(addr: mmio_base + XLNX_AUD_CTRL);
256 /* Poll for maximum timeout of approximately 100ms (1 * 100)*/
257 while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) {
258 mdelay(1);
259 retries++;
260 val = readl(addr: mmio_base + XLNX_AUD_CTRL);
261 }
262 if (val & AUD_CTRL_RESET_MASK)
263 return -ENODEV;
264
265 return 0;
266}
267
268static void xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream)
269{
270 u32 val;
271
272 val = readl(addr: mmio_base + XLNX_AUD_CTRL);
273 val &= ~AUD_CTRL_IOC_IRQ_MASK;
274 if (stream == SNDRV_PCM_STREAM_CAPTURE)
275 val &= ~AUD_CTRL_TOUT_IRQ_MASK;
276
277 writel(val, addr: mmio_base + XLNX_AUD_CTRL);
278}
279
280static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg)
281{
282 u32 val;
283 void __iomem *reg;
284 struct device *dev = arg;
285 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
286
287 reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS;
288 val = readl(addr: reg);
289 if (val & AUD_STS_IOC_IRQ_MASK) {
290 writel(val: val & AUD_STS_IOC_IRQ_MASK, addr: reg);
291 if (adata->play_stream)
292 snd_pcm_period_elapsed(substream: adata->play_stream);
293 return IRQ_HANDLED;
294 }
295
296 return IRQ_NONE;
297}
298
299static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg)
300{
301 u32 val;
302 void __iomem *reg;
303 struct device *dev = arg;
304 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
305
306 reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS;
307 val = readl(addr: reg);
308 if (val & AUD_STS_IOC_IRQ_MASK) {
309 writel(val: val & AUD_STS_IOC_IRQ_MASK, addr: reg);
310 if (adata->capture_stream)
311 snd_pcm_period_elapsed(substream: adata->capture_stream);
312 return IRQ_HANDLED;
313 }
314
315 return IRQ_NONE;
316}
317
318static int xlnx_formatter_set_sysclk(struct snd_soc_component *component,
319 int clk_id, int source, unsigned int freq, int dir)
320{
321 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev: component->dev);
322
323 adata->sysclk = freq;
324 return 0;
325}
326
327static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
328 struct snd_pcm_substream *substream)
329{
330 int err;
331 u32 val, data_format_mode;
332 u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift;
333 struct xlnx_pcm_stream_param *stream_data;
334 struct snd_pcm_runtime *runtime = substream->runtime;
335 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev: component->dev);
336
337 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
338 !adata->mm2s_presence)
339 return -ENODEV;
340 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
341 !adata->s2mm_presence)
342 return -ENODEV;
343
344 stream_data = kzalloc(size: sizeof(*stream_data), GFP_KERNEL);
345 if (!stream_data)
346 return -ENOMEM;
347
348 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
349 ch_count_mask = CFG_MM2S_CH_MASK;
350 ch_count_shift = CFG_MM2S_CH_SHIFT;
351 data_xfer_mode = CFG_MM2S_XFER_MASK;
352 data_xfer_shift = CFG_MM2S_XFER_SHIFT;
353 data_format_mode = CFG_MM2S_PKG_MASK;
354 stream_data->mmio = adata->mmio + XLNX_MM2S_OFFSET;
355 adata->play_stream = substream;
356
357 } else {
358 ch_count_mask = CFG_S2MM_CH_MASK;
359 ch_count_shift = CFG_S2MM_CH_SHIFT;
360 data_xfer_mode = CFG_S2MM_XFER_MASK;
361 data_xfer_shift = CFG_S2MM_XFER_SHIFT;
362 data_format_mode = CFG_S2MM_PKG_MASK;
363 stream_data->mmio = adata->mmio + XLNX_S2MM_OFFSET;
364 adata->capture_stream = substream;
365 }
366
367 val = readl(addr: adata->mmio + XLNX_AUD_CORE_CONFIG);
368
369 if (!(val & data_format_mode))
370 stream_data->interleaved = true;
371
372 stream_data->xfer_mode = (val & data_xfer_mode) >> data_xfer_shift;
373 stream_data->ch_limit = (val & ch_count_mask) >> ch_count_shift;
374 dev_info(component->dev,
375 "stream %d : format = %d mode = %d ch_limit = %d\n",
376 substream->stream, stream_data->interleaved,
377 stream_data->xfer_mode, stream_data->ch_limit);
378
379 snd_soc_set_runtime_hwparams(substream, hw: &xlnx_pcm_hardware);
380 runtime->private_data = stream_data;
381
382 /* Resize the period bytes as divisible by 64 */
383 err = snd_pcm_hw_constraint_step(runtime, cond: 0,
384 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
385 XLNX_AUD_ALIGN_BYTES);
386 if (err) {
387 dev_err(component->dev,
388 "Unable to set constraint on period bytes\n");
389 return err;
390 }
391
392 /* Resize the buffer bytes as divisible by 64 */
393 err = snd_pcm_hw_constraint_step(runtime, cond: 0,
394 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
395 XLNX_AUD_ALIGN_BYTES);
396 if (err) {
397 dev_err(component->dev,
398 "Unable to set constraint on buffer bytes\n");
399 return err;
400 }
401
402 /* Set periods as integer multiple */
403 err = snd_pcm_hw_constraint_integer(runtime,
404 SNDRV_PCM_HW_PARAM_PERIODS);
405 if (err < 0) {
406 dev_err(component->dev,
407 "Unable to set constraint on periods to be integer\n");
408 return err;
409 }
410
411 /* enable DMA IOC irq */
412 val = readl(addr: stream_data->mmio + XLNX_AUD_CTRL);
413 val |= AUD_CTRL_IOC_IRQ_MASK;
414 writel(val, addr: stream_data->mmio + XLNX_AUD_CTRL);
415
416 return 0;
417}
418
419static int xlnx_formatter_pcm_close(struct snd_soc_component *component,
420 struct snd_pcm_substream *substream)
421{
422 int ret;
423 struct xlnx_pcm_stream_param *stream_data =
424 substream->runtime->private_data;
425
426 ret = xlnx_formatter_pcm_reset(mmio_base: stream_data->mmio);
427 if (ret) {
428 dev_err(component->dev, "audio formatter reset failed\n");
429 goto err_reset;
430 }
431 xlnx_formatter_disable_irqs(mmio_base: stream_data->mmio, stream: substream->stream);
432
433err_reset:
434 kfree(objp: stream_data);
435 return 0;
436}
437
438static snd_pcm_uframes_t
439xlnx_formatter_pcm_pointer(struct snd_soc_component *component,
440 struct snd_pcm_substream *substream)
441{
442 u32 pos;
443 struct snd_pcm_runtime *runtime = substream->runtime;
444 struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
445
446 pos = readl(addr: stream_data->mmio + XLNX_AUD_XFER_COUNT);
447
448 if (pos >= stream_data->buffer_size)
449 pos = 0;
450
451 return bytes_to_frames(runtime, size: pos);
452}
453
454static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
455 struct snd_pcm_substream *substream,
456 struct snd_pcm_hw_params *params)
457{
458 u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
459 u32 aes_reg1_val, aes_reg2_val;
460 u64 size;
461 struct snd_pcm_runtime *runtime = substream->runtime;
462 struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
463 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev: component->dev);
464
465 active_ch = params_channels(p: params);
466 if (active_ch > stream_data->ch_limit)
467 return -EINVAL;
468
469 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
470 adata->sysclk) {
471 unsigned int mclk_fs = adata->sysclk / params_rate(p: params);
472
473 if (adata->sysclk % params_rate(p: params) != 0) {
474 dev_warn(component->dev, "sysclk %u not divisible by rate %u\n",
475 adata->sysclk, params_rate(params));
476 return -EINVAL;
477 }
478
479 writel(val: mclk_fs, addr: stream_data->mmio + XLNX_AUD_FS_MULTIPLIER);
480 }
481
482 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
483 stream_data->xfer_mode == AES_TO_PCM) {
484 val = readl(addr: stream_data->mmio + XLNX_AUD_STS);
485 if (val & AUD_STS_CH_STS_MASK) {
486 aes_reg1_val = readl(addr: stream_data->mmio +
487 XLNX_AUD_CH_STS_START);
488 aes_reg2_val = readl(addr: stream_data->mmio +
489 XLNX_AUD_CH_STS_START + 0x4);
490
491 xlnx_parse_aes_params(chsts_reg1_val: aes_reg1_val, chsts_reg2_val: aes_reg2_val,
492 dev: component->dev);
493 }
494 }
495
496 size = params_buffer_bytes(p: params);
497
498 stream_data->buffer_size = size;
499
500 low = lower_32_bits(runtime->dma_addr);
501 high = upper_32_bits(runtime->dma_addr);
502 writel(val: low, addr: stream_data->mmio + XLNX_AUD_BUFF_ADDR_LSB);
503 writel(val: high, addr: stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);
504
505 val = readl(addr: stream_data->mmio + XLNX_AUD_CTRL);
506 bits_per_sample = params_width(p: params);
507 switch (bits_per_sample) {
508 case 8:
509 val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);
510 break;
511 case 16:
512 val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);
513 break;
514 case 20:
515 val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);
516 break;
517 case 24:
518 val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);
519 break;
520 case 32:
521 val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);
522 break;
523 default:
524 return -EINVAL;
525 }
526
527 val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
528 writel(val, addr: stream_data->mmio + XLNX_AUD_CTRL);
529
530 val = (params_periods(p: params) << PERIOD_CFG_PERIODS_SHIFT)
531 | params_period_bytes(p: params);
532 writel(val, addr: stream_data->mmio + XLNX_AUD_PERIOD_CONFIG);
533 bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch);
534 writel(val: bytes_per_ch, addr: stream_data->mmio + XLNX_BYTES_PER_CH);
535
536 return 0;
537}
538
539static int xlnx_formatter_pcm_trigger(struct snd_soc_component *component,
540 struct snd_pcm_substream *substream,
541 int cmd)
542{
543 u32 val;
544 struct xlnx_pcm_stream_param *stream_data =
545 substream->runtime->private_data;
546
547 switch (cmd) {
548 case SNDRV_PCM_TRIGGER_START:
549 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
550 case SNDRV_PCM_TRIGGER_RESUME:
551 val = readl(addr: stream_data->mmio + XLNX_AUD_CTRL);
552 val |= AUD_CTRL_DMA_EN_MASK;
553 writel(val, addr: stream_data->mmio + XLNX_AUD_CTRL);
554 break;
555 case SNDRV_PCM_TRIGGER_STOP:
556 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
557 case SNDRV_PCM_TRIGGER_SUSPEND:
558 val = readl(addr: stream_data->mmio + XLNX_AUD_CTRL);
559 val &= ~AUD_CTRL_DMA_EN_MASK;
560 writel(val, addr: stream_data->mmio + XLNX_AUD_CTRL);
561 break;
562 }
563
564 return 0;
565}
566
567static int xlnx_formatter_pcm_new(struct snd_soc_component *component,
568 struct snd_soc_pcm_runtime *rtd)
569{
570 snd_pcm_set_managed_buffer_all(pcm: rtd->pcm,
571 SNDRV_DMA_TYPE_DEV, data: component->dev,
572 size: xlnx_pcm_hardware.buffer_bytes_max,
573 max: xlnx_pcm_hardware.buffer_bytes_max);
574 return 0;
575}
576
577static const struct snd_soc_component_driver xlnx_asoc_component = {
578 .name = DRV_NAME,
579 .set_sysclk = xlnx_formatter_set_sysclk,
580 .open = xlnx_formatter_pcm_open,
581 .close = xlnx_formatter_pcm_close,
582 .hw_params = xlnx_formatter_pcm_hw_params,
583 .trigger = xlnx_formatter_pcm_trigger,
584 .pointer = xlnx_formatter_pcm_pointer,
585 .pcm_construct = xlnx_formatter_pcm_new,
586};
587
588static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
589{
590 int ret;
591 u32 val;
592 struct xlnx_pcm_drv_data *aud_drv_data;
593 struct device *dev = &pdev->dev;
594
595 aud_drv_data = devm_kzalloc(dev, size: sizeof(*aud_drv_data), GFP_KERNEL);
596 if (!aud_drv_data)
597 return -ENOMEM;
598
599 aud_drv_data->axi_clk = devm_clk_get(dev, id: "s_axi_lite_aclk");
600 if (IS_ERR(ptr: aud_drv_data->axi_clk)) {
601 ret = PTR_ERR(ptr: aud_drv_data->axi_clk);
602 dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret);
603 return ret;
604 }
605 ret = clk_prepare_enable(clk: aud_drv_data->axi_clk);
606 if (ret) {
607 dev_err(dev,
608 "failed to enable s_axi_lite_aclk(%d)\n", ret);
609 return ret;
610 }
611
612 aud_drv_data->mmio = devm_platform_ioremap_resource(pdev, index: 0);
613 if (IS_ERR(ptr: aud_drv_data->mmio)) {
614 dev_err(dev, "audio formatter ioremap failed\n");
615 ret = PTR_ERR(ptr: aud_drv_data->mmio);
616 goto clk_err;
617 }
618
619 val = readl(addr: aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG);
620 if (val & AUD_CFG_MM2S_MASK) {
621 aud_drv_data->mm2s_presence = true;
622 ret = xlnx_formatter_pcm_reset(mmio_base: aud_drv_data->mmio +
623 XLNX_MM2S_OFFSET);
624 if (ret) {
625 dev_err(dev, "audio formatter reset failed\n");
626 goto clk_err;
627 }
628 xlnx_formatter_disable_irqs(mmio_base: aud_drv_data->mmio +
629 XLNX_MM2S_OFFSET,
630 stream: SNDRV_PCM_STREAM_PLAYBACK);
631
632 aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev,
633 "irq_mm2s");
634 if (aud_drv_data->mm2s_irq < 0) {
635 ret = aud_drv_data->mm2s_irq;
636 goto clk_err;
637 }
638 ret = devm_request_irq(dev, irq: aud_drv_data->mm2s_irq,
639 handler: xlnx_mm2s_irq_handler, irqflags: 0,
640 devname: "xlnx_formatter_pcm_mm2s_irq", dev_id: dev);
641 if (ret) {
642 dev_err(dev, "xlnx audio mm2s irq request failed\n");
643 goto clk_err;
644 }
645 }
646 if (val & AUD_CFG_S2MM_MASK) {
647 aud_drv_data->s2mm_presence = true;
648 ret = xlnx_formatter_pcm_reset(mmio_base: aud_drv_data->mmio +
649 XLNX_S2MM_OFFSET);
650 if (ret) {
651 dev_err(dev, "audio formatter reset failed\n");
652 goto clk_err;
653 }
654 xlnx_formatter_disable_irqs(mmio_base: aud_drv_data->mmio +
655 XLNX_S2MM_OFFSET,
656 stream: SNDRV_PCM_STREAM_CAPTURE);
657
658 aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev,
659 "irq_s2mm");
660 if (aud_drv_data->s2mm_irq < 0) {
661 ret = aud_drv_data->s2mm_irq;
662 goto clk_err;
663 }
664 ret = devm_request_irq(dev, irq: aud_drv_data->s2mm_irq,
665 handler: xlnx_s2mm_irq_handler, irqflags: 0,
666 devname: "xlnx_formatter_pcm_s2mm_irq",
667 dev_id: dev);
668 if (ret) {
669 dev_err(dev, "xlnx audio s2mm irq request failed\n");
670 goto clk_err;
671 }
672 }
673
674 dev_set_drvdata(dev, data: aud_drv_data);
675
676 ret = devm_snd_soc_register_component(dev, component_driver: &xlnx_asoc_component,
677 NULL, num_dai: 0);
678 if (ret) {
679 dev_err(dev, "pcm platform device register failed\n");
680 goto clk_err;
681 }
682
683 return 0;
684
685clk_err:
686 clk_disable_unprepare(clk: aud_drv_data->axi_clk);
687 return ret;
688}
689
690static void xlnx_formatter_pcm_remove(struct platform_device *pdev)
691{
692 int ret = 0;
693 struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev: &pdev->dev);
694
695 if (adata->s2mm_presence)
696 ret = xlnx_formatter_pcm_reset(mmio_base: adata->mmio + XLNX_S2MM_OFFSET);
697
698 /* Try MM2S reset, even if S2MM reset fails */
699 if (adata->mm2s_presence)
700 ret = xlnx_formatter_pcm_reset(mmio_base: adata->mmio + XLNX_MM2S_OFFSET);
701
702 if (ret)
703 dev_err(&pdev->dev, "audio formatter reset failed\n");
704
705 clk_disable_unprepare(clk: adata->axi_clk);
706}
707
708static const struct of_device_id xlnx_formatter_pcm_of_match[] = {
709 { .compatible = "xlnx,audio-formatter-1.0"},
710 {},
711};
712MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match);
713
714static struct platform_driver xlnx_formatter_pcm_driver = {
715 .probe = xlnx_formatter_pcm_probe,
716 .remove_new = xlnx_formatter_pcm_remove,
717 .driver = {
718 .name = DRV_NAME,
719 .of_match_table = xlnx_formatter_pcm_of_match,
720 },
721};
722
723module_platform_driver(xlnx_formatter_pcm_driver);
724MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>");
725MODULE_LICENSE("GPL v2");
726

source code of linux/sound/soc/xilinx/xlnx_formatter_pcm.c