aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Abreu <Jose.Abreu@synopsys.com>2016-06-09 07:47:05 -0400
committerMark Brown <broonie@kernel.org>2016-06-13 12:52:00 -0400
commit79361b2b98b7b64bcf71e0aa4e4dac497bcb94bc (patch)
tree96626073b00934428d9d85f2a2e2937396f01df3
parentb1d32feb9a1c0d26d1749519d598b676bc7b5d80 (diff)
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 <joabreu@synopsys.com> Cc: Carlos Palminha <palminha@synopsys.com> Cc: Mark Brown <broonie@kernel.org> Cc: Liam Girdwood <lgirdwood@gmail.com> Cc: Jaroslav Kysela <perex@perex.cz> Cc: Takashi Iwai <tiwai@suse.com> Cc: Rob Herring <robh@kernel.org> Cc: Alexey Brodkin <abrodkin@synopsys.com> Cc: linux-snps-arc@lists.infradead.org Cc: alsa-devel@alsa-project.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/dwc/Kconfig9
-rw-r--r--sound/soc/dwc/Makefile1
-rw-r--r--sound/soc/dwc/designware_i2s.c161
-rw-r--r--sound/soc/dwc/designware_pcm.c225
-rw-r--r--sound/soc/dwc/local.h128
5 files changed, 436 insertions, 88 deletions
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index d50e08517dce..c297efe43861 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -7,4 +7,13 @@ config SND_DESIGNWARE_I2S
7 Synopsys desigwnware I2S device. The device supports upto 7 Synopsys desigwnware I2S device. The device supports upto
8 maximum of 8 channels each for play and record. 8 maximum of 8 channels each for play and record.
9 9
10config 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.
10 19
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile
index 319371f690f4..1b48bcccbc51 100644
--- a/sound/soc/dwc/Makefile
+++ b/sound/soc/dwc/Makefile
@@ -1,3 +1,4 @@
1# SYNOPSYS Platform Support 1# SYNOPSYS Platform Support
2obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o 2obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
3obj-$(CONFIG_SND_DESIGNWARE_PCM) += designware_pcm.o
3 4
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 4c4f0dc24f10..591854e97190 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -24,90 +24,7 @@
24#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
25#include <sound/soc.h> 25#include <sound/soc.h>
26#include <sound/dmaengine_pcm.h> 26#include <sound/dmaengine_pcm.h>
27 27#include "local.h"
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
87union dw_i2s_snd_dma_data {
88 struct i2s_dma_data pd;
89 struct snd_dmaengine_dai_dma_data dt;
90};
91
92struct 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};
111 28
112static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val) 29static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
113{ 30{
@@ -181,6 +98,52 @@ static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream,
181 } 98 }
182} 99}
183 100
101static 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
184static void i2s_start(struct dw_i2s_dev *dev, 147static void i2s_start(struct dw_i2s_dev *dev,
185 struct snd_pcm_substream *substream) 148 struct snd_pcm_substream *substream)
186{ 149{
@@ -640,7 +603,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
640 const struct i2s_platform_data *pdata = pdev->dev.platform_data; 603 const struct i2s_platform_data *pdata = pdev->dev.platform_data;
641 struct dw_i2s_dev *dev; 604 struct dw_i2s_dev *dev;
642 struct resource *res; 605 struct resource *res;
643 int ret; 606 int ret, irq;
644 struct snd_soc_dai_driver *dw_i2s_dai; 607 struct snd_soc_dai_driver *dw_i2s_dai;
645 const char *clk_id; 608 const char *clk_id;
646 609
@@ -665,6 +628,16 @@ static int dw_i2s_probe(struct platform_device *pdev)
665 628
666 dev->dev = &pdev->dev; 629 dev->dev = &pdev->dev;
667 630
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
668 dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; 641 dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
669 dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; 642 dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
670 if (pdata) { 643 if (pdata) {
@@ -711,12 +684,24 @@ static int dw_i2s_probe(struct platform_device *pdev)
711 684
712 if (!pdata) { 685 if (!pdata) {
713 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 686 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) {
715 dev_err(&pdev->dev, 692 dev_err(&pdev->dev,
716 "Could not register PCM: %d\n", ret); 693 "Could not register DMA PCM: %d\n"
717 goto err_clk_disable; 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 }
718 } 702 }
719 } 703 }
704
720 pm_runtime_enable(&pdev->dev); 705 pm_runtime_enable(&pdev->dev);
721 return 0; 706 return 0;
722 707
diff --git a/sound/soc/dwc/designware_pcm.c b/sound/soc/dwc/designware_pcm.c
new file mode 100644
index 000000000000..4a83a22fa3cb
--- /dev/null
+++ b/sound/soc/dwc/designware_pcm.c
@@ -0,0 +1,225 @@
1/*
2 * ALSA SoC Synopsys PIO PCM for I2S driver
3 *
4 * sound/soc/dwc/designware_pcm.c
5 *
6 * Copyright (C) 2016 Synopsys
7 * Jose Abreu <joabreu@synopsys.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#include <linux/io.h>
15#include <linux/rcupdate.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include "local.h"
19
20#define BUFFER_BYTES_MAX (3 * 2 * 8 * PERIOD_BYTES_MIN)
21#define PERIOD_BYTES_MIN 4096
22#define PERIODS_MIN 2
23
24#define dw_pcm_tx_fn(sample_bits) \
25static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
26 struct snd_pcm_runtime *runtime, unsigned int tx_ptr, \
27 bool *period_elapsed) \
28{ \
29 const u##sample_bits (*p)[2] = (void *)runtime->dma_area; \
30 unsigned int period_pos = tx_ptr % runtime->period_size; \
31 int i; \
32\
33 for (i = 0; i < dev->fifo_th; i++) { \
34 iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \
35 iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \
36 period_pos++; \
37 if (++tx_ptr >= runtime->buffer_size) \
38 tx_ptr = 0; \
39 } \
40 *period_elapsed = period_pos >= runtime->period_size; \
41 return tx_ptr; \
42}
43
44dw_pcm_tx_fn(16);
45dw_pcm_tx_fn(32);
46
47#undef dw_pcm_tx_fn
48
49static const struct snd_pcm_hardware dw_pcm_hardware = {
50 .info = SNDRV_PCM_INFO_INTERLEAVED |
51 SNDRV_PCM_INFO_MMAP |
52 SNDRV_PCM_INFO_MMAP_VALID |
53 SNDRV_PCM_INFO_BLOCK_TRANSFER,
54 .rates = SNDRV_PCM_RATE_32000 |
55 SNDRV_PCM_RATE_44100 |
56 SNDRV_PCM_RATE_48000,
57 .rate_min = 32000,
58 .rate_max = 48000,
59 .formats = SNDRV_PCM_FMTBIT_S16_LE |
60 SNDRV_PCM_FMTBIT_S32_LE,
61 .channels_min = 2,
62 .channels_max = 2,
63 .buffer_bytes_max = BUFFER_BYTES_MAX,
64 .period_bytes_min = PERIOD_BYTES_MIN,
65 .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
66 .periods_min = PERIODS_MIN,
67 .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
68 .fifo_size = 16,
69};
70
71void dw_pcm_push_tx(struct dw_i2s_dev *dev)
72{
73 struct snd_pcm_substream *tx_substream;
74 bool tx_active, period_elapsed;
75
76 rcu_read_lock();
77 tx_substream = rcu_dereference(dev->tx_substream);
78 tx_active = tx_substream && snd_pcm_running(tx_substream);
79 if (tx_active) {
80 unsigned int tx_ptr = READ_ONCE(dev->tx_ptr);
81 unsigned int new_tx_ptr = dev->tx_fn(dev, tx_substream->runtime,
82 tx_ptr, &period_elapsed);
83 cmpxchg(&dev->tx_ptr, tx_ptr, new_tx_ptr);
84
85 if (period_elapsed)
86 snd_pcm_period_elapsed(tx_substream);
87 }
88 rcu_read_unlock();
89}
90EXPORT_SYMBOL_GPL(dw_pcm_push_tx);
91
92static int dw_pcm_open(struct snd_pcm_substream *substream)
93{
94 struct snd_pcm_runtime *runtime = substream->runtime;
95 struct snd_soc_pcm_runtime *rtd = substream->private_data;
96 struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
97
98 snd_soc_set_runtime_hwparams(substream, &dw_pcm_hardware);
99 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
100 runtime->private_data = dev;
101
102 return 0;
103}
104
105static int dw_pcm_close(struct snd_pcm_substream *substream)
106{
107 synchronize_rcu();
108 return 0;
109}
110
111static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
112 struct snd_pcm_hw_params *hw_params)
113{
114 struct snd_pcm_runtime *runtime = substream->runtime;
115 struct dw_i2s_dev *dev = runtime->private_data;
116 int ret;
117
118 switch (params_channels(hw_params)) {
119 case 2:
120 break;
121 default:
122 dev_err(dev->dev, "invalid channels number\n");
123 return -EINVAL;
124 }
125
126 switch (params_format(hw_params)) {
127 case SNDRV_PCM_FORMAT_S16_LE:
128 dev->tx_fn = dw_pcm_tx_16;
129 break;
130 case SNDRV_PCM_FORMAT_S32_LE:
131 dev->tx_fn = dw_pcm_tx_32;
132 break;
133 default:
134 dev_err(dev->dev, "invalid format\n");
135 return -EINVAL;
136 }
137
138 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
139 dev_err(dev->dev, "only playback is available\n");
140 return -EINVAL;
141 }
142
143 ret = snd_pcm_lib_malloc_pages(substream,
144 params_buffer_bytes(hw_params));
145 if (ret < 0)
146 return ret;
147 else
148 return 0;
149}
150
151static int dw_pcm_hw_free(struct snd_pcm_substream *substream)
152{
153 return snd_pcm_lib_free_pages(substream);
154}
155
156static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
157{
158 struct snd_pcm_runtime *runtime = substream->runtime;
159 struct dw_i2s_dev *dev = runtime->private_data;
160 int ret = 0;
161
162 switch (cmd) {
163 case SNDRV_PCM_TRIGGER_START:
164 case SNDRV_PCM_TRIGGER_RESUME:
165 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
166 WRITE_ONCE(dev->tx_ptr, 0);
167 rcu_assign_pointer(dev->tx_substream, substream);
168 break;
169 case SNDRV_PCM_TRIGGER_STOP:
170 case SNDRV_PCM_TRIGGER_SUSPEND:
171 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
172 rcu_assign_pointer(dev->tx_substream, NULL);
173 break;
174 default:
175 ret = -EINVAL;
176 break;
177 }
178
179 return ret;
180}
181
182static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
183{
184 struct snd_pcm_runtime *runtime = substream->runtime;
185 struct dw_i2s_dev *dev = runtime->private_data;
186 snd_pcm_uframes_t pos = READ_ONCE(dev->tx_ptr);
187
188 return pos < runtime->buffer_size ? pos : 0;
189}
190
191static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd)
192{
193 size_t size = dw_pcm_hardware.buffer_bytes_max;
194
195 return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
196 SNDRV_DMA_TYPE_CONTINUOUS,
197 snd_dma_continuous_data(GFP_KERNEL), size, size);
198}
199
200static void dw_pcm_free(struct snd_pcm *pcm)
201{
202 snd_pcm_lib_preallocate_free_for_all(pcm);
203}
204
205static const struct snd_pcm_ops dw_pcm_ops = {
206 .open = dw_pcm_open,
207 .close = dw_pcm_close,
208 .ioctl = snd_pcm_lib_ioctl,
209 .hw_params = dw_pcm_hw_params,
210 .hw_free = dw_pcm_hw_free,
211 .trigger = dw_pcm_trigger,
212 .pointer = dw_pcm_pointer,
213};
214
215static const struct snd_soc_platform_driver dw_pcm_platform = {
216 .pcm_new = dw_pcm_new,
217 .pcm_free = dw_pcm_free,
218 .ops = &dw_pcm_ops,
219};
220
221int dw_pcm_register(struct platform_device *pdev)
222{
223 return devm_snd_soc_register_platform(&pdev->dev, &dw_pcm_platform);
224}
225EXPORT_SYMBOL_GPL(dw_pcm_register);
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
new file mode 100644
index 000000000000..68afd7577343
--- /dev/null
+++ b/sound/soc/dwc/local.h
@@ -0,0 +1,128 @@
1/*
2 * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com)
3 *
4 * This file is licensed under the terms of the GNU General Public
5 * License version 2. This program is licensed "as is" without any
6 * warranty of any kind, whether express or implied.
7 */
8
9#ifndef __DESIGNWARE_LOCAL_H
10#define __DESIGNWARE_LOCAL_H
11
12#include <linux/clk.h>
13#include <linux/device.h>
14#include <linux/types.h>
15#include <sound/dmaengine_pcm.h>
16#include <sound/pcm.h>
17#include <sound/designware_i2s.h>
18
19/* common register for all channel */
20#define IER 0x000
21#define IRER 0x004
22#define ITER 0x008
23#define CER 0x00C
24#define CCR 0x010
25#define RXFFR 0x014
26#define TXFFR 0x018
27
28/* Interrupt status register fields */
29#define ISR_TXFO BIT(5)
30#define ISR_TXFE BIT(4)
31#define ISR_RXFO BIT(1)
32#define ISR_RXDA BIT(0)
33
34/* I2STxRxRegisters for all channels */
35#define LRBR_LTHR(x) (0x40 * x + 0x020)
36#define RRBR_RTHR(x) (0x40 * x + 0x024)
37#define RER(x) (0x40 * x + 0x028)
38#define TER(x) (0x40 * x + 0x02C)
39#define RCR(x) (0x40 * x + 0x030)
40#define TCR(x) (0x40 * x + 0x034)
41#define ISR(x) (0x40 * x + 0x038)
42#define IMR(x) (0x40 * x + 0x03C)
43#define ROR(x) (0x40 * x + 0x040)
44#define TOR(x) (0x40 * x + 0x044)
45#define RFCR(x) (0x40 * x + 0x048)
46#define TFCR(x) (0x40 * x + 0x04C)
47#define RFF(x) (0x40 * x + 0x050)
48#define TFF(x) (0x40 * x + 0x054)
49
50/* I2SCOMPRegisters */
51#define I2S_COMP_PARAM_2 0x01F0
52#define I2S_COMP_PARAM_1 0x01F4
53#define I2S_COMP_VERSION 0x01F8
54#define I2S_COMP_TYPE 0x01FC
55
56/*
57 * Component parameter register fields - define the I2S block's
58 * configuration.
59 */
60#define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25)
61#define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22)
62#define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19)
63#define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16)
64#define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9)
65#define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7)
66#define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6)
67#define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5)
68#define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4)
69#define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2)
70#define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0)
71
72#define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10)
73#define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7)
74#define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3)
75#define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0)
76
77/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */
78#define COMP_MAX_WORDSIZE (1 << 3)
79#define COMP_MAX_DATA_WIDTH (1 << 2)
80
81#define MAX_CHANNEL_NUM 8
82#define MIN_CHANNEL_NUM 2
83
84union dw_i2s_snd_dma_data {
85 struct i2s_dma_data pd;
86 struct snd_dmaengine_dai_dma_data dt;
87};
88
89struct dw_i2s_dev {
90 void __iomem *i2s_base;
91 struct clk *clk;
92 int active;
93 unsigned int capability;
94 unsigned int quirks;
95 unsigned int i2s_reg_comp1;
96 unsigned int i2s_reg_comp2;
97 struct device *dev;
98 u32 ccr;
99 u32 xfer_resolution;
100 u32 fifo_th;
101
102 /* data related to DMA transfers b/w i2s and DMAC */
103 union dw_i2s_snd_dma_data play_dma_data;
104 union dw_i2s_snd_dma_data capture_dma_data;
105 struct i2s_clk_config_data config;
106 int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
107
108 /* data related to PIO transfers (TX) */
109 bool use_pio;
110 struct snd_pcm_substream __rcu *tx_substream;
111 unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
112 struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
113 bool *period_elapsed);
114 unsigned int tx_ptr;
115};
116
117#if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM)
118void dw_pcm_push_tx(struct dw_i2s_dev *dev);
119int dw_pcm_register(struct platform_device *pdev);
120#else
121void dw_pcm_push_tx(struct dw_i2s_dev *dev) { }
122int dw_pcm_register(struct platform_device *pdev)
123{
124 return -EINVAL;
125}
126#endif
127
128#endif