mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
ASoC: loongson: Refactor DMA and regmap handling
Binbin Zhou <zhoubinbin@loongson.cn> says: This series refactors the Loongson I2S ASoC drivers, reducing code duplication and improving DMA differentiation. It also adds an entry in MAINTAINERS and applies a few fixes to the es8323 codec driver. These changes have been tested on Loongson-2K0300 (platform, eDMA) and Loongson-2K2000 (PCI, iDMA) boards. Link: https://patch.msgid.link/cover.1780304703.git.zhoubinbin@loongson.cn
This commit is contained in:
commit
d1712cd69d
|
|
@ -15051,6 +15051,15 @@ F: arch/loongarch/
|
|||
F: drivers/*/*loongarch*
|
||||
F: drivers/cpufreq/loongson3_cpufreq.c
|
||||
|
||||
LOONGSON AUDIO (ASoC) DRIVERS
|
||||
M: Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
|
||||
F: Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
|
||||
F: sound/soc/loongson/loongson_*.c
|
||||
F: sound/soc/loongson/loongson_*.h
|
||||
|
||||
LOONGSON GPIO DRIVER
|
||||
M: Yinbo Zhu <zhuyinbo@loongson.cn>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#Platform Support
|
||||
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o
|
||||
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o
|
||||
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o
|
||||
|
||||
snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o
|
||||
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o
|
||||
|
||||
snd-soc-loongson-i2s-y := loongson_i2s.o
|
||||
snd-soc-loongson-i2s-y := loongson_i2s.o loongson_dma.o
|
||||
|
||||
obj-$(CONFIG_SND_LOONGSON1_AC97) += loongson1_ac97.o
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// Copyright (C) 2023 Loongson Technology Corporation Limited
|
||||
// Author: Yingkun Meng <mengyingkun@loongson.cn>
|
||||
// Binbin ZHou <zhoubinbin@loongson.cn>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include "loongson_i2s.h"
|
||||
|
||||
/* DMA dma_order Register */
|
||||
/* Internal DMA dma_order Register */
|
||||
#define DMA_ORDER_STOP BIT(4) /* DMA stop */
|
||||
#define DMA_ORDER_START BIT(3) /* DMA start */
|
||||
#define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */
|
||||
|
|
@ -27,9 +28,9 @@
|
|||
#define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */
|
||||
|
||||
/*
|
||||
* DMA registers descriptor.
|
||||
* Internal DMA registers descriptor.
|
||||
*/
|
||||
struct loongson_dma_desc {
|
||||
struct loongson_idma_desc {
|
||||
u32 order; /* Next descriptor address register */
|
||||
u32 saddr; /* Source address register */
|
||||
u32 daddr; /* Device address register */
|
||||
|
|
@ -44,17 +45,17 @@ struct loongson_dma_desc {
|
|||
} __packed;
|
||||
|
||||
struct loongson_runtime_data {
|
||||
struct loongson_dma_data *dma_data;
|
||||
struct loongson_idma_data *dma_data;
|
||||
|
||||
struct loongson_dma_desc *dma_desc_arr;
|
||||
struct loongson_idma_desc *dma_desc_arr;
|
||||
dma_addr_t dma_desc_arr_phy;
|
||||
int dma_desc_arr_size;
|
||||
|
||||
struct loongson_dma_desc *dma_pos_desc;
|
||||
struct loongson_idma_desc *dma_pos_desc;
|
||||
dma_addr_t dma_pos_desc_phy;
|
||||
};
|
||||
|
||||
static const struct snd_pcm_hardware ls_pcm_hardware = {
|
||||
static const struct snd_pcm_hardware loongson_idma_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
|
|
@ -67,12 +68,11 @@ static const struct snd_pcm_hardware ls_pcm_hardware = {
|
|||
.period_bytes_min = 128,
|
||||
.period_bytes_max = 128 * 1024,
|
||||
.periods_min = 1,
|
||||
.periods_max = PAGE_SIZE / sizeof(struct loongson_dma_desc),
|
||||
.periods_max = PAGE_SIZE / sizeof(struct loongson_idma_desc),
|
||||
.buffer_bytes_max = 1024 * 1024,
|
||||
};
|
||||
|
||||
static struct
|
||||
loongson_dma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
|
||||
static struct loongson_idma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
|
||||
{
|
||||
void __iomem *order_reg = prtd->dma_data->order_addr;
|
||||
u64 val;
|
||||
|
|
@ -88,8 +88,8 @@ loongson_dma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
|
|||
return prtd->dma_pos_desc;
|
||||
}
|
||||
|
||||
static int loongson_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
static int loongson_idma_pcm_trigger(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct loongson_runtime_data *prtd = substream->runtime->private_data;
|
||||
struct device *dev = substream->pcm->card->dev;
|
||||
|
|
@ -131,9 +131,9 @@ static int loongson_pcm_trigger(struct snd_soc_component *component,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
static int loongson_idma_pcm_hw_params(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct device *dev = substream->pcm->card->dev;
|
||||
|
|
@ -141,7 +141,7 @@ static int loongson_pcm_hw_params(struct snd_soc_component *component,
|
|||
size_t buf_len = params_buffer_bytes(params);
|
||||
size_t period_len = params_period_bytes(params);
|
||||
dma_addr_t order_addr, mem_addr;
|
||||
struct loongson_dma_desc *desc;
|
||||
struct loongson_idma_desc *desc;
|
||||
u32 num_periods;
|
||||
int i;
|
||||
|
||||
|
|
@ -195,12 +195,12 @@ static int loongson_pcm_hw_params(struct snd_soc_component *component,
|
|||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
loongson_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
loongson_idma_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct loongson_runtime_data *prtd = runtime->private_data;
|
||||
struct loongson_dma_desc *desc;
|
||||
struct loongson_idma_desc *desc;
|
||||
snd_pcm_uframes_t x;
|
||||
u64 addr;
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ loongson_pcm_pointer(struct snd_soc_component *component,
|
|||
return x;
|
||||
}
|
||||
|
||||
static irqreturn_t loongson_pcm_dma_irq(int irq, void *devid)
|
||||
static irqreturn_t loongson_idma_pcm_dma_irq(int irq, void *devid)
|
||||
{
|
||||
struct snd_pcm_substream *substream = devid;
|
||||
|
||||
|
|
@ -221,14 +221,14 @@ static irqreturn_t loongson_pcm_dma_irq(int irq, void *devid)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int loongson_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
static int loongson_idma_pcm_open(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 snd_card *card = substream->pcm->card;
|
||||
struct loongson_runtime_data *prtd;
|
||||
struct loongson_dma_data *dma_data;
|
||||
struct loongson_idma_data *dma_data;
|
||||
|
||||
/*
|
||||
* For mysterious reasons (and despite what the manual says)
|
||||
|
|
@ -241,7 +241,7 @@ static int loongson_pcm_open(struct snd_soc_component *component,
|
|||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
snd_soc_set_runtime_hwparams(substream, &ls_pcm_hardware);
|
||||
snd_soc_set_runtime_hwparams(substream, &loongson_idma_hardware);
|
||||
|
||||
prtd = kzalloc_obj(*prtd);
|
||||
if (!prtd)
|
||||
|
|
@ -277,8 +277,8 @@ static int loongson_pcm_open(struct snd_soc_component *component,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int loongson_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
static int loongson_idma_pcm_close(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_card *card = substream->pcm->card;
|
||||
struct loongson_runtime_data *prtd = substream->runtime->private_data;
|
||||
|
|
@ -293,21 +293,21 @@ static int loongson_pcm_close(struct snd_soc_component *component,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
static int loongson_idma_pcm_mmap(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return remap_pfn_range(vma, vma->vm_start,
|
||||
substream->dma_buffer.addr >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
substream->dma_buffer.addr >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static int loongson_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
static int loongson_idma_pcm_new(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_pcm_substream *substream;
|
||||
struct loongson_dma_data *dma_data;
|
||||
struct loongson_idma_data *dma_data;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ static int loongson_pcm_new(struct snd_soc_component *component,
|
|||
dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0),
|
||||
substream);
|
||||
ret = devm_request_irq(card->dev, dma_data->irq,
|
||||
loongson_pcm_dma_irq,
|
||||
loongson_idma_pcm_dma_irq,
|
||||
IRQF_TRIGGER_HIGH, LS_I2S_DRVNAME,
|
||||
substream);
|
||||
if (ret < 0) {
|
||||
|
|
@ -330,16 +330,76 @@ static int loongson_pcm_new(struct snd_soc_component *component,
|
|||
|
||||
return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
|
||||
card->dev,
|
||||
ls_pcm_hardware.buffer_bytes_max);
|
||||
loongson_idma_hardware.buffer_bytes_max);
|
||||
}
|
||||
|
||||
const struct snd_soc_component_driver loongson_i2s_component = {
|
||||
/* Internal DMA component */
|
||||
const struct snd_soc_component_driver loongson_i2s_idma_component = {
|
||||
.name = LS_I2S_DRVNAME,
|
||||
.open = loongson_pcm_open,
|
||||
.close = loongson_pcm_close,
|
||||
.hw_params = loongson_pcm_hw_params,
|
||||
.trigger = loongson_pcm_trigger,
|
||||
.pointer = loongson_pcm_pointer,
|
||||
.mmap = loongson_pcm_mmap,
|
||||
.pcm_new = loongson_pcm_new,
|
||||
.open = loongson_idma_pcm_open,
|
||||
.close = loongson_idma_pcm_close,
|
||||
.hw_params = loongson_idma_pcm_hw_params,
|
||||
.trigger = loongson_idma_pcm_trigger,
|
||||
.pointer = loongson_idma_pcm_pointer,
|
||||
.mmap = loongson_idma_pcm_mmap,
|
||||
.pcm_new = loongson_idma_pcm_new,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(loongson_i2s_idma_component);
|
||||
|
||||
static const struct snd_pcm_hardware loongson_edma_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_PAUSE,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.period_bytes_min = 128,
|
||||
.period_bytes_max = 128 * 1024,
|
||||
.periods_min = 1,
|
||||
.periods_max = 64,
|
||||
.buffer_bytes_max = 1024 * 1024,
|
||||
};
|
||||
|
||||
const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &loongson_edma_hardware,
|
||||
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
.prealloc_buffer_size = 128 * 1024,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(loongson_dmaengine_pcm_config);
|
||||
|
||||
/* External DMA component */
|
||||
static int loongson_edma_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
if (substream->pcm->device & 1) {
|
||||
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
|
||||
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
|
||||
}
|
||||
|
||||
if (substream->pcm->device & 2)
|
||||
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID);
|
||||
/*
|
||||
* For mysterious reasons (and despite what the manual says)
|
||||
* playback samples are lost if the DMA count is not a multiple
|
||||
* of the DMA burst size. Let's add a rule to enforce that.
|
||||
*/
|
||||
snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
|
||||
snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_component_driver loongson_i2s_edma_component = {
|
||||
.name = LS_I2S_DRVNAME,
|
||||
.open = loongson_edma_pcm_open,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(loongson_i2s_edma_component);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
#ifndef _LOONGSON_DMA_H
|
||||
#define _LOONGSON_DMA_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
extern const struct snd_soc_component_driver loongson_i2s_component;
|
||||
extern const struct snd_soc_component_driver loongson_i2s_idma_component;
|
||||
extern const struct snd_soc_component_driver loongson_i2s_edma_component;
|
||||
extern const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ static int i2s_suspend(struct device *dev)
|
|||
struct loongson_i2s *i2s = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(i2s->regmap, true);
|
||||
regcache_mark_dirty(i2s->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -263,7 +264,7 @@ static int i2s_resume(struct device *dev)
|
|||
struct loongson_i2s *i2s = dev_get_drvdata(dev);
|
||||
|
||||
regcache_cache_only(i2s->regmap, false);
|
||||
regcache_mark_dirty(i2s->regmap);
|
||||
|
||||
return regcache_sync(i2s->regmap);
|
||||
}
|
||||
|
||||
|
|
@ -272,5 +273,58 @@ const struct dev_pm_ops loongson_i2s_pm = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(loongson_i2s_pm);
|
||||
|
||||
static bool loongson_i2s_rd_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_VER:
|
||||
case LS_I2S_CFG:
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
case LS_I2S_CFG1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_CFG:
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
case LS_I2S_CFG1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool loongson_i2s_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
const struct regmap_config loongson_i2s_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = LS_I2S_CFG1,
|
||||
.readable_reg = loongson_i2s_rd_reg,
|
||||
.writeable_reg = loongson_i2s_wr_reg,
|
||||
.volatile_reg = loongson_i2s_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(loongson_i2s_regmap_config);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Common functions for loongson I2S controller driver");
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
#define LS_I2S_DRVNAME "loongson-i2s"
|
||||
|
||||
struct loongson_dma_data {
|
||||
struct loongson_idma_data {
|
||||
dma_addr_t dev_addr; /* device physical address for DMA */
|
||||
void __iomem *order_addr; /* DMA order register */
|
||||
int irq; /* DMA irq */
|
||||
|
|
@ -52,11 +52,11 @@ struct loongson_i2s {
|
|||
struct device *dev;
|
||||
union {
|
||||
struct snd_dmaengine_dai_dma_data playback_dma_data;
|
||||
struct loongson_dma_data tx_dma_data;
|
||||
struct loongson_idma_data tx_dma_data;
|
||||
};
|
||||
union {
|
||||
struct snd_dmaengine_dai_dma_data capture_dma_data;
|
||||
struct loongson_dma_data rx_dma_data;
|
||||
struct loongson_idma_data rx_dma_data;
|
||||
};
|
||||
struct regmap *regmap;
|
||||
void __iomem *reg_base;
|
||||
|
|
@ -65,6 +65,7 @@ struct loongson_i2s {
|
|||
u32 sysclk;
|
||||
};
|
||||
|
||||
extern const struct regmap_config loongson_i2s_regmap_config;
|
||||
extern const struct dev_pm_ops loongson_i2s_pm;
|
||||
extern struct snd_soc_dai_driver loongson_i2s_dai;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,70 +13,17 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "loongson_i2s.h"
|
||||
#include "loongson_dma.h"
|
||||
|
||||
#define DRIVER_NAME "loongson-i2s-pci"
|
||||
|
||||
static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_CFG:
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
case LS_I2S_CFG1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool loongson_i2s_rd_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_VER:
|
||||
case LS_I2S_CFG:
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
case LS_I2S_CFG1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool loongson_i2s_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case LS_I2S_CFG:
|
||||
case LS_I2S_CTRL:
|
||||
case LS_I2S_RX_DATA:
|
||||
case LS_I2S_TX_DATA:
|
||||
case LS_I2S_CFG1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static const struct regmap_config loongson_i2s_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = LS_I2S_CFG1,
|
||||
.writeable_reg = loongson_i2s_wr_reg,
|
||||
.readable_reg = loongson_i2s_rd_reg,
|
||||
.volatile_reg = loongson_i2s_volatile_reg,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int loongson_i2s_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *pid)
|
||||
{
|
||||
const struct fwnode_handle *fwnode = pdev->dev.fwnode;
|
||||
struct loongson_dma_data *tx_data, *rx_data;
|
||||
struct loongson_idma_data *tx_data, *rx_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct loongson_i2s *i2s;
|
||||
int ret;
|
||||
|
|
@ -133,7 +80,7 @@ static int loongson_i2s_pci_probe(struct pci_dev *pdev,
|
|||
udelay(200);
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &loongson_i2s_component,
|
||||
ret = devm_snd_soc_register_component(dev, &loongson_i2s_idma_component,
|
||||
&loongson_i2s_dai, 1);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "register DAI failed\n");
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <sound/soc.h>
|
||||
|
||||
#include "loongson_i2s.h"
|
||||
#include "loongson_dma.h"
|
||||
|
||||
#define LOONGSON_I2S_RX_DMA_OFFSET 21
|
||||
#define LOONGSON_I2S_TX_DMA_OFFSET 18
|
||||
|
|
@ -29,70 +30,6 @@
|
|||
#define LOONGSON_DMA3_CONF 0x3
|
||||
#define LOONGSON_DMA4_CONF 0x4
|
||||
|
||||
/* periods_max = PAGE_SIZE / sizeof(struct ls_dma_chan_reg) */
|
||||
static const struct snd_pcm_hardware loongson_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_PAUSE,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.period_bytes_min = 128,
|
||||
.period_bytes_max = 128 * 1024,
|
||||
.periods_min = 1,
|
||||
.periods_max = 64,
|
||||
.buffer_bytes_max = 1024 * 1024,
|
||||
};
|
||||
|
||||
static const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &loongson_pcm_hardware,
|
||||
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
.prealloc_buffer_size = 128 * 1024,
|
||||
};
|
||||
|
||||
static int loongson_pcm_open(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
if (substream->pcm->device & 1) {
|
||||
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
|
||||
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
|
||||
}
|
||||
|
||||
if (substream->pcm->device & 2)
|
||||
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID);
|
||||
/*
|
||||
* For mysterious reasons (and despite what the manual says)
|
||||
* playback samples are lost if the DMA count is not a multiple
|
||||
* of the DMA burst size. Let's add a rule to enforce that.
|
||||
*/
|
||||
snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
|
||||
snd_pcm_hw_constraint_step(runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
|
||||
snd_pcm_hw_constraint_integer(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver loongson_i2s_component_driver = {
|
||||
.name = LS_I2S_DRVNAME,
|
||||
.open = loongson_pcm_open,
|
||||
};
|
||||
|
||||
static const struct regmap_config loongson_i2s_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0x14,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
|
||||
{
|
||||
int val;
|
||||
|
|
@ -155,7 +92,7 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
|
|||
dev_set_name(dev, LS_I2S_DRVNAME);
|
||||
dev_set_drvdata(dev, i2s);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &loongson_i2s_component_driver,
|
||||
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
|
||||
&loongson_i2s_dai, 1);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to register DAI\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user