162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// idma.c - I2S0 internal DMA driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2011 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci// http://www.samsung.com 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <sound/pcm.h> 1462306a36Sopenharmony_ci#include <sound/pcm_params.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "i2s.h" 1862306a36Sopenharmony_ci#include "idma.h" 1962306a36Sopenharmony_ci#include "i2s-regs.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define ST_RUNNING (1<<0) 2262306a36Sopenharmony_ci#define ST_OPENED (1<<1) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct snd_pcm_hardware idma_hardware = { 2562306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 2662306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 2762306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 2862306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 2962306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 3062306a36Sopenharmony_ci SNDRV_PCM_INFO_RESUME, 3162306a36Sopenharmony_ci .buffer_bytes_max = MAX_IDMA_BUFFER, 3262306a36Sopenharmony_ci .period_bytes_min = 128, 3362306a36Sopenharmony_ci .period_bytes_max = MAX_IDMA_PERIOD, 3462306a36Sopenharmony_ci .periods_min = 1, 3562306a36Sopenharmony_ci .periods_max = 2, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct idma_ctrl { 3962306a36Sopenharmony_ci spinlock_t lock; 4062306a36Sopenharmony_ci int state; 4162306a36Sopenharmony_ci dma_addr_t start; 4262306a36Sopenharmony_ci dma_addr_t pos; 4362306a36Sopenharmony_ci dma_addr_t end; 4462306a36Sopenharmony_ci dma_addr_t period; 4562306a36Sopenharmony_ci dma_addr_t periodsz; 4662306a36Sopenharmony_ci void *token; 4762306a36Sopenharmony_ci void (*cb)(void *dt, int bytes_xfer); 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic struct idma_info { 5162306a36Sopenharmony_ci spinlock_t lock; 5262306a36Sopenharmony_ci void __iomem *regs; 5362306a36Sopenharmony_ci dma_addr_t lp_tx_addr; 5462306a36Sopenharmony_ci} idma; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int idma_irq; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void idma_getpos(dma_addr_t *src) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci *src = idma.lp_tx_addr + 6162306a36Sopenharmony_ci (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int idma_enqueue(struct snd_pcm_substream *substream) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 6762306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 6862306a36Sopenharmony_ci u32 val; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci spin_lock(&prtd->lock); 7162306a36Sopenharmony_ci prtd->token = (void *) substream; 7262306a36Sopenharmony_ci spin_unlock(&prtd->lock); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Internal DMA Level0 Interrupt Address */ 7562306a36Sopenharmony_ci val = idma.lp_tx_addr + prtd->periodsz; 7662306a36Sopenharmony_ci writel(val, idma.regs + I2SLVL0ADDR); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Start address0 of I2S internal DMA operation. */ 7962306a36Sopenharmony_ci val = idma.lp_tx_addr; 8062306a36Sopenharmony_ci writel(val, idma.regs + I2SSTR0); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * Transfer block size for I2S internal DMA. 8462306a36Sopenharmony_ci * Should decide transfer size before start dma operation 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci val = readl(idma.regs + I2SSIZE); 8762306a36Sopenharmony_ci val &= ~(I2SSIZE_TRNMSK << I2SSIZE_SHIFT); 8862306a36Sopenharmony_ci val |= (((runtime->dma_bytes >> 2) & 8962306a36Sopenharmony_ci I2SSIZE_TRNMSK) << I2SSIZE_SHIFT); 9062306a36Sopenharmony_ci writel(val, idma.regs + I2SSIZE); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci val = readl(idma.regs + I2SAHB); 9362306a36Sopenharmony_ci val |= AHB_INTENLVL0; 9462306a36Sopenharmony_ci writel(val, idma.regs + I2SAHB); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void idma_setcallbk(struct snd_pcm_substream *substream, 10062306a36Sopenharmony_ci void (*cb)(void *, int)) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci spin_lock(&prtd->lock); 10562306a36Sopenharmony_ci prtd->cb = cb; 10662306a36Sopenharmony_ci spin_unlock(&prtd->lock); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void idma_control(int op) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci u32 val = readl(idma.regs + I2SAHB); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci spin_lock(&idma.lock); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci switch (op) { 11662306a36Sopenharmony_ci case LPAM_DMA_START: 11762306a36Sopenharmony_ci val |= (AHB_INTENLVL0 | AHB_DMAEN); 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case LPAM_DMA_STOP: 12062306a36Sopenharmony_ci val &= ~(AHB_INTENLVL0 | AHB_DMAEN); 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci default: 12362306a36Sopenharmony_ci spin_unlock(&idma.lock); 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci writel(val, idma.regs + I2SAHB); 12862306a36Sopenharmony_ci spin_unlock(&idma.lock); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void idma_done(void *id, int bytes_xfer) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct snd_pcm_substream *substream = id; 13462306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (prtd && (prtd->state & ST_RUNNING)) 13762306a36Sopenharmony_ci snd_pcm_period_elapsed(substream); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int idma_hw_params(struct snd_soc_component *component, 14162306a36Sopenharmony_ci struct snd_pcm_substream *substream, 14262306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 14562306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 14662306a36Sopenharmony_ci u32 mod = readl(idma.regs + I2SMOD); 14762306a36Sopenharmony_ci u32 ahb = readl(idma.regs + I2SAHB); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ahb |= (AHB_DMARLD | AHB_INTMASK); 15062306a36Sopenharmony_ci mod |= MOD_TXS_IDMA; 15162306a36Sopenharmony_ci writel(ahb, idma.regs + I2SAHB); 15262306a36Sopenharmony_ci writel(mod, idma.regs + I2SMOD); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 15562306a36Sopenharmony_ci runtime->dma_bytes = params_buffer_bytes(params); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci prtd->start = prtd->pos = runtime->dma_addr; 15862306a36Sopenharmony_ci prtd->period = params_periods(params); 15962306a36Sopenharmony_ci prtd->periodsz = params_period_bytes(params); 16062306a36Sopenharmony_ci prtd->end = runtime->dma_addr + runtime->dma_bytes; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci idma_setcallbk(substream, idma_done); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int idma_hw_free(struct snd_soc_component *component, 16862306a36Sopenharmony_ci struct snd_pcm_substream *substream) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci snd_pcm_set_runtime_buffer(substream, NULL); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int idma_prepare(struct snd_soc_component *component, 17662306a36Sopenharmony_ci struct snd_pcm_substream *substream) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci prtd->pos = prtd->start; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* flush the DMA channel */ 18362306a36Sopenharmony_ci idma_control(LPAM_DMA_STOP); 18462306a36Sopenharmony_ci idma_enqueue(substream); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int idma_trigger(struct snd_soc_component *component, 19062306a36Sopenharmony_ci struct snd_pcm_substream *substream, int cmd) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct idma_ctrl *prtd = substream->runtime->private_data; 19362306a36Sopenharmony_ci int ret = 0; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci spin_lock(&prtd->lock); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci switch (cmd) { 19862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 19962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 20062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 20162306a36Sopenharmony_ci prtd->state |= ST_RUNNING; 20262306a36Sopenharmony_ci idma_control(LPAM_DMA_START); 20362306a36Sopenharmony_ci break; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 20662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 20762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 20862306a36Sopenharmony_ci prtd->state &= ~ST_RUNNING; 20962306a36Sopenharmony_ci idma_control(LPAM_DMA_STOP); 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci default: 21362306a36Sopenharmony_ci ret = -EINVAL; 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci spin_unlock(&prtd->lock); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic snd_pcm_uframes_t 22362306a36Sopenharmony_ciidma_pointer(struct snd_soc_component *component, 22462306a36Sopenharmony_ci struct snd_pcm_substream *substream) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 22762306a36Sopenharmony_ci struct idma_ctrl *prtd = runtime->private_data; 22862306a36Sopenharmony_ci dma_addr_t src; 22962306a36Sopenharmony_ci unsigned long res; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci spin_lock(&prtd->lock); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci idma_getpos(&src); 23462306a36Sopenharmony_ci res = src - prtd->start; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci spin_unlock(&prtd->lock); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return bytes_to_frames(substream->runtime, res); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int idma_mmap(struct snd_soc_component *component, 24262306a36Sopenharmony_ci struct snd_pcm_substream *substream, 24362306a36Sopenharmony_ci struct vm_area_struct *vma) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 24662306a36Sopenharmony_ci unsigned long size, offset; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* From snd_pcm_lib_mmap_iomem */ 24962306a36Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 25062306a36Sopenharmony_ci size = vma->vm_end - vma->vm_start; 25162306a36Sopenharmony_ci offset = vma->vm_pgoff << PAGE_SHIFT; 25262306a36Sopenharmony_ci return io_remap_pfn_range(vma, vma->vm_start, 25362306a36Sopenharmony_ci (runtime->dma_addr + offset) >> PAGE_SHIFT, 25462306a36Sopenharmony_ci size, vma->vm_page_prot); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic irqreturn_t iis_irq(int irqno, void *dev_id) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id; 26062306a36Sopenharmony_ci u32 iisahb, val, addr; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci iisahb = readl(idma.regs + I2SAHB); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (val) { 26762306a36Sopenharmony_ci iisahb |= val; 26862306a36Sopenharmony_ci writel(iisahb, idma.regs + I2SAHB); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr; 27162306a36Sopenharmony_ci addr += prtd->periodsz; 27262306a36Sopenharmony_ci addr %= (u32)(prtd->end - prtd->start); 27362306a36Sopenharmony_ci addr += idma.lp_tx_addr; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci writel(addr, idma.regs + I2SLVL0ADDR); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (prtd->cb) 27862306a36Sopenharmony_ci prtd->cb(prtd->token, prtd->period); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return IRQ_HANDLED; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int idma_open(struct snd_soc_component *component, 28562306a36Sopenharmony_ci struct snd_pcm_substream *substream) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 28862306a36Sopenharmony_ci struct idma_ctrl *prtd; 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &idma_hardware); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci prtd = kzalloc(sizeof(struct idma_ctrl), GFP_KERNEL); 29462306a36Sopenharmony_ci if (prtd == NULL) 29562306a36Sopenharmony_ci return -ENOMEM; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd); 29862306a36Sopenharmony_ci if (ret < 0) { 29962306a36Sopenharmony_ci pr_err("fail to claim i2s irq , ret = %d\n", ret); 30062306a36Sopenharmony_ci kfree(prtd); 30162306a36Sopenharmony_ci return ret; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci spin_lock_init(&prtd->lock); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci runtime->private_data = prtd; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int idma_close(struct snd_soc_component *component, 31262306a36Sopenharmony_ci struct snd_pcm_substream *substream) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 31562306a36Sopenharmony_ci struct idma_ctrl *prtd = runtime->private_data; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci free_irq(idma_irq, prtd); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (!prtd) 32062306a36Sopenharmony_ci pr_err("idma_close called with prtd == NULL\n"); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci kfree(prtd); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void idma_free(struct snd_soc_component *component, 32862306a36Sopenharmony_ci struct snd_pcm *pcm) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct snd_pcm_substream *substream; 33162306a36Sopenharmony_ci struct snd_dma_buffer *buf; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 33462306a36Sopenharmony_ci if (!substream) 33562306a36Sopenharmony_ci return; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci buf = &substream->dma_buffer; 33862306a36Sopenharmony_ci if (!buf->area) 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci iounmap((void __iomem *)buf->area); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci buf->area = NULL; 34462306a36Sopenharmony_ci buf->addr = 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct snd_pcm_substream *substream = pcm->streams[stream].substream; 35062306a36Sopenharmony_ci struct snd_dma_buffer *buf = &substream->dma_buffer; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci buf->dev.dev = pcm->card->dev; 35362306a36Sopenharmony_ci buf->private_data = NULL; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Assign PCM buffer pointers */ 35662306a36Sopenharmony_ci buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; 35762306a36Sopenharmony_ci buf->addr = idma.lp_tx_addr; 35862306a36Sopenharmony_ci buf->bytes = idma_hardware.buffer_bytes_max; 35962306a36Sopenharmony_ci buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes); 36062306a36Sopenharmony_ci if (!buf->area) 36162306a36Sopenharmony_ci return -ENOMEM; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int idma_new(struct snd_soc_component *component, 36762306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct snd_card *card = rtd->card->snd_card; 37062306a36Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 37162306a36Sopenharmony_ci int ret; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 37462306a36Sopenharmony_ci if (ret) 37562306a36Sopenharmony_ci return ret; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 37862306a36Sopenharmony_ci ret = preallocate_idma_buffer(pcm, 37962306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return ret; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_civoid idma_reg_addr_init(void __iomem *regs, dma_addr_t addr) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci spin_lock_init(&idma.lock); 38862306a36Sopenharmony_ci idma.regs = regs; 38962306a36Sopenharmony_ci idma.lp_tx_addr = addr; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(idma_reg_addr_init); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic const struct snd_soc_component_driver asoc_idma_platform = { 39462306a36Sopenharmony_ci .open = idma_open, 39562306a36Sopenharmony_ci .close = idma_close, 39662306a36Sopenharmony_ci .trigger = idma_trigger, 39762306a36Sopenharmony_ci .pointer = idma_pointer, 39862306a36Sopenharmony_ci .mmap = idma_mmap, 39962306a36Sopenharmony_ci .hw_params = idma_hw_params, 40062306a36Sopenharmony_ci .hw_free = idma_hw_free, 40162306a36Sopenharmony_ci .prepare = idma_prepare, 40262306a36Sopenharmony_ci .pcm_construct = idma_new, 40362306a36Sopenharmony_ci .pcm_destruct = idma_free, 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int asoc_idma_platform_probe(struct platform_device *pdev) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci idma_irq = platform_get_irq(pdev, 0); 40962306a36Sopenharmony_ci if (idma_irq < 0) 41062306a36Sopenharmony_ci return idma_irq; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return devm_snd_soc_register_component(&pdev->dev, &asoc_idma_platform, 41362306a36Sopenharmony_ci NULL, 0); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic struct platform_driver asoc_idma_driver = { 41762306a36Sopenharmony_ci .driver = { 41862306a36Sopenharmony_ci .name = "samsung-idma", 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci .probe = asoc_idma_platform_probe, 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cimodule_platform_driver(asoc_idma_driver); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciMODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>"); 42762306a36Sopenharmony_ciMODULE_DESCRIPTION("Samsung ASoC IDMA Driver"); 42862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 429