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