Skip to content

Commit 79361b2

Browse files
joabreubroonie
authored andcommitted
ASoC: dwc: Add PIO PCM extension
A PCM extension was added to I2S driver so that audio samples are transferred using PIO mode. The PCM supports two channels @ 16 or 32 bits with rates 32k, 44.1k and 48k. Although the mainline I2S driver uses ALSA DMA engine the I2S controller can be built without DMA support, therefore this is the reason why this extension was added. Signed-off-by: Jose Abreu <[email protected]> Cc: Carlos Palminha <[email protected]> Cc: Mark Brown <[email protected]> Cc: Liam Girdwood <[email protected]> Cc: Jaroslav Kysela <[email protected]> Cc: Takashi Iwai <[email protected]> Cc: Rob Herring <[email protected]> Cc: Alexey Brodkin <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent b1d32fe commit 79361b2

File tree

5 files changed

+436
-88
lines changed

5 files changed

+436
-88
lines changed

sound/soc/dwc/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,13 @@ config SND_DESIGNWARE_I2S
77
Synopsys desigwnware I2S device. The device supports upto
88
maximum of 8 channels each for play and record.
99

10+
config SND_DESIGNWARE_PCM
11+
tristate "PCM PIO extension for I2S driver"
12+
depends on SND_DESIGNWARE_I2S
13+
help
14+
Say Y, M or N if you want to add a custom ALSA extension that registers
15+
a PCM and uses PIO to transfer data.
16+
17+
This functionality is specially suited for I2S devices that don't have
18+
DMA support.
1019

sound/soc/dwc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SYNOPSYS Platform Support
22
obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
3+
obj-$(CONFIG_SND_DESIGNWARE_PCM) += designware_pcm.o
34

sound/soc/dwc/designware_i2s.c

Lines changed: 73 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -24,90 +24,7 @@
2424
#include <sound/pcm_params.h>
2525
#include <sound/soc.h>
2626
#include <sound/dmaengine_pcm.h>
27-
28-
/* common register for all channel */
29-
#define IER 0x000
30-
#define IRER 0x004
31-
#define ITER 0x008
32-
#define CER 0x00C
33-
#define CCR 0x010
34-
#define RXFFR 0x014
35-
#define TXFFR 0x018
36-
37-
/* I2STxRxRegisters for all channels */
38-
#define LRBR_LTHR(x) (0x40 * x + 0x020)
39-
#define RRBR_RTHR(x) (0x40 * x + 0x024)
40-
#define RER(x) (0x40 * x + 0x028)
41-
#define TER(x) (0x40 * x + 0x02C)
42-
#define RCR(x) (0x40 * x + 0x030)
43-
#define TCR(x) (0x40 * x + 0x034)
44-
#define ISR(x) (0x40 * x + 0x038)
45-
#define IMR(x) (0x40 * x + 0x03C)
46-
#define ROR(x) (0x40 * x + 0x040)
47-
#define TOR(x) (0x40 * x + 0x044)
48-
#define RFCR(x) (0x40 * x + 0x048)
49-
#define TFCR(x) (0x40 * x + 0x04C)
50-
#define RFF(x) (0x40 * x + 0x050)
51-
#define TFF(x) (0x40 * x + 0x054)
52-
53-
/* I2SCOMPRegisters */
54-
#define I2S_COMP_PARAM_2 0x01F0
55-
#define I2S_COMP_PARAM_1 0x01F4
56-
#define I2S_COMP_VERSION 0x01F8
57-
#define I2S_COMP_TYPE 0x01FC
58-
59-
/*
60-
* Component parameter register fields - define the I2S block's
61-
* configuration.
62-
*/
63-
#define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25)
64-
#define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22)
65-
#define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19)
66-
#define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16)
67-
#define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9)
68-
#define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7)
69-
#define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6)
70-
#define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5)
71-
#define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4)
72-
#define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2)
73-
#define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0)
74-
75-
#define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10)
76-
#define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7)
77-
#define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3)
78-
#define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0)
79-
80-
/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */
81-
#define COMP_MAX_WORDSIZE (1 << 3)
82-
#define COMP_MAX_DATA_WIDTH (1 << 2)
83-
84-
#define MAX_CHANNEL_NUM 8
85-
#define MIN_CHANNEL_NUM 2
86-
87-
union dw_i2s_snd_dma_data {
88-
struct i2s_dma_data pd;
89-
struct snd_dmaengine_dai_dma_data dt;
90-
};
91-
92-
struct dw_i2s_dev {
93-
void __iomem *i2s_base;
94-
struct clk *clk;
95-
int active;
96-
unsigned int capability;
97-
unsigned int quirks;
98-
unsigned int i2s_reg_comp1;
99-
unsigned int i2s_reg_comp2;
100-
struct device *dev;
101-
u32 ccr;
102-
u32 xfer_resolution;
103-
u32 fifo_th;
104-
105-
/* data related to DMA transfers b/w i2s and DMAC */
106-
union dw_i2s_snd_dma_data play_dma_data;
107-
union dw_i2s_snd_dma_data capture_dma_data;
108-
struct i2s_clk_config_data config;
109-
int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
110-
};
27+
#include "local.h"
11128

11229
static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
11330
{
@@ -181,6 +98,52 @@ static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream,
18198
}
18299
}
183100

101+
static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
102+
{
103+
struct dw_i2s_dev *dev = dev_id;
104+
bool irq_valid = false;
105+
u32 isr[4];
106+
int i;
107+
108+
for (i = 0; i < 4; i++)
109+
isr[i] = i2s_read_reg(dev->i2s_base, ISR(i));
110+
111+
i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
112+
i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE);
113+
114+
for (i = 0; i < 4; i++) {
115+
/*
116+
* Check if TX fifo is empty. If empty fill FIFO with samples
117+
* NOTE: Only two channels supported
118+
*/
119+
if ((isr[i] & ISR_TXFE) && (i == 0) && dev->use_pio) {
120+
dw_pcm_push_tx(dev);
121+
irq_valid = true;
122+
}
123+
124+
/* Data available. Record mode not supported in PIO mode */
125+
if (isr[i] & ISR_RXDA)
126+
irq_valid = true;
127+
128+
/* Error Handling: TX */
129+
if (isr[i] & ISR_TXFO) {
130+
dev_err(dev->dev, "TX overrun (ch_id=%d)\n", i);
131+
irq_valid = true;
132+
}
133+
134+
/* Error Handling: TX */
135+
if (isr[i] & ISR_RXFO) {
136+
dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i);
137+
irq_valid = true;
138+
}
139+
}
140+
141+
if (irq_valid)
142+
return IRQ_HANDLED;
143+
else
144+
return IRQ_NONE;
145+
}
146+
184147
static void i2s_start(struct dw_i2s_dev *dev,
185148
struct snd_pcm_substream *substream)
186149
{
@@ -640,7 +603,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
640603
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
641604
struct dw_i2s_dev *dev;
642605
struct resource *res;
643-
int ret;
606+
int ret, irq;
644607
struct snd_soc_dai_driver *dw_i2s_dai;
645608
const char *clk_id;
646609

@@ -665,6 +628,16 @@ static int dw_i2s_probe(struct platform_device *pdev)
665628

666629
dev->dev = &pdev->dev;
667630

631+
irq = platform_get_irq(pdev, 0);
632+
if (irq >= 0) {
633+
ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
634+
pdev->name, dev);
635+
if (ret < 0) {
636+
dev_err(&pdev->dev, "failed to request irq\n");
637+
return ret;
638+
}
639+
}
640+
668641
dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
669642
dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
670643
if (pdata) {
@@ -711,12 +684,24 @@ static int dw_i2s_probe(struct platform_device *pdev)
711684

712685
if (!pdata) {
713686
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
714-
if (ret) {
687+
if (ret == -EPROBE_DEFER) {
688+
dev_err(&pdev->dev,
689+
"failed to register PCM, deferring probe\n");
690+
return ret;
691+
} else if (ret) {
715692
dev_err(&pdev->dev,
716-
"Could not register PCM: %d\n", ret);
717-
goto err_clk_disable;
693+
"Could not register DMA PCM: %d\n"
694+
"falling back to PIO mode\n", ret);
695+
ret = dw_pcm_register(pdev);
696+
if (ret) {
697+
dev_err(&pdev->dev,
698+
"Could not register PIO PCM: %d\n",
699+
ret);
700+
goto err_clk_disable;
701+
}
718702
}
719703
}
704+
720705
pm_runtime_enable(&pdev->dev);
721706
return 0;
722707

0 commit comments

Comments
 (0)