Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // idma.c - I2S0 internal DMA driver
0004 //
0005 // Copyright (c) 2011 Samsung Electronics Co., Ltd.
0006 //      http://www.samsung.com
0007 
0008 #include <linux/interrupt.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/dma-mapping.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <sound/pcm.h>
0014 #include <sound/pcm_params.h>
0015 #include <sound/soc.h>
0016 
0017 #include "i2s.h"
0018 #include "idma.h"
0019 #include "i2s-regs.h"
0020 
0021 #define ST_RUNNING      (1<<0)
0022 #define ST_OPENED       (1<<1)
0023 
0024 static const struct snd_pcm_hardware idma_hardware = {
0025     .info = SNDRV_PCM_INFO_INTERLEAVED |
0026             SNDRV_PCM_INFO_BLOCK_TRANSFER |
0027             SNDRV_PCM_INFO_MMAP |
0028             SNDRV_PCM_INFO_MMAP_VALID |
0029             SNDRV_PCM_INFO_PAUSE |
0030             SNDRV_PCM_INFO_RESUME,
0031     .buffer_bytes_max = MAX_IDMA_BUFFER,
0032     .period_bytes_min = 128,
0033     .period_bytes_max = MAX_IDMA_PERIOD,
0034     .periods_min = 1,
0035     .periods_max = 2,
0036 };
0037 
0038 struct idma_ctrl {
0039     spinlock_t  lock;
0040     int     state;
0041     dma_addr_t  start;
0042     dma_addr_t  pos;
0043     dma_addr_t  end;
0044     dma_addr_t  period;
0045     dma_addr_t  periodsz;
0046     void        *token;
0047     void        (*cb)(void *dt, int bytes_xfer);
0048 };
0049 
0050 static struct idma_info {
0051     spinlock_t  lock;
0052     void         __iomem  *regs;
0053     dma_addr_t  lp_tx_addr;
0054 } idma;
0055 
0056 static int idma_irq;
0057 
0058 static void idma_getpos(dma_addr_t *src)
0059 {
0060     *src = idma.lp_tx_addr +
0061         (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4;
0062 }
0063 
0064 static int idma_enqueue(struct snd_pcm_substream *substream)
0065 {
0066     struct snd_pcm_runtime *runtime = substream->runtime;
0067     struct idma_ctrl *prtd = substream->runtime->private_data;
0068     u32 val;
0069 
0070     spin_lock(&prtd->lock);
0071     prtd->token = (void *) substream;
0072     spin_unlock(&prtd->lock);
0073 
0074     /* Internal DMA Level0 Interrupt Address */
0075     val = idma.lp_tx_addr + prtd->periodsz;
0076     writel(val, idma.regs + I2SLVL0ADDR);
0077 
0078     /* Start address0 of I2S internal DMA operation. */
0079     val = idma.lp_tx_addr;
0080     writel(val, idma.regs + I2SSTR0);
0081 
0082     /*
0083      * Transfer block size for I2S internal DMA.
0084      * Should decide transfer size before start dma operation
0085      */
0086     val = readl(idma.regs + I2SSIZE);
0087     val &= ~(I2SSIZE_TRNMSK << I2SSIZE_SHIFT);
0088     val |= (((runtime->dma_bytes >> 2) &
0089             I2SSIZE_TRNMSK) << I2SSIZE_SHIFT);
0090     writel(val, idma.regs + I2SSIZE);
0091 
0092     val = readl(idma.regs + I2SAHB);
0093     val |= AHB_INTENLVL0;
0094     writel(val, idma.regs + I2SAHB);
0095 
0096     return 0;
0097 }
0098 
0099 static void idma_setcallbk(struct snd_pcm_substream *substream,
0100                 void (*cb)(void *, int))
0101 {
0102     struct idma_ctrl *prtd = substream->runtime->private_data;
0103 
0104     spin_lock(&prtd->lock);
0105     prtd->cb = cb;
0106     spin_unlock(&prtd->lock);
0107 }
0108 
0109 static void idma_control(int op)
0110 {
0111     u32 val = readl(idma.regs + I2SAHB);
0112 
0113     spin_lock(&idma.lock);
0114 
0115     switch (op) {
0116     case LPAM_DMA_START:
0117         val |= (AHB_INTENLVL0 | AHB_DMAEN);
0118         break;
0119     case LPAM_DMA_STOP:
0120         val &= ~(AHB_INTENLVL0 | AHB_DMAEN);
0121         break;
0122     default:
0123         spin_unlock(&idma.lock);
0124         return;
0125     }
0126 
0127     writel(val, idma.regs + I2SAHB);
0128     spin_unlock(&idma.lock);
0129 }
0130 
0131 static void idma_done(void *id, int bytes_xfer)
0132 {
0133     struct snd_pcm_substream *substream = id;
0134     struct idma_ctrl *prtd = substream->runtime->private_data;
0135 
0136     if (prtd && (prtd->state & ST_RUNNING))
0137         snd_pcm_period_elapsed(substream);
0138 }
0139 
0140 static int idma_hw_params(struct snd_soc_component *component,
0141               struct snd_pcm_substream *substream,
0142               struct snd_pcm_hw_params *params)
0143 {
0144     struct snd_pcm_runtime *runtime = substream->runtime;
0145     struct idma_ctrl *prtd = substream->runtime->private_data;
0146     u32 mod = readl(idma.regs + I2SMOD);
0147     u32 ahb = readl(idma.regs + I2SAHB);
0148 
0149     ahb |= (AHB_DMARLD | AHB_INTMASK);
0150     mod |= MOD_TXS_IDMA;
0151     writel(ahb, idma.regs + I2SAHB);
0152     writel(mod, idma.regs + I2SMOD);
0153 
0154     snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
0155     runtime->dma_bytes = params_buffer_bytes(params);
0156 
0157     prtd->start = prtd->pos = runtime->dma_addr;
0158     prtd->period = params_periods(params);
0159     prtd->periodsz = params_period_bytes(params);
0160     prtd->end = runtime->dma_addr + runtime->dma_bytes;
0161 
0162     idma_setcallbk(substream, idma_done);
0163 
0164     return 0;
0165 }
0166 
0167 static int idma_hw_free(struct snd_soc_component *component,
0168             struct snd_pcm_substream *substream)
0169 {
0170     snd_pcm_set_runtime_buffer(substream, NULL);
0171 
0172     return 0;
0173 }
0174 
0175 static int idma_prepare(struct snd_soc_component *component,
0176             struct snd_pcm_substream *substream)
0177 {
0178     struct idma_ctrl *prtd = substream->runtime->private_data;
0179 
0180     prtd->pos = prtd->start;
0181 
0182     /* flush the DMA channel */
0183     idma_control(LPAM_DMA_STOP);
0184     idma_enqueue(substream);
0185 
0186     return 0;
0187 }
0188 
0189 static int idma_trigger(struct snd_soc_component *component,
0190             struct snd_pcm_substream *substream, int cmd)
0191 {
0192     struct idma_ctrl *prtd = substream->runtime->private_data;
0193     int ret = 0;
0194 
0195     spin_lock(&prtd->lock);
0196 
0197     switch (cmd) {
0198     case SNDRV_PCM_TRIGGER_RESUME:
0199     case SNDRV_PCM_TRIGGER_START:
0200     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0201         prtd->state |= ST_RUNNING;
0202         idma_control(LPAM_DMA_START);
0203         break;
0204 
0205     case SNDRV_PCM_TRIGGER_SUSPEND:
0206     case SNDRV_PCM_TRIGGER_STOP:
0207     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0208         prtd->state &= ~ST_RUNNING;
0209         idma_control(LPAM_DMA_STOP);
0210         break;
0211 
0212     default:
0213         ret = -EINVAL;
0214         break;
0215     }
0216 
0217     spin_unlock(&prtd->lock);
0218 
0219     return ret;
0220 }
0221 
0222 static snd_pcm_uframes_t
0223 idma_pointer(struct snd_soc_component *component,
0224          struct snd_pcm_substream *substream)
0225 {
0226     struct snd_pcm_runtime *runtime = substream->runtime;
0227     struct idma_ctrl *prtd = runtime->private_data;
0228     dma_addr_t src;
0229     unsigned long res;
0230 
0231     spin_lock(&prtd->lock);
0232 
0233     idma_getpos(&src);
0234     res = src - prtd->start;
0235 
0236     spin_unlock(&prtd->lock);
0237 
0238     return bytes_to_frames(substream->runtime, res);
0239 }
0240 
0241 static int idma_mmap(struct snd_soc_component *component,
0242              struct snd_pcm_substream *substream,
0243     struct vm_area_struct *vma)
0244 {
0245     struct snd_pcm_runtime *runtime = substream->runtime;
0246     unsigned long size, offset;
0247 
0248     /* From snd_pcm_lib_mmap_iomem */
0249     vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
0250     size = vma->vm_end - vma->vm_start;
0251     offset = vma->vm_pgoff << PAGE_SHIFT;
0252     return io_remap_pfn_range(vma, vma->vm_start,
0253             (runtime->dma_addr + offset) >> PAGE_SHIFT,
0254             size, vma->vm_page_prot);
0255 }
0256 
0257 static irqreturn_t iis_irq(int irqno, void *dev_id)
0258 {
0259     struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id;
0260     u32 iisahb, val, addr;
0261 
0262     iisahb  = readl(idma.regs + I2SAHB);
0263 
0264     val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0;
0265 
0266     if (val) {
0267         iisahb |= val;
0268         writel(iisahb, idma.regs + I2SAHB);
0269 
0270         addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
0271         addr += prtd->periodsz;
0272         addr %= (u32)(prtd->end - prtd->start);
0273         addr += idma.lp_tx_addr;
0274 
0275         writel(addr, idma.regs + I2SLVL0ADDR);
0276 
0277         if (prtd->cb)
0278             prtd->cb(prtd->token, prtd->period);
0279     }
0280 
0281     return IRQ_HANDLED;
0282 }
0283 
0284 static int idma_open(struct snd_soc_component *component,
0285              struct snd_pcm_substream *substream)
0286 {
0287     struct snd_pcm_runtime *runtime = substream->runtime;
0288     struct idma_ctrl *prtd;
0289     int ret;
0290 
0291     snd_soc_set_runtime_hwparams(substream, &idma_hardware);
0292 
0293     prtd = kzalloc(sizeof(struct idma_ctrl), GFP_KERNEL);
0294     if (prtd == NULL)
0295         return -ENOMEM;
0296 
0297     ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd);
0298     if (ret < 0) {
0299         pr_err("fail to claim i2s irq , ret = %d\n", ret);
0300         kfree(prtd);
0301         return ret;
0302     }
0303 
0304     spin_lock_init(&prtd->lock);
0305 
0306     runtime->private_data = prtd;
0307 
0308     return 0;
0309 }
0310 
0311 static int idma_close(struct snd_soc_component *component,
0312               struct snd_pcm_substream *substream)
0313 {
0314     struct snd_pcm_runtime *runtime = substream->runtime;
0315     struct idma_ctrl *prtd = runtime->private_data;
0316 
0317     free_irq(idma_irq, prtd);
0318 
0319     if (!prtd)
0320         pr_err("idma_close called with prtd == NULL\n");
0321 
0322     kfree(prtd);
0323 
0324     return 0;
0325 }
0326 
0327 static void idma_free(struct snd_soc_component *component,
0328               struct snd_pcm *pcm)
0329 {
0330     struct snd_pcm_substream *substream;
0331     struct snd_dma_buffer *buf;
0332 
0333     substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
0334     if (!substream)
0335         return;
0336 
0337     buf = &substream->dma_buffer;
0338     if (!buf->area)
0339         return;
0340 
0341     iounmap((void __iomem *)buf->area);
0342 
0343     buf->area = NULL;
0344     buf->addr = 0;
0345 }
0346 
0347 static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
0348 {
0349     struct snd_pcm_substream *substream = pcm->streams[stream].substream;
0350     struct snd_dma_buffer *buf = &substream->dma_buffer;
0351 
0352     buf->dev.dev = pcm->card->dev;
0353     buf->private_data = NULL;
0354 
0355     /* Assign PCM buffer pointers */
0356     buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
0357     buf->addr = idma.lp_tx_addr;
0358     buf->bytes = idma_hardware.buffer_bytes_max;
0359     buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
0360     if (!buf->area)
0361         return -ENOMEM;
0362 
0363     return 0;
0364 }
0365 
0366 static int idma_new(struct snd_soc_component *component,
0367             struct snd_soc_pcm_runtime *rtd)
0368 {
0369     struct snd_card *card = rtd->card->snd_card;
0370     struct snd_pcm *pcm = rtd->pcm;
0371     int ret;
0372 
0373     ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
0374     if (ret)
0375         return ret;
0376 
0377     if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
0378         ret = preallocate_idma_buffer(pcm,
0379                 SNDRV_PCM_STREAM_PLAYBACK);
0380     }
0381 
0382     return ret;
0383 }
0384 
0385 void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
0386 {
0387     spin_lock_init(&idma.lock);
0388     idma.regs = regs;
0389     idma.lp_tx_addr = addr;
0390 }
0391 EXPORT_SYMBOL_GPL(idma_reg_addr_init);
0392 
0393 static const struct snd_soc_component_driver asoc_idma_platform = {
0394     .open       = idma_open,
0395     .close      = idma_close,
0396     .trigger    = idma_trigger,
0397     .pointer    = idma_pointer,
0398     .mmap       = idma_mmap,
0399     .hw_params  = idma_hw_params,
0400     .hw_free    = idma_hw_free,
0401     .prepare    = idma_prepare,
0402     .pcm_construct  = idma_new,
0403     .pcm_destruct   = idma_free,
0404 };
0405 
0406 static int asoc_idma_platform_probe(struct platform_device *pdev)
0407 {
0408     idma_irq = platform_get_irq(pdev, 0);
0409     if (idma_irq < 0)
0410         return idma_irq;
0411 
0412     return devm_snd_soc_register_component(&pdev->dev, &asoc_idma_platform,
0413                            NULL, 0);
0414 }
0415 
0416 static struct platform_driver asoc_idma_driver = {
0417     .driver = {
0418         .name = "samsung-idma",
0419     },
0420 
0421     .probe = asoc_idma_platform_probe,
0422 };
0423 
0424 module_platform_driver(asoc_idma_driver);
0425 
0426 MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
0427 MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
0428 MODULE_LICENSE("GPL");