xref: /linux/sound/soc/amd/vangogh/acp5x-pcm-dma.c (revision cab396d8b22c13b424d9ba66f626f036f802658c)
177f61444SVijendar Mukunda // SPDX-License-Identifier: GPL-2.0+
277f61444SVijendar Mukunda //
377f61444SVijendar Mukunda // AMD ALSA SoC PCM Driver
477f61444SVijendar Mukunda //
577f61444SVijendar Mukunda // Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
677f61444SVijendar Mukunda 
777f61444SVijendar Mukunda #include <linux/platform_device.h>
877f61444SVijendar Mukunda #include <linux/module.h>
977f61444SVijendar Mukunda #include <linux/err.h>
1077f61444SVijendar Mukunda #include <linux/io.h>
1177f61444SVijendar Mukunda #include <sound/pcm.h>
1277f61444SVijendar Mukunda #include <sound/pcm_params.h>
1377f61444SVijendar Mukunda #include <sound/soc.h>
1477f61444SVijendar Mukunda #include <sound/soc-dai.h>
1577f61444SVijendar Mukunda 
1677f61444SVijendar Mukunda #include "acp5x.h"
1777f61444SVijendar Mukunda 
1877f61444SVijendar Mukunda #define DRV_NAME "acp5x_i2s_dma"
1977f61444SVijendar Mukunda 
20cab396d8SVijendar Mukunda static const struct snd_pcm_hardware acp5x_pcm_hardware_playback = {
21cab396d8SVijendar Mukunda 	.info = SNDRV_PCM_INFO_INTERLEAVED |
22cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
23cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
24cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
25cab396d8SVijendar Mukunda 	.formats = SNDRV_PCM_FMTBIT_S16_LE |  SNDRV_PCM_FMTBIT_S8 |
26cab396d8SVijendar Mukunda 		   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
27cab396d8SVijendar Mukunda 	.channels_min = 2,
28cab396d8SVijendar Mukunda 	.channels_max = 2,
29cab396d8SVijendar Mukunda 	.rates = SNDRV_PCM_RATE_8000_96000,
30cab396d8SVijendar Mukunda 	.rate_min = 8000,
31cab396d8SVijendar Mukunda 	.rate_max = 96000,
32cab396d8SVijendar Mukunda 	.buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
33cab396d8SVijendar Mukunda 	.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
34cab396d8SVijendar Mukunda 	.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
35cab396d8SVijendar Mukunda 	.periods_min = PLAYBACK_MIN_NUM_PERIODS,
36cab396d8SVijendar Mukunda 	.periods_max = PLAYBACK_MAX_NUM_PERIODS,
37cab396d8SVijendar Mukunda };
38cab396d8SVijendar Mukunda 
39cab396d8SVijendar Mukunda static const struct snd_pcm_hardware acp5x_pcm_hardware_capture = {
40cab396d8SVijendar Mukunda 	.info = SNDRV_PCM_INFO_INTERLEAVED |
41cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
42cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
43cab396d8SVijendar Mukunda 		SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
44cab396d8SVijendar Mukunda 	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
45cab396d8SVijendar Mukunda 		   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
46cab396d8SVijendar Mukunda 	.channels_min = 2,
47cab396d8SVijendar Mukunda 	.channels_max = 2,
48cab396d8SVijendar Mukunda 	.rates = SNDRV_PCM_RATE_8000_96000,
49cab396d8SVijendar Mukunda 	.rate_min = 8000,
50cab396d8SVijendar Mukunda 	.rate_max = 96000,
51cab396d8SVijendar Mukunda 	.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
52cab396d8SVijendar Mukunda 	.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
53cab396d8SVijendar Mukunda 	.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
54cab396d8SVijendar Mukunda 	.periods_min = CAPTURE_MIN_NUM_PERIODS,
55cab396d8SVijendar Mukunda 	.periods_max = CAPTURE_MAX_NUM_PERIODS,
5677f61444SVijendar Mukunda };
5777f61444SVijendar Mukunda 
58fc2c8067SVijendar Mukunda static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
59fc2c8067SVijendar Mukunda {
60fc2c8067SVijendar Mukunda 	struct i2s_dev_data *vg_i2s_data;
61fc2c8067SVijendar Mukunda 	u16 irq_flag;
62fc2c8067SVijendar Mukunda 	u32 val;
63fc2c8067SVijendar Mukunda 
64fc2c8067SVijendar Mukunda 	vg_i2s_data = dev_id;
65fc2c8067SVijendar Mukunda 	if (!vg_i2s_data)
66fc2c8067SVijendar Mukunda 		return IRQ_NONE;
67fc2c8067SVijendar Mukunda 
68fc2c8067SVijendar Mukunda 	irq_flag = 0;
69fc2c8067SVijendar Mukunda 	val = acp_readl(vg_i2s_data->acp5x_base + ACP_EXTERNAL_INTR_STAT);
70fc2c8067SVijendar Mukunda 	if ((val & BIT(HS_TX_THRESHOLD)) && vg_i2s_data->play_stream) {
71fc2c8067SVijendar Mukunda 		acp_writel(BIT(HS_TX_THRESHOLD), vg_i2s_data->acp5x_base +
72fc2c8067SVijendar Mukunda 			   ACP_EXTERNAL_INTR_STAT);
73fc2c8067SVijendar Mukunda 		snd_pcm_period_elapsed(vg_i2s_data->play_stream);
74fc2c8067SVijendar Mukunda 		irq_flag = 1;
75fc2c8067SVijendar Mukunda 	}
76fc2c8067SVijendar Mukunda 	if ((val & BIT(I2S_TX_THRESHOLD)) && vg_i2s_data->i2ssp_play_stream) {
77fc2c8067SVijendar Mukunda 		acp_writel(BIT(I2S_TX_THRESHOLD),
78fc2c8067SVijendar Mukunda 			   vg_i2s_data->acp5x_base + ACP_EXTERNAL_INTR_STAT);
79fc2c8067SVijendar Mukunda 		snd_pcm_period_elapsed(vg_i2s_data->i2ssp_play_stream);
80fc2c8067SVijendar Mukunda 		irq_flag = 1;
81fc2c8067SVijendar Mukunda 	}
82fc2c8067SVijendar Mukunda 
83fc2c8067SVijendar Mukunda 	if ((val & BIT(HS_RX_THRESHOLD)) && vg_i2s_data->capture_stream) {
84fc2c8067SVijendar Mukunda 		acp_writel(BIT(HS_RX_THRESHOLD), vg_i2s_data->acp5x_base +
85fc2c8067SVijendar Mukunda 			   ACP_EXTERNAL_INTR_STAT);
86fc2c8067SVijendar Mukunda 		snd_pcm_period_elapsed(vg_i2s_data->capture_stream);
87fc2c8067SVijendar Mukunda 		irq_flag = 1;
88fc2c8067SVijendar Mukunda 	}
89fc2c8067SVijendar Mukunda 	if ((val & BIT(I2S_RX_THRESHOLD)) && vg_i2s_data->i2ssp_capture_stream) {
90fc2c8067SVijendar Mukunda 		acp_writel(BIT(I2S_RX_THRESHOLD),
91fc2c8067SVijendar Mukunda 			   vg_i2s_data->acp5x_base + ACP_EXTERNAL_INTR_STAT);
92fc2c8067SVijendar Mukunda 		snd_pcm_period_elapsed(vg_i2s_data->i2ssp_capture_stream);
93fc2c8067SVijendar Mukunda 		irq_flag = 1;
94fc2c8067SVijendar Mukunda 	}
95fc2c8067SVijendar Mukunda 
96fc2c8067SVijendar Mukunda 	if (irq_flag)
97fc2c8067SVijendar Mukunda 		return IRQ_HANDLED;
98fc2c8067SVijendar Mukunda 	else
99fc2c8067SVijendar Mukunda 		return IRQ_NONE;
100fc2c8067SVijendar Mukunda }
101fc2c8067SVijendar Mukunda 
102cab396d8SVijendar Mukunda static void config_acp5x_dma(struct i2s_stream_instance *rtd, int direction)
103cab396d8SVijendar Mukunda {
104cab396d8SVijendar Mukunda 	u16 page_idx;
105cab396d8SVijendar Mukunda 	u32 low, high, val, acp_fifo_addr, reg_fifo_addr;
106cab396d8SVijendar Mukunda 	u32 reg_dma_size, reg_fifo_size;
107cab396d8SVijendar Mukunda 	dma_addr_t addr;
108cab396d8SVijendar Mukunda 
109cab396d8SVijendar Mukunda 	addr = rtd->dma_addr;
110cab396d8SVijendar Mukunda 	if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
111cab396d8SVijendar Mukunda 		switch (rtd->i2s_instance) {
112cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
113cab396d8SVijendar Mukunda 			val = ACP_SRAM_HS_PB_PTE_OFFSET;
114cab396d8SVijendar Mukunda 			break;
115cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
116cab396d8SVijendar Mukunda 		default:
117cab396d8SVijendar Mukunda 			val = ACP_SRAM_SP_PB_PTE_OFFSET;
118cab396d8SVijendar Mukunda 		}
119cab396d8SVijendar Mukunda 	} else {
120cab396d8SVijendar Mukunda 		switch (rtd->i2s_instance) {
121cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
122cab396d8SVijendar Mukunda 			val = ACP_SRAM_HS_CP_PTE_OFFSET;
123cab396d8SVijendar Mukunda 			break;
124cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
125cab396d8SVijendar Mukunda 		default:
126cab396d8SVijendar Mukunda 			val = ACP_SRAM_SP_CP_PTE_OFFSET;
127cab396d8SVijendar Mukunda 		}
128cab396d8SVijendar Mukunda 	}
129cab396d8SVijendar Mukunda 	/* Group Enable */
130cab396d8SVijendar Mukunda 	acp_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp5x_base +
131cab396d8SVijendar Mukunda 		   ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
132cab396d8SVijendar Mukunda 	acp_writel(PAGE_SIZE_4K_ENABLE, rtd->acp5x_base +
133cab396d8SVijendar Mukunda 		   ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
134cab396d8SVijendar Mukunda 
135cab396d8SVijendar Mukunda 	for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
136cab396d8SVijendar Mukunda 		/* Load the low address of page int ACP SRAM through SRBM */
137cab396d8SVijendar Mukunda 		low = lower_32_bits(addr);
138cab396d8SVijendar Mukunda 		high = upper_32_bits(addr);
139cab396d8SVijendar Mukunda 
140cab396d8SVijendar Mukunda 		acp_writel(low, rtd->acp5x_base + ACP_SCRATCH_REG_0 + val);
141cab396d8SVijendar Mukunda 		high |= BIT(31);
142cab396d8SVijendar Mukunda 		acp_writel(high, rtd->acp5x_base + ACP_SCRATCH_REG_0 + val + 4);
143cab396d8SVijendar Mukunda 		/* Move to next physically contiguous page */
144cab396d8SVijendar Mukunda 		val += 8;
145cab396d8SVijendar Mukunda 		addr += PAGE_SIZE;
146cab396d8SVijendar Mukunda 	}
147cab396d8SVijendar Mukunda 
148cab396d8SVijendar Mukunda 	if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
149cab396d8SVijendar Mukunda 		switch (rtd->i2s_instance) {
150cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
151cab396d8SVijendar Mukunda 			reg_dma_size = ACP_HS_TX_DMA_SIZE;
152cab396d8SVijendar Mukunda 			acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
153cab396d8SVijendar Mukunda 					HS_PB_FIFO_ADDR_OFFSET;
154cab396d8SVijendar Mukunda 			reg_fifo_addr = ACP_HS_TX_FIFOADDR;
155cab396d8SVijendar Mukunda 			reg_fifo_size = ACP_HS_TX_FIFOSIZE;
156cab396d8SVijendar Mukunda 			acp_writel(I2S_HS_TX_MEM_WINDOW_START,
157cab396d8SVijendar Mukunda 				   rtd->acp5x_base + ACP_HS_TX_RINGBUFADDR);
158cab396d8SVijendar Mukunda 			break;
159cab396d8SVijendar Mukunda 
160cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
161cab396d8SVijendar Mukunda 		default:
162cab396d8SVijendar Mukunda 			reg_dma_size = ACP_I2S_TX_DMA_SIZE;
163cab396d8SVijendar Mukunda 			acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
164cab396d8SVijendar Mukunda 					SP_PB_FIFO_ADDR_OFFSET;
165cab396d8SVijendar Mukunda 			reg_fifo_addr =	ACP_I2S_TX_FIFOADDR;
166cab396d8SVijendar Mukunda 			reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
167cab396d8SVijendar Mukunda 			acp_writel(I2S_SP_TX_MEM_WINDOW_START,
168cab396d8SVijendar Mukunda 				   rtd->acp5x_base + ACP_I2S_TX_RINGBUFADDR);
169cab396d8SVijendar Mukunda 		}
170cab396d8SVijendar Mukunda 	} else {
171cab396d8SVijendar Mukunda 		switch (rtd->i2s_instance) {
172cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
173cab396d8SVijendar Mukunda 			reg_dma_size = ACP_HS_RX_DMA_SIZE;
174cab396d8SVijendar Mukunda 			acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
175cab396d8SVijendar Mukunda 					HS_CAPT_FIFO_ADDR_OFFSET;
176cab396d8SVijendar Mukunda 			reg_fifo_addr = ACP_HS_RX_FIFOADDR;
177cab396d8SVijendar Mukunda 			reg_fifo_size = ACP_HS_RX_FIFOSIZE;
178cab396d8SVijendar Mukunda 			acp_writel(I2S_HS_RX_MEM_WINDOW_START,
179cab396d8SVijendar Mukunda 				   rtd->acp5x_base + ACP_HS_RX_RINGBUFADDR);
180cab396d8SVijendar Mukunda 			break;
181cab396d8SVijendar Mukunda 
182cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
183cab396d8SVijendar Mukunda 		default:
184cab396d8SVijendar Mukunda 			reg_dma_size = ACP_I2S_RX_DMA_SIZE;
185cab396d8SVijendar Mukunda 			acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
186cab396d8SVijendar Mukunda 					SP_CAPT_FIFO_ADDR_OFFSET;
187cab396d8SVijendar Mukunda 			reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
188cab396d8SVijendar Mukunda 			reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
189cab396d8SVijendar Mukunda 			acp_writel(I2S_SP_RX_MEM_WINDOW_START,
190cab396d8SVijendar Mukunda 				   rtd->acp5x_base + ACP_I2S_RX_RINGBUFADDR);
191cab396d8SVijendar Mukunda 		}
192cab396d8SVijendar Mukunda 	}
193cab396d8SVijendar Mukunda 	acp_writel(DMA_SIZE, rtd->acp5x_base + reg_dma_size);
194cab396d8SVijendar Mukunda 	acp_writel(acp_fifo_addr, rtd->acp5x_base + reg_fifo_addr);
195cab396d8SVijendar Mukunda 	acp_writel(FIFO_SIZE, rtd->acp5x_base + reg_fifo_size);
196cab396d8SVijendar Mukunda 	acp_writel(BIT(I2S_RX_THRESHOLD) | BIT(HS_RX_THRESHOLD)
197cab396d8SVijendar Mukunda 		   | BIT(I2S_TX_THRESHOLD) | BIT(HS_TX_THRESHOLD),
198cab396d8SVijendar Mukunda 		   rtd->acp5x_base + ACP_EXTERNAL_INTR_CNTL);
199cab396d8SVijendar Mukunda }
200cab396d8SVijendar Mukunda 
201cab396d8SVijendar Mukunda static int acp5x_dma_open(struct snd_soc_component *component,
202cab396d8SVijendar Mukunda 			  struct snd_pcm_substream *substream)
203cab396d8SVijendar Mukunda {
204cab396d8SVijendar Mukunda 	struct snd_pcm_runtime *runtime;
205cab396d8SVijendar Mukunda 	struct snd_soc_pcm_runtime *prtd;
206cab396d8SVijendar Mukunda 	struct i2s_dev_data *adata;
207cab396d8SVijendar Mukunda 	struct i2s_stream_instance *i2s_data;
208cab396d8SVijendar Mukunda 	int ret;
209cab396d8SVijendar Mukunda 
210cab396d8SVijendar Mukunda 	runtime = substream->runtime;
211cab396d8SVijendar Mukunda 	prtd = asoc_substream_to_rtd(substream);
212cab396d8SVijendar Mukunda 	component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
213cab396d8SVijendar Mukunda 	adata = dev_get_drvdata(component->dev);
214cab396d8SVijendar Mukunda 
215cab396d8SVijendar Mukunda 	i2s_data = kzalloc(sizeof(*i2s_data), GFP_KERNEL);
216cab396d8SVijendar Mukunda 	if (!i2s_data)
217cab396d8SVijendar Mukunda 		return -ENOMEM;
218cab396d8SVijendar Mukunda 
219cab396d8SVijendar Mukunda 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
220cab396d8SVijendar Mukunda 		runtime->hw = acp5x_pcm_hardware_playback;
221cab396d8SVijendar Mukunda 	else
222cab396d8SVijendar Mukunda 		runtime->hw = acp5x_pcm_hardware_capture;
223cab396d8SVijendar Mukunda 
224cab396d8SVijendar Mukunda 	ret = snd_pcm_hw_constraint_integer(runtime,
225cab396d8SVijendar Mukunda 					    SNDRV_PCM_HW_PARAM_PERIODS);
226cab396d8SVijendar Mukunda 	if (ret < 0) {
227cab396d8SVijendar Mukunda 		dev_err(component->dev, "set integer constraint failed\n");
228cab396d8SVijendar Mukunda 		kfree(i2s_data);
229cab396d8SVijendar Mukunda 		return ret;
230cab396d8SVijendar Mukunda 	}
231cab396d8SVijendar Mukunda 	i2s_data->acp5x_base = adata->acp5x_base;
232cab396d8SVijendar Mukunda 	runtime->private_data = i2s_data;
233cab396d8SVijendar Mukunda 	return ret;
234cab396d8SVijendar Mukunda }
235cab396d8SVijendar Mukunda 
236cab396d8SVijendar Mukunda static int acp5x_dma_hw_params(struct snd_soc_component *component,
237cab396d8SVijendar Mukunda 			       struct snd_pcm_substream *substream,
238cab396d8SVijendar Mukunda 			       struct snd_pcm_hw_params *params)
239cab396d8SVijendar Mukunda {
240cab396d8SVijendar Mukunda 	struct i2s_stream_instance *rtd;
241cab396d8SVijendar Mukunda 	struct snd_soc_pcm_runtime *prtd;
242cab396d8SVijendar Mukunda 	struct snd_soc_card *card;
243cab396d8SVijendar Mukunda 	struct acp5x_platform_info *pinfo;
244cab396d8SVijendar Mukunda 	struct i2s_dev_data *adata;
245cab396d8SVijendar Mukunda 	u64 size;
246cab396d8SVijendar Mukunda 
247cab396d8SVijendar Mukunda 	prtd = asoc_substream_to_rtd(substream);
248cab396d8SVijendar Mukunda 	card = prtd->card;
249cab396d8SVijendar Mukunda 	pinfo = snd_soc_card_get_drvdata(card);
250cab396d8SVijendar Mukunda 	adata = dev_get_drvdata(component->dev);
251cab396d8SVijendar Mukunda 	rtd = substream->runtime->private_data;
252cab396d8SVijendar Mukunda 
253cab396d8SVijendar Mukunda 	if (!rtd)
254cab396d8SVijendar Mukunda 		return -EINVAL;
255cab396d8SVijendar Mukunda 
256cab396d8SVijendar Mukunda 	if (pinfo) {
257cab396d8SVijendar Mukunda 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
258cab396d8SVijendar Mukunda 			rtd->i2s_instance = pinfo->play_i2s_instance;
259cab396d8SVijendar Mukunda 			switch (rtd->i2s_instance) {
260cab396d8SVijendar Mukunda 			case I2S_HS_INSTANCE:
261cab396d8SVijendar Mukunda 				adata->play_stream = substream;
262cab396d8SVijendar Mukunda 				break;
263cab396d8SVijendar Mukunda 			case I2S_SP_INSTANCE:
264cab396d8SVijendar Mukunda 			default:
265cab396d8SVijendar Mukunda 				adata->i2ssp_play_stream = substream;
266cab396d8SVijendar Mukunda 			}
267cab396d8SVijendar Mukunda 		} else {
268cab396d8SVijendar Mukunda 			rtd->i2s_instance = pinfo->cap_i2s_instance;
269cab396d8SVijendar Mukunda 			switch (rtd->i2s_instance) {
270cab396d8SVijendar Mukunda 			case I2S_HS_INSTANCE:
271cab396d8SVijendar Mukunda 				adata->capture_stream = substream;
272cab396d8SVijendar Mukunda 				break;
273cab396d8SVijendar Mukunda 			case I2S_SP_INSTANCE:
274cab396d8SVijendar Mukunda 			default:
275cab396d8SVijendar Mukunda 				adata->i2ssp_capture_stream = substream;
276cab396d8SVijendar Mukunda 			}
277cab396d8SVijendar Mukunda 		}
278cab396d8SVijendar Mukunda 	} else {
279cab396d8SVijendar Mukunda 		dev_err(component->dev, "pinfo failed\n");
280cab396d8SVijendar Mukunda 		return -EINVAL;
281cab396d8SVijendar Mukunda 	}
282cab396d8SVijendar Mukunda 	size = params_buffer_bytes(params);
283cab396d8SVijendar Mukunda 	rtd->dma_addr = substream->dma_buffer.addr;
284cab396d8SVijendar Mukunda 	rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
285cab396d8SVijendar Mukunda 	config_acp5x_dma(rtd, substream->stream);
286cab396d8SVijendar Mukunda 	return 0;
287cab396d8SVijendar Mukunda }
288cab396d8SVijendar Mukunda 
289cab396d8SVijendar Mukunda static snd_pcm_uframes_t acp5x_dma_pointer(struct snd_soc_component *component,
290cab396d8SVijendar Mukunda 					   struct snd_pcm_substream *substream)
291cab396d8SVijendar Mukunda {
292cab396d8SVijendar Mukunda 	struct i2s_stream_instance *rtd;
293cab396d8SVijendar Mukunda 	u32 pos;
294cab396d8SVijendar Mukunda 	u32 buffersize;
295cab396d8SVijendar Mukunda 	u64 bytescount;
296cab396d8SVijendar Mukunda 
297cab396d8SVijendar Mukunda 	rtd = substream->runtime->private_data;
298cab396d8SVijendar Mukunda 	buffersize = frames_to_bytes(substream->runtime,
299cab396d8SVijendar Mukunda 				     substream->runtime->buffer_size);
300cab396d8SVijendar Mukunda 	bytescount = acp_get_byte_count(rtd, substream->stream);
301cab396d8SVijendar Mukunda 	if (bytescount > rtd->bytescount)
302cab396d8SVijendar Mukunda 		bytescount -= rtd->bytescount;
303cab396d8SVijendar Mukunda 	pos = do_div(bytescount, buffersize);
304cab396d8SVijendar Mukunda 	return bytes_to_frames(substream->runtime, pos);
305cab396d8SVijendar Mukunda }
306cab396d8SVijendar Mukunda 
307cab396d8SVijendar Mukunda static int acp5x_dma_new(struct snd_soc_component *component,
308cab396d8SVijendar Mukunda 			 struct snd_soc_pcm_runtime *rtd)
309cab396d8SVijendar Mukunda {
310cab396d8SVijendar Mukunda 	struct device *parent = component->dev->parent;
311cab396d8SVijendar Mukunda 
312cab396d8SVijendar Mukunda 	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
313cab396d8SVijendar Mukunda 				       parent, MIN_BUFFER, MAX_BUFFER);
314cab396d8SVijendar Mukunda 	return 0;
315cab396d8SVijendar Mukunda }
316cab396d8SVijendar Mukunda 
317cab396d8SVijendar Mukunda static int acp5x_dma_mmap(struct snd_soc_component *component,
318cab396d8SVijendar Mukunda 			  struct snd_pcm_substream *substream,
319cab396d8SVijendar Mukunda 			  struct vm_area_struct *vma)
320cab396d8SVijendar Mukunda {
321cab396d8SVijendar Mukunda 	return snd_pcm_lib_default_mmap(substream, vma);
322cab396d8SVijendar Mukunda }
323cab396d8SVijendar Mukunda 
324cab396d8SVijendar Mukunda static int acp5x_dma_close(struct snd_soc_component *component,
325cab396d8SVijendar Mukunda 			   struct snd_pcm_substream *substream)
326cab396d8SVijendar Mukunda {
327cab396d8SVijendar Mukunda 	struct snd_soc_pcm_runtime *prtd;
328cab396d8SVijendar Mukunda 	struct i2s_dev_data *adata;
329cab396d8SVijendar Mukunda 	struct i2s_stream_instance *ins;
330cab396d8SVijendar Mukunda 
331cab396d8SVijendar Mukunda 	prtd = asoc_substream_to_rtd(substream);
332cab396d8SVijendar Mukunda 	component = snd_soc_rtdcom_lookup(prtd, DRV_NAME);
333cab396d8SVijendar Mukunda 	adata = dev_get_drvdata(component->dev);
334cab396d8SVijendar Mukunda 	ins = substream->runtime->private_data;
335cab396d8SVijendar Mukunda 	if (!ins)
336cab396d8SVijendar Mukunda 		return -EINVAL;
337cab396d8SVijendar Mukunda 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
338cab396d8SVijendar Mukunda 		switch (ins->i2s_instance) {
339cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
340cab396d8SVijendar Mukunda 			adata->play_stream = NULL;
341cab396d8SVijendar Mukunda 			break;
342cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
343cab396d8SVijendar Mukunda 		default:
344cab396d8SVijendar Mukunda 			adata->i2ssp_play_stream = NULL;
345cab396d8SVijendar Mukunda 		}
346cab396d8SVijendar Mukunda 	} else {
347cab396d8SVijendar Mukunda 		switch (ins->i2s_instance) {
348cab396d8SVijendar Mukunda 		case I2S_HS_INSTANCE:
349cab396d8SVijendar Mukunda 			adata->capture_stream = NULL;
350cab396d8SVijendar Mukunda 			break;
351cab396d8SVijendar Mukunda 		case I2S_SP_INSTANCE:
352cab396d8SVijendar Mukunda 		default:
353cab396d8SVijendar Mukunda 			adata->i2ssp_capture_stream = NULL;
354cab396d8SVijendar Mukunda 		}
355cab396d8SVijendar Mukunda 	}
356cab396d8SVijendar Mukunda 	kfree(ins);
357cab396d8SVijendar Mukunda 	return 0;
358cab396d8SVijendar Mukunda }
359cab396d8SVijendar Mukunda 
360cab396d8SVijendar Mukunda static const struct snd_soc_component_driver acp5x_i2s_component = {
361cab396d8SVijendar Mukunda 	.name		= DRV_NAME,
362cab396d8SVijendar Mukunda 	.open		= acp5x_dma_open,
363cab396d8SVijendar Mukunda 	.close		= acp5x_dma_close,
364cab396d8SVijendar Mukunda 	.hw_params	= acp5x_dma_hw_params,
365cab396d8SVijendar Mukunda 	.pointer	= acp5x_dma_pointer,
366cab396d8SVijendar Mukunda 	.mmap		= acp5x_dma_mmap,
367cab396d8SVijendar Mukunda 	.pcm_construct	= acp5x_dma_new,
368cab396d8SVijendar Mukunda };
369cab396d8SVijendar Mukunda 
37077f61444SVijendar Mukunda static int acp5x_audio_probe(struct platform_device *pdev)
37177f61444SVijendar Mukunda {
37277f61444SVijendar Mukunda 	struct resource *res;
37377f61444SVijendar Mukunda 	struct i2s_dev_data *adata;
374fc2c8067SVijendar Mukunda 	unsigned int irqflags;
37577f61444SVijendar Mukunda 	int status;
37677f61444SVijendar Mukunda 
37777f61444SVijendar Mukunda 	if (!pdev->dev.platform_data) {
37877f61444SVijendar Mukunda 		dev_err(&pdev->dev, "platform_data not retrieved\n");
37977f61444SVijendar Mukunda 		return -ENODEV;
38077f61444SVijendar Mukunda 	}
38177f61444SVijendar Mukunda 	irqflags = *((unsigned int *)(pdev->dev.platform_data));
38277f61444SVijendar Mukunda 
38377f61444SVijendar Mukunda 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
38477f61444SVijendar Mukunda 	if (!res) {
38577f61444SVijendar Mukunda 		dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
38677f61444SVijendar Mukunda 		return -ENODEV;
38777f61444SVijendar Mukunda 	}
38877f61444SVijendar Mukunda 
38977f61444SVijendar Mukunda 	adata = devm_kzalloc(&pdev->dev, sizeof(*adata), GFP_KERNEL);
39077f61444SVijendar Mukunda 	if (!adata)
39177f61444SVijendar Mukunda 		return -ENOMEM;
39277f61444SVijendar Mukunda 
39377f61444SVijendar Mukunda 	adata->acp5x_base = devm_ioremap(&pdev->dev, res->start,
39477f61444SVijendar Mukunda 					 resource_size(res));
39577f61444SVijendar Mukunda 	if (!adata->acp5x_base)
39677f61444SVijendar Mukunda 		return -ENOMEM;
397fc2c8067SVijendar Mukunda 
398fc2c8067SVijendar Mukunda 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
399fc2c8067SVijendar Mukunda 	if (!res) {
400fc2c8067SVijendar Mukunda 		dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
401fc2c8067SVijendar Mukunda 		return -ENODEV;
402fc2c8067SVijendar Mukunda 	}
403fc2c8067SVijendar Mukunda 
404fc2c8067SVijendar Mukunda 	adata->i2s_irq = res->start;
40577f61444SVijendar Mukunda 	dev_set_drvdata(&pdev->dev, adata);
40677f61444SVijendar Mukunda 	status = devm_snd_soc_register_component(&pdev->dev,
40777f61444SVijendar Mukunda 						 &acp5x_i2s_component,
40877f61444SVijendar Mukunda 						 NULL, 0);
409fc2c8067SVijendar Mukunda 	if (status) {
41077f61444SVijendar Mukunda 		dev_err(&pdev->dev, "Fail to register acp i2s component\n");
411fc2c8067SVijendar Mukunda 		return status;
412fc2c8067SVijendar Mukunda 	}
413fc2c8067SVijendar Mukunda 	status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
414fc2c8067SVijendar Mukunda 				  irqflags, "ACP5x_I2S_IRQ", adata);
415fc2c8067SVijendar Mukunda 	if (status)
416fc2c8067SVijendar Mukunda 		dev_err(&pdev->dev, "ACP5x I2S IRQ request failed\n");
41777f61444SVijendar Mukunda 
41877f61444SVijendar Mukunda 	return status;
41977f61444SVijendar Mukunda }
42077f61444SVijendar Mukunda 
42177f61444SVijendar Mukunda static struct platform_driver acp5x_dma_driver = {
42277f61444SVijendar Mukunda 	.probe = acp5x_audio_probe,
42377f61444SVijendar Mukunda 	.driver = {
42477f61444SVijendar Mukunda 		.name = "acp5x_i2s_dma",
42577f61444SVijendar Mukunda 	},
42677f61444SVijendar Mukunda };
42777f61444SVijendar Mukunda 
42877f61444SVijendar Mukunda module_platform_driver(acp5x_dma_driver);
42977f61444SVijendar Mukunda 
43077f61444SVijendar Mukunda MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
43177f61444SVijendar Mukunda MODULE_DESCRIPTION("AMD ACP 5.x PCM Driver");
43277f61444SVijendar Mukunda MODULE_LICENSE("GPL v2");
43377f61444SVijendar Mukunda MODULE_ALIAS("platform:" DRV_NAME);
434