aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/st,stm32-sai.txt12
-rw-r--r--Documentation/devicetree/bindings/sound/sun4i-i2s.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/tas5720.txt4
-rw-r--r--include/sound/soc-dai.h3
-rw-r--r--sound/soc/codecs/tas5720.c61
-rw-r--r--sound/soc/codecs/tas5720.h31
-rw-r--r--sound/soc/codecs/wm2200.c9
-rw-r--r--sound/soc/stm/stm32_sai.c114
-rw-r--r--sound/soc/sunxi/sun4i-codec.c29
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c57
10 files changed, 195 insertions, 127 deletions
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index 1f9cd7095337..b1acc1a256ba 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -20,11 +20,6 @@ Required properties:
20 20
21Optional properties: 21Optional properties:
22 - resets: Reference to a reset controller asserting the SAI 22 - resets: Reference to a reset controller asserting the SAI
23 - st,sync: specify synchronization mode.
24 By default SAI sub-block is in asynchronous mode.
25 This property sets SAI sub-block as slave of another SAI sub-block.
26 Must contain the phandle and index of the sai sub-block providing
27 the synchronization.
28 23
29SAI subnodes: 24SAI subnodes:
30Two subnodes corresponding to SAI sub-block instances A et B can be defined. 25Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -44,6 +39,13 @@ SAI subnodes required properties:
44 - pinctrl-names: should contain only value "default" 39 - pinctrl-names: should contain only value "default"
45 - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt 40 - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
46 41
42SAI subnodes Optional properties:
43 - st,sync: specify synchronization mode.
44 By default SAI sub-block is in asynchronous mode.
45 This property sets SAI sub-block as slave of another SAI sub-block.
46 Must contain the phandle and index of the sai sub-block providing
47 the synchronization.
48
47The device node should contain one 'port' child node with one child 'endpoint' 49The device node should contain one 'port' child node with one child 'endpoint'
48node, according to the bindings defined in Documentation/devicetree/bindings/ 50node, according to the bindings defined in Documentation/devicetree/bindings/
49graph.txt. 51graph.txt.
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 05d7135a8d2f..b9d50d6cdef3 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-a83t-i2s"
11 - "allwinner,sun8i-h3-i2s" 12 - "allwinner,sun8i-h3-i2s"
12- reg: physical base address of the controller and length of memory mapped 13- reg: physical base address of the controller and length of memory mapped
13 region. 14 region.
@@ -23,6 +24,7 @@ Required properties:
23 24
24Required properties for the following compatibles: 25Required properties for the following compatibles:
25 - "allwinner,sun6i-a31-i2s" 26 - "allwinner,sun6i-a31-i2s"
27 - "allwinner,sun8i-a83t-i2s"
26 - "allwinner,sun8i-h3-i2s" 28 - "allwinner,sun8i-h3-i2s"
27- resets: phandle to the reset line for this codec 29- resets: phandle to the reset line for this codec
28 30
diff --git a/Documentation/devicetree/bindings/sound/tas5720.txt b/Documentation/devicetree/bindings/sound/tas5720.txt
index 40d94f82beb3..7481653fe8e3 100644
--- a/Documentation/devicetree/bindings/sound/tas5720.txt
+++ b/Documentation/devicetree/bindings/sound/tas5720.txt
@@ -6,10 +6,12 @@ audio playback. For more product information please see the links below:
6 6
7http://www.ti.com/product/TAS5720L 7http://www.ti.com/product/TAS5720L
8http://www.ti.com/product/TAS5720M 8http://www.ti.com/product/TAS5720M
9http://www.ti.com/product/TAS5722L
9 10
10Required properties: 11Required properties:
11 12
12- compatible : "ti,tas5720" 13- compatible : "ti,tas5720",
14 "ti,tas5722"
13- reg : I2C slave address 15- reg : I2C slave address
14- dvdd-supply : phandle to a 3.3-V supply for the digital circuitry 16- dvdd-supply : phandle to a 3.3-V supply for the digital circuitry
15- pvdd-supply : phandle to a supply used for the Class-D amp and the analog 17- pvdd-supply : phandle to a supply used for the Class-D amp and the analog
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index d970879944fc..8ad11669e4d8 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -296,9 +296,6 @@ struct snd_soc_dai {
296 /* DAI runtime info */ 296 /* DAI runtime info */
297 unsigned int capture_active:1; /* stream is in use */ 297 unsigned int capture_active:1; /* stream is in use */
298 unsigned int playback_active:1; /* stream is in use */ 298 unsigned int playback_active:1; /* stream is in use */
299 unsigned int symmetric_rates:1;
300 unsigned int symmetric_channels:1;
301 unsigned int symmetric_samplebits:1;
302 unsigned int probed:1; 299 unsigned int probed:1;
303 300
304 unsigned int active; 301 unsigned int active;
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index a736a2a6976c..f3006f301fe8 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -36,6 +36,11 @@
36/* Define how often to check (and clear) the fault status register (in ms) */ 36/* Define how often to check (and clear) the fault status register (in ms) */
37#define TAS5720_FAULT_CHECK_INTERVAL 200 37#define TAS5720_FAULT_CHECK_INTERVAL 200
38 38
39enum tas572x_type {
40 TAS5720,
41 TAS5722,
42};
43
39static const char * const tas5720_supply_names[] = { 44static const char * const tas5720_supply_names[] = {
40 "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ 45 "dvdd", /* Digital power supply. Connect to 3.3-V supply. */
41 "pvdd", /* Class-D amp and analog power supply (connected). */ 46 "pvdd", /* Class-D amp and analog power supply (connected). */
@@ -47,6 +52,7 @@ struct tas5720_data {
47 struct snd_soc_codec *codec; 52 struct snd_soc_codec *codec;
48 struct regmap *regmap; 53 struct regmap *regmap;
49 struct i2c_client *tas5720_client; 54 struct i2c_client *tas5720_client;
55 enum tas572x_type devtype;
50 struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES]; 56 struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
51 struct delayed_work fault_check_work; 57 struct delayed_work fault_check_work;
52 unsigned int last_fault; 58 unsigned int last_fault;
@@ -264,7 +270,7 @@ out:
264static int tas5720_codec_probe(struct snd_soc_codec *codec) 270static int tas5720_codec_probe(struct snd_soc_codec *codec)
265{ 271{
266 struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); 272 struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec);
267 unsigned int device_id; 273 unsigned int device_id, expected_device_id;
268 int ret; 274 int ret;
269 275
270 tas5720->codec = codec; 276 tas5720->codec = codec;
@@ -276,6 +282,11 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
276 return ret; 282 return ret;
277 } 283 }
278 284
285 /*
286 * Take a liberal approach to checking the device ID to allow the
287 * driver to be used even if the device ID does not match, however
288 * issue a warning if there is a mismatch.
289 */
279 ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id); 290 ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
280 if (ret < 0) { 291 if (ret < 0) {
281 dev_err(codec->dev, "failed to read device ID register: %d\n", 292 dev_err(codec->dev, "failed to read device ID register: %d\n",
@@ -283,13 +294,22 @@ static int tas5720_codec_probe(struct snd_soc_codec *codec)
283 goto probe_fail; 294 goto probe_fail;
284 } 295 }
285 296
286 if (device_id != TAS5720_DEVICE_ID) { 297 switch (tas5720->devtype) {
287 dev_err(codec->dev, "wrong device ID. expected: %u read: %u\n", 298 case TAS5720:
288 TAS5720_DEVICE_ID, device_id); 299 expected_device_id = TAS5720_DEVICE_ID;
289 ret = -ENODEV; 300 break;
290 goto probe_fail; 301 case TAS5722:
302 expected_device_id = TAS5722_DEVICE_ID;
303 break;
304 default:
305 dev_err(codec->dev, "unexpected private driver data\n");
306 return -EINVAL;
291 } 307 }
292 308
309 if (device_id != expected_device_id)
310 dev_warn(codec->dev, "wrong device ID. expected: %u read: %u\n",
311 expected_device_id, device_id);
312
293 /* Set device to mute */ 313 /* Set device to mute */
294 ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, 314 ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG,
295 TAS5720_MUTE, TAS5720_MUTE); 315 TAS5720_MUTE, TAS5720_MUTE);
@@ -446,6 +466,15 @@ static const struct regmap_config tas5720_regmap_config = {
446 .volatile_reg = tas5720_is_volatile_reg, 466 .volatile_reg = tas5720_is_volatile_reg,
447}; 467};
448 468
469static const struct regmap_config tas5722_regmap_config = {
470 .reg_bits = 8,
471 .val_bits = 8,
472
473 .max_register = TAS5722_MAX_REG,
474 .cache_type = REGCACHE_RBTREE,
475 .volatile_reg = tas5720_is_volatile_reg,
476};
477
449/* 478/*
450 * DAC analog gain. There are four discrete values to select from, ranging 479 * DAC analog gain. There are four discrete values to select from, ranging
451 * from 19.2 dB to 26.3dB. 480 * from 19.2 dB to 26.3dB.
@@ -544,6 +573,7 @@ static int tas5720_probe(struct i2c_client *client,
544{ 573{
545 struct device *dev = &client->dev; 574 struct device *dev = &client->dev;
546 struct tas5720_data *data; 575 struct tas5720_data *data;
576 const struct regmap_config *regmap_config;
547 int ret; 577 int ret;
548 int i; 578 int i;
549 579
@@ -552,7 +582,20 @@ static int tas5720_probe(struct i2c_client *client,
552 return -ENOMEM; 582 return -ENOMEM;
553 583
554 data->tas5720_client = client; 584 data->tas5720_client = client;
555 data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config); 585 data->devtype = id->driver_data;
586
587 switch (id->driver_data) {
588 case TAS5720:
589 regmap_config = &tas5720_regmap_config;
590 break;
591 case TAS5722:
592 regmap_config = &tas5722_regmap_config;
593 break;
594 default:
595 dev_err(dev, "unexpected private driver data\n");
596 return -EINVAL;
597 }
598 data->regmap = devm_regmap_init_i2c(client, regmap_config);
556 if (IS_ERR(data->regmap)) { 599 if (IS_ERR(data->regmap)) {
557 ret = PTR_ERR(data->regmap); 600 ret = PTR_ERR(data->regmap);
558 dev_err(dev, "failed to allocate register map: %d\n", ret); 601 dev_err(dev, "failed to allocate register map: %d\n", ret);
@@ -592,7 +635,8 @@ static int tas5720_remove(struct i2c_client *client)
592} 635}
593 636
594static const struct i2c_device_id tas5720_id[] = { 637static const struct i2c_device_id tas5720_id[] = {
595 { "tas5720", 0 }, 638 { "tas5720", TAS5720 },
639 { "tas5722", TAS5722 },
596 { } 640 { }
597}; 641};
598MODULE_DEVICE_TABLE(i2c, tas5720_id); 642MODULE_DEVICE_TABLE(i2c, tas5720_id);
@@ -600,6 +644,7 @@ MODULE_DEVICE_TABLE(i2c, tas5720_id);
600#if IS_ENABLED(CONFIG_OF) 644#if IS_ENABLED(CONFIG_OF)
601static const struct of_device_id tas5720_of_match[] = { 645static const struct of_device_id tas5720_of_match[] = {
602 { .compatible = "ti,tas5720", }, 646 { .compatible = "ti,tas5720", },
647 { .compatible = "ti,tas5722", },
603 { }, 648 { },
604}; 649};
605MODULE_DEVICE_TABLE(of, tas5720_of_match); 650MODULE_DEVICE_TABLE(of, tas5720_of_match);
diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h
index 3d077c779b12..1dda3095961d 100644
--- a/sound/soc/codecs/tas5720.h
+++ b/sound/soc/codecs/tas5720.h
@@ -30,8 +30,14 @@
30#define TAS5720_DIGITAL_CLIP1_REG 0x11 30#define TAS5720_DIGITAL_CLIP1_REG 0x11
31#define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG 31#define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG
32 32
33/* Additional TAS5722-specific Registers */
34#define TAS5722_DIGITAL_CTRL2_REG 0x13
35#define TAS5722_ANALOG_CTRL2_REG 0x14
36#define TAS5722_MAX_REG TAS5722_ANALOG_CTRL2_REG
37
33/* TAS5720_DEVICE_ID_REG */ 38/* TAS5720_DEVICE_ID_REG */
34#define TAS5720_DEVICE_ID 0x01 39#define TAS5720_DEVICE_ID 0x01
40#define TAS5722_DEVICE_ID 0x12
35 41
36/* TAS5720_POWER_CTRL_REG */ 42/* TAS5720_POWER_CTRL_REG */
37#define TAS5720_DIG_CLIP_MASK GENMASK(7, 2) 43#define TAS5720_DIG_CLIP_MASK GENMASK(7, 2)
@@ -51,6 +57,7 @@
51#define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0) 57#define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0)
52 58
53/* TAS5720_DIGITAL_CTRL2_REG */ 59/* TAS5720_DIGITAL_CTRL2_REG */
60#define TAS5722_VOL_RAMP_RATE BIT(6)
54#define TAS5720_MUTE BIT(4) 61#define TAS5720_MUTE BIT(4)
55#define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0) 62#define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0)
56 63
@@ -87,4 +94,28 @@
87#define TAS5720_CLIP1_MASK GENMASK(7, 2) 94#define TAS5720_CLIP1_MASK GENMASK(7, 2)
88#define TAS5720_CLIP1_SHIFT (0x2) 95#define TAS5720_CLIP1_SHIFT (0x2)
89 96
97/* TAS5722_DIGITAL_CTRL2_REG */
98#define TAS5722_HPF_3_7HZ (0x0 << 5)
99#define TAS5722_HPF_7_4HZ (0x1 << 5)
100#define TAS5722_HPF_14_9HZ (0x2 << 5)
101#define TAS5722_HPF_29_7HZ (0x3 << 5)
102#define TAS5722_HPF_59_4HZ (0x4 << 5)
103#define TAS5722_HPF_118_4HZ (0x5 << 5)
104#define TAS5722_HPF_235_0HZ (0x6 << 5)
105#define TAS5722_HPF_463_2HZ (0x7 << 5)
106#define TAS5722_HPF_MASK GENMASK(7, 5)
107#define TAS5722_AUTO_SLEEP_OFF (0x0 << 3)
108#define TAS5722_AUTO_SLEEP_1024LR (0x1 << 3)
109#define TAS5722_AUTO_SLEEP_65536LR (0x2 << 3)
110#define TAS5722_AUTO_SLEEP_262144LR (0x3 << 3)
111#define TAS5722_AUTO_SLEEP_MASK GENMASK(4, 3)
112#define TAS5722_TDM_SLOT_16B BIT(2)
113#define TAS5722_MCLK_PIN_CFG BIT(1)
114#define TAS5722_VOL_CONTROL_LSB BIT(0)
115
116/* TAS5722_ANALOG_CTRL2_REG */
117#define TAS5722_FAULTZ_PU BIT(3)
118#define TAS5722_VREG_LVL BIT(2)
119#define TAS5722_PWR_TUNE BIT(0)
120
90#endif /* __TAS5720_H__ */ 121#endif /* __TAS5720_H__ */
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index d83dab57a1d1..5c2f5727244d 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -98,6 +98,8 @@ struct wm2200_priv {
98 98
99 int rev; 99 int rev;
100 int sysclk; 100 int sysclk;
101
102 unsigned int symmetric_rates:1;
101}; 103};
102 104
103#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1) 105#define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1)
@@ -1550,7 +1552,7 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
1550 1552
1551static int wm2200_probe(struct snd_soc_codec *codec) 1553static int wm2200_probe(struct snd_soc_codec *codec)
1552{ 1554{
1553 struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev); 1555 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
1554 int ret; 1556 int ret;
1555 1557
1556 wm2200->codec = codec; 1558 wm2200->codec = codec;
@@ -1758,7 +1760,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
1758 lrclk = bclk_rates[bclk] / params_rate(params); 1760 lrclk = bclk_rates[bclk] / params_rate(params);
1759 dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk); 1761 dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
1760 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || 1762 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
1761 dai->symmetric_rates) 1763 wm2200->symmetric_rates)
1762 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7, 1764 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
1763 WM2200_AIF1RX_BCPF_MASK, lrclk); 1765 WM2200_AIF1RX_BCPF_MASK, lrclk);
1764 else 1766 else
@@ -2059,13 +2061,14 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2059static int wm2200_dai_probe(struct snd_soc_dai *dai) 2061static int wm2200_dai_probe(struct snd_soc_dai *dai)
2060{ 2062{
2061 struct snd_soc_codec *codec = dai->codec; 2063 struct snd_soc_codec *codec = dai->codec;
2064 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
2062 unsigned int val = 0; 2065 unsigned int val = 0;
2063 int ret; 2066 int ret;
2064 2067
2065 ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1); 2068 ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
2066 if (ret >= 0) { 2069 if (ret >= 0) {
2067 if ((ret & WM2200_GP1_FN_MASK) != 0) { 2070 if ((ret & WM2200_GP1_FN_MASK) != 0) {
2068 dai->symmetric_rates = true; 2071 wm2200->symmetric_rates = true;
2069 val = WM2200_AIF1TX_LRCLK_SRC; 2072 val = WM2200_AIF1TX_LRCLK_SRC;
2070 } 2073 }
2071 } else { 2074 } else {
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d6f71a3406e9..d743b7dd52fb 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -28,16 +28,6 @@
28 28
29#include "stm32_sai.h" 29#include "stm32_sai.h"
30 30
31static LIST_HEAD(sync_providers);
32static DEFINE_MUTEX(sync_mutex);
33
34struct sync_provider {
35 struct list_head link;
36 struct device_node *node;
37 int (*sync_conf)(void *data, int synco);
38 void *data;
39};
40
41static const struct stm32_sai_conf stm32_sai_conf_f4 = { 31static const struct stm32_sai_conf stm32_sai_conf_f4 = {
42 .version = SAI_STM32F4, 32 .version = SAI_STM32F4,
43}; 33};
@@ -70,9 +60,8 @@ static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
70 return 0; 60 return 0;
71} 61}
72 62
73static int stm32_sai_sync_conf_provider(void *data, int synco) 63static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
74{ 64{
75 struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
76 u32 prev_synco; 65 u32 prev_synco;
77 int ret; 66 int ret;
78 67
@@ -103,83 +92,42 @@ static int stm32_sai_sync_conf_provider(void *data, int synco)
103 return 0; 92 return 0;
104} 93}
105 94
106static int stm32_sai_set_sync_provider(struct device_node *np, int synco) 95static int stm32_sai_set_sync(struct stm32_sai_data *sai_client,
96 struct device_node *np_provider,
97 int synco, int synci)
107{ 98{
108 struct sync_provider *provider; 99 struct platform_device *pdev = of_find_device_by_node(np_provider);
100 struct stm32_sai_data *sai_provider;
109 int ret; 101 int ret;
110 102
111 mutex_lock(&sync_mutex); 103 if (!pdev) {
112 list_for_each_entry(provider, &sync_providers, link) { 104 dev_err(&sai_client->pdev->dev,
113 if (provider->node == np) { 105 "Device not found for node %s\n", np_provider->name);
114 ret = provider->sync_conf(provider->data, synco); 106 return -ENODEV;
115 mutex_unlock(&sync_mutex);
116 return ret;
117 }
118 } 107 }
119 mutex_unlock(&sync_mutex);
120 108
121 /* SAI sync provider not found */ 109 sai_provider = platform_get_drvdata(pdev);
122 return -ENODEV; 110 if (!sai_provider) {
123} 111 dev_err(&sai_client->pdev->dev,
124 112 "SAI sync provider data not found\n");
125static int stm32_sai_set_sync(struct stm32_sai_data *sai, 113 return -EINVAL;
126 struct device_node *np_provider, 114 }
127 int synco, int synci)
128{
129 int ret;
130 115
131 /* Configure sync client */ 116 /* Configure sync client */
132 stm32_sai_sync_conf_client(sai, synci); 117 ret = stm32_sai_sync_conf_client(sai_client, synci);
118 if (ret < 0)
119 return ret;
133 120
134 /* Configure sync provider */ 121 /* Configure sync provider */
135 ret = stm32_sai_set_sync_provider(np_provider, synco); 122 return stm32_sai_sync_conf_provider(sai_provider, synco);
136
137 return ret;
138}
139
140static int stm32_sai_sync_add_provider(struct platform_device *pdev,
141 void *data)
142{
143 struct sync_provider *sp;
144
145 sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
146 if (!sp)
147 return -ENOMEM;
148
149 sp->node = of_node_get(pdev->dev.of_node);
150 sp->data = data;
151 sp->sync_conf = &stm32_sai_sync_conf_provider;
152
153 mutex_lock(&sync_mutex);
154 list_add(&sp->link, &sync_providers);
155 mutex_unlock(&sync_mutex);
156
157 return 0;
158}
159
160static void stm32_sai_sync_del_provider(struct device_node *np)
161{
162 struct sync_provider *sp;
163
164 mutex_lock(&sync_mutex);
165 list_for_each_entry(sp, &sync_providers, link) {
166 if (sp->node == np) {
167 list_del(&sp->link);
168 of_node_put(sp->node);
169 break;
170 }
171 }
172 mutex_unlock(&sync_mutex);
173} 123}
174 124
175static int stm32_sai_probe(struct platform_device *pdev) 125static int stm32_sai_probe(struct platform_device *pdev)
176{ 126{
177 struct device_node *np = pdev->dev.of_node;
178 struct stm32_sai_data *sai; 127 struct stm32_sai_data *sai;
179 struct reset_control *rst; 128 struct reset_control *rst;
180 struct resource *res; 129 struct resource *res;
181 const struct of_device_id *of_id; 130 const struct of_device_id *of_id;
182 int ret;
183 131
184 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 132 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
185 if (!sai) 133 if (!sai)
@@ -231,28 +179,11 @@ static int stm32_sai_probe(struct platform_device *pdev)
231 reset_control_deassert(rst); 179 reset_control_deassert(rst);
232 } 180 }
233 181
234 ret = stm32_sai_sync_add_provider(pdev, sai);
235 if (ret < 0)
236 return ret;
237 sai->set_sync = &stm32_sai_set_sync;
238
239 sai->pdev = pdev; 182 sai->pdev = pdev;
183 sai->set_sync = &stm32_sai_set_sync;
240 platform_set_drvdata(pdev, sai); 184 platform_set_drvdata(pdev, sai);
241 185
242 ret = of_platform_populate(np, NULL, NULL, &pdev->dev); 186 return devm_of_platform_populate(&pdev->dev);
243 if (ret < 0)
244 stm32_sai_sync_del_provider(np);
245
246 return ret;
247}
248
249static int stm32_sai_remove(struct platform_device *pdev)
250{
251 of_platform_depopulate(&pdev->dev);
252
253 stm32_sai_sync_del_provider(pdev->dev.of_node);
254
255 return 0;
256} 187}
257 188
258MODULE_DEVICE_TABLE(of, stm32_sai_ids); 189MODULE_DEVICE_TABLE(of, stm32_sai_ids);
@@ -263,7 +194,6 @@ static struct platform_driver stm32_sai_driver = {
263 .of_match_table = stm32_sai_ids, 194 .of_match_table = stm32_sai_ids,
264 }, 195 },
265 .probe = stm32_sai_probe, 196 .probe = stm32_sai_probe,
266 .remove = stm32_sai_remove,
267}; 197};
268 198
269module_platform_driver(stm32_sai_driver); 199module_platform_driver(stm32_sai_driver);
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 5da4efe7a550..886281673972 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -590,12 +590,28 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
590 hwrate); 590 hwrate);
591} 591}
592 592
593
594static unsigned int sun4i_codec_src_rates[] = {
595 8000, 11025, 12000, 16000, 22050, 24000, 32000,
596 44100, 48000, 96000, 192000
597};
598
599
600static struct snd_pcm_hw_constraint_list sun4i_codec_constraints = {
601 .count = ARRAY_SIZE(sun4i_codec_src_rates),
602 .list = sun4i_codec_src_rates,
603};
604
605
593static int sun4i_codec_startup(struct snd_pcm_substream *substream, 606static int sun4i_codec_startup(struct snd_pcm_substream *substream,
594 struct snd_soc_dai *dai) 607 struct snd_soc_dai *dai)
595{ 608{
596 struct snd_soc_pcm_runtime *rtd = substream->private_data; 609 struct snd_soc_pcm_runtime *rtd = substream->private_data;
597 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); 610 struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
598 611
612 snd_pcm_hw_constraint_list(substream->runtime, 0,
613 SNDRV_PCM_HW_PARAM_RATE, &sun4i_codec_constraints);
614
599 /* 615 /*
600 * Stop issuing DRQ when we have room for less than 16 samples 616 * Stop issuing DRQ when we have room for less than 16 samples
601 * in our TX FIFO 617 * in our TX FIFO
@@ -633,9 +649,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
633 .channels_max = 2, 649 .channels_max = 2,
634 .rate_min = 8000, 650 .rate_min = 8000,
635 .rate_max = 192000, 651 .rate_max = 192000,
636 .rates = SNDRV_PCM_RATE_8000_48000 | 652 .rates = SNDRV_PCM_RATE_CONTINUOUS,
637 SNDRV_PCM_RATE_96000 |
638 SNDRV_PCM_RATE_192000,
639 .formats = SNDRV_PCM_FMTBIT_S16_LE | 653 .formats = SNDRV_PCM_FMTBIT_S16_LE |
640 SNDRV_PCM_FMTBIT_S32_LE, 654 SNDRV_PCM_FMTBIT_S32_LE,
641 .sig_bits = 24, 655 .sig_bits = 24,
@@ -645,11 +659,8 @@ static struct snd_soc_dai_driver sun4i_codec_dai = {
645 .channels_min = 1, 659 .channels_min = 1,
646 .channels_max = 2, 660 .channels_max = 2,
647 .rate_min = 8000, 661 .rate_min = 8000,
648 .rate_max = 192000, 662 .rate_max = 48000,
649 .rates = SNDRV_PCM_RATE_8000_48000 | 663 .rates = SNDRV_PCM_RATE_CONTINUOUS,
650 SNDRV_PCM_RATE_96000 |
651 SNDRV_PCM_RATE_192000 |
652 SNDRV_PCM_RATE_KNOT,
653 .formats = SNDRV_PCM_FMTBIT_S16_LE | 664 .formats = SNDRV_PCM_FMTBIT_S16_LE |
654 SNDRV_PCM_FMTBIT_S32_LE, 665 SNDRV_PCM_FMTBIT_S32_LE,
655 .sig_bits = 24, 666 .sig_bits = 24,
@@ -1128,7 +1139,7 @@ static const struct snd_soc_component_driver sun4i_codec_component = {
1128 .name = "sun4i-codec", 1139 .name = "sun4i-codec",
1129}; 1140};
1130 1141
1131#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_8000_192000 1142#define SUN4I_CODEC_RATES SNDRV_PCM_RATE_CONTINUOUS
1132#define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 1143#define SUN4I_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
1133 SNDRV_PCM_FMTBIT_S32_LE) 1144 SNDRV_PCM_FMTBIT_S32_LE)
1134 1145
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 04f92583a969..dca1143c1150 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -269,10 +269,11 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
269 return false; 269 return false;
270} 270}
271 271
272static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, 272static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
273 unsigned int rate, 273 unsigned int rate,
274 unsigned int word_size) 274 unsigned int word_size)
275{ 275{
276 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
276 unsigned int oversample_rate, clk_rate; 277 unsigned int oversample_rate, clk_rate;
277 int bclk_div, mclk_div; 278 int bclk_div, mclk_div;
278 int ret; 279 int ret;
@@ -300,6 +301,7 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
300 break; 301 break;
301 302
302 default: 303 default:
304 dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);
303 return -EINVAL; 305 return -EINVAL;
304 } 306 }
305 307
@@ -308,18 +310,25 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
308 return ret; 310 return ret;
309 311
310 oversample_rate = i2s->mclk_freq / rate; 312 oversample_rate = i2s->mclk_freq / rate;
311 if (!sun4i_i2s_oversample_is_valid(oversample_rate)) 313 if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
314 dev_err(dai->dev, "Unsupported oversample rate: %d\n",
315 oversample_rate);
312 return -EINVAL; 316 return -EINVAL;
317 }
313 318
314 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, 319 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
315 word_size); 320 word_size);
316 if (bclk_div < 0) 321 if (bclk_div < 0) {
322 dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
317 return -EINVAL; 323 return -EINVAL;
324 }
318 325
319 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, 326 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
320 clk_rate, rate); 327 clk_rate, rate);
321 if (mclk_div < 0) 328 if (mclk_div < 0) {
329 dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
322 return -EINVAL; 330 return -EINVAL;
331 }
323 332
324 /* Adjust the clock division values if needed */ 333 /* Adjust the clock division values if needed */
325 bclk_div += i2s->variant->bclk_offset; 334 bclk_div += i2s->variant->bclk_offset;
@@ -349,8 +358,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
349 u32 width; 358 u32 width;
350 359
351 channels = params_channels(params); 360 channels = params_channels(params);
352 if (channels != 2) 361 if (channels != 2) {
362 dev_err(dai->dev, "Unsupported number of channels: %d\n",
363 channels);
353 return -EINVAL; 364 return -EINVAL;
365 }
354 366
355 if (i2s->variant->has_chcfg) { 367 if (i2s->variant->has_chcfg) {
356 regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 368 regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
@@ -382,6 +394,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
382 width = DMA_SLAVE_BUSWIDTH_2_BYTES; 394 width = DMA_SLAVE_BUSWIDTH_2_BYTES;
383 break; 395 break;
384 default: 396 default:
397 dev_err(dai->dev, "Unsupported physical sample width: %d\n",
398 params_physical_width(params));
385 return -EINVAL; 399 return -EINVAL;
386 } 400 }
387 i2s->playback_dma_data.addr_width = width; 401 i2s->playback_dma_data.addr_width = width;
@@ -393,6 +407,8 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
393 break; 407 break;
394 408
395 default: 409 default:
410 dev_err(dai->dev, "Unsupported sample width: %d\n",
411 params_width(params));
396 return -EINVAL; 412 return -EINVAL;
397 } 413 }
398 414
@@ -401,7 +417,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
401 regmap_field_write(i2s->field_fmt_sr, 417 regmap_field_write(i2s->field_fmt_sr,
402 sr + i2s->variant->fmt_offset); 418 sr + i2s->variant->fmt_offset);
403 419
404 return sun4i_i2s_set_clk_rate(i2s, params_rate(params), 420 return sun4i_i2s_set_clk_rate(dai, params_rate(params),
405 params_width(params)); 421 params_width(params));
406} 422}
407 423
@@ -426,6 +442,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
426 val = SUN4I_I2S_FMT0_FMT_RIGHT_J; 442 val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
427 break; 443 break;
428 default: 444 default:
445 dev_err(dai->dev, "Unsupported format: %d\n",
446 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
429 return -EINVAL; 447 return -EINVAL;
430 } 448 }
431 449
@@ -464,6 +482,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
464 case SND_SOC_DAIFMT_NB_NF: 482 case SND_SOC_DAIFMT_NB_NF:
465 break; 483 break;
466 default: 484 default:
485 dev_err(dai->dev, "Unsupported clock polarity: %d\n",
486 fmt & SND_SOC_DAIFMT_INV_MASK);
467 return -EINVAL; 487 return -EINVAL;
468 } 488 }
469 489
@@ -482,6 +502,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
482 val = SUN4I_I2S_CTRL_MODE_SLAVE; 502 val = SUN4I_I2S_CTRL_MODE_SLAVE;
483 break; 503 break;
484 default: 504 default:
505 dev_err(dai->dev, "Unsupported slave setting: %d\n",
506 fmt & SND_SOC_DAIFMT_MASTER_MASK);
485 return -EINVAL; 507 return -EINVAL;
486 } 508 }
487 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 509 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -504,6 +526,8 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
504 val = 0; 526 val = 0;
505 break; 527 break;
506 default: 528 default:
529 dev_err(dai->dev, "Unsupported slave setting: %d\n",
530 fmt & SND_SOC_DAIFMT_MASTER_MASK);
507 return -EINVAL; 531 return -EINVAL;
508 } 532 }
509 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 533 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
@@ -897,6 +921,23 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
897 .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), 921 .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
898}; 922};
899 923
924static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
925 .has_reset = true,
926 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
927 .sun4i_i2s_regmap = &sun4i_i2s_regmap_config,
928 .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
929 .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
930 .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
931 .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6),
932 .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7),
933 .has_slave_select_bit = true,
934 .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1),
935 .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31),
936 .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31),
937 .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2),
938 .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2),
939};
940
900static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { 941static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
901 .has_reset = true, 942 .has_reset = true,
902 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 943 .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
@@ -1121,6 +1162,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
1121 .data = &sun6i_a31_i2s_quirks, 1162 .data = &sun6i_a31_i2s_quirks,
1122 }, 1163 },
1123 { 1164 {
1165 .compatible = "allwinner,sun8i-a83t-i2s",
1166 .data = &sun8i_a83t_i2s_quirks,
1167 },
1168 {
1124 .compatible = "allwinner,sun8i-h3-i2s", 1169 .compatible = "allwinner,sun8i-h3-i2s",
1125 .data = &sun8i_h3_i2s_quirks, 1170 .data = &sun8i_h3_i2s_quirks,
1126 }, 1171 },