blob: ed2c16379d2c122d2729bd96c99913b9878ed764 [file] [log] [blame]
Vijendar Mukundaac289c72018-11-12 11:04:55 +05301/*
2 * AMD ALSA SoC PCM Driver
3 *
4 * Copyright 2016 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#include <linux/platform_device.h>
17#include <linux/module.h>
18#include <linux/err.h>
19#include <linux/io.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23#include <sound/soc-dai.h>
24
25#include "acp3x.h"
26
27#define DRV_NAME "acp3x-i2s-audio"
28
29struct i2s_dev_data {
Vijendar Mukunda32feac92018-11-12 11:04:56 +053030 unsigned int i2s_irq;
Vijendar Mukundaac289c72018-11-12 11:04:55 +053031 void __iomem *acp3x_base;
32 struct snd_pcm_substream *play_stream;
33 struct snd_pcm_substream *capture_stream;
34};
35
Vijendar Mukunda0b87d6b2018-11-12 11:04:57 +053036struct i2s_stream_instance {
37 u16 num_pages;
38 u16 channels;
39 u32 xfer_resolution;
40 struct page *pg;
41 void __iomem *acp3x_base;
42};
43
44static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
45 .info = SNDRV_PCM_INFO_INTERLEAVED |
46 SNDRV_PCM_INFO_BLOCK_TRANSFER |
47 SNDRV_PCM_INFO_BATCH |
48 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
49 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
50 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
51 SNDRV_PCM_FMTBIT_S32_LE,
52 .channels_min = 2,
53 .channels_max = 8,
54 .rates = SNDRV_PCM_RATE_8000_96000,
55 .rate_min = 8000,
56 .rate_max = 96000,
57 .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
58 .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
59 .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
60 .periods_min = PLAYBACK_MIN_NUM_PERIODS,
61 .periods_max = PLAYBACK_MAX_NUM_PERIODS,
62};
63
64static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
65 .info = SNDRV_PCM_INFO_INTERLEAVED |
66 SNDRV_PCM_INFO_BLOCK_TRANSFER |
67 SNDRV_PCM_INFO_BATCH |
68 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
69 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
70 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
71 SNDRV_PCM_FMTBIT_S32_LE,
72 .channels_min = 2,
73 .channels_max = 2,
74 .rates = SNDRV_PCM_RATE_8000_48000,
75 .rate_min = 8000,
76 .rate_max = 48000,
77 .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
78 .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
79 .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
80 .periods_min = CAPTURE_MIN_NUM_PERIODS,
81 .periods_max = CAPTURE_MAX_NUM_PERIODS,
82};
83
Vijendar Mukundaac289c72018-11-12 11:04:55 +053084static int acp3x_power_on(void __iomem *acp3x_base, bool on)
85{
86 u16 val, mask;
87 u32 timeout;
88
89 if (on == true) {
90 val = 1;
91 mask = ACP3x_POWER_ON;
92 } else {
93 val = 0;
94 mask = ACP3x_POWER_OFF;
95 }
96
97 rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
98 timeout = 0;
99 while (true) {
100 val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
101 if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
102 break;
103 if (timeout > 100) {
104 pr_err("ACP3x power state change failure\n");
105 return -ENODEV;
106 }
107 timeout++;
108 cpu_relax();
109 }
110 return 0;
111}
112
113static int acp3x_reset(void __iomem *acp3x_base)
114{
115 u32 val, timeout;
116
117 rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
118 timeout = 0;
119 while (true) {
120 val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
121 if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
122 timeout > 100) {
123 if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
124 break;
125 return -ENODEV;
126 }
127 timeout++;
128 cpu_relax();
129 }
130
131 rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
132 timeout = 0;
133 while (true) {
134 val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
135 if (!val || timeout > 100) {
136 if (!val)
137 break;
138 return -ENODEV;
139 }
140 timeout++;
141 cpu_relax();
142 }
143 return 0;
144}
145
146static int acp3x_init(void __iomem *acp3x_base)
147{
148 int ret;
149
150 /* power on */
151 ret = acp3x_power_on(acp3x_base, true);
152 if (ret) {
153 pr_err("ACP3x power on failed\n");
154 return ret;
155 }
156 /* Reset */
157 ret = acp3x_reset(acp3x_base);
158 if (ret) {
159 pr_err("ACP3x reset failed\n");
160 return ret;
161 }
162 return 0;
163}
164
165static int acp3x_deinit(void __iomem *acp3x_base)
166{
167 int ret;
168
169 /* Reset */
170 ret = acp3x_reset(acp3x_base);
171 if (ret) {
172 pr_err("ACP3x reset failed\n");
173 return ret;
174 }
175 /* power off */
176 ret = acp3x_power_on(acp3x_base, false);
177 if (ret) {
178 pr_err("ACP3x power off failed\n");
179 return ret;
180 }
181 return 0;
182}
183
Vijendar Mukunda32feac92018-11-12 11:04:56 +0530184static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
185{
186 u16 play_flag, cap_flag;
187 u32 val;
188 struct i2s_dev_data *rv_i2s_data = dev_id;
189
190 if (!rv_i2s_data)
191 return IRQ_NONE;
192
193 play_flag = 0;
194 cap_flag = 0;
195 val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
196 if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
197 rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
198 mmACP_EXTERNAL_INTR_STAT);
199 snd_pcm_period_elapsed(rv_i2s_data->play_stream);
200 play_flag = 1;
201 }
202
203 if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
204 rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
205 mmACP_EXTERNAL_INTR_STAT);
206 snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
207 cap_flag = 1;
208 }
209
210 if (play_flag | cap_flag)
211 return IRQ_HANDLED;
212 else
213 return IRQ_NONE;
214}
215
Vijendar Mukunda0b87d6b2018-11-12 11:04:57 +0530216static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
217{
218 u16 page_idx;
219 u64 addr;
220 u32 low, high, val, acp_fifo_addr;
221 struct page *pg = rtd->pg;
222
223 /* 8 scratch registers used to map one 64 bit address */
224 if (direction == SNDRV_PCM_STREAM_PLAYBACK)
225 val = 0;
226 else
227 val = rtd->num_pages * 8;
228
229 /* Group Enable */
230 rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
231 mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
232 rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
233 mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
234
235 for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
236 /* Load the low address of page int ACP SRAM through SRBM */
237 addr = page_to_phys(pg);
238 low = lower_32_bits(addr);
239 high = upper_32_bits(addr);
240
241 rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
242 high |= BIT(31);
243 rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
244 + 4);
245 /* Move to next physically contiguos page */
246 val += 8;
247 pg++;
248 }
249
250 if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
251 /* Config ringbuffer */
252 rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
253 mmACP_BT_TX_RINGBUFADDR);
254 rv_writel(MAX_BUFFER, rtd->acp3x_base +
255 mmACP_BT_TX_RINGBUFSIZE);
256 rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
257
258 /* Config audio fifo */
259 acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
260 + PLAYBACK_FIFO_ADDR_OFFSET;
261 rv_writel(acp_fifo_addr, rtd->acp3x_base +
262 mmACP_BT_TX_FIFOADDR);
263 rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
264 } else {
265 /* Config ringbuffer */
266 rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
267 mmACP_BT_RX_RINGBUFADDR);
268 rv_writel(MAX_BUFFER, rtd->acp3x_base +
269 mmACP_BT_RX_RINGBUFSIZE);
270 rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
271
272 /* Config audio fifo */
273 acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
274 (rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
275 rv_writel(acp_fifo_addr, rtd->acp3x_base +
276 mmACP_BT_RX_FIFOADDR);
277 rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
278 }
279
280 /* Enable watermark/period interrupt to host */
281 rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
282 rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
283}
284
285static int acp3x_dma_open(struct snd_pcm_substream *substream)
286{
287 int ret = 0;
288
289 struct snd_pcm_runtime *runtime = substream->runtime;
290 struct snd_soc_pcm_runtime *prtd = substream->private_data;
291 struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
292 DRV_NAME);
293 struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
294
295 struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
296 GFP_KERNEL);
297 if (!i2s_data)
298 return -EINVAL;
299
300 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
301 runtime->hw = acp3x_pcm_hardware_playback;
302 else
303 runtime->hw = acp3x_pcm_hardware_capture;
304
305 ret = snd_pcm_hw_constraint_integer(runtime,
306 SNDRV_PCM_HW_PARAM_PERIODS);
307 if (ret < 0) {
308 dev_err(component->dev, "set integer constraint failed\n");
309 return ret;
310 }
311
312 if (!adata->play_stream && !adata->capture_stream)
313 rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
314
315 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
316 adata->play_stream = substream;
317 else
318 adata->capture_stream = substream;
319
320 i2s_data->acp3x_base = adata->acp3x_base;
321 runtime->private_data = i2s_data;
322 return 0;
323}
324
325static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
326 struct snd_pcm_hw_params *params)
327{
328 int status;
329 u64 size;
330 struct snd_dma_buffer *dma_buffer;
331 struct page *pg;
332 struct snd_pcm_runtime *runtime = substream->runtime;
333 struct i2s_stream_instance *rtd = runtime->private_data;
334
335 if (!rtd)
336 return -EINVAL;
337
338 dma_buffer = &substream->dma_buffer;
339 size = params_buffer_bytes(params);
340 status = snd_pcm_lib_malloc_pages(substream, size);
341 if (status < 0)
342 return status;
343
344 memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
345 pg = virt_to_page(substream->dma_buffer.area);
346 if (pg) {
347 rtd->pg = pg;
348 rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
349 config_acp3x_dma(rtd, substream->stream);
350 status = 0;
351 } else {
352 status = -ENOMEM;
353 }
354 return status;
355}
356
357static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
358{
359 u32 pos = 0;
360 struct i2s_stream_instance *rtd = substream->runtime->private_data;
361
362 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
363 pos = rv_readl(rtd->acp3x_base +
364 mmACP_BT_TX_LINKPOSITIONCNTR);
365 else
366 pos = rv_readl(rtd->acp3x_base +
367 mmACP_BT_RX_LINKPOSITIONCNTR);
368
369 if (pos >= MAX_BUFFER)
370 pos = 0;
371
372 return bytes_to_frames(substream->runtime, pos);
373}
374
375static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
376{
377 return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
378 SNDRV_DMA_TYPE_DEV,
379 NULL, MIN_BUFFER,
380 MAX_BUFFER);
381}
382
383static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
384{
385 return snd_pcm_lib_free_pages(substream);
386}
387
388static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
389 struct vm_area_struct *vma)
390{
391 return snd_pcm_lib_default_mmap(substream, vma);
392}
393
394static int acp3x_dma_close(struct snd_pcm_substream *substream)
395{
396 struct snd_soc_pcm_runtime *prtd = substream->private_data;
397 struct i2s_stream_instance *rtd = substream->runtime->private_data;
398 struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
399 DRV_NAME);
400 struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
401
402 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
403 adata->play_stream = NULL;
404 else
405 adata->capture_stream = NULL;
406
407 /* Disable ACP irq, when the current stream is being closed and
408 * another stream is also not active.
409 */
410 if (!adata->play_stream && !adata->capture_stream)
411 rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
412 kfree(rtd);
413 return 0;
414}
415
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530416static struct snd_pcm_ops acp3x_dma_ops = {
Vijendar Mukunda0b87d6b2018-11-12 11:04:57 +0530417 .open = acp3x_dma_open,
418 .close = acp3x_dma_close,
419 .ioctl = snd_pcm_lib_ioctl,
420 .hw_params = acp3x_dma_hw_params,
421 .hw_free = acp3x_dma_hw_free,
422 .pointer = acp3x_dma_pointer,
423 .mmap = acp3x_dma_mmap,
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530424};
425
Vijendar Mukunda2b5f2902018-11-12 11:04:58 +0530426static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream,
427 struct snd_pcm_hw_params *params,
428 struct snd_soc_dai *dai)
429{
430 u32 val = 0;
431 struct i2s_stream_instance *rtd = substream->runtime->private_data;
432
433 switch (params_format(params)) {
434 case SNDRV_PCM_FORMAT_U8:
435 case SNDRV_PCM_FORMAT_S8:
436 rtd->xfer_resolution = 0x0;
437 break;
438 case SNDRV_PCM_FORMAT_S16_LE:
439 rtd->xfer_resolution = 0x02;
440 break;
441 case SNDRV_PCM_FORMAT_S24_LE:
442 rtd->xfer_resolution = 0x04;
443 break;
444 case SNDRV_PCM_FORMAT_S32_LE:
445 rtd->xfer_resolution = 0x05;
446 break;
447 default:
448 return -EINVAL;
449 }
450 val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
451 val = val | (rtd->xfer_resolution << 3);
452 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
453 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
454 else
455 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
456
457 return 0;
458}
459
460static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
461 int cmd, struct snd_soc_dai *dai)
462{
463 int ret = 0;
464 struct i2s_stream_instance *rtd = substream->runtime->private_data;
465 u32 val, period_bytes;
466
467 period_bytes = frames_to_bytes(substream->runtime,
468 substream->runtime->period_size);
469 switch (cmd) {
470 case SNDRV_PCM_TRIGGER_START:
471 case SNDRV_PCM_TRIGGER_RESUME:
472 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
473 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
474 rv_writel(period_bytes, rtd->acp3x_base +
475 mmACP_BT_TX_INTR_WATERMARK_SIZE);
476 val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
477 val = val | BIT(0);
478 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
479 } else {
480 rv_writel(period_bytes, rtd->acp3x_base +
481 mmACP_BT_RX_INTR_WATERMARK_SIZE);
482 val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
483 val = val | BIT(0);
484 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
485 }
486 rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
487 break;
488 case SNDRV_PCM_TRIGGER_STOP:
489 case SNDRV_PCM_TRIGGER_SUSPEND:
490 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
491 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
492 val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
493 val = val & ~BIT(0);
494 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
495 } else {
496 val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
497 val = val & ~BIT(0);
498 rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
499 }
500 rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
501 break;
502 default:
503 ret = -EINVAL;
504 break;
505 }
506
507 return ret;
508}
509
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530510struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
Vijendar Mukunda2b5f2902018-11-12 11:04:58 +0530511 .hw_params = acp3x_dai_i2s_hwparams,
512 .trigger = acp3x_dai_i2s_trigger,
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530513};
514
515static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
516 .playback = {
517 .rates = SNDRV_PCM_RATE_8000_96000,
518 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
519 SNDRV_PCM_FMTBIT_U8 |
520 SNDRV_PCM_FMTBIT_S24_LE |
521 SNDRV_PCM_FMTBIT_S32_LE,
522 .channels_min = 2,
523 .channels_max = 8,
524
525 .rate_min = 8000,
526 .rate_max = 96000,
527 },
528 .capture = {
529 .rates = SNDRV_PCM_RATE_8000_48000,
530 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
531 SNDRV_PCM_FMTBIT_U8 |
532 SNDRV_PCM_FMTBIT_S24_LE |
533 SNDRV_PCM_FMTBIT_S32_LE,
534 .channels_min = 2,
535 .channels_max = 2,
536 .rate_min = 8000,
537 .rate_max = 48000,
538 },
539 .ops = &acp3x_dai_i2s_ops,
540};
541
542static const struct snd_soc_component_driver acp3x_i2s_component = {
543 .name = DRV_NAME,
544 .ops = &acp3x_dma_ops,
545 .pcm_new = acp3x_dma_new,
546};
547
548static int acp3x_audio_probe(struct platform_device *pdev)
549{
550 int status;
551 struct resource *res;
552 struct i2s_dev_data *adata;
553 unsigned int irqflags;
554
555 if (!pdev->dev.platform_data) {
556 dev_err(&pdev->dev, "platform_data not retrieved\n");
557 return -ENODEV;
558 }
559 irqflags = *((unsigned int *)(pdev->dev.platform_data));
560
561 adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
562 GFP_KERNEL);
563 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
564 if (!res) {
565 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
566 return -ENODEV;
567 }
568
569 adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
570 resource_size(res));
571
Vijendar Mukunda32feac92018-11-12 11:04:56 +0530572 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
573 if (!res) {
574 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
575 return -ENODEV;
576 }
577
578 adata->i2s_irq = res->start;
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530579 adata->play_stream = NULL;
580 adata->capture_stream = NULL;
581
582 dev_set_drvdata(&pdev->dev, adata);
583 /* Initialize ACP */
584 status = acp3x_init(adata->acp3x_base);
585 if (status)
586 return -ENODEV;
587 status = devm_snd_soc_register_component(&pdev->dev,
588 &acp3x_i2s_component,
589 &acp3x_i2s_dai_driver, 1);
590 if (status) {
591 dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
592 goto dev_err;
593 }
Vijendar Mukunda32feac92018-11-12 11:04:56 +0530594 status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
595 irqflags, "ACP3x_I2S_IRQ", adata);
596 if (status) {
597 dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");
598 goto dev_err;
599 }
Vijendar Mukundaac289c72018-11-12 11:04:55 +0530600
601 return 0;
602dev_err:
603 status = acp3x_deinit(adata->acp3x_base);
604 if (status)
605 dev_err(&pdev->dev, "ACP de-init failed\n");
606 else
607 dev_info(&pdev->dev, "ACP de-initialized\n");
608 /*ignore device status and return driver probe error*/
609 return -ENODEV;
610}
611
612static int acp3x_audio_remove(struct platform_device *pdev)
613{
614 int ret;
615 struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
616
617 ret = acp3x_deinit(adata->acp3x_base);
618 if (ret)
619 dev_err(&pdev->dev, "ACP de-init failed\n");
620 else
621 dev_info(&pdev->dev, "ACP de-initialized\n");
622
623 return 0;
624}
625
626static struct platform_driver acp3x_dma_driver = {
627 .probe = acp3x_audio_probe,
628 .remove = acp3x_audio_remove,
629 .driver = {
630 .name = "acp3x_rv_i2s",
631 },
632};
633
634module_platform_driver(acp3x_dma_driver);
635
636MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
637MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
638MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
639MODULE_LICENSE("GPL v2");
640MODULE_ALIAS("platform:" DRV_NAME);