Skip to content

Commit d1712cd

Browse files
committed
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
2 parents aec0d8c + 767a1b5 commit d1712cd

8 files changed

Lines changed: 182 additions & 174 deletions

File tree

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15051,6 +15051,15 @@ F: arch/loongarch/
1505115051
F: drivers/*/*loongarch*
1505215052
F: drivers/cpufreq/loongson3_cpufreq.c
1505315053

15054+
LOONGSON AUDIO (ASoC) DRIVERS
15055+
M: Binbin Zhou <zhoubinbin@loongson.cn>
15056+
L: linux-sound@vger.kernel.org
15057+
S: Maintained
15058+
F: Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
15059+
F: Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
15060+
F: sound/soc/loongson/loongson_*.c
15061+
F: sound/soc/loongson/loongson_*.h
15062+
1505415063
LOONGSON GPIO DRIVER
1505515064
M: Yinbo Zhu <zhuyinbo@loongson.cn>
1505615065
L: linux-gpio@vger.kernel.org

sound/soc/loongson/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# SPDX-License-Identifier: GPL-2.0
22
#Platform Support
3-
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o
3+
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o
44
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o
55

66
snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o
77
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o
88

9-
snd-soc-loongson-i2s-y := loongson_i2s.o
9+
snd-soc-loongson-i2s-y := loongson_i2s.o loongson_dma.o
1010

1111
obj-$(CONFIG_SND_LOONGSON1_AC97) += loongson1_ac97.o
1212

sound/soc/loongson/loongson_dma.c

Lines changed: 104 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// Copyright (C) 2023 Loongson Technology Corporation Limited
66
// Author: Yingkun Meng <mengyingkun@loongson.cn>
7+
// Binbin ZHou <zhoubinbin@loongson.cn>
78
//
89

910
#include <linux/module.h>
@@ -16,7 +17,7 @@
1617
#include <sound/pcm_params.h>
1718
#include "loongson_i2s.h"
1819

19-
/* DMA dma_order Register */
20+
/* Internal DMA dma_order Register */
2021
#define DMA_ORDER_STOP BIT(4) /* DMA stop */
2122
#define DMA_ORDER_START BIT(3) /* DMA start */
2223
#define DMA_ORDER_ASK_VALID BIT(2) /* DMA ask valid flag */
@@ -27,9 +28,9 @@
2728
#define DMA_ORDER_CTRL_MASK (0x0fUL) /* Control mask */
2829

2930
/*
30-
* DMA registers descriptor.
31+
* Internal DMA registers descriptor.
3132
*/
32-
struct loongson_dma_desc {
33+
struct loongson_idma_desc {
3334
u32 order; /* Next descriptor address register */
3435
u32 saddr; /* Source address register */
3536
u32 daddr; /* Device address register */
@@ -44,17 +45,17 @@ struct loongson_dma_desc {
4445
} __packed;
4546

4647
struct loongson_runtime_data {
47-
struct loongson_dma_data *dma_data;
48+
struct loongson_idma_data *dma_data;
4849

49-
struct loongson_dma_desc *dma_desc_arr;
50+
struct loongson_idma_desc *dma_desc_arr;
5051
dma_addr_t dma_desc_arr_phy;
5152
int dma_desc_arr_size;
5253

53-
struct loongson_dma_desc *dma_pos_desc;
54+
struct loongson_idma_desc *dma_pos_desc;
5455
dma_addr_t dma_pos_desc_phy;
5556
};
5657

57-
static const struct snd_pcm_hardware ls_pcm_hardware = {
58+
static const struct snd_pcm_hardware loongson_idma_hardware = {
5859
.info = SNDRV_PCM_INFO_MMAP |
5960
SNDRV_PCM_INFO_INTERLEAVED |
6061
SNDRV_PCM_INFO_MMAP_VALID |
@@ -67,12 +68,11 @@ static const struct snd_pcm_hardware ls_pcm_hardware = {
6768
.period_bytes_min = 128,
6869
.period_bytes_max = 128 * 1024,
6970
.periods_min = 1,
70-
.periods_max = PAGE_SIZE / sizeof(struct loongson_dma_desc),
71+
.periods_max = PAGE_SIZE / sizeof(struct loongson_idma_desc),
7172
.buffer_bytes_max = 1024 * 1024,
7273
};
7374

74-
static struct
75-
loongson_dma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
75+
static struct loongson_idma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
7676
{
7777
void __iomem *order_reg = prtd->dma_data->order_addr;
7878
u64 val;
@@ -88,8 +88,8 @@ loongson_dma_desc *dma_desc_save(struct loongson_runtime_data *prtd)
8888
return prtd->dma_pos_desc;
8989
}
9090

91-
static int loongson_pcm_trigger(struct snd_soc_component *component,
92-
struct snd_pcm_substream *substream, int cmd)
91+
static int loongson_idma_pcm_trigger(struct snd_soc_component *component,
92+
struct snd_pcm_substream *substream, int cmd)
9393
{
9494
struct loongson_runtime_data *prtd = substream->runtime->private_data;
9595
struct device *dev = substream->pcm->card->dev;
@@ -131,17 +131,17 @@ static int loongson_pcm_trigger(struct snd_soc_component *component,
131131
return 0;
132132
}
133133

134-
static int loongson_pcm_hw_params(struct snd_soc_component *component,
135-
struct snd_pcm_substream *substream,
136-
struct snd_pcm_hw_params *params)
134+
static int loongson_idma_pcm_hw_params(struct snd_soc_component *component,
135+
struct snd_pcm_substream *substream,
136+
struct snd_pcm_hw_params *params)
137137
{
138138
struct snd_pcm_runtime *runtime = substream->runtime;
139139
struct device *dev = substream->pcm->card->dev;
140140
struct loongson_runtime_data *prtd = runtime->private_data;
141141
size_t buf_len = params_buffer_bytes(params);
142142
size_t period_len = params_period_bytes(params);
143143
dma_addr_t order_addr, mem_addr;
144-
struct loongson_dma_desc *desc;
144+
struct loongson_idma_desc *desc;
145145
u32 num_periods;
146146
int i;
147147

@@ -195,12 +195,12 @@ static int loongson_pcm_hw_params(struct snd_soc_component *component,
195195
}
196196

197197
static snd_pcm_uframes_t
198-
loongson_pcm_pointer(struct snd_soc_component *component,
199-
struct snd_pcm_substream *substream)
198+
loongson_idma_pcm_pointer(struct snd_soc_component *component,
199+
struct snd_pcm_substream *substream)
200200
{
201201
struct snd_pcm_runtime *runtime = substream->runtime;
202202
struct loongson_runtime_data *prtd = runtime->private_data;
203-
struct loongson_dma_desc *desc;
203+
struct loongson_idma_desc *desc;
204204
snd_pcm_uframes_t x;
205205
u64 addr;
206206

@@ -213,22 +213,22 @@ loongson_pcm_pointer(struct snd_soc_component *component,
213213
return x;
214214
}
215215

216-
static irqreturn_t loongson_pcm_dma_irq(int irq, void *devid)
216+
static irqreturn_t loongson_idma_pcm_dma_irq(int irq, void *devid)
217217
{
218218
struct snd_pcm_substream *substream = devid;
219219

220220
snd_pcm_period_elapsed(substream);
221221
return IRQ_HANDLED;
222222
}
223223

224-
static int loongson_pcm_open(struct snd_soc_component *component,
225-
struct snd_pcm_substream *substream)
224+
static int loongson_idma_pcm_open(struct snd_soc_component *component,
225+
struct snd_pcm_substream *substream)
226226
{
227227
struct snd_pcm_runtime *runtime = substream->runtime;
228228
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
229229
struct snd_card *card = substream->pcm->card;
230230
struct loongson_runtime_data *prtd;
231-
struct loongson_dma_data *dma_data;
231+
struct loongson_idma_data *dma_data;
232232

233233
/*
234234
* For mysterious reasons (and despite what the manual says)
@@ -241,7 +241,7 @@ static int loongson_pcm_open(struct snd_soc_component *component,
241241
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
242242
snd_pcm_hw_constraint_integer(substream->runtime,
243243
SNDRV_PCM_HW_PARAM_PERIODS);
244-
snd_soc_set_runtime_hwparams(substream, &ls_pcm_hardware);
244+
snd_soc_set_runtime_hwparams(substream, &loongson_idma_hardware);
245245

246246
prtd = kzalloc_obj(*prtd);
247247
if (!prtd)
@@ -277,8 +277,8 @@ static int loongson_pcm_open(struct snd_soc_component *component,
277277
return -ENOMEM;
278278
}
279279

280-
static int loongson_pcm_close(struct snd_soc_component *component,
281-
struct snd_pcm_substream *substream)
280+
static int loongson_idma_pcm_close(struct snd_soc_component *component,
281+
struct snd_pcm_substream *substream)
282282
{
283283
struct snd_card *card = substream->pcm->card;
284284
struct loongson_runtime_data *prtd = substream->runtime->private_data;
@@ -293,21 +293,21 @@ static int loongson_pcm_close(struct snd_soc_component *component,
293293
return 0;
294294
}
295295

296-
static int loongson_pcm_mmap(struct snd_soc_component *component,
297-
struct snd_pcm_substream *substream,
298-
struct vm_area_struct *vma)
296+
static int loongson_idma_pcm_mmap(struct snd_soc_component *component,
297+
struct snd_pcm_substream *substream,
298+
struct vm_area_struct *vma)
299299
{
300300
return remap_pfn_range(vma, vma->vm_start,
301-
substream->dma_buffer.addr >> PAGE_SHIFT,
302-
vma->vm_end - vma->vm_start, vma->vm_page_prot);
301+
substream->dma_buffer.addr >> PAGE_SHIFT,
302+
vma->vm_end - vma->vm_start, vma->vm_page_prot);
303303
}
304304

305-
static int loongson_pcm_new(struct snd_soc_component *component,
306-
struct snd_soc_pcm_runtime *rtd)
305+
static int loongson_idma_pcm_new(struct snd_soc_component *component,
306+
struct snd_soc_pcm_runtime *rtd)
307307
{
308308
struct snd_card *card = rtd->card->snd_card;
309309
struct snd_pcm_substream *substream;
310-
struct loongson_dma_data *dma_data;
310+
struct loongson_idma_data *dma_data;
311311
unsigned int i;
312312
int ret;
313313

@@ -319,7 +319,7 @@ static int loongson_pcm_new(struct snd_soc_component *component,
319319
dma_data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0),
320320
substream);
321321
ret = devm_request_irq(card->dev, dma_data->irq,
322-
loongson_pcm_dma_irq,
322+
loongson_idma_pcm_dma_irq,
323323
IRQF_TRIGGER_HIGH, LS_I2S_DRVNAME,
324324
substream);
325325
if (ret < 0) {
@@ -330,16 +330,76 @@ static int loongson_pcm_new(struct snd_soc_component *component,
330330

331331
return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
332332
card->dev,
333-
ls_pcm_hardware.buffer_bytes_max);
333+
loongson_idma_hardware.buffer_bytes_max);
334334
}
335335

336-
const struct snd_soc_component_driver loongson_i2s_component = {
336+
/* Internal DMA component */
337+
const struct snd_soc_component_driver loongson_i2s_idma_component = {
337338
.name = LS_I2S_DRVNAME,
338-
.open = loongson_pcm_open,
339-
.close = loongson_pcm_close,
340-
.hw_params = loongson_pcm_hw_params,
341-
.trigger = loongson_pcm_trigger,
342-
.pointer = loongson_pcm_pointer,
343-
.mmap = loongson_pcm_mmap,
344-
.pcm_new = loongson_pcm_new,
339+
.open = loongson_idma_pcm_open,
340+
.close = loongson_idma_pcm_close,
341+
.hw_params = loongson_idma_pcm_hw_params,
342+
.trigger = loongson_idma_pcm_trigger,
343+
.pointer = loongson_idma_pcm_pointer,
344+
.mmap = loongson_idma_pcm_mmap,
345+
.pcm_new = loongson_idma_pcm_new,
346+
};
347+
EXPORT_SYMBOL_GPL(loongson_i2s_idma_component);
348+
349+
static const struct snd_pcm_hardware loongson_edma_hardware = {
350+
.info = SNDRV_PCM_INFO_MMAP |
351+
SNDRV_PCM_INFO_INTERLEAVED |
352+
SNDRV_PCM_INFO_MMAP_VALID |
353+
SNDRV_PCM_INFO_RESUME |
354+
SNDRV_PCM_INFO_PAUSE,
355+
.formats = SNDRV_PCM_FMTBIT_S16_LE |
356+
SNDRV_PCM_FMTBIT_S20_3LE |
357+
SNDRV_PCM_FMTBIT_S24_LE,
358+
.period_bytes_min = 128,
359+
.period_bytes_max = 128 * 1024,
360+
.periods_min = 1,
361+
.periods_max = 64,
362+
.buffer_bytes_max = 1024 * 1024,
363+
};
364+
365+
const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
366+
.pcm_hardware = &loongson_edma_hardware,
367+
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
368+
.prealloc_buffer_size = 128 * 1024,
369+
};
370+
EXPORT_SYMBOL_GPL(loongson_dmaengine_pcm_config);
371+
372+
/* External DMA component */
373+
static int loongson_edma_pcm_open(struct snd_soc_component *component,
374+
struct snd_pcm_substream *substream)
375+
{
376+
struct snd_pcm_runtime *runtime = substream->runtime;
377+
378+
if (substream->pcm->device & 1) {
379+
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
380+
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
381+
}
382+
383+
if (substream->pcm->device & 2)
384+
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
385+
SNDRV_PCM_INFO_MMAP_VALID);
386+
/*
387+
* For mysterious reasons (and despite what the manual says)
388+
* playback samples are lost if the DMA count is not a multiple
389+
* of the DMA burst size. Let's add a rule to enforce that.
390+
*/
391+
snd_pcm_hw_constraint_step(runtime, 0,
392+
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
393+
snd_pcm_hw_constraint_step(runtime, 0,
394+
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
395+
snd_pcm_hw_constraint_integer(substream->runtime,
396+
SNDRV_PCM_HW_PARAM_PERIODS);
397+
398+
return 0;
399+
}
400+
401+
const struct snd_soc_component_driver loongson_i2s_edma_component = {
402+
.name = LS_I2S_DRVNAME,
403+
.open = loongson_edma_pcm_open,
345404
};
405+
EXPORT_SYMBOL_GPL(loongson_i2s_edma_component);

sound/soc/loongson/loongson_dma.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#ifndef _LOONGSON_DMA_H
1010
#define _LOONGSON_DMA_H
1111

12-
#include <sound/soc.h>
13-
14-
extern const struct snd_soc_component_driver loongson_i2s_component;
12+
extern const struct snd_soc_component_driver loongson_i2s_idma_component;
13+
extern const struct snd_soc_component_driver loongson_i2s_edma_component;
14+
extern const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config;
1515

1616
#endif

0 commit comments

Comments
 (0)