Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  aio-dma.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
//
// Socionext UniPhier AIO DMA driver.
//
// Copyright (c) 2016-2018 Socionext Inc.

#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>

#include "aio.h"

static const struct snd_pcm_hardware uniphier_aiodma_hw = {
 .info = SNDRV_PCM_INFO_MMAP |
  SNDRV_PCM_INFO_MMAP_VALID |
  SNDRV_PCM_INFO_INTERLEAVED,
 .period_bytes_min = 256,
 .period_bytes_max = 4096,
 .periods_min      = 4,
 .periods_max      = 1024,
 .buffer_bytes_max = 128 * 1024,
};

static void aiodma_pcm_irq(struct uniphier_aio_sub *sub)
{
 struct snd_pcm_runtime *runtime = sub->substream->runtime;
 int bytes = runtime->period_size *
  runtime->channels * samples_to_bytes(runtime, 1);
 int ret;

 spin_lock(&sub->lock);
 ret = aiodma_rb_set_threshold(sub, runtime->dma_bytes,
          sub->threshold + bytes);
 if (!ret)
  sub->threshold += bytes;

 aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);
 aiodma_rb_clear_irq(sub);
 spin_unlock(&sub->lock);

 snd_pcm_period_elapsed(sub->substream);
}

static void aiodma_compr_irq(struct uniphier_aio_sub *sub)
{
 struct snd_compr_runtime *runtime = sub->cstream->runtime;
 int bytes = runtime->fragment_size;
 int ret;

 spin_lock(&sub->lock);
 ret = aiodma_rb_set_threshold(sub, sub->compr_bytes,
          sub->threshold + bytes);
 if (!ret)
  sub->threshold += bytes;

 aiodma_rb_sync(sub, sub->compr_addr, sub->compr_bytes, bytes);
 aiodma_rb_clear_irq(sub);
 spin_unlock(&sub->lock);

 snd_compr_fragment_elapsed(sub->cstream);
}

static irqreturn_t aiodma_irq(int irq, void *p)
{
 struct platform_device *pdev = p;
 struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
 irqreturn_t ret = IRQ_NONE;
 int i, j;

 for (i = 0; i < chip->num_aios; i++) {
  struct uniphier_aio *aio = &chip->aios[i];

  for (j = 0; j < ARRAY_SIZE(aio->sub); j++) {
   struct uniphier_aio_sub *sub = &aio->sub[j];

   /* Skip channel that does not trigger */
   if (!sub->running || !aiodma_rb_is_irq(sub))
    continue;

   if (sub->substream)
    aiodma_pcm_irq(sub);
   if (sub->cstream)
    aiodma_compr_irq(sub);

   ret = IRQ_HANDLED;
  }
 }

 return ret;
}

static int uniphier_aiodma_open(struct snd_soc_component *component,
    struct snd_pcm_substream *substream)
{
 struct snd_pcm_runtime *runtime = substream->runtime;

 snd_soc_set_runtime_hwparams(substream, &uniphier_aiodma_hw);

 return snd_pcm_hw_constraint_step(runtime, 0,
  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256);
}

static int uniphier_aiodma_prepare(struct snd_soc_component *component,
       struct snd_pcm_substream *substream)
{
 struct snd_pcm_runtime *runtime = substream->runtime;
 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 struct uniphier_aio *aio = uniphier_priv(snd_soc_rtd_to_cpu(rtd, 0));
 struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 int bytes = runtime->period_size *
  runtime->channels * samples_to_bytes(runtime, 1);
 unsigned long flags;
 int ret;

 ret = aiodma_ch_set_param(sub);
 if (ret)
  return ret;

 spin_lock_irqsave(&sub->lock, flags);
 ret = aiodma_rb_set_buffer(sub, runtime->dma_addr,
       runtime->dma_addr + runtime->dma_bytes,
       bytes);
 spin_unlock_irqrestore(&sub->lock, flags);
 if (ret)
  return ret;

 return 0;
}

static int uniphier_aiodma_trigger(struct snd_soc_component *component,
       struct snd_pcm_substream *substream, int cmd)
{
 struct snd_pcm_runtime *runtime = substream->runtime;
 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 struct uniphier_aio *aio = uniphier_priv(snd_soc_rtd_to_cpu(rtd, 0));
 struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 struct device *dev = &aio->chip->pdev->dev;
 int bytes = runtime->period_size *
  runtime->channels * samples_to_bytes(runtime, 1);
 unsigned long flags;

 spin_lock_irqsave(&sub->lock, flags);
 switch (cmd) {
 case SNDRV_PCM_TRIGGER_START:
  aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes,
          bytes);
  aiodma_ch_set_enable(sub, 1);
  sub->running = 1;

  break;
 case SNDRV_PCM_TRIGGER_STOP:
  sub->running = 0;
  aiodma_ch_set_enable(sub, 0);

  break;
 default:
  dev_warn(dev, "Unknown trigger(%d) ignored\n", cmd);
  break;
 }
 spin_unlock_irqrestore(&sub->lock, flags);

 return 0;
}

static snd_pcm_uframes_t uniphier_aiodma_pointer(
     struct snd_soc_component *component,
     struct snd_pcm_substream *substream)
{
 struct snd_pcm_runtime *runtime = substream->runtime;
 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 struct uniphier_aio *aio = uniphier_priv(snd_soc_rtd_to_cpu(rtd, 0));
 struct uniphier_aio_sub *sub = &aio->sub[substream->stream];
 int bytes = runtime->period_size *
  runtime->channels * samples_to_bytes(runtime, 1);
 unsigned long flags;
 snd_pcm_uframes_t pos;

 spin_lock_irqsave(&sub->lock, flags);
 aiodma_rb_sync(sub, runtime->dma_addr, runtime->dma_bytes, bytes);

 if (sub->swm->dir == PORT_DIR_OUTPUT)
  pos = bytes_to_frames(runtime, sub->rd_offs);
 else
  pos = bytes_to_frames(runtime, sub->wr_offs);
 spin_unlock_irqrestore(&sub->lock, flags);

 return pos;
}

static int uniphier_aiodma_mmap(struct snd_soc_component *component,
    struct snd_pcm_substream *substream,
    struct vm_area_struct *vma)
{
 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

 return remap_pfn_range(vma, vma->vm_start,
          substream->runtime->dma_addr >> PAGE_SHIFT,
          vma->vm_end - vma->vm_start, vma->vm_page_prot);
}

static int uniphier_aiodma_new(struct snd_soc_component *component,
          struct snd_soc_pcm_runtime *rtd)
{
 struct device *dev = rtd->card->snd_card->dev;
 struct snd_pcm *pcm = rtd->pcm;
 int ret;

 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(33));
 if (ret)
  return ret;

 snd_pcm_set_managed_buffer_all(pcm,
  SNDRV_DMA_TYPE_DEV, dev,
  uniphier_aiodma_hw.buffer_bytes_max,
  uniphier_aiodma_hw.buffer_bytes_max);
 return 0;
}

static const struct snd_soc_component_driver uniphier_soc_platform = {
 .open  = uniphier_aiodma_open,
 .prepare = uniphier_aiodma_prepare,
 .trigger = uniphier_aiodma_trigger,
 .pointer = uniphier_aiodma_pointer,
 .mmap  = uniphier_aiodma_mmap,
 .pcm_construct = uniphier_aiodma_new,
 .compress_ops = &uniphier_aio_compress_ops,
};

static const struct regmap_config aiodma_regmap_config = {
 .reg_bits      = 32,
 .reg_stride    = 4,
 .val_bits      = 32,
 .max_register  = 0x7fffc,
 .cache_type    = REGCACHE_NONE,
};

/**
 * uniphier_aiodma_soc_register_platform - register the AIO DMA
 * @pdev: the platform device
 *
 * Register and setup the DMA of AIO to transfer the sound data to device.
 * This function need to call once at driver startup and need NOT to call
 * unregister function.
 *
 * Return: Zero if successful, otherwise a negative value on error.
 */

int uniphier_aiodma_soc_register_platform(struct platform_device *pdev)
{
 struct uniphier_aio_chip *chip = platform_get_drvdata(pdev);
 struct device *dev = &pdev->dev;
 void __iomem *preg;
 int irq, ret;

 preg = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(preg))
  return PTR_ERR(preg);

 chip->regmap = devm_regmap_init_mmio(dev, preg,
          &aiodma_regmap_config);
 if (IS_ERR(chip->regmap))
  return PTR_ERR(chip->regmap);

 irq = platform_get_irq(pdev, 0);
 if (irq < 0)
  return irq;

 ret = devm_request_irq(dev, irq, aiodma_irq,
          IRQF_SHARED, dev_name(dev), pdev);
 if (ret)
  return ret;

 return devm_snd_soc_register_component(dev, &uniphier_soc_platform,
            NULL, 0);
}
EXPORT_SYMBOL_GPL(uniphier_aiodma_soc_register_platform);

Messung V0.5
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge