aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/simple-scu-card.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/sun4i-i2s.txt2
-rw-r--r--include/sound/simple_card_utils.h1
-rw-r--r--sound/soc/codecs/sta32x.c3
-rw-r--r--sound/soc/generic/audio-graph-card.c1
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c1
-rw-r--r--sound/soc/generic/simple-card-utils.c9
-rw-r--r--sound/soc/generic/simple-scu-card.c5
-rw-r--r--sound/soc/spear/spdif_in.c12
-rw-r--r--sound/soc/spear/spdif_out.c4
-rw-r--r--sound/soc/stm/stm32_i2s.c2
-rw-r--r--sound/soc/stm/stm32_sai.c2
-rw-r--r--sound/soc/stm/stm32_spdifrx.c2
-rw-r--r--sound/soc/sunxi/sun4i-codec.c15
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c455
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c14
-rw-r--r--sound/soc/sunxi/sun8i-codec.c4
18 files changed, 442 insertions, 94 deletions
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index c7a93931fad2..166f2290233b 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -86,6 +86,9 @@ Optional CPU/CODEC subnodes properties:
86 in dai startup() and disabled with 86 in dai startup() and disabled with
87 clk_disable_unprepare() in dai 87 clk_disable_unprepare() in dai
88 shutdown(). 88 shutdown().
89- system-clock-direction-out : specifies clock direction as 'out' on
90 initialization. It is useful for some aCPUs with
91 fixed clocks.
89 92
90Example 1 - single DAI link: 93Example 1 - single DAI link:
91 94
diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
index 327d229a51b2..32f8dbce5241 100644
--- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-scu-card.txt
@@ -24,6 +24,7 @@ Optional subnode properties:
24- simple-audio-card,convert-rate : platform specified sampling rate convert 24- simple-audio-card,convert-rate : platform specified sampling rate convert
25- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) 25- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch)
26- simple-audio-card,prefix : see routing 26- simple-audio-card,prefix : see routing
27- simple-audio-card,widgets : Please refer to widgets.txt.
27- simple-audio-card,routing : A list of the connections between audio components. 28- simple-audio-card,routing : A list of the connections between audio components.
28 Each entry is a pair of strings, the first being the connection's sink, 29 Each entry is a pair of strings, the first being the connection's sink,
29 the second being the connection's source. Valid names for sources. 30 the second being the connection's source. Valid names for sources.
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index ee21da865771..fc5da6080759 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -8,6 +8,7 @@ Required properties:
8- compatible: should be one of the following: 8- compatible: should be one of the following:
9 - "allwinner,sun4i-a10-i2s" 9 - "allwinner,sun4i-a10-i2s"
10 - "allwinner,sun6i-a31-i2s" 10 - "allwinner,sun6i-a31-i2s"
11 - "allwinner,sun8i-h3-i2s"
11- reg: physical base address of the controller and length of memory mapped 12- reg: physical base address of the controller and length of memory mapped
12 region. 13 region.
13- interrupts: should contain the I2S interrupt. 14- interrupts: should contain the I2S interrupt.
@@ -22,6 +23,7 @@ Required properties:
22 23
23Required properties for the following compatibles: 24Required properties for the following compatibles:
24 - "allwinner,sun6i-a31-i2s" 25 - "allwinner,sun6i-a31-i2s"
26 - "allwinner,sun8i-h3-i2s"
25- resets: phandle to the reset line for this codec 27- resets: phandle to the reset line for this codec
26 28
27Example: 29Example:
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 42c6a6ac3ce6..7e25afce6566 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -15,6 +15,7 @@
15struct asoc_simple_dai { 15struct asoc_simple_dai {
16 const char *name; 16 const char *name;
17 unsigned int sysclk; 17 unsigned int sysclk;
18 int clk_direction;
18 int slots; 19 int slots;
19 int slot_width; 20 int slot_width;
20 unsigned int tx_slot_mask; 21 unsigned int tx_slot_mask;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 0790ae8530d9..5b888476d9ff 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -847,8 +847,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
847 msleep(300); 847 msleep(300);
848 sta32x_watchdog_stop(sta32x); 848 sta32x_watchdog_stop(sta32x);
849 849
850 if (sta32x->gpiod_nreset) 850 gpiod_set_value(sta32x->gpiod_nreset, 0);
851 gpiod_set_value(sta32x->gpiod_nreset, 0);
852 851
853 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), 852 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
854 sta32x->supplies); 853 sta32x->supplies);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 2f7c8cf6f123..488c52f9405f 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -325,6 +325,7 @@ MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
325static struct platform_driver asoc_graph_card = { 325static struct platform_driver asoc_graph_card = {
326 .driver = { 326 .driver = {
327 .name = "asoc-audio-graph-card", 327 .name = "asoc-audio-graph-card",
328 .pm = &snd_soc_pm_ops,
328 .of_match_table = asoc_graph_of_match, 329 .of_match_table = asoc_graph_of_match,
329 }, 330 },
330 .probe = asoc_graph_card_probe, 331 .probe = asoc_graph_card_probe,
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index 06b6fcf0513e..a967aa143d51 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -401,6 +401,7 @@ MODULE_DEVICE_TABLE(of, asoc_graph_of_match);
401static struct platform_driver asoc_graph_card = { 401static struct platform_driver asoc_graph_card = {
402 .driver = { 402 .driver = {
403 .name = "asoc-audio-graph-scu-card", 403 .name = "asoc-audio-graph-scu-card",
404 .pm = &snd_soc_pm_ops,
404 .of_match_table = asoc_graph_of_match, 405 .of_match_table = asoc_graph_of_match,
405 }, 406 },
406 .probe = asoc_graph_card_probe, 407 .probe = asoc_graph_card_probe,
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index d72f7d58102f..3751a07de6aa 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -196,7 +196,11 @@ int asoc_simple_card_parse_clk(struct device *dev,
196 simple_dai->sysclk = clk_get_rate(clk); 196 simple_dai->sysclk = clk_get_rate(clk);
197 } 197 }
198 198
199 dev_dbg(dev, "%s : sysclk = %d\n", name, simple_dai->sysclk); 199 if (of_property_read_bool(node, "system-clock-direction-out"))
200 simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
201
202 dev_dbg(dev, "%s : sysclk = %d, direction %d\n", name,
203 simple_dai->sysclk, simple_dai->clk_direction);
200 204
201 return 0; 205 return 0;
202} 206}
@@ -308,7 +312,8 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
308 int ret; 312 int ret;
309 313
310 if (simple_dai->sysclk) { 314 if (simple_dai->sysclk) {
311 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, 0); 315 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
316 simple_dai->clk_direction);
312 if (ret && ret != -ENOTSUPP) { 317 if (ret && ret != -ENOTSUPP) {
313 dev_err(dai->dev, "simple-card: set_sysclk error\n"); 318 dev_err(dai->dev, "simple-card: set_sysclk error\n");
314 return ret; 319 return ret;
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index a75b385455c4..48606c63562a 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -191,6 +191,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
191 if (!node) 191 if (!node)
192 return -EINVAL; 192 return -EINVAL;
193 193
194 ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
195 if (ret < 0)
196 return ret;
197
194 ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0); 198 ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
195 if (ret < 0) 199 if (ret < 0)
196 return ret; 200 return ret;
@@ -296,6 +300,7 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
296static struct platform_driver asoc_simple_card = { 300static struct platform_driver asoc_simple_card = {
297 .driver = { 301 .driver = {
298 .name = "simple-scu-audio-card", 302 .name = "simple-scu-audio-card",
303 .pm = &snd_soc_pm_ops,
299 .of_match_table = asoc_simple_of_match, 304 .of_match_table = asoc_simple_of_match,
300 }, 305 },
301 .probe = asoc_simple_card_probe, 306 .probe = asoc_simple_card_probe,
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index 977a078eb92f..78a6a360b4a6 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -151,7 +151,7 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
151 return ret; 151 return ret;
152} 152}
153 153
154static struct snd_soc_dai_ops spdif_in_dai_ops = { 154static const struct snd_soc_dai_ops spdif_in_dai_ops = {
155 .shutdown = spdif_in_shutdown, 155 .shutdown = spdif_in_shutdown,
156 .trigger = spdif_in_trigger, 156 .trigger = spdif_in_trigger,
157 .hw_params = spdif_in_hw_params, 157 .hw_params = spdif_in_hw_params,
@@ -216,15 +216,15 @@ static int spdif_in_probe(struct platform_device *pdev)
216 return -EINVAL; 216 return -EINVAL;
217 217
218 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 218 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
219 if (!host) { 219 if (!host)
220 dev_warn(&pdev->dev, "kzalloc fail\n");
221 return -ENOMEM; 220 return -ENOMEM;
222 }
223 221
224 host->io_base = io_base; 222 host->io_base = io_base;
225 host->irq = platform_get_irq(pdev, 0); 223 host->irq = platform_get_irq(pdev, 0);
226 if (host->irq < 0) 224 if (host->irq < 0) {
227 return -EINVAL; 225 dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq);
226 return host->irq;
227 }
228 228
229 host->clk = devm_clk_get(&pdev->dev, NULL); 229 host->clk = devm_clk_get(&pdev->dev, NULL);
230 if (IS_ERR(host->clk)) 230 if (IS_ERR(host->clk))
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index 0a72d52d533e..58d5843811f9 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -282,10 +282,8 @@ static int spdif_out_probe(struct platform_device *pdev)
282 int ret; 282 int ret;
283 283
284 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 284 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
285 if (!host) { 285 if (!host)
286 dev_warn(&pdev->dev, "kzalloc fail\n");
287 return -ENOMEM; 286 return -ENOMEM;
288 }
289 287
290 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 288 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
291 host->io_base = devm_ioremap_resource(&pdev->dev, res); 289 host->io_base = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 8052629a89df..6d0bf78d114d 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -840,7 +840,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
840 } 840 }
841 841
842 /* Reset */ 842 /* Reset */
843 rst = devm_reset_control_get(&pdev->dev, NULL); 843 rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
844 if (!IS_ERR(rst)) { 844 if (!IS_ERR(rst)) {
845 reset_control_assert(rst); 845 reset_control_assert(rst);
846 udelay(2); 846 udelay(2);
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index f7713314913b..1258bef4dcb3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
85 } 85 }
86 86
87 /* reset */ 87 /* reset */
88 rst = reset_control_get(&pdev->dev, NULL); 88 rst = reset_control_get_exclusive(&pdev->dev, NULL);
89 if (!IS_ERR(rst)) { 89 if (!IS_ERR(rst)) {
90 reset_control_assert(rst); 90 reset_control_assert(rst);
91 udelay(2); 91 udelay(2);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 4e4250bdb75a..84cc5678beba 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -930,7 +930,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
930 return ret; 930 return ret;
931 } 931 }
932 932
933 rst = devm_reset_control_get(&pdev->dev, NULL); 933 rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
934 if (!IS_ERR(rst)) { 934 if (!IS_ERR(rst)) {
935 reset_control_assert(rst); 935 reset_control_assert(rst);
936 udelay(2); 936 udelay(2);
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 150069987c0c..baa9007464ed 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -762,7 +762,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = {
762 { "Mic1", NULL, "VMIC" }, 762 { "Mic1", NULL, "VMIC" },
763}; 763};
764 764
765static struct snd_soc_codec_driver sun4i_codec_codec = { 765static const struct snd_soc_codec_driver sun4i_codec_codec = {
766 .component_driver = { 766 .component_driver = {
767 .controls = sun4i_codec_controls, 767 .controls = sun4i_codec_controls,
768 .num_controls = ARRAY_SIZE(sun4i_codec_controls), 768 .num_controls = ARRAY_SIZE(sun4i_codec_controls),
@@ -1068,7 +1068,7 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
1068 { "Right ADC", NULL, "Right ADC Mixer" }, 1068 { "Right ADC", NULL, "Right ADC Mixer" },
1069}; 1069};
1070 1070
1071static struct snd_soc_codec_driver sun6i_codec_codec = { 1071static const struct snd_soc_codec_driver sun6i_codec_codec = {
1072 .component_driver = { 1072 .component_driver = {
1073 .controls = sun6i_codec_codec_widgets, 1073 .controls = sun6i_codec_codec_widgets,
1074 .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets), 1074 .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets),
@@ -1096,7 +1096,7 @@ static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = {
1096 1096
1097}; 1097};
1098 1098
1099static struct snd_soc_codec_driver sun8i_a23_codec_codec = { 1099static const struct snd_soc_codec_driver sun8i_a23_codec_codec = {
1100 .component_driver = { 1100 .component_driver = {
1101 .controls = sun8i_a23_codec_codec_controls, 1101 .controls = sun8i_a23_codec_codec_controls,
1102 .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls), 1102 .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls),
@@ -1171,9 +1171,8 @@ static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w,
1171{ 1171{
1172 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card); 1172 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card);
1173 1173
1174 if (scodec->gpio_pa) 1174 gpiod_set_value_cansleep(scodec->gpio_pa,
1175 gpiod_set_value_cansleep(scodec->gpio_pa, 1175 !!SND_SOC_DAPM_EVENT_ON(event));
1176 !!SND_SOC_DAPM_EVENT_ON(event));
1177 1176
1178 return 0; 1177 return 0;
1179} 1178}
@@ -1574,7 +1573,8 @@ static int sun4i_codec_probe(struct platform_device *pdev)
1574 } 1573 }
1575 1574
1576 if (quirks->has_reset) { 1575 if (quirks->has_reset) {
1577 scodec->rst = devm_reset_control_get(&pdev->dev, NULL); 1576 scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
1577 NULL);
1578 if (IS_ERR(scodec->rst)) { 1578 if (IS_ERR(scodec->rst)) {
1579 dev_err(&pdev->dev, "Failed to get reset control\n"); 1579 dev_err(&pdev->dev, "Failed to get reset control\n");
1580 return PTR_ERR(scodec->rst); 1580 return PTR_ERR(scodec->rst);
@@ -1655,7 +1655,6 @@ static int sun4i_codec_probe(struct platform_device *pdev)
1655 goto err_unregister_codec; 1655 goto err_unregister_codec;
1656 } 1656 }
1657 1657
1658 platform_set_drvdata(pdev, card);
1659 snd_soc_card_set_drvdata(card, scodec); 1658 snd_soc_card_set_drvdata(card, scodec);
1660 1659
1661 ret = snd_soc_register_card(card); 1660 ret = snd_soc_register_card(card);
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 3635bbc72cbc..04f92583a969 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -50,6 +50,8 @@
50#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) 50#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
51#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) 51#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0)
52#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) 52#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
53#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1)
54#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0)
53 55
54#define SUN4I_I2S_FMT1_REG 0x08 56#define SUN4I_I2S_FMT1_REG 0x08
55#define SUN4I_I2S_FIFO_TX_REG 0x0c 57#define SUN4I_I2S_FIFO_TX_REG 0x0c
@@ -82,7 +84,7 @@
82#define SUN4I_I2S_TX_CNT_REG 0x2c 84#define SUN4I_I2S_TX_CNT_REG 0x2c
83 85
84#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 86#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
85#define SUN4I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) 87#define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
86 88
87#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 89#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34
88#define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2)) 90#define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2))
@@ -90,6 +92,83 @@
90#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38 92#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38
91#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c 93#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c
92 94
95/* Defines required for sun8i-h3 support */
96#define SUN8I_I2S_CTRL_BCLK_OUT BIT(18)
97#define SUN8I_I2S_CTRL_LRCK_OUT BIT(17)
98
99#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
100#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
101
102#define SUN8I_I2S_INT_STA_REG 0x0c
103#define SUN8I_I2S_FIFO_TX_REG 0x20
104
105#define SUN8I_I2S_CHAN_CFG_REG 0x30
106#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
107#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) (chan - 1)
108#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
109#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
110
111#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
112#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
113#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 11)
114#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
115#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
116#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
117
118#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
119#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
120
121/**
122 * struct sun4i_i2s_quirks - Differences between SoC variants.
123 *
124 * @has_reset: SoC needs reset deasserted.
125 * @has_slave_select_bit: SoC has a bit to enable slave mode.
126 * @has_fmt_set_lrck_period: SoC requires lrclk period to be set.
127 * @has_chcfg: tx and rx slot number need to be set.
128 * @has_chsel_tx_chen: SoC requires that the tx channels are enabled.
129 * @has_chsel_offset: SoC uses offset for selecting dai operational mode.
130 * @reg_offset_txdata: offset of the tx fifo.
131 * @sun4i_i2s_regmap: regmap config to use.
132 * @mclk_offset: Value by which mclkdiv needs to be adjusted.
133 * @bclk_offset: Value by which bclkdiv needs to be adjusted.
134 * @fmt_offset: Value by which wss and sr needs to be adjusted.
135 * @field_clkdiv_mclk_en: regmap field to enable mclk output.
136 * @field_fmt_wss: regmap field to set word select size.
137 * @field_fmt_sr: regmap field to set sample resolution.
138 * @field_fmt_bclk: regmap field to set clk polarity.
139 * @field_fmt_lrclk: regmap field to set frame polarity.
140 * @field_fmt_mode: regmap field to set the operational mode.
141 * @field_txchanmap: location of the tx channel mapping register.
142 * @field_rxchanmap: location of the rx channel mapping register.
143 * @field_txchansel: location of the tx channel select bit fields.
144 * @field_rxchansel: location of the rx channel select bit fields.
145 */
146struct sun4i_i2s_quirks {
147 bool has_reset;
148 bool has_slave_select_bit;
149 bool has_fmt_set_lrck_period;
150 bool has_chcfg;
151 bool has_chsel_tx_chen;
152 bool has_chsel_offset;
153 unsigned int reg_offset_txdata; /* TX FIFO */
154 const struct regmap_config *sun4i_i2s_regmap;
155 unsigned int mclk_offset;
156 unsigned int bclk_offset;
157 unsigned int fmt_offset;
158
159 /* Register fields for i2s */
160 struct reg_field field_clkdiv_mclk_en;
161 struct reg_field field_fmt_wss;
162 struct reg_field field_fmt_sr;
163 struct reg_field field_fmt_bclk;
164 struct reg_field field_fmt_lrclk;
165 struct reg_field field_fmt_mode;
166 struct reg_field field_txchanmap;
167 struct reg_field field_rxchanmap;
168 struct reg_field field_txchansel;
169 struct reg_field field_rxchansel;
170};
171
93struct sun4i_i2s { 172struct sun4i_i2s {
94 struct clk *bus_clk; 173 struct clk *bus_clk;
95 struct clk *mod_clk; 174 struct clk *mod_clk;
@@ -100,6 +179,20 @@ struct sun4i_i2s {
100 179
101 struct snd_dmaengine_dai_dma_data capture_dma_data; 180 struct snd_dmaengine_dai_dma_data capture_dma_data;
102 struct snd_dmaengine_dai_dma_data playback_dma_data; 181 struct snd_dmaengine_dai_dma_data playback_dma_data;
182
183 /* Register fields for i2s */
184 struct regmap_field *field_clkdiv_mclk_en;
185 struct regmap_field *field_fmt_wss;
186 struct regmap_field *field_fmt_sr;
187 struct regmap_field *field_fmt_bclk;
188 struct regmap_field *field_fmt_lrclk;
189 struct regmap_field *field_fmt_mode;
190 struct regmap_field *field_txchanmap;
191 struct regmap_field *field_rxchanmap;
192 struct regmap_field *field_txchansel;
193 struct regmap_field *field_rxchansel;
194
195 const struct sun4i_i2s_quirks *variant;
103}; 196};
104 197
105struct sun4i_i2s_clk_div { 198struct sun4i_i2s_clk_div {
@@ -114,6 +207,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
114 { .div = 8, .val = 3 }, 207 { .div = 8, .val = 3 },
115 { .div = 12, .val = 4 }, 208 { .div = 12, .val = 4 },
116 { .div = 16, .val = 5 }, 209 { .div = 16, .val = 5 },
210 /* TODO - extend divide ratio supported by newer SoCs */
117}; 211};
118 212
119static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { 213static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
@@ -125,6 +219,7 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
125 { .div = 12, .val = 5 }, 219 { .div = 12, .val = 5 },
126 { .div = 16, .val = 6 }, 220 { .div = 16, .val = 6 },
127 { .div = 24, .val = 7 }, 221 { .div = 24, .val = 7 },
222 /* TODO - extend divide ratio supported by newer SoCs */
128}; 223};
129 224
130static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, 225static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
@@ -226,10 +321,21 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
226 if (mclk_div < 0) 321 if (mclk_div < 0)
227 return -EINVAL; 322 return -EINVAL;
228 323
324 /* Adjust the clock division values if needed */
325 bclk_div += i2s->variant->bclk_offset;
326 mclk_div += i2s->variant->mclk_offset;
327
229 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, 328 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
230 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | 329 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
231 SUN4I_I2S_CLK_DIV_MCLK(mclk_div) | 330 SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
232 SUN4I_I2S_CLK_DIV_MCLK_EN); 331
332 regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
333
334 /* Set sync period */
335 if (i2s->variant->has_fmt_set_lrck_period)
336 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
337 SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
338 SUN8I_I2S_FMT0_LRCK_PERIOD(32));
233 339
234 return 0; 340 return 0;
235} 341}
@@ -239,12 +345,38 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
239 struct snd_soc_dai *dai) 345 struct snd_soc_dai *dai)
240{ 346{
241 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 347 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
242 int sr, wss; 348 int sr, wss, channels;
243 u32 width; 349 u32 width;
244 350
245 if (params_channels(params) != 2) 351 channels = params_channels(params);
352 if (channels != 2)
246 return -EINVAL; 353 return -EINVAL;
247 354
355 if (i2s->variant->has_chcfg) {
356 regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
357 SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
358 SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
359 regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
360 SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
361 SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
362 }
363
364 /* Map the channels for playback and capture */
365 regmap_field_write(i2s->field_txchanmap, 0x76543210);
366 regmap_field_write(i2s->field_rxchanmap, 0x00003210);
367
368 /* Configure the channels */
369 regmap_field_write(i2s->field_txchansel,
370 SUN4I_I2S_CHAN_SEL(params_channels(params)));
371
372 regmap_field_write(i2s->field_rxchansel,
373 SUN4I_I2S_CHAN_SEL(params_channels(params)));
374
375 if (i2s->variant->has_chsel_tx_chen)
376 regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
377 SUN8I_I2S_TX_CHAN_EN_MASK,
378 SUN8I_I2S_TX_CHAN_EN(channels));
379
248 switch (params_physical_width(params)) { 380 switch (params_physical_width(params)) {
249 case 16: 381 case 16:
250 width = DMA_SLAVE_BUSWIDTH_2_BYTES; 382 width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -264,9 +396,10 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
264 return -EINVAL; 396 return -EINVAL;
265 } 397 }
266 398
267 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 399 regmap_field_write(i2s->field_fmt_wss,
268 SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK, 400 wss + i2s->variant->fmt_offset);
269 SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr)); 401 regmap_field_write(i2s->field_fmt_sr,
402 sr + i2s->variant->fmt_offset);
270 403
271 return sun4i_i2s_set_clk_rate(i2s, params_rate(params), 404 return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
272 params_width(params)); 405 params_width(params));
@@ -276,11 +409,15 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
276{ 409{
277 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 410 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
278 u32 val; 411 u32 val;
412 u32 offset = 0;
413 u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
414 u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL;
279 415
280 /* DAI Mode */ 416 /* DAI Mode */
281 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 417 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
282 case SND_SOC_DAIFMT_I2S: 418 case SND_SOC_DAIFMT_I2S:
283 val = SUN4I_I2S_FMT0_FMT_I2S; 419 val = SUN4I_I2S_FMT0_FMT_I2S;
420 offset = 1;
284 break; 421 break;
285 case SND_SOC_DAIFMT_LEFT_J: 422 case SND_SOC_DAIFMT_LEFT_J:
286 val = SUN4I_I2S_FMT0_FMT_LEFT_J; 423 val = SUN4I_I2S_FMT0_FMT_LEFT_J;
@@ -292,59 +429,89 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
292 return -EINVAL; 429 return -EINVAL;
293 } 430 }
294 431
295 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 432 if (i2s->variant->has_chsel_offset) {
296 SUN4I_I2S_FMT0_FMT_MASK, 433 /*
297 val); 434 * offset being set indicates that we're connected to an i2s
435 * device, however offset is only used on the sun8i block and
436 * i2s shares the same setting with the LJ format. Increment
437 * val so that the bit to value to write is correct.
438 */
439 if (offset > 0)
440 val++;
441 /* blck offset determines whether i2s or LJ */
442 regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
443 SUN8I_I2S_TX_CHAN_OFFSET_MASK,
444 SUN8I_I2S_TX_CHAN_OFFSET(offset));
445 }
446
447 regmap_field_write(i2s->field_fmt_mode, val);
298 448
299 /* DAI clock polarity */ 449 /* DAI clock polarity */
300 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 450 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
301 case SND_SOC_DAIFMT_IB_IF: 451 case SND_SOC_DAIFMT_IB_IF:
302 /* Invert both clocks */ 452 /* Invert both clocks */
303 val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | 453 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
304 SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 454 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
305 break; 455 break;
306 case SND_SOC_DAIFMT_IB_NF: 456 case SND_SOC_DAIFMT_IB_NF:
307 /* Invert bit clock */ 457 /* Invert bit clock */
308 val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | 458 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
309 SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
310 break; 459 break;
311 case SND_SOC_DAIFMT_NB_IF: 460 case SND_SOC_DAIFMT_NB_IF:
312 /* Invert frame clock */ 461 /* Invert frame clock */
313 val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED | 462 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED;
314 SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
315 break; 463 break;
316 case SND_SOC_DAIFMT_NB_NF: 464 case SND_SOC_DAIFMT_NB_NF:
317 /* Nothing to do for both normal cases */
318 val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
319 SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
320 break; 465 break;
321 default: 466 default:
322 return -EINVAL; 467 return -EINVAL;
323 } 468 }
324 469
325 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 470 regmap_field_write(i2s->field_fmt_bclk, bclk_polarity);
326 SUN4I_I2S_FMT0_BCLK_POLARITY_MASK | 471 regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity);
327 SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK, 472
328 val); 473 if (i2s->variant->has_slave_select_bit) {
329 474 /* DAI clock master masks */
330 /* DAI clock master masks */ 475 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
331 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 476 case SND_SOC_DAIFMT_CBS_CFS:
332 case SND_SOC_DAIFMT_CBS_CFS: 477 /* BCLK and LRCLK master */
333 /* BCLK and LRCLK master */ 478 val = SUN4I_I2S_CTRL_MODE_MASTER;
334 val = SUN4I_I2S_CTRL_MODE_MASTER; 479 break;
335 break; 480 case SND_SOC_DAIFMT_CBM_CFM:
336 case SND_SOC_DAIFMT_CBM_CFM: 481 /* BCLK and LRCLK slave */
337 /* BCLK and LRCLK slave */ 482 val = SUN4I_I2S_CTRL_MODE_SLAVE;
338 val = SUN4I_I2S_CTRL_MODE_SLAVE; 483 break;
339 break; 484 default:
340 default: 485 return -EINVAL;
341 return -EINVAL; 486 }
487 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
488 SUN4I_I2S_CTRL_MODE_MASK,
489 val);
490 } else {
491 /*
492 * The newer i2s block does not have a slave select bit,
493 * instead the clk pins are configured as inputs.
494 */
495 /* DAI clock master masks */
496 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
497 case SND_SOC_DAIFMT_CBS_CFS:
498 /* BCLK and LRCLK master */
499 val = SUN8I_I2S_CTRL_BCLK_OUT |
500 SUN8I_I2S_CTRL_LRCK_OUT;
501 break;
502 case SND_SOC_DAIFMT_CBM_CFM:
503 /* BCLK and LRCLK slave */
504 val = 0;
505 break;
506 default:
507 return -EINVAL;
508 }
509 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
510 SUN8I_I2S_CTRL_BCLK_OUT |
511 SUN8I_I2S_CTRL_LRCK_OUT,
512 val);
342 } 513 }
343 514
344 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
345 SUN4I_I2S_CTRL_MODE_MASK,
346 val);
347
348 /* Set significant bits in our FIFOs */ 515 /* Set significant bits in our FIFOs */
349 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, 516 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
350 SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | 517 SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
@@ -459,21 +626,14 @@ static int sun4i_i2s_startup(struct snd_pcm_substream *substream,
459 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 626 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
460 627
461 /* Enable the whole hardware block */ 628 /* Enable the whole hardware block */
462 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 629 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
463 SUN4I_I2S_CTRL_GL_EN); 630 SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
464 631
465 /* Enable the first output line */ 632 /* Enable the first output line */
466 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 633 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
467 SUN4I_I2S_CTRL_SDO_EN_MASK, 634 SUN4I_I2S_CTRL_SDO_EN_MASK,
468 SUN4I_I2S_CTRL_SDO_EN(0)); 635 SUN4I_I2S_CTRL_SDO_EN(0));
469 636
470 /* Enable the first two channels */
471 regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
472 SUN4I_I2S_TX_CHAN_SEL(2));
473
474 /* Map them to the two first samples coming in */
475 regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
476 SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
477 637
478 return clk_prepare_enable(i2s->mod_clk); 638 return clk_prepare_enable(i2s->mod_clk);
479} 639}
@@ -490,7 +650,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
490 SUN4I_I2S_CTRL_SDO_EN_MASK, 0); 650 SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
491 651
492 /* Disable the whole hardware block */ 652 /* Disable the whole hardware block */
493 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); 653 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
654 SUN4I_I2S_CTRL_GL_EN, 0);
494} 655}
495 656
496static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, 657static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -589,6 +750,27 @@ static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
589 } 750 }
590} 751}
591 752
753static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
754{
755 switch (reg) {
756 case SUN8I_I2S_FIFO_TX_REG:
757 return false;
758
759 default:
760 return true;
761 }
762}
763
764static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
765{
766 if (reg == SUN8I_I2S_INT_STA_REG)
767 return true;
768 if (reg == SUN8I_I2S_FIFO_TX_REG)
769 return false;
770
771 return sun4i_i2s_volatile_reg(dev, reg);
772}
773
592static const struct reg_default sun4i_i2s_reg_defaults[] = { 774static const struct reg_default sun4i_i2s_reg_defaults[] = {
593 { SUN4I_I2S_CTRL_REG, 0x00000000 }, 775 { SUN4I_I2S_CTRL_REG, 0x00000000 },
594 { SUN4I_I2S_FMT0_REG, 0x0000000c }, 776 { SUN4I_I2S_FMT0_REG, 0x0000000c },
@@ -602,6 +784,20 @@ static const struct reg_default sun4i_i2s_reg_defaults[] = {
602 { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 }, 784 { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },
603}; 785};
604 786
787static const struct reg_default sun8i_i2s_reg_defaults[] = {
788 { SUN4I_I2S_CTRL_REG, 0x00060000 },
789 { SUN4I_I2S_FMT0_REG, 0x00000033 },
790 { SUN4I_I2S_FMT1_REG, 0x00000030 },
791 { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
792 { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
793 { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
794 { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
795 { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
796 { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 },
797 { SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 },
798 { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
799};
800
605static const struct regmap_config sun4i_i2s_regmap_config = { 801static const struct regmap_config sun4i_i2s_regmap_config = {
606 .reg_bits = 32, 802 .reg_bits = 32,
607 .reg_stride = 4, 803 .reg_stride = 4,
@@ -616,6 +812,19 @@ static const struct regmap_config sun4i_i2s_regmap_config = {
616 .volatile_reg = sun4i_i2s_volatile_reg, 812 .volatile_reg = sun4i_i2s_volatile_reg,
617}; 813};
618 814
815static const struct regmap_config sun8i_i2s_regmap_config = {
816 .reg_bits = 32,
817 .reg_stride = 4,
818 .val_bits = 32,
819 .max_register = SUN8I_I2S_RX_CHAN_MAP_REG,
820 .cache_type = REGCACHE_FLAT,
821 .reg_defaults = sun8i_i2s_reg_defaults,
822 .num_reg_defaults = ARRAY_SIZE(sun8i_i2s_reg_defaults),
823 .writeable_reg = sun4i_i2s_wr_reg,
824 .readable_reg = sun8i_i2s_rd_reg,
825 .volatile_reg = sun8i_i2s_volatile_reg,
826};
827
619static int sun4i_i2s_runtime_resume(struct device *dev) 828static int sun4i_i2s_runtime_resume(struct device *dev)
620{ 829{
621 struct sun4i_i2s *i2s = dev_get_drvdata(dev); 830 struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -654,22 +863,129 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
654 return 0; 863 return 0;
655} 864}
656 865
657struct sun4i_i2s_quirks {
658 bool has_reset;
659};
660
661static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { 866static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
662 .has_reset = false, 867 .has_reset = false,
868 .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG,
869 .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
870 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
871 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
872 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
873 .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
874 .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
875 .has_slave_select_bit = true,
876 .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
877 .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
878 .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
879 .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
880 .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
663}; 881};
664 882
665static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { 883static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
666 .has_reset = true, 884 .has_reset = true,
885 .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG,
886 .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
887 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
888 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
889 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
890 .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
891 .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
892 .has_slave_select_bit = true,
893 .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
894 .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
895 .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
896 .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
897 .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
898};
899
900static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
901 .has_reset = true,
902 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
903 .sun4i_i2s_regmap = &sun8i_i2s_regmap_config,
904 .mclk_offset = 1,
905 .bclk_offset = 2,
906 .fmt_offset = 3,
907 .has_fmt_set_lrck_period = true,
908 .has_chcfg = true,
909 .has_chsel_tx_chen = true,
910 .has_chsel_offset = true,
911 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
912 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
913 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
914 .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
915 .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19),
916 .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5),
917 .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31),
918 .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31),
919 .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2),
920 .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2),
667}; 921};
668 922
923static int sun4i_i2s_init_regmap_fields(struct device *dev,
924 struct sun4i_i2s *i2s)
925{
926 i2s->field_clkdiv_mclk_en =
927 devm_regmap_field_alloc(dev, i2s->regmap,
928 i2s->variant->field_clkdiv_mclk_en);
929 if (IS_ERR(i2s->field_clkdiv_mclk_en))
930 return PTR_ERR(i2s->field_clkdiv_mclk_en);
931
932 i2s->field_fmt_wss =
933 devm_regmap_field_alloc(dev, i2s->regmap,
934 i2s->variant->field_fmt_wss);
935 if (IS_ERR(i2s->field_fmt_wss))
936 return PTR_ERR(i2s->field_fmt_wss);
937
938 i2s->field_fmt_sr =
939 devm_regmap_field_alloc(dev, i2s->regmap,
940 i2s->variant->field_fmt_sr);
941 if (IS_ERR(i2s->field_fmt_sr))
942 return PTR_ERR(i2s->field_fmt_sr);
943
944 i2s->field_fmt_bclk =
945 devm_regmap_field_alloc(dev, i2s->regmap,
946 i2s->variant->field_fmt_bclk);
947 if (IS_ERR(i2s->field_fmt_bclk))
948 return PTR_ERR(i2s->field_fmt_bclk);
949
950 i2s->field_fmt_lrclk =
951 devm_regmap_field_alloc(dev, i2s->regmap,
952 i2s->variant->field_fmt_lrclk);
953 if (IS_ERR(i2s->field_fmt_lrclk))
954 return PTR_ERR(i2s->field_fmt_lrclk);
955
956 i2s->field_fmt_mode =
957 devm_regmap_field_alloc(dev, i2s->regmap,
958 i2s->variant->field_fmt_mode);
959 if (IS_ERR(i2s->field_fmt_mode))
960 return PTR_ERR(i2s->field_fmt_mode);
961
962 i2s->field_txchanmap =
963 devm_regmap_field_alloc(dev, i2s->regmap,
964 i2s->variant->field_txchanmap);
965 if (IS_ERR(i2s->field_txchanmap))
966 return PTR_ERR(i2s->field_txchanmap);
967
968 i2s->field_rxchanmap =
969 devm_regmap_field_alloc(dev, i2s->regmap,
970 i2s->variant->field_rxchanmap);
971 if (IS_ERR(i2s->field_rxchanmap))
972 return PTR_ERR(i2s->field_rxchanmap);
973
974 i2s->field_txchansel =
975 devm_regmap_field_alloc(dev, i2s->regmap,
976 i2s->variant->field_txchansel);
977 if (IS_ERR(i2s->field_txchansel))
978 return PTR_ERR(i2s->field_txchansel);
979
980 i2s->field_rxchansel =
981 devm_regmap_field_alloc(dev, i2s->regmap,
982 i2s->variant->field_rxchansel);
983 return PTR_ERR_OR_ZERO(i2s->field_rxchansel);
984}
985
669static int sun4i_i2s_probe(struct platform_device *pdev) 986static int sun4i_i2s_probe(struct platform_device *pdev)
670{ 987{
671 struct sun4i_i2s *i2s; 988 struct sun4i_i2s *i2s;
672 const struct sun4i_i2s_quirks *quirks;
673 struct resource *res; 989 struct resource *res;
674 void __iomem *regs; 990 void __iomem *regs;
675 int irq, ret; 991 int irq, ret;
@@ -690,8 +1006,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
690 return irq; 1006 return irq;
691 } 1007 }
692 1008
693 quirks = of_device_get_match_data(&pdev->dev); 1009 i2s->variant = of_device_get_match_data(&pdev->dev);
694 if (!quirks) { 1010 if (!i2s->variant) {
695 dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); 1011 dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
696 return -ENODEV; 1012 return -ENODEV;
697 } 1013 }
@@ -703,7 +1019,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
703 } 1019 }
704 1020
705 i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 1021 i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
706 &sun4i_i2s_regmap_config); 1022 i2s->variant->sun4i_i2s_regmap);
707 if (IS_ERR(i2s->regmap)) { 1023 if (IS_ERR(i2s->regmap)) {
708 dev_err(&pdev->dev, "Regmap initialisation failed\n"); 1024 dev_err(&pdev->dev, "Regmap initialisation failed\n");
709 return PTR_ERR(i2s->regmap); 1025 return PTR_ERR(i2s->regmap);
@@ -715,8 +1031,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
715 return PTR_ERR(i2s->mod_clk); 1031 return PTR_ERR(i2s->mod_clk);
716 } 1032 }
717 1033
718 if (quirks->has_reset) { 1034 if (i2s->variant->has_reset) {
719 i2s->rst = devm_reset_control_get(&pdev->dev, NULL); 1035 i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
720 if (IS_ERR(i2s->rst)) { 1036 if (IS_ERR(i2s->rst)) {
721 dev_err(&pdev->dev, "Failed to get reset control\n"); 1037 dev_err(&pdev->dev, "Failed to get reset control\n");
722 return PTR_ERR(i2s->rst); 1038 return PTR_ERR(i2s->rst);
@@ -732,7 +1048,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
732 } 1048 }
733 } 1049 }
734 1050
735 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; 1051 i2s->playback_dma_data.addr = res->start +
1052 i2s->variant->reg_offset_txdata;
736 i2s->playback_dma_data.maxburst = 8; 1053 i2s->playback_dma_data.maxburst = 8;
737 1054
738 i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; 1055 i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
@@ -759,6 +1076,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
759 goto err_suspend; 1076 goto err_suspend;
760 } 1077 }
761 1078
1079 ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);
1080 if (ret) {
1081 dev_err(&pdev->dev, "Could not initialise regmap fields\n");
1082 goto err_suspend;
1083 }
1084
762 return 0; 1085 return 0;
763 1086
764err_suspend: 1087err_suspend:
@@ -797,6 +1120,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
797 .compatible = "allwinner,sun6i-a31-i2s", 1120 .compatible = "allwinner,sun6i-a31-i2s",
798 .data = &sun6i_a31_i2s_quirks, 1121 .data = &sun6i_a31_i2s_quirks,
799 }, 1122 },
1123 {
1124 .compatible = "allwinner,sun8i-h3-i2s",
1125 .data = &sun8i_h3_i2s_quirks,
1126 },
800 {} 1127 {}
801}; 1128};
802MODULE_DEVICE_TABLE(of, sun4i_i2s_match); 1129MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index eaefd07a5ed0..b4af4aabead1 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -458,11 +458,16 @@ static int sun4i_spdif_runtime_suspend(struct device *dev)
458static int sun4i_spdif_runtime_resume(struct device *dev) 458static int sun4i_spdif_runtime_resume(struct device *dev)
459{ 459{
460 struct sun4i_spdif_dev *host = dev_get_drvdata(dev); 460 struct sun4i_spdif_dev *host = dev_get_drvdata(dev);
461 int ret;
461 462
462 clk_prepare_enable(host->spdif_clk); 463 ret = clk_prepare_enable(host->spdif_clk);
463 clk_prepare_enable(host->apb_clk); 464 if (ret)
465 return ret;
466 ret = clk_prepare_enable(host->apb_clk);
467 if (ret)
468 clk_disable_unprepare(host->spdif_clk);
464 469
465 return 0; 470 return ret;
466} 471}
467 472
468static int sun4i_spdif_probe(struct platform_device *pdev) 473static int sun4i_spdif_probe(struct platform_device *pdev)
@@ -520,7 +525,8 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
520 platform_set_drvdata(pdev, host); 525 platform_set_drvdata(pdev, host);
521 526
522 if (quirks->has_reset) { 527 if (quirks->has_reset) {
523 host->rst = devm_reset_control_get_optional(&pdev->dev, NULL); 528 host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
529 NULL);
524 if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) { 530 if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) {
525 ret = -EPROBE_DEFER; 531 ret = -EPROBE_DEFER;
526 dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); 532 dev_err(&pdev->dev, "Failed to get reset: %d\n", ret);
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 5723c3404f6b..abfb710df7cb 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -341,7 +341,7 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
341 "AIF1 Slot 0 Right"}, 341 "AIF1 Slot 0 Right"},
342}; 342};
343 343
344static struct snd_soc_dai_ops sun8i_codec_dai_ops = { 344static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
345 .hw_params = sun8i_codec_hw_params, 345 .hw_params = sun8i_codec_hw_params,
346 .set_fmt = sun8i_set_fmt, 346 .set_fmt = sun8i_set_fmt,
347}; 347};
@@ -360,7 +360,7 @@ static struct snd_soc_dai_driver sun8i_codec_dai = {
360 .ops = &sun8i_codec_dai_ops, 360 .ops = &sun8i_codec_dai_ops,
361}; 361};
362 362
363static struct snd_soc_codec_driver sun8i_soc_codec = { 363static const struct snd_soc_codec_driver sun8i_soc_codec = {
364 .component_driver = { 364 .component_driver = {
365 .dapm_widgets = sun8i_codec_dapm_widgets, 365 .dapm_widgets = sun8i_codec_dapm_widgets,
366 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets), 366 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),