aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/sun4i-codec.txt65
-rw-r--r--Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt16
-rw-r--r--sound/soc/codecs/stac9766.c162
-rw-r--r--sound/soc/codecs/stac9766.h17
-rw-r--r--sound/soc/codecs/sti-sas.c179
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c1
-rw-r--r--sound/soc/sti/sti_uniperif.c43
-rw-r--r--sound/soc/sti/uniperif.h2
-rw-r--r--sound/soc/sti/uniperif_player.c91
-rw-r--r--sound/soc/sti/uniperif_reader.c41
-rw-r--r--sound/soc/sunxi/Kconfig8
-rw-r--r--sound/soc/sunxi/Makefile1
-rw-r--r--sound/soc/sunxi/sun4i-codec.c867
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c105
-rw-r--r--sound/soc/sunxi/sun8i-codec-analog.c665
-rw-r--r--sound/soc/tegra/tegra_alc5632.c2
-rw-r--r--sound/soc/tegra/tegra_max98090.c2
-rw-r--r--sound/soc/tegra/tegra_rt5640.c2
-rw-r--r--sound/soc/tegra/tegra_rt5677.c2
-rw-r--r--sound/soc/tegra/tegra_sgtl5000.c2
-rw-r--r--sound/soc/tegra/tegra_wm8753.c2
-rw-r--r--sound/soc/tegra/tegra_wm8903.c2
-rw-r--r--sound/soc/tegra/trimslice.c2
23 files changed, 1816 insertions, 463 deletions
diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index 0dce690f78f5..3033bd8aab0f 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -1,8 +1,12 @@
1* Allwinner A10 Codec 1* Allwinner A10 Codec
2 2
3Required properties: 3Required properties:
4- compatible: must be either "allwinner,sun4i-a10-codec" or 4- compatible: must be one of the following compatibles:
5 "allwinner,sun7i-a20-codec" 5 - "allwinner,sun4i-a10-codec"
6 - "allwinner,sun6i-a31-codec"
7 - "allwinner,sun7i-a20-codec"
8 - "allwinner,sun8i-a23-codec"
9 - "allwinner,sun8i-h3-codec"
6- reg: must contain the registers location and length 10- reg: must contain the registers location and length
7- interrupts: must contain the codec interrupt 11- interrupts: must contain the codec interrupt
8- dmas: DMA channels for tx and rx dma. See the DMA client binding, 12- dmas: DMA channels for tx and rx dma. See the DMA client binding,
@@ -17,6 +21,43 @@ Required properties:
17Optional properties: 21Optional properties:
18- allwinner,pa-gpios: gpio to enable external amplifier 22- allwinner,pa-gpios: gpio to enable external amplifier
19 23
24Required properties for the following compatibles:
25 - "allwinner,sun6i-a31-codec"
26 - "allwinner,sun8i-a23-codec"
27 - "allwinner,sun8i-h3-codec"
28- resets: phandle to the reset control for this device
29- allwinner,audio-routing: A list of the connections between audio components.
30 Each entry is a pair of strings, the first being the
31 connection's sink, the second being the connection's
32 source. Valid names include:
33
34 Audio pins on the SoC:
35 "HP"
36 "HPCOM"
37 "LINEIN"
38 "LINEOUT" (not on sun8i-a23)
39 "MIC1"
40 "MIC2"
41 "MIC3" (sun6i-a31 only)
42
43 Microphone biases from the SoC:
44 "HBIAS"
45 "MBIAS"
46
47 Board connectors:
48 "Headphone"
49 "Headset Mic"
50 "Line In"
51 "Line Out"
52 "Mic"
53 "Speaker"
54
55Required properties for the following compatibles:
56 - "allwinner,sun8i-a23-codec"
57 - "allwinner,sun8i-h3-codec"
58- allwinner,codec-analog-controls: A phandle to the codec analog controls
59 block in the PRCM.
60
20Example: 61Example:
21codec: codec@01c22c00 { 62codec: codec@01c22c00 {
22 #sound-dai-cells = <0>; 63 #sound-dai-cells = <0>;
@@ -28,3 +69,23 @@ codec: codec@01c22c00 {
28 dmas = <&dma 0 19>, <&dma 0 19>; 69 dmas = <&dma 0 19>, <&dma 0 19>;
29 dma-names = "rx", "tx"; 70 dma-names = "rx", "tx";
30}; 71};
72
73codec: codec@01c22c00 {
74 #sound-dai-cells = <0>;
75 compatible = "allwinner,sun6i-a31-codec";
76 reg = <0x01c22c00 0x98>;
77 interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
78 clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>;
79 clock-names = "apb", "codec";
80 resets = <&ccu RST_APB1_CODEC>;
81 dmas = <&dma 15>, <&dma 15>;
82 dma-names = "rx", "tx";
83 allwinner,audio-routing =
84 "Headphone", "HP",
85 "Speaker", "LINEOUT",
86 "LINEIN", "Line In",
87 "MIC1", "MBIAS",
88 "MIC1", "Mic",
89 "MIC2", "HBIAS",
90 "MIC2", "Headset Mic";
91};
diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
new file mode 100644
index 000000000000..779b735781ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
@@ -0,0 +1,16 @@
1* Allwinner Codec Analog Controls
2
3Required properties:
4- compatible: must be one of the following compatibles:
5 - "allwinner,sun8i-a23-codec-analog"
6 - "allwinner,sun8i-h3-codec-analog"
7
8Required properties if not a sub-node of the PRCM node:
9- reg: must contain the registers location and length
10
11Example:
12prcm: prcm@01f01400 {
13 codec_analog: codec-analog {
14 compatible = "allwinner,sun8i-a23-codec-analog";
15 };
16};
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 27f30d352867..9de7fe8af255 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -18,6 +18,7 @@
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/regmap.h>
21#include <sound/core.h> 22#include <sound/core.h>
22#include <sound/pcm.h> 23#include <sound/pcm.h>
23#include <sound/ac97_codec.h> 24#include <sound/ac97_codec.h>
@@ -26,31 +27,56 @@
26#include <sound/soc.h> 27#include <sound/soc.h>
27#include <sound/tlv.h> 28#include <sound/tlv.h>
28 29
29#include "stac9766.h"
30
31#define STAC9766_VENDOR_ID 0x83847666 30#define STAC9766_VENDOR_ID 0x83847666
32#define STAC9766_VENDOR_ID_MASK 0xffffffff 31#define STAC9766_VENDOR_ID_MASK 0xffffffff
33 32
34/* 33#define AC97_STAC_DA_CONTROL 0x6A
35 * STAC9766 register cache 34#define AC97_STAC_ANALOG_SPECIAL 0x6E
36 */ 35#define AC97_STAC_STEREO_MIC 0x78
37static const u16 stac9766_reg[] = { 36
38 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ 37static const struct reg_default stac9766_reg_defaults[] = {
39 0x0000, 0x0000, 0x8008, 0x8008, /* e */ 38 { 0x02, 0x8000 },
40 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ 39 { 0x04, 0x8000 },
41 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ 40 { 0x06, 0x8000 },
42 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ 41 { 0x0a, 0x0000 },
43 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ 42 { 0x0c, 0x8008 },
44 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ 43 { 0x0e, 0x8008 },
45 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ 44 { 0x10, 0x8808 },
46 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ 45 { 0x12, 0x8808 },
47 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ 46 { 0x14, 0x8808 },
48 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ 47 { 0x16, 0x8808 },
49 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ 48 { 0x18, 0x8808 },
50 0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ 49 { 0x1a, 0x0000 },
51 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ 50 { 0x1c, 0x8000 },
52 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ 51 { 0x20, 0x0000 },
53 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ 52 { 0x22, 0x0000 },
53 { 0x28, 0x0a05 },
54 { 0x2c, 0xbb80 },
55 { 0x32, 0xbb80 },
56 { 0x3a, 0x2000 },
57 { 0x3e, 0x0100 },
58 { 0x4c, 0x0300 },
59 { 0x4e, 0xffff },
60 { 0x50, 0x0000 },
61 { 0x52, 0x0000 },
62 { 0x54, 0x0000 },
63 { 0x6a, 0x0000 },
64 { 0x6e, 0x1000 },
65 { 0x72, 0x0000 },
66 { 0x78, 0x0000 },
67};
68
69static const struct regmap_config stac9766_regmap_config = {
70 .reg_bits = 16,
71 .reg_stride = 2,
72 .val_bits = 16,
73 .max_register = 0x78,
74 .cache_type = REGCACHE_RBTREE,
75
76 .volatile_reg = regmap_ac97_default_volatile,
77
78 .reg_defaults = stac9766_reg_defaults,
79 .num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults),
54}; 80};
55 81
56static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", 82static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX",
@@ -139,71 +165,22 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
139 SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), 165 SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum),
140}; 166};
141 167
142static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
143 unsigned int val)
144{
145 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
146 u16 *cache = codec->reg_cache;
147
148 if (reg > AC97_STAC_PAGE0) {
149 stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
150 soc_ac97_ops->write(ac97, reg, val);
151 stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
152 return 0;
153 }
154 if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
155 return -EIO;
156
157 soc_ac97_ops->write(ac97, reg, val);
158 cache[reg / 2] = val;
159 return 0;
160}
161
162static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
163 unsigned int reg)
164{
165 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
166 u16 val = 0, *cache = codec->reg_cache;
167
168 if (reg > AC97_STAC_PAGE0) {
169 stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
170 val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0);
171 stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
172 return val;
173 }
174 if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
175 return -EIO;
176
177 if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
178 reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
179 reg == AC97_VENDOR_ID2) {
180
181 val = soc_ac97_ops->read(ac97, reg);
182 return val;
183 }
184 return cache[reg / 2];
185}
186
187static int ac97_analog_prepare(struct snd_pcm_substream *substream, 168static int ac97_analog_prepare(struct snd_pcm_substream *substream,
188 struct snd_soc_dai *dai) 169 struct snd_soc_dai *dai)
189{ 170{
190 struct snd_soc_codec *codec = dai->codec; 171 struct snd_soc_codec *codec = dai->codec;
191 struct snd_pcm_runtime *runtime = substream->runtime; 172 struct snd_pcm_runtime *runtime = substream->runtime;
192 unsigned short reg, vra; 173 unsigned short reg;
193
194 vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS);
195 174
196 vra |= 0x1; /* enable variable rate audio */ 175 /* enable variable rate audio, disable SPDIF output */
197 vra &= ~0x4; /* disable SPDIF output */ 176 snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1);
198
199 stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra);
200 177
201 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 178 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
202 reg = AC97_PCM_FRONT_DAC_RATE; 179 reg = AC97_PCM_FRONT_DAC_RATE;
203 else 180 else
204 reg = AC97_PCM_LR_ADC_RATE; 181 reg = AC97_PCM_LR_ADC_RATE;
205 182
206 return stac9766_ac97_write(codec, reg, runtime->rate); 183 return snd_soc_write(codec, reg, runtime->rate);
207} 184}
208 185
209static int ac97_digital_prepare(struct snd_pcm_substream *substream, 186static int ac97_digital_prepare(struct snd_pcm_substream *substream,
@@ -211,18 +188,16 @@ static int ac97_digital_prepare(struct snd_pcm_substream *substream,
211{ 188{
212 struct snd_soc_codec *codec = dai->codec; 189 struct snd_soc_codec *codec = dai->codec;
213 struct snd_pcm_runtime *runtime = substream->runtime; 190 struct snd_pcm_runtime *runtime = substream->runtime;
214 unsigned short reg, vra; 191 unsigned short reg;
215
216 stac9766_ac97_write(codec, AC97_SPDIF, 0x2002);
217 192
218 vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); 193 snd_soc_write(codec, AC97_SPDIF, 0x2002);
219 vra |= 0x5; /* Enable VRA and SPDIF out */
220 194
221 stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); 195 /* Enable VRA and SPDIF out */
196 snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5);
222 197
223 reg = AC97_PCM_FRONT_DAC_RATE; 198 reg = AC97_PCM_FRONT_DAC_RATE;
224 199
225 return stac9766_ac97_write(codec, reg, runtime->rate); 200 return snd_soc_write(codec, reg, runtime->rate);
226} 201}
227 202
228static int stac9766_set_bias_level(struct snd_soc_codec *codec, 203static int stac9766_set_bias_level(struct snd_soc_codec *codec,
@@ -232,11 +207,11 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
232 case SND_SOC_BIAS_ON: /* full On */ 207 case SND_SOC_BIAS_ON: /* full On */
233 case SND_SOC_BIAS_PREPARE: /* partial On */ 208 case SND_SOC_BIAS_PREPARE: /* partial On */
234 case SND_SOC_BIAS_STANDBY: /* Off, with power */ 209 case SND_SOC_BIAS_STANDBY: /* Off, with power */
235 stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); 210 snd_soc_write(codec, AC97_POWERDOWN, 0x0000);
236 break; 211 break;
237 case SND_SOC_BIAS_OFF: /* Off, without power */ 212 case SND_SOC_BIAS_OFF: /* Off, without power */
238 /* disable everything including AC link */ 213 /* disable everything including AC link */
239 stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); 214 snd_soc_write(codec, AC97_POWERDOWN, 0xffff);
240 break; 215 break;
241 } 216 }
242 return 0; 217 return 0;
@@ -300,21 +275,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
300static int stac9766_codec_probe(struct snd_soc_codec *codec) 275static int stac9766_codec_probe(struct snd_soc_codec *codec)
301{ 276{
302 struct snd_ac97 *ac97; 277 struct snd_ac97 *ac97;
278 struct regmap *regmap;
279 int ret;
303 280
304 ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, 281 ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID,
305 STAC9766_VENDOR_ID_MASK); 282 STAC9766_VENDOR_ID_MASK);
306 if (IS_ERR(ac97)) 283 if (IS_ERR(ac97))
307 return PTR_ERR(ac97); 284 return PTR_ERR(ac97);
308 285
286 regmap = regmap_init_ac97(ac97, &stac9766_regmap_config);
287 if (IS_ERR(regmap)) {
288 ret = PTR_ERR(regmap);
289 goto err_free_ac97;
290 }
291
292 snd_soc_codec_init_regmap(codec, regmap);
309 snd_soc_codec_set_drvdata(codec, ac97); 293 snd_soc_codec_set_drvdata(codec, ac97);
310 294
311 return 0; 295 return 0;
296err_free_ac97:
297 snd_soc_free_ac97_codec(ac97);
298 return ret;
312} 299}
313 300
314static int stac9766_codec_remove(struct snd_soc_codec *codec) 301static int stac9766_codec_remove(struct snd_soc_codec *codec)
315{ 302{
316 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); 303 struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
317 304
305 snd_soc_codec_exit_regmap(codec);
318 snd_soc_free_ac97_codec(ac97); 306 snd_soc_free_ac97_codec(ac97);
319 return 0; 307 return 0;
320} 308}
@@ -324,17 +312,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
324 .controls = stac9766_snd_ac97_controls, 312 .controls = stac9766_snd_ac97_controls,
325 .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), 313 .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls),
326 }, 314 },
327 .write = stac9766_ac97_write,
328 .read = stac9766_ac97_read,
329 .set_bias_level = stac9766_set_bias_level, 315 .set_bias_level = stac9766_set_bias_level,
330 .suspend_bias_off = true, 316 .suspend_bias_off = true,
331 .probe = stac9766_codec_probe, 317 .probe = stac9766_codec_probe,
332 .remove = stac9766_codec_remove, 318 .remove = stac9766_codec_remove,
333 .resume = stac9766_codec_resume, 319 .resume = stac9766_codec_resume,
334 .reg_cache_size = ARRAY_SIZE(stac9766_reg),
335 .reg_word_size = sizeof(u16),
336 .reg_cache_step = 2,
337 .reg_cache_default = stac9766_reg,
338}; 320};
339 321
340static int stac9766_probe(struct platform_device *pdev) 322static int stac9766_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h
deleted file mode 100644
index c726f907e2c0..000000000000
--- a/sound/soc/codecs/stac9766.h
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * stac9766.h -- STAC9766 Soc Audio driver
3 */
4
5#ifndef _STAC9766_H
6#define _STAC9766_H
7
8#define AC97_STAC_PAGE0 0x1000
9#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A)
10#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E)
11#define AC97_STAC_STEREO_MIC 0x78
12
13/* STAC9766 DAI ID's */
14#define STAC9766_DAI_AC97_ANALOG 0
15#define STAC9766_DAI_AC97_DIGITAL 1
16
17#endif
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index d6e00c77edcd..62c618765224 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -14,28 +14,8 @@
14#include <sound/soc.h> 14#include <sound/soc.h>
15#include <sound/soc-dapm.h> 15#include <sound/soc-dapm.h>
16 16
17/* chipID supported */
18#define CHIPID_STIH416 0
19#define CHIPID_STIH407 1
20
21/* DAC definitions */ 17/* DAC definitions */
22 18
23/* stih416 DAC registers */
24/* sysconf 2517: Audio-DAC-Control */
25#define STIH416_AUDIO_DAC_CTRL 0x00000814
26/* sysconf 2519: Audio-Gue-Control */
27#define STIH416_AUDIO_GLUE_CTRL 0x0000081C
28
29#define STIH416_DAC_NOT_STANDBY 0x3
30#define STIH416_DAC_SOFTMUTE 0x4
31#define STIH416_DAC_ANA_NOT_PWR 0x5
32#define STIH416_DAC_NOT_PNDBG 0x6
33
34#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY)
35#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE)
36#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR)
37#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG)
38
39/* stih407 DAC registers */ 19/* stih407 DAC registers */
40/* sysconf 5041: Audio-Gue-Control */ 20/* sysconf 5041: Audio-Gue-Control */
41#define STIH407_AUDIO_GLUE_CTRL 0x000000A4 21#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
@@ -63,14 +43,9 @@ enum {
63 STI_SAS_DAI_ANALOG_OUT, 43 STI_SAS_DAI_ANALOG_OUT,
64}; 44};
65 45
66static const struct reg_default stih416_sas_reg_defaults[] = {
67 { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
68 { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
69};
70
71static const struct reg_default stih407_sas_reg_defaults[] = { 46static const struct reg_default stih407_sas_reg_defaults[] = {
72 { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, 47 { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
73 { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, 48 { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
74}; 49};
75 50
76struct sti_dac_audio { 51struct sti_dac_audio {
@@ -89,7 +64,6 @@ struct sti_spdif_audio {
89 64
90/* device data structure */ 65/* device data structure */
91struct sti_sas_dev_data { 66struct sti_sas_dev_data {
92 const int chipid; /* IC version */
93 const struct regmap_config *regmap; 67 const struct regmap_config *regmap;
94 const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ 68 const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
95 const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ 69 const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
@@ -150,51 +124,27 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec,
150 ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, 124 ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL,
151 SPDIF_BIPHASE_IDLE_MASK, 0); 125 SPDIF_BIPHASE_IDLE_MASK, 0);
152 if (ret < 0) { 126 if (ret < 0) {
153 dev_err(codec->dev, "Failed to update SPDIF registers"); 127 dev_err(codec->dev, "Failed to update SPDIF registers\n");
154 return ret; 128 return ret;
155 } 129 }
156 130
157 /* Init DAC configuration */ 131 /* Init DAC configuration */
158 switch (data->dev_data->chipid) { 132 /* init configuration */
159 case CHIPID_STIH407: 133 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
160 /* init configuration */ 134 STIH407_DAC_STANDBY_MASK,
161 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 135 STIH407_DAC_STANDBY_MASK);
162 STIH407_DAC_STANDBY_MASK, 136
163 STIH407_DAC_STANDBY_MASK); 137 if (!ret)
164 138 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
165 if (!ret) 139 STIH407_DAC_STANDBY_ANA_MASK,
166 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 140 STIH407_DAC_STANDBY_ANA_MASK);
167 STIH407_DAC_STANDBY_ANA_MASK, 141 if (!ret)
168 STIH407_DAC_STANDBY_ANA_MASK); 142 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL,
169 if (!ret) 143 STIH407_DAC_SOFTMUTE_MASK,
170 ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, 144 STIH407_DAC_SOFTMUTE_MASK);
171 STIH407_DAC_SOFTMUTE_MASK,
172 STIH407_DAC_SOFTMUTE_MASK);
173 break;
174 case CHIPID_STIH416:
175 ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
176 STIH416_DAC_NOT_STANDBY_MASK, 0);
177 if (!ret)
178 ret = snd_soc_update_bits(codec,
179 STIH416_AUDIO_DAC_CTRL,
180 STIH416_DAC_ANA_NOT_PWR, 0);
181 if (!ret)
182 ret = snd_soc_update_bits(codec,
183 STIH416_AUDIO_DAC_CTRL,
184 STIH416_DAC_NOT_PNDBG_MASK,
185 0);
186 if (!ret)
187 ret = snd_soc_update_bits(codec,
188 STIH416_AUDIO_DAC_CTRL,
189 STIH416_DAC_SOFTMUTE_MASK,
190 STIH416_DAC_SOFTMUTE_MASK);
191 break;
192 default:
193 return -EINVAL;
194 }
195 145
196 if (ret < 0) { 146 if (ret < 0) {
197 dev_err(codec->dev, "Failed to update DAC registers"); 147 dev_err(codec->dev, "Failed to update DAC registers\n");
198 return ret; 148 return ret;
199 } 149 }
200 150
@@ -217,37 +167,6 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
217 return 0; 167 return 0;
218} 168}
219 169
220static int stih416_dac_probe(struct snd_soc_dai *dai)
221{
222 struct snd_soc_codec *codec = dai->codec;
223 struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev);
224 struct sti_dac_audio *dac = &drvdata->dac;
225
226 /* Get reset control */
227 dac->rst = devm_reset_control_get(codec->dev, "dac_rst");
228 if (IS_ERR(dac->rst)) {
229 dev_err(dai->codec->dev,
230 "%s: ERROR: DAC reset control not defined !\n",
231 __func__);
232 dac->rst = NULL;
233 return -EFAULT;
234 }
235 /* Put the DAC into reset */
236 reset_control_assert(dac->rst);
237
238 return 0;
239}
240
241static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = {
242 SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL,
243 STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0),
244 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL,
245 STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0),
246 SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL,
247 STIH416_DAC_NOT_STANDBY, 0),
248 SND_SOC_DAPM_OUTPUT("DAC Output"),
249};
250
251static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { 170static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
252 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, 171 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
253 STIH407_DAC_STANDBY_ANA, 1, NULL, 0), 172 STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
@@ -256,30 +175,11 @@ static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
256 SND_SOC_DAPM_OUTPUT("DAC Output"), 175 SND_SOC_DAPM_OUTPUT("DAC Output"),
257}; 176};
258 177
259static const struct snd_soc_dapm_route stih416_sas_route[] = {
260 {"DAC Output", NULL, "DAC bandgap"},
261 {"DAC Output", NULL, "DAC standby ana"},
262 {"DAC standby ana", NULL, "DAC standby"},
263};
264
265static const struct snd_soc_dapm_route stih407_sas_route[] = { 178static const struct snd_soc_dapm_route stih407_sas_route[] = {
266 {"DAC Output", NULL, "DAC standby ana"}, 179 {"DAC Output", NULL, "DAC standby ana"},
267 {"DAC standby ana", NULL, "DAC standby"}, 180 {"DAC standby ana", NULL, "DAC standby"},
268}; 181};
269 182
270static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
271{
272 struct snd_soc_codec *codec = dai->codec;
273
274 if (mute) {
275 return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
276 STIH416_DAC_SOFTMUTE_MASK,
277 STIH416_DAC_SOFTMUTE_MASK);
278 } else {
279 return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL,
280 STIH416_DAC_SOFTMUTE_MASK, 0);
281 }
282}
283 183
284static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) 184static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
285{ 185{
@@ -392,13 +292,13 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream,
392 switch (dai->id) { 292 switch (dai->id) {
393 case STI_SAS_DAI_SPDIF_OUT: 293 case STI_SAS_DAI_SPDIF_OUT:
394 if ((drvdata->spdif.mclk / runtime->rate) != 128) { 294 if ((drvdata->spdif.mclk / runtime->rate) != 128) {
395 dev_err(codec->dev, "unexpected mclk-fs ratio"); 295 dev_err(codec->dev, "unexpected mclk-fs ratio\n");
396 return -EINVAL; 296 return -EINVAL;
397 } 297 }
398 break; 298 break;
399 case STI_SAS_DAI_ANALOG_OUT: 299 case STI_SAS_DAI_ANALOG_OUT:
400 if ((drvdata->dac.mclk / runtime->rate) != 256) { 300 if ((drvdata->dac.mclk / runtime->rate) != 256) {
401 dev_err(codec->dev, "unexpected mclk-fs ratio"); 301 dev_err(codec->dev, "unexpected mclk-fs ratio\n");
402 return -EINVAL; 302 return -EINVAL;
403 } 303 }
404 break; 304 break;
@@ -407,13 +307,6 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream,
407 return 0; 307 return 0;
408} 308}
409 309
410static const struct snd_soc_dai_ops stih416_dac_ops = {
411 .set_fmt = sti_sas_dac_set_fmt,
412 .mute_stream = stih416_sas_dac_mute,
413 .prepare = sti_sas_prepare,
414 .set_sysclk = sti_sas_set_sysclk,
415};
416
417static const struct snd_soc_dai_ops stih407_dac_ops = { 310static const struct snd_soc_dai_ops stih407_dac_ops = {
418 .set_fmt = sti_sas_dac_set_fmt, 311 .set_fmt = sti_sas_dac_set_fmt,
419 .mute_stream = stih407_sas_dac_mute, 312 .mute_stream = stih407_sas_dac_mute,
@@ -434,31 +327,7 @@ static const struct regmap_config stih407_sas_regmap = {
434 .reg_write = sti_sas_write_reg, 327 .reg_write = sti_sas_write_reg,
435}; 328};
436 329
437static const struct regmap_config stih416_sas_regmap = {
438 .reg_bits = 32,
439 .val_bits = 32,
440
441 .max_register = STIH416_AUDIO_DAC_CTRL,
442 .reg_defaults = stih416_sas_reg_defaults,
443 .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults),
444 .volatile_reg = sti_sas_volatile_register,
445 .cache_type = REGCACHE_RBTREE,
446 .reg_read = sti_sas_read_reg,
447 .reg_write = sti_sas_write_reg,
448};
449
450static const struct sti_sas_dev_data stih416_data = {
451 .chipid = CHIPID_STIH416,
452 .regmap = &stih416_sas_regmap,
453 .dac_ops = &stih416_dac_ops,
454 .dapm_widgets = stih416_sas_dapm_widgets,
455 .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets),
456 .dapm_routes = stih416_sas_route,
457 .num_dapm_routes = ARRAY_SIZE(stih416_sas_route),
458};
459
460static const struct sti_sas_dev_data stih407_data = { 330static const struct sti_sas_dev_data stih407_data = {
461 .chipid = CHIPID_STIH407,
462 .regmap = &stih407_sas_regmap, 331 .regmap = &stih407_sas_regmap,
463 .dac_ops = &stih407_dac_ops, 332 .dac_ops = &stih407_dac_ops,
464 .dapm_widgets = stih407_sas_dapm_widgets, 333 .dapm_widgets = stih407_sas_dapm_widgets,
@@ -533,10 +402,6 @@ static struct snd_soc_codec_driver sti_sas_driver = {
533 402
534static const struct of_device_id sti_sas_dev_match[] = { 403static const struct of_device_id sti_sas_dev_match[] = {
535 { 404 {
536 .compatible = "st,stih416-sas-codec",
537 .data = &stih416_data,
538 },
539 {
540 .compatible = "st,stih407-sas-codec", 405 .compatible = "st,stih407-sas-codec",
541 .data = &stih407_data, 406 .data = &stih407_data,
542 }, 407 },
@@ -558,7 +423,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
558 /* Populate data structure depending on compatibility */ 423 /* Populate data structure depending on compatibility */
559 of_id = of_match_node(sti_sas_dev_match, pnode); 424 of_id = of_match_node(sti_sas_dev_match, pnode);
560 if (!of_id->data) { 425 if (!of_id->data) {
561 dev_err(&pdev->dev, "data associated to device is missing"); 426 dev_err(&pdev->dev, "data associated to device is missing\n");
562 return -EINVAL; 427 return -EINVAL;
563 } 428 }
564 429
@@ -584,10 +449,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev)
584 } 449 }
585 drvdata->spdif.regmap = drvdata->dac.regmap; 450 drvdata->spdif.regmap = drvdata->dac.regmap;
586 451
587 /* Set DAC dai probe */
588 if (drvdata->dev_data->chipid == CHIPID_STIH416)
589 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe;
590
591 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; 452 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
592 453
593 /* Set dapms*/ 454 /* Set dapms*/
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index b2acd3293ea8..f200d1cfc4bd 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -27,7 +27,6 @@
27 27
28#include "mpc5200_dma.h" 28#include "mpc5200_dma.h"
29#include "mpc5200_psc_ac97.h" 29#include "mpc5200_psc_ac97.h"
30#include "../codecs/stac9766.h"
31 30
32#define DRV_NAME "efika-audio-fabric" 31#define DRV_NAME "efika-audio-fabric"
33 32
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c
index 549fac349fa0..98eb205a0b62 100644
--- a/sound/soc/sti/sti_uniperif.c
+++ b/sound/soc/sti/sti_uniperif.c
@@ -7,6 +7,7 @@
7 7
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/pinctrl/consumer.h> 9#include <linux/pinctrl/consumer.h>
10#include <linux/delay.h>
10 11
11#include "uniperif.h" 12#include "uniperif.h"
12 13
@@ -97,6 +98,28 @@ static const struct of_device_id snd_soc_sti_match[] = {
97 {}, 98 {},
98}; 99};
99 100
101int sti_uniperiph_reset(struct uniperif *uni)
102{
103 int count = 10;
104
105 /* Reset uniperipheral uni */
106 SET_UNIPERIF_SOFT_RST_SOFT_RST(uni);
107
108 if (uni->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
109 while (GET_UNIPERIF_SOFT_RST_SOFT_RST(uni) && count) {
110 udelay(5);
111 count--;
112 }
113 }
114
115 if (!count) {
116 dev_err(uni->dev, "Failed to reset uniperif\n");
117 return -EIO;
118 }
119
120 return 0;
121}
122
100int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 123int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
101 unsigned int rx_mask, int slots, 124 unsigned int rx_mask, int slots,
102 int slot_width) 125 int slot_width)
@@ -293,7 +316,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)
293 316
294 /* The uniperipheral should be in stopped state */ 317 /* The uniperipheral should be in stopped state */
295 if (uni->state != UNIPERIF_STATE_STOPPED) { 318 if (uni->state != UNIPERIF_STATE_STOPPED) {
296 dev_err(uni->dev, "%s: invalid uni state( %d)", 319 dev_err(uni->dev, "%s: invalid uni state( %d)\n",
297 __func__, (int)uni->state); 320 __func__, (int)uni->state);
298 return -EBUSY; 321 return -EBUSY;
299 } 322 }
@@ -301,7 +324,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai)
301 /* Pinctrl: switch pinstate to sleep */ 324 /* Pinctrl: switch pinstate to sleep */
302 ret = pinctrl_pm_select_sleep_state(uni->dev); 325 ret = pinctrl_pm_select_sleep_state(uni->dev);
303 if (ret) 326 if (ret)
304 dev_err(uni->dev, "%s: failed to select pinctrl state", 327 dev_err(uni->dev, "%s: failed to select pinctrl state\n",
305 __func__); 328 __func__);
306 329
307 return ret; 330 return ret;
@@ -322,7 +345,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai)
322 /* pinctrl: switch pinstate to default */ 345 /* pinctrl: switch pinstate to default */
323 ret = pinctrl_pm_select_default_state(uni->dev); 346 ret = pinctrl_pm_select_default_state(uni->dev);
324 if (ret) 347 if (ret)
325 dev_err(uni->dev, "%s: failed to select pinctrl state", 348 dev_err(uni->dev, "%s: failed to select pinctrl state\n",
326 __func__); 349 __func__);
327 350
328 return ret; 351 return ret;
@@ -366,11 +389,12 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
366 const struct of_device_id *of_id; 389 const struct of_device_id *of_id;
367 const struct sti_uniperiph_dev_data *dev_data; 390 const struct sti_uniperiph_dev_data *dev_data;
368 const char *mode; 391 const char *mode;
392 int ret;
369 393
370 /* Populate data structure depending on compatibility */ 394 /* Populate data structure depending on compatibility */
371 of_id = of_match_node(snd_soc_sti_match, node); 395 of_id = of_match_node(snd_soc_sti_match, node);
372 if (!of_id->data) { 396 if (!of_id->data) {
373 dev_err(dev, "data associated to device is missing"); 397 dev_err(dev, "data associated to device is missing\n");
374 return -EINVAL; 398 return -EINVAL;
375 } 399 }
376 dev_data = (struct sti_uniperiph_dev_data *)of_id->data; 400 dev_data = (struct sti_uniperiph_dev_data *)of_id->data;
@@ -389,7 +413,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
389 uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); 413 uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);
390 414
391 if (!uni->mem_region) { 415 if (!uni->mem_region) {
392 dev_err(dev, "Failed to get memory resource"); 416 dev_err(dev, "Failed to get memory resource\n");
393 return -ENODEV; 417 return -ENODEV;
394 } 418 }
395 419
@@ -403,7 +427,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
403 427
404 uni->irq = platform_get_irq(priv->pdev, 0); 428 uni->irq = platform_get_irq(priv->pdev, 0);
405 if (uni->irq < 0) { 429 if (uni->irq < 0) {
406 dev_err(dev, "Failed to get IRQ resource"); 430 dev_err(dev, "Failed to get IRQ resource\n");
407 return -ENXIO; 431 return -ENXIO;
408 } 432 }
409 433
@@ -421,12 +445,15 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node,
421 dai_data->stream = dev_data->stream; 445 dai_data->stream = dev_data->stream;
422 446
423 if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { 447 if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) {
424 uni_player_init(priv->pdev, uni); 448 ret = uni_player_init(priv->pdev, uni);
425 stream = &dai->playback; 449 stream = &dai->playback;
426 } else { 450 } else {
427 uni_reader_init(priv->pdev, uni); 451 ret = uni_reader_init(priv->pdev, uni);
428 stream = &dai->capture; 452 stream = &dai->capture;
429 } 453 }
454 if (ret < 0)
455 return ret;
456
430 dai->ops = uni->dai_ops; 457 dai->ops = uni->dai_ops;
431 458
432 stream->stream_name = dai->name; 459 stream->stream_name = dai->name;
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h
index 1993c655fb79..d487dd2ef016 100644
--- a/sound/soc/sti/uniperif.h
+++ b/sound/soc/sti/uniperif.h
@@ -1397,6 +1397,8 @@ static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni)
1397 return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); 1397 return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8);
1398} 1398}
1399 1399
1400int sti_uniperiph_reset(struct uniperif *uni);
1401
1400int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 1402int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1401 unsigned int rx_mask, int slots, 1403 unsigned int rx_mask, int slots,
1402 int slot_width); 1404 int slot_width);
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index ad54d4cf58ad..60ae31a303ab 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -6,8 +6,6 @@
6 */ 6 */
7 7
8#include <linux/clk.h> 8#include <linux/clk.h>
9#include <linux/delay.h>
10#include <linux/io.h>
11#include <linux/mfd/syscon.h> 9#include <linux/mfd/syscon.h>
12 10
13#include <sound/asoundef.h> 11#include <sound/asoundef.h>
@@ -55,25 +53,6 @@ static const struct snd_pcm_hardware uni_player_pcm_hw = {
55 .buffer_bytes_max = 256 * PAGE_SIZE 53 .buffer_bytes_max = 256 * PAGE_SIZE
56}; 54};
57 55
58static inline int reset_player(struct uniperif *player)
59{
60 int count = 10;
61
62 if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
63 while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) {
64 udelay(5);
65 count--;
66 }
67 }
68
69 if (!count) {
70 dev_err(player->dev, "Failed to reset uniperif");
71 return -EIO;
72 }
73
74 return 0;
75}
76
77/* 56/*
78 * uni_player_irq_handler 57 * uni_player_irq_handler
79 * In case of error audio stream is stopped; stop action is protected via PCM 58 * In case of error audio stream is stopped; stop action is protected via PCM
@@ -97,7 +76,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
97 76
98 /* Check for fifo error (underrun) */ 77 /* Check for fifo error (underrun) */
99 if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { 78 if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) {
100 dev_err(player->dev, "FIFO underflow error detected"); 79 dev_err(player->dev, "FIFO underflow error detected\n");
101 80
102 /* Interrupt is just for information when underflow recovery */ 81 /* Interrupt is just for information when underflow recovery */
103 if (player->underflow_enabled) { 82 if (player->underflow_enabled) {
@@ -119,7 +98,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
119 98
120 /* Check for dma error (overrun) */ 99 /* Check for dma error (overrun) */
121 if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { 100 if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) {
122 dev_err(player->dev, "DMA error detected"); 101 dev_err(player->dev, "DMA error detected\n");
123 102
124 /* Disable interrupt so doesn't continually fire */ 103 /* Disable interrupt so doesn't continually fire */
125 SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); 104 SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
@@ -135,11 +114,14 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
135 /* Check for underflow recovery done */ 114 /* Check for underflow recovery done */
136 if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { 115 if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {
137 if (!player->underflow_enabled) { 116 if (!player->underflow_enabled) {
138 dev_err(player->dev, "unexpected Underflow recovering"); 117 dev_err(player->dev,
118 "unexpected Underflow recovering\n");
139 return -EPERM; 119 return -EPERM;
140 } 120 }
141 /* Read the underflow recovery duration */ 121 /* Read the underflow recovery duration */
142 tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); 122 tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player);
123 dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n",
124 tmp);
143 125
144 /* Clear the underflow recovery duration */ 126 /* Clear the underflow recovery duration */
145 SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); 127 SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player);
@@ -153,7 +135,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
153 /* Check if underflow recovery failed */ 135 /* Check if underflow recovery failed */
154 if (unlikely(status & 136 if (unlikely(status &
155 UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { 137 UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) {
156 dev_err(player->dev, "Underflow recovery failed"); 138 dev_err(player->dev, "Underflow recovery failed\n");
157 139
158 /* Stop the player */ 140 /* Stop the player */
159 snd_pcm_stream_lock(player->substream); 141 snd_pcm_stream_lock(player->substream);
@@ -336,7 +318,7 @@ static int uni_player_prepare_iec958(struct uniperif *player,
336 318
337 /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ 319 /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */
338 if ((clk_div % 128) || (clk_div <= 0)) { 320 if ((clk_div % 128) || (clk_div <= 0)) {
339 dev_err(player->dev, "%s: invalid clk_div %d", 321 dev_err(player->dev, "%s: invalid clk_div %d\n",
340 __func__, clk_div); 322 __func__, clk_div);
341 return -EINVAL; 323 return -EINVAL;
342 } 324 }
@@ -359,7 +341,7 @@ static int uni_player_prepare_iec958(struct uniperif *player,
359 SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); 341 SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player);
360 break; 342 break;
361 default: 343 default:
362 dev_err(player->dev, "format not supported"); 344 dev_err(player->dev, "format not supported\n");
363 return -EINVAL; 345 return -EINVAL;
364 } 346 }
365 347
@@ -448,12 +430,12 @@ static int uni_player_prepare_pcm(struct uniperif *player,
448 * for 16 bits must be a multiple of 64 430 * for 16 bits must be a multiple of 64
449 */ 431 */
450 if ((slot_width == 32) && (clk_div % 128)) { 432 if ((slot_width == 32) && (clk_div % 128)) {
451 dev_err(player->dev, "%s: invalid clk_div", __func__); 433 dev_err(player->dev, "%s: invalid clk_div\n", __func__);
452 return -EINVAL; 434 return -EINVAL;
453 } 435 }
454 436
455 if ((slot_width == 16) && (clk_div % 64)) { 437 if ((slot_width == 16) && (clk_div % 64)) {
456 dev_err(player->dev, "%s: invalid clk_div", __func__); 438 dev_err(player->dev, "%s: invalid clk_div\n", __func__);
457 return -EINVAL; 439 return -EINVAL;
458 } 440 }
459 441
@@ -471,7 +453,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,
471 SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); 453 SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player);
472 break; 454 break;
473 default: 455 default:
474 dev_err(player->dev, "subframe format not supported"); 456 dev_err(player->dev, "subframe format not supported\n");
475 return -EINVAL; 457 return -EINVAL;
476 } 458 }
477 459
@@ -491,7 +473,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,
491 break; 473 break;
492 474
493 default: 475 default:
494 dev_err(player->dev, "format not supported"); 476 dev_err(player->dev, "format not supported\n");
495 return -EINVAL; 477 return -EINVAL;
496 } 478 }
497 479
@@ -504,7 +486,7 @@ static int uni_player_prepare_pcm(struct uniperif *player,
504 /* Number of channelsmust be even*/ 486 /* Number of channelsmust be even*/
505 if ((runtime->channels % 2) || (runtime->channels < 2) || 487 if ((runtime->channels % 2) || (runtime->channels < 2) ||
506 (runtime->channels > 10)) { 488 (runtime->channels > 10)) {
507 dev_err(player->dev, "%s: invalid nb of channels", __func__); 489 dev_err(player->dev, "%s: invalid nb of channels\n", __func__);
508 return -EINVAL; 490 return -EINVAL;
509 } 491 }
510 492
@@ -762,7 +744,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
762 744
763 /* The player should be stopped */ 745 /* The player should be stopped */
764 if (player->state != UNIPERIF_STATE_STOPPED) { 746 if (player->state != UNIPERIF_STATE_STOPPED) {
765 dev_err(player->dev, "%s: invalid player state %d", __func__, 747 dev_err(player->dev, "%s: invalid player state %d\n", __func__,
766 player->state); 748 player->state);
767 return -EINVAL; 749 return -EINVAL;
768 } 750 }
@@ -791,7 +773,8 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
791 /* Trigger limit must be an even number */ 773 /* Trigger limit must be an even number */
792 if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || 774 if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) ||
793 (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { 775 (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) {
794 dev_err(player->dev, "invalid trigger limit %d", trigger_limit); 776 dev_err(player->dev, "invalid trigger limit %d\n",
777 trigger_limit);
795 return -EINVAL; 778 return -EINVAL;
796 } 779 }
797 780
@@ -812,7 +795,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
812 ret = uni_player_prepare_tdm(player, runtime); 795 ret = uni_player_prepare_tdm(player, runtime);
813 break; 796 break;
814 default: 797 default:
815 dev_err(player->dev, "invalid player type"); 798 dev_err(player->dev, "invalid player type\n");
816 return -EINVAL; 799 return -EINVAL;
817 } 800 }
818 801
@@ -852,16 +835,14 @@ static int uni_player_prepare(struct snd_pcm_substream *substream,
852 SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); 835 SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player);
853 break; 836 break;
854 default: 837 default:
855 dev_err(player->dev, "format not supported"); 838 dev_err(player->dev, "format not supported\n");
856 return -EINVAL; 839 return -EINVAL;
857 } 840 }
858 841
859 SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); 842 SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0);
860 843
861 /* Reset uniperipheral player */
862 SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
863 844
864 return reset_player(player); 845 return sti_uniperiph_reset(player);
865} 846}
866 847
867static int uni_player_start(struct uniperif *player) 848static int uni_player_start(struct uniperif *player)
@@ -870,13 +851,13 @@ static int uni_player_start(struct uniperif *player)
870 851
871 /* The player should be stopped */ 852 /* The player should be stopped */
872 if (player->state != UNIPERIF_STATE_STOPPED) { 853 if (player->state != UNIPERIF_STATE_STOPPED) {
873 dev_err(player->dev, "%s: invalid player state", __func__); 854 dev_err(player->dev, "%s: invalid player state\n", __func__);
874 return -EINVAL; 855 return -EINVAL;
875 } 856 }
876 857
877 ret = clk_prepare_enable(player->clk); 858 ret = clk_prepare_enable(player->clk);
878 if (ret) { 859 if (ret) {
879 dev_err(player->dev, "%s: Failed to enable clock", __func__); 860 dev_err(player->dev, "%s: Failed to enable clock\n", __func__);
880 return ret; 861 return ret;
881 } 862 }
882 863
@@ -893,10 +874,7 @@ static int uni_player_start(struct uniperif *player)
893 SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); 874 SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player);
894 } 875 }
895 876
896 /* Reset uniperipheral player */ 877 ret = sti_uniperiph_reset(player);
897 SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
898
899 ret = reset_player(player);
900 if (ret < 0) { 878 if (ret < 0) {
901 clk_disable_unprepare(player->clk); 879 clk_disable_unprepare(player->clk);
902 return ret; 880 return ret;
@@ -938,17 +916,14 @@ static int uni_player_stop(struct uniperif *player)
938 916
939 /* The player should not be in stopped state */ 917 /* The player should not be in stopped state */
940 if (player->state == UNIPERIF_STATE_STOPPED) { 918 if (player->state == UNIPERIF_STATE_STOPPED) {
941 dev_err(player->dev, "%s: invalid player state", __func__); 919 dev_err(player->dev, "%s: invalid player state\n", __func__);
942 return -EINVAL; 920 return -EINVAL;
943 } 921 }
944 922
945 /* Turn the player off */ 923 /* Turn the player off */
946 SET_UNIPERIF_CTRL_OPERATION_OFF(player); 924 SET_UNIPERIF_CTRL_OPERATION_OFF(player);
947 925
948 /* Soft reset the player */ 926 ret = sti_uniperiph_reset(player);
949 SET_UNIPERIF_SOFT_RST_SOFT_RST(player);
950
951 ret = reset_player(player);
952 if (ret < 0) 927 if (ret < 0)
953 return ret; 928 return ret;
954 929
@@ -973,7 +948,7 @@ int uni_player_resume(struct uniperif *player)
973 ret = regmap_field_write(player->clk_sel, 1); 948 ret = regmap_field_write(player->clk_sel, 1);
974 if (ret) { 949 if (ret) {
975 dev_err(player->dev, 950 dev_err(player->dev,
976 "%s: Failed to select freq synth clock", 951 "%s: Failed to select freq synth clock\n",
977 __func__); 952 __func__);
978 return ret; 953 return ret;
979 } 954 }
@@ -1070,7 +1045,7 @@ int uni_player_init(struct platform_device *pdev,
1070 ret = uni_player_parse_dt_audio_glue(pdev, player); 1045 ret = uni_player_parse_dt_audio_glue(pdev, player);
1071 1046
1072 if (ret < 0) { 1047 if (ret < 0) {
1073 dev_err(player->dev, "Failed to parse DeviceTree"); 1048 dev_err(player->dev, "Failed to parse DeviceTree\n");
1074 return ret; 1049 return ret;
1075 } 1050 }
1076 1051
@@ -1085,15 +1060,17 @@ int uni_player_init(struct platform_device *pdev,
1085 1060
1086 /* Get uniperif resource */ 1061 /* Get uniperif resource */
1087 player->clk = of_clk_get(pdev->dev.of_node, 0); 1062 player->clk = of_clk_get(pdev->dev.of_node, 0);
1088 if (IS_ERR(player->clk)) 1063 if (IS_ERR(player->clk)) {
1064 dev_err(player->dev, "Failed to get clock\n");
1089 ret = PTR_ERR(player->clk); 1065 ret = PTR_ERR(player->clk);
1066 }
1090 1067
1091 /* Select the frequency synthesizer clock */ 1068 /* Select the frequency synthesizer clock */
1092 if (player->clk_sel) { 1069 if (player->clk_sel) {
1093 ret = regmap_field_write(player->clk_sel, 1); 1070 ret = regmap_field_write(player->clk_sel, 1);
1094 if (ret) { 1071 if (ret) {
1095 dev_err(player->dev, 1072 dev_err(player->dev,
1096 "%s: Failed to select freq synth clock", 1073 "%s: Failed to select freq synth clock\n",
1097 __func__); 1074 __func__);
1098 return ret; 1075 return ret;
1099 } 1076 }
@@ -1105,7 +1082,7 @@ int uni_player_init(struct platform_device *pdev,
1105 ret = regmap_field_write(player->valid_sel, player->id); 1082 ret = regmap_field_write(player->valid_sel, player->id);
1106 if (ret) { 1083 if (ret) {
1107 dev_err(player->dev, 1084 dev_err(player->dev,
1108 "%s: unable to connect to tdm bus", __func__); 1085 "%s: unable to connect to tdm bus\n", __func__);
1109 return ret; 1086 return ret;
1110 } 1087 }
1111 } 1088 }
@@ -1113,8 +1090,10 @@ int uni_player_init(struct platform_device *pdev,
1113 ret = devm_request_irq(&pdev->dev, player->irq, 1090 ret = devm_request_irq(&pdev->dev, player->irq,
1114 uni_player_irq_handler, IRQF_SHARED, 1091 uni_player_irq_handler, IRQF_SHARED,
1115 dev_name(&pdev->dev), player); 1092 dev_name(&pdev->dev), player);
1116 if (ret < 0) 1093 if (ret < 0) {
1094 dev_err(player->dev, "unable to request IRQ %d\n", player->irq);
1117 return ret; 1095 return ret;
1096 }
1118 1097
1119 mutex_init(&player->ctrl_lock); 1098 mutex_init(&player->ctrl_lock);
1120 1099
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index 0e1c3ee56675..5992c6ab3833 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -5,10 +5,6 @@
5 * License terms: GNU General Public License (GPL), version 2 5 * License terms: GNU General Public License (GPL), version 2
6 */ 6 */
7 7
8#include <linux/clk.h>
9#include <linux/delay.h>
10#include <linux/io.h>
11
12#include <sound/soc.h> 8#include <sound/soc.h>
13 9
14#include "uniperif.h" 10#include "uniperif.h"
@@ -52,7 +48,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
52 48
53 if (reader->state == UNIPERIF_STATE_STOPPED) { 49 if (reader->state == UNIPERIF_STATE_STOPPED) {
54 /* Unexpected IRQ: do nothing */ 50 /* Unexpected IRQ: do nothing */
55 dev_warn(reader->dev, "unexpected IRQ "); 51 dev_warn(reader->dev, "unexpected IRQ\n");
56 return IRQ_HANDLED; 52 return IRQ_HANDLED;
57 } 53 }
58 54
@@ -62,7 +58,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
62 58
63 /* Check for fifo overflow error */ 59 /* Check for fifo overflow error */
64 if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { 60 if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
65 dev_err(reader->dev, "FIFO error detected"); 61 dev_err(reader->dev, "FIFO error detected\n");
66 62
67 snd_pcm_stream_lock(reader->substream); 63 snd_pcm_stream_lock(reader->substream);
68 snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); 64 snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
@@ -105,7 +101,7 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime,
105 SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); 101 SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader);
106 break; 102 break;
107 default: 103 default:
108 dev_err(reader->dev, "subframe format not supported"); 104 dev_err(reader->dev, "subframe format not supported\n");
109 return -EINVAL; 105 return -EINVAL;
110 } 106 }
111 107
@@ -125,14 +121,14 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime,
125 break; 121 break;
126 122
127 default: 123 default:
128 dev_err(reader->dev, "format not supported"); 124 dev_err(reader->dev, "format not supported\n");
129 return -EINVAL; 125 return -EINVAL;
130 } 126 }
131 127
132 /* Number of channels must be even */ 128 /* Number of channels must be even */
133 if ((runtime->channels % 2) || (runtime->channels < 2) || 129 if ((runtime->channels % 2) || (runtime->channels < 2) ||
134 (runtime->channels > 10)) { 130 (runtime->channels > 10)) {
135 dev_err(reader->dev, "%s: invalid nb of channels", __func__); 131 dev_err(reader->dev, "%s: invalid nb of channels\n", __func__);
136 return -EINVAL; 132 return -EINVAL;
137 } 133 }
138 134
@@ -186,11 +182,10 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
186 struct uniperif *reader = priv->dai_data.uni; 182 struct uniperif *reader = priv->dai_data.uni;
187 struct snd_pcm_runtime *runtime = substream->runtime; 183 struct snd_pcm_runtime *runtime = substream->runtime;
188 int transfer_size, trigger_limit, ret; 184 int transfer_size, trigger_limit, ret;
189 int count = 10;
190 185
191 /* The reader should be stopped */ 186 /* The reader should be stopped */
192 if (reader->state != UNIPERIF_STATE_STOPPED) { 187 if (reader->state != UNIPERIF_STATE_STOPPED) {
193 dev_err(reader->dev, "%s: invalid reader state %d", __func__, 188 dev_err(reader->dev, "%s: invalid reader state %d\n", __func__,
194 reader->state); 189 reader->state);
195 return -EINVAL; 190 return -EINVAL;
196 } 191 }
@@ -219,7 +214,8 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
219 if ((!trigger_limit % 2) || 214 if ((!trigger_limit % 2) ||
220 (trigger_limit != 1 && transfer_size % 2) || 215 (trigger_limit != 1 && transfer_size % 2) ||
221 (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { 216 (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) {
222 dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); 217 dev_err(reader->dev, "invalid trigger limit %d\n",
218 trigger_limit);
223 return -EINVAL; 219 return -EINVAL;
224 } 220 }
225 221
@@ -246,7 +242,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
246 SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); 242 SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader);
247 break; 243 break;
248 default: 244 default:
249 dev_err(reader->dev, "format not supported"); 245 dev_err(reader->dev, "format not supported\n");
250 return -EINVAL; 246 return -EINVAL;
251 } 247 }
252 248
@@ -287,25 +283,14 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream,
287 } 283 }
288 284
289 /* Reset uniperipheral reader */ 285 /* Reset uniperipheral reader */
290 SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); 286 return sti_uniperiph_reset(reader);
291
292 while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) {
293 udelay(5);
294 count--;
295 }
296 if (!count) {
297 dev_err(reader->dev, "Failed to reset uniperif");
298 return -EIO;
299 }
300
301 return 0;
302} 287}
303 288
304static int uni_reader_start(struct uniperif *reader) 289static int uni_reader_start(struct uniperif *reader)
305{ 290{
306 /* The reader should be stopped */ 291 /* The reader should be stopped */
307 if (reader->state != UNIPERIF_STATE_STOPPED) { 292 if (reader->state != UNIPERIF_STATE_STOPPED) {
308 dev_err(reader->dev, "%s: invalid reader state", __func__); 293 dev_err(reader->dev, "%s: invalid reader state\n", __func__);
309 return -EINVAL; 294 return -EINVAL;
310 } 295 }
311 296
@@ -325,7 +310,7 @@ static int uni_reader_stop(struct uniperif *reader)
325{ 310{
326 /* The reader should not be in stopped state */ 311 /* The reader should not be in stopped state */
327 if (reader->state == UNIPERIF_STATE_STOPPED) { 312 if (reader->state == UNIPERIF_STATE_STOPPED) {
328 dev_err(reader->dev, "%s: invalid reader state", __func__); 313 dev_err(reader->dev, "%s: invalid reader state\n", __func__);
329 return -EINVAL; 314 return -EINVAL;
330 } 315 }
331 316
@@ -423,7 +408,7 @@ int uni_reader_init(struct platform_device *pdev,
423 uni_reader_irq_handler, IRQF_SHARED, 408 uni_reader_irq_handler, IRQF_SHARED,
424 dev_name(&pdev->dev), reader); 409 dev_name(&pdev->dev), reader);
425 if (ret < 0) { 410 if (ret < 0) {
426 dev_err(&pdev->dev, "Failed to request IRQ"); 411 dev_err(&pdev->dev, "Failed to request IRQ\n");
427 return -EBUSY; 412 return -EBUSY;
428 } 413 }
429 414
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index dd2368297fd3..6c344e16aca4 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -9,6 +9,14 @@ config SND_SUN4I_CODEC
9 Select Y or M to add support for the Codec embedded in the Allwinner 9 Select Y or M to add support for the Codec embedded in the Allwinner
10 A10 and affiliated SoCs. 10 A10 and affiliated SoCs.
11 11
12config SND_SUN8I_CODEC_ANALOG
13 tristate "Allwinner sun8i Codec Analog Controls Support"
14 depends on MACH_SUN8I || COMPILE_TEST
15 select REGMAP
16 help
17 Say Y or M if you want to add support for the analog controls for
18 the codec embedded in newer Allwinner SoCs.
19
12config SND_SUN4I_I2S 20config SND_SUN4I_I2S
13 tristate "Allwinner A10 I2S Support" 21 tristate "Allwinner A10 I2S Support"
14 select SND_SOC_GENERIC_DMAENGINE_PCM 22 select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index 604c7b842837..241c0df9ca0c 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o 1obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
2obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o 2obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
3obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o 3obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
4obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 56ed9472e89f..848af01692a0 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -3,6 +3,7 @@
3 * Copyright 2014 Jon Smirl <jonsmirl@gmail.com> 3 * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
4 * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com> 4 * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
5 * Copyright 2015 Adam Sampson <ats@offog.org> 5 * Copyright 2015 Adam Sampson <ats@offog.org>
6 * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
6 * 7 *
7 * Based on the Allwinner SDK driver, released under the GPL. 8 * Based on the Allwinner SDK driver, released under the GPL.
8 * 9 *
@@ -24,10 +25,12 @@
24#include <linux/delay.h> 25#include <linux/delay.h>
25#include <linux/slab.h> 26#include <linux/slab.h>
26#include <linux/of.h> 27#include <linux/of.h>
27#include <linux/of_platform.h>
28#include <linux/of_address.h> 28#include <linux/of_address.h>
29#include <linux/of_device.h>
30#include <linux/of_platform.h>
29#include <linux/clk.h> 31#include <linux/clk.h>
30#include <linux/regmap.h> 32#include <linux/regmap.h>
33#include <linux/reset.h>
31#include <linux/gpio/consumer.h> 34#include <linux/gpio/consumer.h>
32 35
33#include <sound/core.h> 36#include <sound/core.h>
@@ -38,7 +41,7 @@
38#include <sound/initval.h> 41#include <sound/initval.h>
39#include <sound/dmaengine_pcm.h> 42#include <sound/dmaengine_pcm.h>
40 43
41/* Codec DAC register offsets and bit fields */ 44/* Codec DAC digital controls and FIFO registers */
42#define SUN4I_CODEC_DAC_DPC (0x00) 45#define SUN4I_CODEC_DAC_DPC (0x00)
43#define SUN4I_CODEC_DAC_DPC_EN_DA (31) 46#define SUN4I_CODEC_DAC_DPC_EN_DA (31)
44#define SUN4I_CODEC_DAC_DPC_DVOL (12) 47#define SUN4I_CODEC_DAC_DPC_DVOL (12)
@@ -55,6 +58,8 @@
55#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0) 58#define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0)
56#define SUN4I_CODEC_DAC_FIFOS (0x08) 59#define SUN4I_CODEC_DAC_FIFOS (0x08)
57#define SUN4I_CODEC_DAC_TXDATA (0x0c) 60#define SUN4I_CODEC_DAC_TXDATA (0x0c)
61
62/* Codec DAC side analog signal controls */
58#define SUN4I_CODEC_DAC_ACTL (0x10) 63#define SUN4I_CODEC_DAC_ACTL (0x10)
59#define SUN4I_CODEC_DAC_ACTL_DACAENR (31) 64#define SUN4I_CODEC_DAC_ACTL_DACAENR (31)
60#define SUN4I_CODEC_DAC_ACTL_DACAENL (30) 65#define SUN4I_CODEC_DAC_ACTL_DACAENL (30)
@@ -69,7 +74,7 @@
69#define SUN4I_CODEC_DAC_TUNE (0x14) 74#define SUN4I_CODEC_DAC_TUNE (0x14)
70#define SUN4I_CODEC_DAC_DEBUG (0x18) 75#define SUN4I_CODEC_DAC_DEBUG (0x18)
71 76
72/* Codec ADC register offsets and bit fields */ 77/* Codec ADC digital controls and FIFO registers */
73#define SUN4I_CODEC_ADC_FIFOC (0x1c) 78#define SUN4I_CODEC_ADC_FIFOC (0x1c)
74#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) 79#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29)
75#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) 80#define SUN4I_CODEC_ADC_FIFOC_EN_AD (28)
@@ -81,6 +86,8 @@
81#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0) 86#define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0)
82#define SUN4I_CODEC_ADC_FIFOS (0x20) 87#define SUN4I_CODEC_ADC_FIFOS (0x20)
83#define SUN4I_CODEC_ADC_RXDATA (0x24) 88#define SUN4I_CODEC_ADC_RXDATA (0x24)
89
90/* Codec ADC side analog signal controls */
84#define SUN4I_CODEC_ADC_ACTL (0x28) 91#define SUN4I_CODEC_ADC_ACTL (0x28)
85#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31) 92#define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31)
86#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30) 93#define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30)
@@ -93,19 +100,141 @@
93#define SUN4I_CODEC_ADC_ACTL_DDE (3) 100#define SUN4I_CODEC_ADC_ACTL_DDE (3)
94#define SUN4I_CODEC_ADC_DEBUG (0x2c) 101#define SUN4I_CODEC_ADC_DEBUG (0x2c)
95 102
96/* Other various ADC registers */ 103/* FIFO counters */
97#define SUN4I_CODEC_DAC_TXCNT (0x30) 104#define SUN4I_CODEC_DAC_TXCNT (0x30)
98#define SUN4I_CODEC_ADC_RXCNT (0x34) 105#define SUN4I_CODEC_ADC_RXCNT (0x34)
106
107/* Calibration register (sun7i only) */
99#define SUN7I_CODEC_AC_DAC_CAL (0x38) 108#define SUN7I_CODEC_AC_DAC_CAL (0x38)
109
110/* Microphone controls (sun7i only) */
100#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) 111#define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c)
101 112
113/*
114 * sun6i specific registers
115 *
116 * sun6i shares the same digital control and FIFO registers as sun4i,
117 * but only the DAC digital controls are at the same offset. The others
118 * have been moved around to accommodate extra analog controls.
119 */
120
121/* Codec DAC digital controls and FIFO registers */
122#define SUN6I_CODEC_ADC_FIFOC (0x10)
123#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28)
124#define SUN6I_CODEC_ADC_FIFOS (0x14)
125#define SUN6I_CODEC_ADC_RXDATA (0x18)
126
127/* Output mixer and gain controls */
128#define SUN6I_CODEC_OM_DACA_CTRL (0x20)
129#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31)
130#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30)
131#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29)
132#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28)
133#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23)
134#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22)
135#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21)
136#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20)
137#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19)
138#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18)
139#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17)
140#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16)
141#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15)
142#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14)
143#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13)
144#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12)
145#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11)
146#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10)
147#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9)
148#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8)
149#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7)
150#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6)
151#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0)
152#define SUN6I_CODEC_OM_PA_CTRL (0x24)
153#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31)
154#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29)
155#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28)
156#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15)
157#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12)
158#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9)
159#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6)
160#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3)
161#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0)
162
163/* Microphone, line out and phone out controls */
164#define SUN6I_CODEC_MIC_CTRL (0x28)
165#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31)
166#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30)
167#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28)
168#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25)
169#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24)
170#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21)
171#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20)
172#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19)
173#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18)
174#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17)
175#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16)
176#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11)
177#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8)
178
179/* ADC mixer controls */
180#define SUN6I_CODEC_ADC_ACTL (0x2c)
181#define SUN6I_CODEC_ADC_ACTL_ADCREN (31)
182#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30)
183#define SUN6I_CODEC_ADC_ACTL_ADCRG (27)
184#define SUN6I_CODEC_ADC_ACTL_ADCLG (24)
185#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13)
186#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12)
187#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11)
188#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10)
189#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9)
190#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8)
191#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7)
192#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6)
193#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5)
194#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4)
195#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3)
196#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2)
197#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1)
198#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0)
199
200/* Analog performance tuning controls */
201#define SUN6I_CODEC_ADDA_TUNE (0x30)
202
203/* Calibration controls */
204#define SUN6I_CODEC_CALIBRATION (0x34)
205
206/* FIFO counters */
207#define SUN6I_CODEC_DAC_TXCNT (0x40)
208#define SUN6I_CODEC_ADC_RXCNT (0x44)
209
210/* headset jack detection and button support registers */
211#define SUN6I_CODEC_HMIC_CTL (0x50)
212#define SUN6I_CODEC_HMIC_DATA (0x54)
213
214/* TODO sun6i DAP (Digital Audio Processing) bits */
215
216/* FIFO counters moved on A23 */
217#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c)
218#define SUN8I_A23_CODEC_ADC_RXCNT (0x20)
219
220/* TX FIFO moved on H3 */
221#define SUN8I_H3_CODEC_DAC_TXDATA (0x20)
222#define SUN8I_H3_CODEC_DAC_DBG (0x48)
223#define SUN8I_H3_CODEC_ADC_DBG (0x4c)
224
225/* TODO H3 DAP (Digital Audio Processing) bits */
226
102struct sun4i_codec { 227struct sun4i_codec {
103 struct device *dev; 228 struct device *dev;
104 struct regmap *regmap; 229 struct regmap *regmap;
105 struct clk *clk_apb; 230 struct clk *clk_apb;
106 struct clk *clk_module; 231 struct clk *clk_module;
232 struct reset_control *rst;
107 struct gpio_desc *gpio_pa; 233 struct gpio_desc *gpio_pa;
108 234
235 /* ADC_FIFOC register is at different offset on different SoCs */
236 struct regmap_field *reg_adc_fifoc;
237
109 struct snd_dmaengine_dai_dma_data capture_dma_data; 238 struct snd_dmaengine_dai_dma_data capture_dma_data;
110 struct snd_dmaengine_dai_dma_data playback_dma_data; 239 struct snd_dmaengine_dai_dma_data playback_dma_data;
111}; 240};
@@ -134,16 +263,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
134static void sun4i_codec_start_capture(struct sun4i_codec *scodec) 263static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
135{ 264{
136 /* Enable ADC DRQ */ 265 /* Enable ADC DRQ */
137 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 266 regmap_field_update_bits(scodec->reg_adc_fifoc,
138 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 267 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
139 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); 268 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
140} 269}
141 270
142static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) 271static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
143{ 272{
144 /* Disable ADC DRQ */ 273 /* Disable ADC DRQ */
145 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 274 regmap_field_update_bits(scodec->reg_adc_fifoc,
146 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); 275 BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
147} 276}
148 277
149static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, 278static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -186,24 +315,29 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
186 315
187 316
188 /* Flush RX FIFO */ 317 /* Flush RX FIFO */
189 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 318 regmap_field_update_bits(scodec->reg_adc_fifoc,
190 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), 319 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
191 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); 320 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
192 321
193 322
194 /* Set RX FIFO trigger level */ 323 /* Set RX FIFO trigger level */
195 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 324 regmap_field_update_bits(scodec->reg_adc_fifoc,
196 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, 325 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL,
197 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); 326 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL);
198 327
199 /* 328 /*
200 * FIXME: Undocumented in the datasheet, but 329 * FIXME: Undocumented in the datasheet, but
201 * Allwinner's code mentions that it is related 330 * Allwinner's code mentions that it is related
202 * related to microphone gain 331 * related to microphone gain
203 */ 332 */
204 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, 333 if (of_device_is_compatible(scodec->dev->of_node,
205 0x3 << 25, 334 "allwinner,sun4i-a10-codec") ||
206 0x1 << 25); 335 of_device_is_compatible(scodec->dev->of_node,
336 "allwinner,sun7i-a20-codec")) {
337 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL,
338 0x3 << 25,
339 0x1 << 25);
340 }
207 341
208 if (of_device_is_compatible(scodec->dev->of_node, 342 if (of_device_is_compatible(scodec->dev->of_node,
209 "allwinner,sun7i-a20-codec")) 343 "allwinner,sun7i-a20-codec"))
@@ -213,9 +347,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
213 0x1 << 8); 347 0x1 << 8);
214 348
215 /* Fill most significant bits with valid data MSB */ 349 /* Fill most significant bits with valid data MSB */
216 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 350 regmap_field_update_bits(scodec->reg_adc_fifoc,
217 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), 351 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
218 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); 352 BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
219 353
220 return 0; 354 return 0;
221} 355}
@@ -342,18 +476,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
342 unsigned int hwrate) 476 unsigned int hwrate)
343{ 477{
344 /* Set ADC sample rate */ 478 /* Set ADC sample rate */
345 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 479 regmap_field_update_bits(scodec->reg_adc_fifoc,
346 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, 480 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS,
347 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); 481 hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS);
348 482
349 /* Set the number of channels we want to use */ 483 /* Set the number of channels we want to use */
350 if (params_channels(params) == 1) 484 if (params_channels(params) == 1)
351 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 485 regmap_field_update_bits(scodec->reg_adc_fifoc,
352 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 486 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
353 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); 487 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
354 else 488 else
355 regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, 489 regmap_field_update_bits(scodec->reg_adc_fifoc,
356 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); 490 BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
491 0);
357 492
358 return 0; 493 return 0;
359} 494}
@@ -502,7 +637,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
502 }, 637 },
503}; 638};
504 639
505/*** Codec ***/ 640/*** sun4i Codec ***/
506static const struct snd_kcontrol_new sun4i_codec_pa_mute = 641static const struct snd_kcontrol_new sun4i_codec_pa_mute =
507 SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL, 642 SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
508 SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); 643 SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
@@ -638,6 +773,337 @@ static struct snd_soc_codec_driver sun4i_codec_codec = {
638 }, 773 },
639}; 774};
640 775
776/*** sun6i Codec ***/
777
778/* mixer controls */
779static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = {
780 SOC_DAPM_DOUBLE("DAC Playback Switch",
781 SUN6I_CODEC_OM_DACA_CTRL,
782 SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL,
783 SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0),
784 SOC_DAPM_DOUBLE("DAC Reversed Playback Switch",
785 SUN6I_CODEC_OM_DACA_CTRL,
786 SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR,
787 SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0),
788 SOC_DAPM_DOUBLE("Line In Playback Switch",
789 SUN6I_CODEC_OM_DACA_CTRL,
790 SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL,
791 SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0),
792 SOC_DAPM_DOUBLE("Mic1 Playback Switch",
793 SUN6I_CODEC_OM_DACA_CTRL,
794 SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1,
795 SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0),
796 SOC_DAPM_DOUBLE("Mic2 Playback Switch",
797 SUN6I_CODEC_OM_DACA_CTRL,
798 SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2,
799 SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0),
800};
801
802/* ADC mixer controls */
803static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = {
804 SOC_DAPM_DOUBLE("Mixer Capture Switch",
805 SUN6I_CODEC_ADC_ACTL,
806 SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL,
807 SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0),
808 SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch",
809 SUN6I_CODEC_ADC_ACTL,
810 SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR,
811 SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0),
812 SOC_DAPM_DOUBLE("Line In Capture Switch",
813 SUN6I_CODEC_ADC_ACTL,
814 SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL,
815 SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0),
816 SOC_DAPM_DOUBLE("Mic1 Capture Switch",
817 SUN6I_CODEC_ADC_ACTL,
818 SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1,
819 SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0),
820 SOC_DAPM_DOUBLE("Mic2 Capture Switch",
821 SUN6I_CODEC_ADC_ACTL,
822 SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2,
823 SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0),
824};
825
826/* headphone controls */
827static const char * const sun6i_codec_hp_src_enum_text[] = {
828 "DAC", "Mixer",
829};
830
831static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum,
832 SUN6I_CODEC_OM_DACA_CTRL,
833 SUN6I_CODEC_OM_DACA_CTRL_LHPIS,
834 SUN6I_CODEC_OM_DACA_CTRL_RHPIS,
835 sun6i_codec_hp_src_enum_text);
836
837static const struct snd_kcontrol_new sun6i_codec_hp_src[] = {
838 SOC_DAPM_ENUM("Headphone Source Playback Route",
839 sun6i_codec_hp_src_enum),
840};
841
842/* microphone controls */
843static const char * const sun6i_codec_mic2_src_enum_text[] = {
844 "Mic2", "Mic3",
845};
846
847static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum,
848 SUN6I_CODEC_MIC_CTRL,
849 SUN6I_CODEC_MIC_CTRL_MIC2SLT,
850 sun6i_codec_mic2_src_enum_text);
851
852static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = {
853 SOC_DAPM_ENUM("Mic2 Amplifier Source Route",
854 sun6i_codec_mic2_src_enum),
855};
856
857/* line out controls */
858static const char * const sun6i_codec_lineout_src_enum_text[] = {
859 "Stereo", "Mono Differential",
860};
861
862static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum,
863 SUN6I_CODEC_MIC_CTRL,
864 SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC,
865 SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC,
866 sun6i_codec_lineout_src_enum_text);
867
868static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = {
869 SOC_DAPM_ENUM("Line Out Source Playback Route",
870 sun6i_codec_lineout_src_enum),
871};
872
873/* volume / mute controls */
874static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0);
875static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1);
876static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale,
877 -450, 150, 0);
878static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale,
879 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
880 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
881);
882static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale,
883 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
884 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
885);
886
887static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = {
888 SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
889 SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
890 sun6i_codec_dvol_scale),
891 SOC_SINGLE_TLV("Headphone Playback Volume",
892 SUN6I_CODEC_OM_DACA_CTRL,
893 SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
894 sun6i_codec_hp_vol_scale),
895 SOC_SINGLE_TLV("Line Out Playback Volume",
896 SUN6I_CODEC_MIC_CTRL,
897 SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0,
898 sun6i_codec_lineout_vol_scale),
899 SOC_DOUBLE("Headphone Playback Switch",
900 SUN6I_CODEC_OM_DACA_CTRL,
901 SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE,
902 SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
903 SOC_DOUBLE("Line Out Playback Switch",
904 SUN6I_CODEC_MIC_CTRL,
905 SUN6I_CODEC_MIC_CTRL_LINEOUTLEN,
906 SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0),
907 /* Mixer pre-gains */
908 SOC_SINGLE_TLV("Line In Playback Volume",
909 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING,
910 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
911 SOC_SINGLE_TLV("Mic1 Playback Volume",
912 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G,
913 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
914 SOC_SINGLE_TLV("Mic2 Playback Volume",
915 SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G,
916 0x7, 0, sun6i_codec_out_mixer_pregain_scale),
917
918 /* Microphone Amp boost gains */
919 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL,
920 SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0,
921 sun6i_codec_mic_gain_scale),
922 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL,
923 SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0,
924 sun6i_codec_mic_gain_scale),
925 SOC_DOUBLE_TLV("ADC Capture Volume",
926 SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG,
927 SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0,
928 sun6i_codec_out_mixer_pregain_scale),
929};
930
931static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = {
932 /* Microphone inputs */
933 SND_SOC_DAPM_INPUT("MIC1"),
934 SND_SOC_DAPM_INPUT("MIC2"),
935 SND_SOC_DAPM_INPUT("MIC3"),
936
937 /* Microphone Bias */
938 SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL,
939 SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0),
940 SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL,
941 SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0),
942
943 /* Mic input path */
944 SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route",
945 SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src),
946 SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL,
947 SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0),
948 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL,
949 SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0),
950
951 /* Line In */
952 SND_SOC_DAPM_INPUT("LINEIN"),
953
954 /* Digital parts of the ADCs */
955 SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
956 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0,
957 NULL, 0),
958
959 /* Analog parts of the ADCs */
960 SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
961 SUN6I_CODEC_ADC_ACTL_ADCLEN, 0),
962 SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL,
963 SUN6I_CODEC_ADC_ACTL_ADCREN, 0),
964
965 /* ADC Mixers */
966 SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
967 sun6i_codec_adc_mixer_controls),
968 SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
969 sun6i_codec_adc_mixer_controls),
970
971 /* Digital parts of the DACs */
972 SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
973 SUN4I_CODEC_DAC_DPC_EN_DA, 0,
974 NULL, 0),
975
976 /* Analog parts of the DACs */
977 SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
978 SUN6I_CODEC_OM_DACA_CTRL,
979 SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0),
980 SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
981 SUN6I_CODEC_OM_DACA_CTRL,
982 SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0),
983
984 /* Mixers */
985 SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL,
986 SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0,
987 sun6i_codec_mixer_controls),
988 SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL,
989 SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0,
990 sun6i_codec_mixer_controls),
991
992 /* Headphone output path */
993 SND_SOC_DAPM_MUX("Headphone Source Playback Route",
994 SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src),
995 SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL,
996 SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0),
997 SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL,
998 SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0),
999 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL,
1000 SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
1001 SND_SOC_DAPM_OUTPUT("HP"),
1002
1003 /* Line Out path */
1004 SND_SOC_DAPM_MUX("Line Out Source Playback Route",
1005 SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src),
1006 SND_SOC_DAPM_OUTPUT("LINEOUT"),
1007};
1008
1009static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1010 /* DAC Routes */
1011 { "Left DAC", NULL, "DAC Enable" },
1012 { "Right DAC", NULL, "DAC Enable" },
1013
1014 /* Microphone Routes */
1015 { "Mic1 Amplifier", NULL, "MIC1"},
1016 { "Mic2 Amplifier Source Route", "Mic2", "MIC2" },
1017 { "Mic2 Amplifier Source Route", "Mic3", "MIC3" },
1018 { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"},
1019
1020 /* Left Mixer Routes */
1021 { "Left Mixer", "DAC Playback Switch", "Left DAC" },
1022 { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
1023 { "Left Mixer", "Line In Playback Switch", "LINEIN" },
1024 { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1025 { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1026
1027 /* Right Mixer Routes */
1028 { "Right Mixer", "DAC Playback Switch", "Right DAC" },
1029 { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
1030 { "Right Mixer", "Line In Playback Switch", "LINEIN" },
1031 { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
1032 { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
1033
1034 /* Left ADC Mixer Routes */
1035 { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
1036 { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
1037 { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
1038 { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1039 { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1040
1041 /* Right ADC Mixer Routes */
1042 { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
1043 { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
1044 { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
1045 { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
1046 { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
1047
1048 /* Headphone Routes */
1049 { "Headphone Source Playback Route", "DAC", "Left DAC" },
1050 { "Headphone Source Playback Route", "DAC", "Right DAC" },
1051 { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
1052 { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
1053 { "Headphone Amp", NULL, "Headphone Source Playback Route" },
1054 { "HP", NULL, "Headphone Amp" },
1055 { "HPCOM", NULL, "HPCOM Protection" },
1056
1057 /* Line Out Routes */
1058 { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
1059 { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
1060 { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
1061 { "LINEOUT", NULL, "Line Out Source Playback Route" },
1062
1063 /* ADC Routes */
1064 { "Left ADC", NULL, "ADC Enable" },
1065 { "Right ADC", NULL, "ADC Enable" },
1066 { "Left ADC", NULL, "Left ADC Mixer" },
1067 { "Right ADC", NULL, "Right ADC Mixer" },
1068};
1069
1070static struct snd_soc_codec_driver sun6i_codec_codec = {
1071 .component_driver = {
1072 .controls = sun6i_codec_codec_widgets,
1073 .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
1074 .dapm_widgets = sun6i_codec_codec_dapm_widgets,
1075 .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets),
1076 .dapm_routes = sun6i_codec_codec_dapm_routes,
1077 .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes),
1078 },
1079};
1080
1081/* sun8i A23 codec */
1082static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = {
1083 SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
1084 SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
1085 sun6i_codec_dvol_scale),
1086};
1087
1088static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1089 /* Digital parts of the ADCs */
1090 SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC,
1091 SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0),
1092 /* Digital parts of the DACs */
1093 SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
1094 SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0),
1095
1096};
1097
1098static struct snd_soc_codec_driver sun8i_a23_codec_codec = {
1099 .component_driver = {
1100 .controls = sun8i_a23_codec_codec_controls,
1101 .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
1102 .dapm_widgets = sun8i_a23_codec_codec_widgets,
1103 .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets),
1104 },
1105};
1106
641static const struct snd_soc_component_driver sun4i_codec_component = { 1107static const struct snd_soc_component_driver sun4i_codec_component = {
642 .name = "sun4i-codec", 1108 .name = "sun4i-codec",
643}; 1109};
@@ -678,45 +1144,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
678 }, 1144 },
679}; 1145};
680 1146
681static const struct regmap_config sun4i_codec_regmap_config = {
682 .reg_bits = 32,
683 .reg_stride = 4,
684 .val_bits = 32,
685 .max_register = SUN4I_CODEC_ADC_RXCNT,
686};
687
688static const struct regmap_config sun7i_codec_regmap_config = {
689 .reg_bits = 32,
690 .reg_stride = 4,
691 .val_bits = 32,
692 .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
693};
694
695struct sun4i_codec_quirks {
696 const struct regmap_config *regmap_config;
697};
698
699static const struct sun4i_codec_quirks sun4i_codec_quirks = {
700 .regmap_config = &sun4i_codec_regmap_config,
701};
702
703static const struct sun4i_codec_quirks sun7i_codec_quirks = {
704 .regmap_config = &sun7i_codec_regmap_config,
705};
706
707static const struct of_device_id sun4i_codec_of_match[] = {
708 {
709 .compatible = "allwinner,sun4i-a10-codec",
710 .data = &sun4i_codec_quirks,
711 },
712 {
713 .compatible = "allwinner,sun7i-a20-codec",
714 .data = &sun7i_codec_quirks,
715 },
716 {}
717};
718MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
719
720static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, 1147static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
721 int *num_links) 1148 int *num_links)
722{ 1149{
@@ -781,6 +1208,259 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
781 return card; 1208 return card;
782}; 1209};
783 1210
1211static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = {
1212 SND_SOC_DAPM_HP("Headphone", NULL),
1213 SND_SOC_DAPM_LINE("Line In", NULL),
1214 SND_SOC_DAPM_LINE("Line Out", NULL),
1215 SND_SOC_DAPM_MIC("Headset Mic", NULL),
1216 SND_SOC_DAPM_MIC("Mic", NULL),
1217 SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
1218};
1219
1220static struct snd_soc_card *sun6i_codec_create_card(struct device *dev)
1221{
1222 struct snd_soc_card *card;
1223 int ret;
1224
1225 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1226 if (!card)
1227 return ERR_PTR(-ENOMEM);
1228
1229 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1230 if (!card->dai_link)
1231 return ERR_PTR(-ENOMEM);
1232
1233 card->dev = dev;
1234 card->name = "A31 Audio Codec";
1235 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1236 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1237 card->fully_routed = true;
1238
1239 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1240 if (ret)
1241 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1242
1243 return card;
1244};
1245
1246/* Connect digital side enables to analog side widgets */
1247static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = {
1248 /* ADC Routes */
1249 { "Left ADC", NULL, "ADC Enable" },
1250 { "Right ADC", NULL, "ADC Enable" },
1251 { "Codec Capture", NULL, "Left ADC" },
1252 { "Codec Capture", NULL, "Right ADC" },
1253
1254 /* DAC Routes */
1255 { "Left DAC", NULL, "DAC Enable" },
1256 { "Right DAC", NULL, "DAC Enable" },
1257 { "Left DAC", NULL, "Codec Playback" },
1258 { "Right DAC", NULL, "Codec Playback" },
1259};
1260
1261static struct snd_soc_aux_dev aux_dev = {
1262 .name = "Codec Analog Controls",
1263};
1264
1265static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev)
1266{
1267 struct snd_soc_card *card;
1268 int ret;
1269
1270 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1271 if (!card)
1272 return ERR_PTR(-ENOMEM);
1273
1274 aux_dev.codec_of_node = of_parse_phandle(dev->of_node,
1275 "allwinner,codec-analog-controls",
1276 0);
1277 if (!aux_dev.codec_of_node) {
1278 dev_err(dev, "Can't find analog controls for codec.\n");
1279 return ERR_PTR(-EINVAL);
1280 };
1281
1282 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1283 if (!card->dai_link)
1284 return ERR_PTR(-ENOMEM);
1285
1286 card->dev = dev;
1287 card->name = "A23 Audio Codec";
1288 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1289 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1290 card->dapm_routes = sun8i_codec_card_routes;
1291 card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1292 card->aux_dev = &aux_dev;
1293 card->num_aux_devs = 1;
1294 card->fully_routed = true;
1295
1296 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1297 if (ret)
1298 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1299
1300 return card;
1301};
1302
1303static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev)
1304{
1305 struct snd_soc_card *card;
1306 int ret;
1307
1308 card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
1309 if (!card)
1310 return ERR_PTR(-ENOMEM);
1311
1312 aux_dev.codec_of_node = of_parse_phandle(dev->of_node,
1313 "allwinner,codec-analog-controls",
1314 0);
1315 if (!aux_dev.codec_of_node) {
1316 dev_err(dev, "Can't find analog controls for codec.\n");
1317 return ERR_PTR(-EINVAL);
1318 };
1319
1320 card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
1321 if (!card->dai_link)
1322 return ERR_PTR(-ENOMEM);
1323
1324 card->dev = dev;
1325 card->name = "H3 Audio Codec";
1326 card->dapm_widgets = sun6i_codec_card_dapm_widgets;
1327 card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets);
1328 card->dapm_routes = sun8i_codec_card_routes;
1329 card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes);
1330 card->aux_dev = &aux_dev;
1331 card->num_aux_devs = 1;
1332 card->fully_routed = true;
1333
1334 ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
1335 if (ret)
1336 dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
1337
1338 return card;
1339};
1340
1341static const struct regmap_config sun4i_codec_regmap_config = {
1342 .reg_bits = 32,
1343 .reg_stride = 4,
1344 .val_bits = 32,
1345 .max_register = SUN4I_CODEC_ADC_RXCNT,
1346};
1347
1348static const struct regmap_config sun6i_codec_regmap_config = {
1349 .reg_bits = 32,
1350 .reg_stride = 4,
1351 .val_bits = 32,
1352 .max_register = SUN6I_CODEC_HMIC_DATA,
1353};
1354
1355static const struct regmap_config sun7i_codec_regmap_config = {
1356 .reg_bits = 32,
1357 .reg_stride = 4,
1358 .val_bits = 32,
1359 .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL,
1360};
1361
1362static const struct regmap_config sun8i_a23_codec_regmap_config = {
1363 .reg_bits = 32,
1364 .reg_stride = 4,
1365 .val_bits = 32,
1366 .max_register = SUN8I_A23_CODEC_ADC_RXCNT,
1367};
1368
1369static const struct regmap_config sun8i_h3_codec_regmap_config = {
1370 .reg_bits = 32,
1371 .reg_stride = 4,
1372 .val_bits = 32,
1373 .max_register = SUN8I_H3_CODEC_ADC_DBG,
1374};
1375
1376struct sun4i_codec_quirks {
1377 const struct regmap_config *regmap_config;
1378 const struct snd_soc_codec_driver *codec;
1379 struct snd_soc_card * (*create_card)(struct device *dev);
1380 struct reg_field reg_adc_fifoc; /* used for regmap_field */
1381 unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */
1382 unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
1383 bool has_reset;
1384};
1385
1386static const struct sun4i_codec_quirks sun4i_codec_quirks = {
1387 .regmap_config = &sun4i_codec_regmap_config,
1388 .codec = &sun4i_codec_codec,
1389 .create_card = sun4i_codec_create_card,
1390 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1391 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1392 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1393};
1394
1395static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
1396 .regmap_config = &sun6i_codec_regmap_config,
1397 .codec = &sun6i_codec_codec,
1398 .create_card = sun6i_codec_create_card,
1399 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1400 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1401 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1402 .has_reset = true,
1403};
1404
1405static const struct sun4i_codec_quirks sun7i_codec_quirks = {
1406 .regmap_config = &sun7i_codec_regmap_config,
1407 .codec = &sun4i_codec_codec,
1408 .create_card = sun4i_codec_create_card,
1409 .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
1410 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1411 .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
1412};
1413
1414static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
1415 .regmap_config = &sun8i_a23_codec_regmap_config,
1416 .codec = &sun8i_a23_codec_codec,
1417 .create_card = sun8i_a23_codec_create_card,
1418 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1419 .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
1420 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1421 .has_reset = true,
1422};
1423
1424static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
1425 .regmap_config = &sun8i_h3_codec_regmap_config,
1426 /*
1427 * TODO Share the codec structure with A23 for now.
1428 * This should be split out when adding digital audio
1429 * processing support for the H3.
1430 */
1431 .codec = &sun8i_a23_codec_codec,
1432 .create_card = sun8i_h3_codec_create_card,
1433 .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31),
1434 .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
1435 .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
1436 .has_reset = true,
1437};
1438
1439static const struct of_device_id sun4i_codec_of_match[] = {
1440 {
1441 .compatible = "allwinner,sun4i-a10-codec",
1442 .data = &sun4i_codec_quirks,
1443 },
1444 {
1445 .compatible = "allwinner,sun6i-a31-codec",
1446 .data = &sun6i_a31_codec_quirks,
1447 },
1448 {
1449 .compatible = "allwinner,sun7i-a20-codec",
1450 .data = &sun7i_codec_quirks,
1451 },
1452 {
1453 .compatible = "allwinner,sun8i-a23-codec",
1454 .data = &sun8i_a23_codec_quirks,
1455 },
1456 {
1457 .compatible = "allwinner,sun8i-h3-codec",
1458 .data = &sun8i_h3_codec_quirks,
1459 },
1460 {}
1461};
1462MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
1463
784static int sun4i_codec_probe(struct platform_device *pdev) 1464static int sun4i_codec_probe(struct platform_device *pdev)
785{ 1465{
786 struct snd_soc_card *card; 1466 struct snd_soc_card *card;
@@ -829,6 +1509,14 @@ static int sun4i_codec_probe(struct platform_device *pdev)
829 return PTR_ERR(scodec->clk_module); 1509 return PTR_ERR(scodec->clk_module);
830 } 1510 }
831 1511
1512 if (quirks->has_reset) {
1513 scodec->rst = devm_reset_control_get(&pdev->dev, NULL);
1514 if (IS_ERR(scodec->rst)) {
1515 dev_err(&pdev->dev, "Failed to get reset control\n");
1516 return PTR_ERR(scodec->rst);
1517 }
1518 }
1519
832 scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", 1520 scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
833 GPIOD_OUT_LOW); 1521 GPIOD_OUT_LOW);
834 if (IS_ERR(scodec->gpio_pa)) { 1522 if (IS_ERR(scodec->gpio_pa)) {
@@ -838,27 +1526,48 @@ static int sun4i_codec_probe(struct platform_device *pdev)
838 return ret; 1526 return ret;
839 } 1527 }
840 1528
1529 /* reg_field setup */
1530 scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
1531 scodec->regmap,
1532 quirks->reg_adc_fifoc);
1533 if (IS_ERR(scodec->reg_adc_fifoc)) {
1534 ret = PTR_ERR(scodec->reg_adc_fifoc);
1535 dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
1536 ret);
1537 return ret;
1538 }
1539
841 /* Enable the bus clock */ 1540 /* Enable the bus clock */
842 if (clk_prepare_enable(scodec->clk_apb)) { 1541 if (clk_prepare_enable(scodec->clk_apb)) {
843 dev_err(&pdev->dev, "Failed to enable the APB clock\n"); 1542 dev_err(&pdev->dev, "Failed to enable the APB clock\n");
844 return -EINVAL; 1543 return -EINVAL;
845 } 1544 }
846 1545
1546 /* Deassert the reset control */
1547 if (scodec->rst) {
1548 ret = reset_control_deassert(scodec->rst);
1549 if (ret) {
1550 dev_err(&pdev->dev,
1551 "Failed to deassert the reset control\n");
1552 goto err_clk_disable;
1553 }
1554 }
1555
847 /* DMA configuration for TX FIFO */ 1556 /* DMA configuration for TX FIFO */
848 scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; 1557 scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
849 scodec->playback_dma_data.maxburst = 4; 1558 scodec->playback_dma_data.maxburst = 8;
850 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 1559 scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
851 1560
852 /* DMA configuration for RX FIFO */ 1561 /* DMA configuration for RX FIFO */
853 scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; 1562 scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
854 scodec->capture_dma_data.maxburst = 4; 1563 scodec->capture_dma_data.maxburst = 8;
855 scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 1564 scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
856 1565
857 ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, 1566 ret = snd_soc_register_codec(&pdev->dev, quirks->codec,
858 &sun4i_codec_dai, 1); 1567 &sun4i_codec_dai, 1);
859 if (ret) { 1568 if (ret) {
860 dev_err(&pdev->dev, "Failed to register our codec\n"); 1569 dev_err(&pdev->dev, "Failed to register our codec\n");
861 goto err_clk_disable; 1570 goto err_assert_reset;
862 } 1571 }
863 1572
864 ret = devm_snd_soc_register_component(&pdev->dev, 1573 ret = devm_snd_soc_register_component(&pdev->dev,
@@ -875,7 +1584,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
875 goto err_unregister_codec; 1584 goto err_unregister_codec;
876 } 1585 }
877 1586
878 card = sun4i_codec_create_card(&pdev->dev); 1587 card = quirks->create_card(&pdev->dev);
879 if (IS_ERR(card)) { 1588 if (IS_ERR(card)) {
880 ret = PTR_ERR(card); 1589 ret = PTR_ERR(card);
881 dev_err(&pdev->dev, "Failed to create our card\n"); 1590 dev_err(&pdev->dev, "Failed to create our card\n");
@@ -895,6 +1604,9 @@ static int sun4i_codec_probe(struct platform_device *pdev)
895 1604
896err_unregister_codec: 1605err_unregister_codec:
897 snd_soc_unregister_codec(&pdev->dev); 1606 snd_soc_unregister_codec(&pdev->dev);
1607err_assert_reset:
1608 if (scodec->rst)
1609 reset_control_assert(scodec->rst);
898err_clk_disable: 1610err_clk_disable:
899 clk_disable_unprepare(scodec->clk_apb); 1611 clk_disable_unprepare(scodec->clk_apb);
900 return ret; 1612 return ret;
@@ -907,6 +1619,8 @@ static int sun4i_codec_remove(struct platform_device *pdev)
907 1619
908 snd_soc_unregister_card(card); 1620 snd_soc_unregister_card(card);
909 snd_soc_unregister_codec(&pdev->dev); 1621 snd_soc_unregister_codec(&pdev->dev);
1622 if (scodec->rst)
1623 reset_control_assert(scodec->rst);
910 clk_disable_unprepare(scodec->clk_apb); 1624 clk_disable_unprepare(scodec->clk_apb);
911 1625
912 return 0; 1626 return 0;
@@ -926,4 +1640,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver");
926MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>"); 1640MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
927MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>"); 1641MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
928MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 1642MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1643MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
929MODULE_LICENSE("GPL"); 1644MODULE_LICENSE("GPL");
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 687a8f83dbe5..f24d19526603 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -93,6 +93,9 @@ struct sun4i_i2s {
93 struct clk *mod_clk; 93 struct clk *mod_clk;
94 struct regmap *regmap; 94 struct regmap *regmap;
95 95
96 unsigned int mclk_freq;
97
98 struct snd_dmaengine_dai_dma_data capture_dma_data;
96 struct snd_dmaengine_dai_dma_data playback_dma_data; 99 struct snd_dmaengine_dai_dma_data playback_dma_data;
97}; 100};
98 101
@@ -157,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
157} 160}
158 161
159static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; 162static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
163static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
164{
165 int i;
166
167 for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++)
168 if (sun4i_i2s_oversample_rates[i] == oversample)
169 return true;
170
171 return false;
172}
160 173
161static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, 174static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
162 unsigned int rate, 175 unsigned int rate,
163 unsigned int word_size) 176 unsigned int word_size)
164{ 177{
165 unsigned int clk_rate; 178 unsigned int oversample_rate, clk_rate;
166 int bclk_div, mclk_div; 179 int bclk_div, mclk_div;
167 int ret, i; 180 int ret;
168 181
169 switch (rate) { 182 switch (rate) {
170 case 176400: 183 case 176400:
@@ -196,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
196 if (ret) 209 if (ret)
197 return ret; 210 return ret;
198 211
199 /* Always favor the highest oversampling rate */ 212 oversample_rate = i2s->mclk_freq / rate;
200 for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { 213 if (!sun4i_i2s_oversample_is_valid(oversample_rate))
201 unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; 214 return -EINVAL;
202
203 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
204 word_size);
205 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
206 clk_rate,
207 rate);
208 215
209 if ((bclk_div >= 0) && (mclk_div >= 0)) 216 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
210 break; 217 word_size);
211 } 218 if (bclk_div < 0)
219 return -EINVAL;
212 220
213 if ((bclk_div < 0) || (mclk_div < 0)) 221 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
222 clk_rate, rate);
223 if (mclk_div < 0)
214 return -EINVAL; 224 return -EINVAL;
215 225
216 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, 226 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
@@ -341,6 +351,27 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
341 return 0; 351 return 0;
342} 352}
343 353
354static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
355{
356 /* Flush RX FIFO */
357 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
358 SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
359 SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
360
361 /* Clear RX counter */
362 regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
363
364 /* Enable RX Block */
365 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
366 SUN4I_I2S_CTRL_RX_EN,
367 SUN4I_I2S_CTRL_RX_EN);
368
369 /* Enable RX DRQ */
370 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
371 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
372 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
373}
374
344static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) 375static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
345{ 376{
346 /* Flush TX FIFO */ 377 /* Flush TX FIFO */
@@ -362,6 +393,18 @@ static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
362 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); 393 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);
363} 394}
364 395
396static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s)
397{
398 /* Disable RX Block */
399 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
400 SUN4I_I2S_CTRL_RX_EN,
401 0);
402
403 /* Disable RX DRQ */
404 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
405 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
406 0);
407}
365 408
366static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) 409static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)
367{ 410{
@@ -388,7 +431,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
388 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 431 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
389 sun4i_i2s_start_playback(i2s); 432 sun4i_i2s_start_playback(i2s);
390 else 433 else
391 return -EINVAL; 434 sun4i_i2s_start_capture(i2s);
392 break; 435 break;
393 436
394 case SNDRV_PCM_TRIGGER_STOP: 437 case SNDRV_PCM_TRIGGER_STOP:
@@ -397,7 +440,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
397 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 440 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
398 sun4i_i2s_stop_playback(i2s); 441 sun4i_i2s_stop_playback(i2s);
399 else 442 else
400 return -EINVAL; 443 sun4i_i2s_stop_capture(i2s);
401 break; 444 break;
402 445
403 default: 446 default:
@@ -447,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
447 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); 490 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
448} 491}
449 492
493static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
494 unsigned int freq, int dir)
495{
496 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
497
498 if (clk_id != 0)
499 return -EINVAL;
500
501 i2s->mclk_freq = freq;
502
503 return 0;
504}
505
450static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { 506static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
451 .hw_params = sun4i_i2s_hw_params, 507 .hw_params = sun4i_i2s_hw_params,
452 .set_fmt = sun4i_i2s_set_fmt, 508 .set_fmt = sun4i_i2s_set_fmt,
509 .set_sysclk = sun4i_i2s_set_sysclk,
453 .shutdown = sun4i_i2s_shutdown, 510 .shutdown = sun4i_i2s_shutdown,
454 .startup = sun4i_i2s_startup, 511 .startup = sun4i_i2s_startup,
455 .trigger = sun4i_i2s_trigger, 512 .trigger = sun4i_i2s_trigger,
@@ -459,7 +516,9 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
459{ 516{
460 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 517 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
461 518
462 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); 519 snd_soc_dai_init_dma_data(dai,
520 &i2s->playback_dma_data,
521 &i2s->capture_dma_data);
463 522
464 snd_soc_dai_set_drvdata(dai, i2s); 523 snd_soc_dai_set_drvdata(dai, i2s);
465 524
@@ -468,6 +527,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
468 527
469static struct snd_soc_dai_driver sun4i_i2s_dai = { 528static struct snd_soc_dai_driver sun4i_i2s_dai = {
470 .probe = sun4i_i2s_dai_probe, 529 .probe = sun4i_i2s_dai_probe,
530 .capture = {
531 .stream_name = "Capture",
532 .channels_min = 2,
533 .channels_max = 2,
534 .rates = SNDRV_PCM_RATE_8000_192000,
535 .formats = SNDRV_PCM_FMTBIT_S16_LE,
536 },
471 .playback = { 537 .playback = {
472 .stream_name = "Playback", 538 .stream_name = "Playback",
473 .channels_min = 2, 539 .channels_min = 2,
@@ -630,6 +696,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
630 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; 696 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
631 i2s->playback_dma_data.maxburst = 4; 697 i2s->playback_dma_data.maxburst = 4;
632 698
699 i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
700 i2s->capture_dma_data.maxburst = 4;
701
633 pm_runtime_enable(&pdev->dev); 702 pm_runtime_enable(&pdev->dev);
634 if (!pm_runtime_enabled(&pdev->dev)) { 703 if (!pm_runtime_enabled(&pdev->dev)) {
635 ret = sun4i_i2s_runtime_resume(&pdev->dev); 704 ret = sun4i_i2s_runtime_resume(&pdev->dev);
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
new file mode 100644
index 000000000000..af02290ebe49
--- /dev/null
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -0,0 +1,665 @@
1/*
2 * This driver supports the analog controls for the internal codec
3 * found in Allwinner's A31s, A23, A33 and H3 SoCs.
4 *
5 * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/of.h>
22#include <linux/of_device.h>
23#include <linux/platform_device.h>
24#include <linux/regmap.h>
25
26#include <sound/soc.h>
27#include <sound/soc-dapm.h>
28#include <sound/tlv.h>
29
30/* Codec analog control register offsets and bit fields */
31#define SUN8I_ADDA_HP_VOLC 0x00
32#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7
33#define SUN8I_ADDA_HP_VOLC_HP_VOL 0
34#define SUN8I_ADDA_LOMIXSC 0x01
35#define SUN8I_ADDA_LOMIXSC_MIC1 6
36#define SUN8I_ADDA_LOMIXSC_MIC2 5
37#define SUN8I_ADDA_LOMIXSC_PHONE 4
38#define SUN8I_ADDA_LOMIXSC_PHONEN 3
39#define SUN8I_ADDA_LOMIXSC_LINEINL 2
40#define SUN8I_ADDA_LOMIXSC_DACL 1
41#define SUN8I_ADDA_LOMIXSC_DACR 0
42#define SUN8I_ADDA_ROMIXSC 0x02
43#define SUN8I_ADDA_ROMIXSC_MIC1 6
44#define SUN8I_ADDA_ROMIXSC_MIC2 5
45#define SUN8I_ADDA_ROMIXSC_PHONE 4
46#define SUN8I_ADDA_ROMIXSC_PHONEP 3
47#define SUN8I_ADDA_ROMIXSC_LINEINR 2
48#define SUN8I_ADDA_ROMIXSC_DACR 1
49#define SUN8I_ADDA_ROMIXSC_DACL 0
50#define SUN8I_ADDA_DAC_PA_SRC 0x03
51#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7
52#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6
53#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5
54#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4
55#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3
56#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2
57#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1
58#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0
59#define SUN8I_ADDA_PHONEIN_GCTRL 0x04
60#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4
61#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0
62#define SUN8I_ADDA_LINEIN_GCTRL 0x05
63#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4
64#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0
65#define SUN8I_ADDA_MICIN_GCTRL 0x06
66#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4
67#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0
68#define SUN8I_ADDA_PAEN_HP_CTRL 0x07
69#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7
70#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */
71#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5
72#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4
73#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2
74#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1
75#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0
76#define SUN8I_ADDA_PHONEOUT_CTRL 0x08
77#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5
78#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4
79#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3
80#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2
81#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1
82#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0
83#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09
84#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3
85#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0
86#define SUN8I_ADDA_MIC2G_CTRL 0x0a
87#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7
88#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4
89#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3
90#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2
91#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1
92#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0
93#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b
94#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7
95#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6
96#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5
97#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3
98#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0
99#define SUN8I_ADDA_LADCMIXSC 0x0c
100#define SUN8I_ADDA_LADCMIXSC_MIC1 6
101#define SUN8I_ADDA_LADCMIXSC_MIC2 5
102#define SUN8I_ADDA_LADCMIXSC_PHONE 4
103#define SUN8I_ADDA_LADCMIXSC_PHONEN 3
104#define SUN8I_ADDA_LADCMIXSC_LINEINL 2
105#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1
106#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0
107#define SUN8I_ADDA_RADCMIXSC 0x0d
108#define SUN8I_ADDA_RADCMIXSC_MIC1 6
109#define SUN8I_ADDA_RADCMIXSC_MIC2 5
110#define SUN8I_ADDA_RADCMIXSC_PHONE 4
111#define SUN8I_ADDA_RADCMIXSC_PHONEP 3
112#define SUN8I_ADDA_RADCMIXSC_LINEINR 2
113#define SUN8I_ADDA_RADCMIXSC_OMIXR 1
114#define SUN8I_ADDA_RADCMIXSC_OMIXL 0
115#define SUN8I_ADDA_RES 0x0e
116#define SUN8I_ADDA_RES_MMICBIAS_SEL 4
117#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0
118#define SUN8I_ADDA_ADC_AP_EN 0x0f
119#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7
120#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
121#define SUN8I_ADDA_ADC_AP_EN_ADCG 0
122
123/* Analog control register access bits */
124#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
125#define ADDA_PR_RESET BIT(28)
126#define ADDA_PR_WRITE BIT(24)
127#define ADDA_PR_ADDR_SHIFT 16
128#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
129#define ADDA_PR_DATA_IN_SHIFT 8
130#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
131#define ADDA_PR_DATA_OUT_SHIFT 0
132#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
133
134/* regmap access bits */
135static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
136{
137 void __iomem *base = (void __iomem *)context;
138 u32 tmp;
139
140 /* De-assert reset */
141 writel(readl(base) | ADDA_PR_RESET, base);
142
143 /* Clear write bit */
144 writel(readl(base) & ~ADDA_PR_WRITE, base);
145
146 /* Set register address */
147 tmp = readl(base);
148 tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
149 tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
150 writel(tmp, base);
151
152 /* Read back value */
153 *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
154
155 return 0;
156}
157
158static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
159{
160 void __iomem *base = (void __iomem *)context;
161 u32 tmp;
162
163 /* De-assert reset */
164 writel(readl(base) | ADDA_PR_RESET, base);
165
166 /* Set register address */
167 tmp = readl(base);
168 tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
169 tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
170 writel(tmp, base);
171
172 /* Set data to write */
173 tmp = readl(base);
174 tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
175 tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
176 writel(tmp, base);
177
178 /* Set write bit to signal a write */
179 writel(readl(base) | ADDA_PR_WRITE, base);
180
181 /* Clear write bit */
182 writel(readl(base) & ~ADDA_PR_WRITE, base);
183
184 return 0;
185}
186
187static const struct regmap_config adda_pr_regmap_cfg = {
188 .name = "adda-pr",
189 .reg_bits = 5,
190 .reg_stride = 1,
191 .val_bits = 8,
192 .reg_read = adda_reg_read,
193 .reg_write = adda_reg_write,
194 .fast_io = true,
195 .max_register = 24,
196};
197
198/* mixer controls */
199static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
200 SOC_DAPM_DOUBLE_R("DAC Playback Switch",
201 SUN8I_ADDA_LOMIXSC,
202 SUN8I_ADDA_ROMIXSC,
203 SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
204 SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
205 SUN8I_ADDA_LOMIXSC,
206 SUN8I_ADDA_ROMIXSC,
207 SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
208 SOC_DAPM_DOUBLE_R("Line In Playback Switch",
209 SUN8I_ADDA_LOMIXSC,
210 SUN8I_ADDA_ROMIXSC,
211 SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
212 SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
213 SUN8I_ADDA_LOMIXSC,
214 SUN8I_ADDA_ROMIXSC,
215 SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
216 SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
217 SUN8I_ADDA_LOMIXSC,
218 SUN8I_ADDA_ROMIXSC,
219 SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
220};
221
222/* ADC mixer controls */
223static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
224 SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
225 SUN8I_ADDA_LADCMIXSC,
226 SUN8I_ADDA_RADCMIXSC,
227 SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
228 SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
229 SUN8I_ADDA_LADCMIXSC,
230 SUN8I_ADDA_RADCMIXSC,
231 SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
232 SOC_DAPM_DOUBLE_R("Line In Capture Switch",
233 SUN8I_ADDA_LADCMIXSC,
234 SUN8I_ADDA_RADCMIXSC,
235 SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
236 SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
237 SUN8I_ADDA_LADCMIXSC,
238 SUN8I_ADDA_RADCMIXSC,
239 SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
240 SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
241 SUN8I_ADDA_LADCMIXSC,
242 SUN8I_ADDA_RADCMIXSC,
243 SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
244};
245
246/* volume / mute controls */
247static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
248 -450, 150, 0);
249static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
250 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
251 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
252);
253
254static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
255 /* Mixer pre-gains */
256 SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
257 SUN8I_ADDA_LINEIN_GCTRL_LINEING,
258 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
259 SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
260 SUN8I_ADDA_MICIN_GCTRL_MIC1G,
261 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
262 SOC_SINGLE_TLV("Mic2 Playback Volume",
263 SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
264 0x7, 0, sun8i_codec_out_mixer_pregain_scale),
265
266 /* Microphone Amp boost gains */
267 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
268 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
269 sun8i_codec_mic_gain_scale),
270 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
271 SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
272 sun8i_codec_mic_gain_scale),
273
274 /* ADC */
275 SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
276 SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
277 sun8i_codec_out_mixer_pregain_scale),
278};
279
280static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
281 /* ADC */
282 SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
283 SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
284 SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
285 SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
286
287 /* DAC */
288 SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
289 SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
290 SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
291 SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
292 /*
293 * Due to this component and the codec belonging to separate DAPM
294 * contexts, we need to manually link the above widgets to their
295 * stream widgets at the card level.
296 */
297
298 /* Line In */
299 SND_SOC_DAPM_INPUT("LINEIN"),
300
301 /* Microphone inputs */
302 SND_SOC_DAPM_INPUT("MIC1"),
303 SND_SOC_DAPM_INPUT("MIC2"),
304
305 /* Microphone Bias */
306 SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
307 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
308 0, NULL, 0),
309
310 /* Mic input path */
311 SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
312 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
313 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
314 SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
315
316 /* Mixers */
317 SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
318 SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
319 sun8i_codec_mixer_controls,
320 ARRAY_SIZE(sun8i_codec_mixer_controls)),
321 SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
322 SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
323 sun8i_codec_mixer_controls,
324 ARRAY_SIZE(sun8i_codec_mixer_controls)),
325 SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
326 SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
327 sun8i_codec_adc_mixer_controls,
328 ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
329 SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
330 SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
331 sun8i_codec_adc_mixer_controls,
332 ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
333};
334
335static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
336 /* Microphone Routes */
337 { "Mic1 Amplifier", NULL, "MIC1"},
338 { "Mic2 Amplifier", NULL, "MIC2"},
339
340 /* Left Mixer Routes */
341 { "Left Mixer", "DAC Playback Switch", "Left DAC" },
342 { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
343 { "Left Mixer", "Line In Playback Switch", "LINEIN" },
344 { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
345 { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
346
347 /* Right Mixer Routes */
348 { "Right Mixer", "DAC Playback Switch", "Right DAC" },
349 { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
350 { "Right Mixer", "Line In Playback Switch", "LINEIN" },
351 { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
352 { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
353
354 /* Left ADC Mixer Routes */
355 { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
356 { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
357 { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
358 { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
359 { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
360
361 /* Right ADC Mixer Routes */
362 { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
363 { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
364 { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
365 { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
366 { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
367
368 /* ADC Routes */
369 { "Left ADC", NULL, "Left ADC Mixer" },
370 { "Right ADC", NULL, "Right ADC Mixer" },
371};
372
373/* headphone specific controls, widgets, and routes */
374static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
375static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
376 SOC_SINGLE_TLV("Headphone Playback Volume",
377 SUN8I_ADDA_HP_VOLC,
378 SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
379 sun8i_codec_hp_vol_scale),
380 SOC_DOUBLE("Headphone Playback Switch",
381 SUN8I_ADDA_DAC_PA_SRC,
382 SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
383 SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
384};
385
386static const char * const sun8i_codec_hp_src_enum_text[] = {
387 "DAC", "Mixer",
388};
389
390static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
391 SUN8I_ADDA_DAC_PA_SRC,
392 SUN8I_ADDA_DAC_PA_SRC_LHPIS,
393 SUN8I_ADDA_DAC_PA_SRC_RHPIS,
394 sun8i_codec_hp_src_enum_text);
395
396static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
397 SOC_DAPM_ENUM("Headphone Source Playback Route",
398 sun8i_codec_hp_src_enum),
399};
400
401static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
402 SND_SOC_DAPM_MUX("Headphone Source Playback Route",
403 SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
404 SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
405 SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
406 SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
407 SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
408 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
409 SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
410 SND_SOC_DAPM_OUTPUT("HP"),
411};
412
413static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
414 { "Headphone Source Playback Route", "DAC", "Left DAC" },
415 { "Headphone Source Playback Route", "DAC", "Right DAC" },
416 { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
417 { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
418 { "Headphone Amp", NULL, "Headphone Source Playback Route" },
419 { "HPCOM", NULL, "HPCOM Protection" },
420 { "HP", NULL, "Headphone Amp" },
421};
422
423static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
424{
425 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
426 struct device *dev = cmpnt->dev;
427 int ret;
428
429 ret = snd_soc_add_component_controls(cmpnt,
430 sun8i_codec_headphone_controls,
431 ARRAY_SIZE(sun8i_codec_headphone_controls));
432 if (ret) {
433 dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
434 return ret;
435 }
436
437 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
438 ARRAY_SIZE(sun8i_codec_headphone_widgets));
439 if (ret) {
440 dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
441 return ret;
442 }
443
444 ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
445 ARRAY_SIZE(sun8i_codec_headphone_routes));
446 if (ret) {
447 dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
448 return ret;
449 }
450
451 return 0;
452}
453
454/* hmic specific widget */
455static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
456 SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
457 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
458 0, NULL, 0),
459};
460
461static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
462{
463 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
464 struct device *dev = cmpnt->dev;
465 int ret;
466
467 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
468 ARRAY_SIZE(sun8i_codec_hmic_widgets));
469 if (ret)
470 dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
471
472 return ret;
473}
474
475/* line out specific controls, widgets and routes */
476static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
477 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
478 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
479);
480static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
481 SOC_SINGLE_TLV("Line Out Playback Volume",
482 SUN8I_ADDA_PHONE_GAIN_CTRL,
483 SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
484 sun8i_codec_lineout_vol_scale),
485 SOC_DOUBLE("Line Out Playback Switch",
486 SUN8I_ADDA_MIC2G_CTRL,
487 SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
488 SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
489};
490
491static const char * const sun8i_codec_lineout_src_enum_text[] = {
492 "Stereo", "Mono Differential",
493};
494
495static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
496 SUN8I_ADDA_MIC2G_CTRL,
497 SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
498 SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
499 sun8i_codec_lineout_src_enum_text);
500
501static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
502 SOC_DAPM_ENUM("Line Out Source Playback Route",
503 sun8i_codec_lineout_src_enum),
504};
505
506static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
507 SND_SOC_DAPM_MUX("Line Out Source Playback Route",
508 SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
509 /* It is unclear if this is a buffer or gate, model it as a supply */
510 SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
511 SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
512 SND_SOC_DAPM_OUTPUT("LINEOUT"),
513};
514
515static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
516 { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
517 { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
518 { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
519 { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
520 { "LINEOUT", NULL, "Line Out Source Playback Route" },
521 { "LINEOUT", NULL, "Line Out Enable", },
522};
523
524static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
525{
526 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
527 struct device *dev = cmpnt->dev;
528 int ret;
529
530 ret = snd_soc_add_component_controls(cmpnt,
531 sun8i_codec_lineout_controls,
532 ARRAY_SIZE(sun8i_codec_lineout_controls));
533 if (ret) {
534 dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
535 return ret;
536 }
537
538 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
539 ARRAY_SIZE(sun8i_codec_lineout_widgets));
540 if (ret) {
541 dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
542 return ret;
543 }
544
545 ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
546 ARRAY_SIZE(sun8i_codec_lineout_routes));
547 if (ret) {
548 dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
549 return ret;
550 }
551
552 return 0;
553}
554
555struct sun8i_codec_analog_quirks {
556 bool has_headphone;
557 bool has_hmic;
558 bool has_lineout;
559};
560
561static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
562 .has_headphone = true,
563 .has_hmic = true,
564};
565
566static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
567 .has_lineout = true,
568};
569
570static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
571{
572 struct device *dev = cmpnt->dev;
573 const struct sun8i_codec_analog_quirks *quirks;
574 int ret;
575
576 /*
577 * This would never return NULL unless someone directly registers a
578 * platform device matching this driver's name, without specifying a
579 * device tree node.
580 */
581 quirks = of_device_get_match_data(dev);
582
583 /* Add controls, widgets, and routes for individual features */
584
585 if (quirks->has_headphone) {
586 ret = sun8i_codec_add_headphone(cmpnt);
587 if (ret)
588 return ret;
589 }
590
591 if (quirks->has_hmic) {
592 ret = sun8i_codec_add_hmic(cmpnt);
593 if (ret)
594 return ret;
595 }
596
597 if (quirks->has_lineout) {
598 ret = sun8i_codec_add_lineout(cmpnt);
599 if (ret)
600 return ret;
601 }
602
603 return 0;
604}
605
606static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
607 .controls = sun8i_codec_common_controls,
608 .num_controls = ARRAY_SIZE(sun8i_codec_common_controls),
609 .dapm_widgets = sun8i_codec_common_widgets,
610 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets),
611 .dapm_routes = sun8i_codec_common_routes,
612 .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes),
613 .probe = sun8i_codec_analog_cmpnt_probe,
614};
615
616static const struct of_device_id sun8i_codec_analog_of_match[] = {
617 {
618 .compatible = "allwinner,sun8i-a23-codec-analog",
619 .data = &sun8i_a23_quirks,
620 },
621 {
622 .compatible = "allwinner,sun8i-h3-codec-analog",
623 .data = &sun8i_h3_quirks,
624 },
625 {}
626};
627MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
628
629static int sun8i_codec_analog_probe(struct platform_device *pdev)
630{
631 struct resource *res;
632 struct regmap *regmap;
633 void __iomem *base;
634
635 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
636 base = devm_ioremap_resource(&pdev->dev, res);
637 if (IS_ERR(base)) {
638 dev_err(&pdev->dev, "Failed to map the registers\n");
639 return PTR_ERR(base);
640 }
641
642 regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
643 if (IS_ERR(regmap)) {
644 dev_err(&pdev->dev, "Failed to create regmap\n");
645 return PTR_ERR(regmap);
646 }
647
648 return devm_snd_soc_register_component(&pdev->dev,
649 &sun8i_codec_analog_cmpnt_drv,
650 NULL, 0);
651}
652
653static struct platform_driver sun8i_codec_analog_driver = {
654 .driver = {
655 .name = "sun8i-codec-analog",
656 .of_match_table = sun8i_codec_analog_of_match,
657 },
658 .probe = sun8i_codec_analog_probe,
659};
660module_platform_driver(sun8i_codec_analog_driver);
661
662MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
663MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
664MODULE_LICENSE("GPL");
665MODULE_ALIAS("platform:sun8i-codec-analog");
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index deb597f7c302..eead6e7f205b 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -65,7 +65,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,
65 return 0; 65 return 0;
66} 66}
67 67
68static struct snd_soc_ops tegra_alc5632_asoc_ops = { 68static const struct snd_soc_ops tegra_alc5632_asoc_ops = {
69 .hw_params = tegra_alc5632_asoc_hw_params, 69 .hw_params = tegra_alc5632_asoc_hw_params,
70}; 70};
71 71
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index 902da36581d1..a403db6d563e 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -93,7 +93,7 @@ static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
93 return 0; 93 return 0;
94} 94}
95 95
96static struct snd_soc_ops tegra_max98090_ops = { 96static const struct snd_soc_ops tegra_max98090_ops = {
97 .hw_params = tegra_max98090_asoc_hw_params, 97 .hw_params = tegra_max98090_asoc_hw_params,
98}; 98};
99 99
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index e5ef4e9c4ac5..25b9fc03ba62 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -76,7 +76,7 @@ static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream,
76 return 0; 76 return 0;
77} 77}
78 78
79static struct snd_soc_ops tegra_rt5640_ops = { 79static const struct snd_soc_ops tegra_rt5640_ops = {
80 .hw_params = tegra_rt5640_asoc_hw_params, 80 .hw_params = tegra_rt5640_asoc_hw_params,
81}; 81};
82 82
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
index 1470873ecde6..ebf58d0e0f10 100644
--- a/sound/soc/tegra/tegra_rt5677.c
+++ b/sound/soc/tegra/tegra_rt5677.c
@@ -93,7 +93,7 @@ static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w,
93 return 0; 93 return 0;
94} 94}
95 95
96static struct snd_soc_ops tegra_rt5677_ops = { 96static const struct snd_soc_ops tegra_rt5677_ops = {
97 .hw_params = tegra_rt5677_asoc_hw_params, 97 .hw_params = tegra_rt5677_asoc_hw_params,
98}; 98};
99 99
diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c
index 1e76869dd488..4bbab098f50b 100644
--- a/sound/soc/tegra/tegra_sgtl5000.c
+++ b/sound/soc/tegra/tegra_sgtl5000.c
@@ -82,7 +82,7 @@ static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream,
82 return 0; 82 return 0;
83} 83}
84 84
85static struct snd_soc_ops tegra_sgtl5000_ops = { 85static const struct snd_soc_ops tegra_sgtl5000_ops = {
86 .hw_params = tegra_sgtl5000_hw_params, 86 .hw_params = tegra_sgtl5000_hw_params,
87}; 87};
88 88
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index f0cd01dbfc38..bdedd1028569 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -89,7 +89,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
89 return 0; 89 return 0;
90} 90}
91 91
92static struct snd_soc_ops tegra_wm8753_ops = { 92static const struct snd_soc_ops tegra_wm8753_ops = {
93 .hw_params = tegra_wm8753_hw_params, 93 .hw_params = tegra_wm8753_hw_params,
94}; 94};
95 95
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index e485278e027a..2013e9c4bba0 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -96,7 +96,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
96 return 0; 96 return 0;
97} 97}
98 98
99static struct snd_soc_ops tegra_wm8903_ops = { 99static const struct snd_soc_ops tegra_wm8903_ops = {
100 .hw_params = tegra_wm8903_hw_params, 100 .hw_params = tegra_wm8903_hw_params,
101}; 101};
102 102
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 2cea203c4f5f..870f84ab5005 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -74,7 +74,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream,
74 return 0; 74 return 0;
75} 75}
76 76
77static struct snd_soc_ops trimslice_asoc_ops = { 77static const struct snd_soc_ops trimslice_asoc_ops = {
78 .hw_params = trimslice_asoc_hw_params, 78 .hw_params = trimslice_asoc_hw_params,
79}; 79};
80 80