aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Moysan <olivier.moysan@st.com>2017-10-19 09:03:23 -0400
committerMark Brown <broonie@kernel.org>2017-10-21 06:17:49 -0400
commit5914d285f6b782892a91d6621723fdc41a775b15 (patch)
tree2b689ee2ee64790d993f78ce454db48bafca7555
parent47a8907d7c73fad81030655f09832fbb4446a2f5 (diff)
ASoC: stm32: sai: Add synchronization support
Add Synchronization support for STM32 SAI. Signed-off-by: olivier moysan <olivier.moysan@st.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/stm/stm32_sai.c160
-rw-r--r--sound/soc/stm/stm32_sai.h22
-rw-r--r--sound/soc/stm/stm32_sai_sub.c95
3 files changed, 269 insertions, 8 deletions
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ace605..d6f71a3406e9 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
16 * details. 16 * details.
17 */ 17 */
18 18
19#include <linux/bitfield.h>
19#include <linux/clk.h> 20#include <linux/clk.h>
20#include <linux/delay.h> 21#include <linux/delay.h>
21#include <linux/module.h> 22#include <linux/module.h>
@@ -27,6 +28,16 @@
27 28
28#include "stm32_sai.h" 29#include "stm32_sai.h"
29 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
30static const struct stm32_sai_conf stm32_sai_conf_f4 = { 41static const struct stm32_sai_conf stm32_sai_conf_f4 = {
31 .version = SAI_STM32F4, 42 .version = SAI_STM32F4,
32}; 43};
@@ -41,23 +52,143 @@ static const struct of_device_id stm32_sai_ids[] = {
41 {} 52 {}
42}; 53};
43 54
55static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
56{
57 int ret;
58
59 /* Enable peripheral clock to allow GCR register access */
60 ret = clk_prepare_enable(sai->pclk);
61 if (ret) {
62 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
63 return ret;
64 }
65
66 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
67
68 clk_disable_unprepare(sai->pclk);
69
70 return 0;
71}
72
73static int stm32_sai_sync_conf_provider(void *data, int synco)
74{
75 struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
76 u32 prev_synco;
77 int ret;
78
79 /* Enable peripheral clock to allow GCR register access */
80 ret = clk_prepare_enable(sai->pclk);
81 if (ret) {
82 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
83 return ret;
84 }
85
86 dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
87 sai->pdev->dev.of_node->name,
88 synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
89
90 prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
91 if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
92 dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
93 sai->pdev->dev.of_node->name,
94 prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
95 clk_disable_unprepare(sai->pclk);
96 return -EINVAL;
97 }
98
99 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
100
101 clk_disable_unprepare(sai->pclk);
102
103 return 0;
104}
105
106static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
107{
108 struct sync_provider *provider;
109 int ret;
110
111 mutex_lock(&sync_mutex);
112 list_for_each_entry(provider, &sync_providers, link) {
113 if (provider->node == np) {
114 ret = provider->sync_conf(provider->data, synco);
115 mutex_unlock(&sync_mutex);
116 return ret;
117 }
118 }
119 mutex_unlock(&sync_mutex);
120
121 /* SAI sync provider not found */
122 return -ENODEV;
123}
124
125static int stm32_sai_set_sync(struct stm32_sai_data *sai,
126 struct device_node *np_provider,
127 int synco, int synci)
128{
129 int ret;
130
131 /* Configure sync client */
132 stm32_sai_sync_conf_client(sai, synci);
133
134 /* Configure sync provider */
135 ret = stm32_sai_set_sync_provider(np_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}
174
44static int stm32_sai_probe(struct platform_device *pdev) 175static int stm32_sai_probe(struct platform_device *pdev)
45{ 176{
46 struct device_node *np = pdev->dev.of_node; 177 struct device_node *np = pdev->dev.of_node;
47 struct stm32_sai_data *sai; 178 struct stm32_sai_data *sai;
48 struct reset_control *rst; 179 struct reset_control *rst;
49 struct resource *res; 180 struct resource *res;
50 void __iomem *base;
51 const struct of_device_id *of_id; 181 const struct of_device_id *of_id;
182 int ret;
52 183
53 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); 184 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
54 if (!sai) 185 if (!sai)
55 return -ENOMEM; 186 return -ENOMEM;
56 187
57 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 188 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
58 base = devm_ioremap_resource(&pdev->dev, res); 189 sai->base = devm_ioremap_resource(&pdev->dev, res);
59 if (IS_ERR(base)) 190 if (IS_ERR(sai->base))
60 return PTR_ERR(base); 191 return PTR_ERR(sai->base);
61 192
62 of_id = of_match_device(stm32_sai_ids, &pdev->dev); 193 of_id = of_match_device(stm32_sai_ids, &pdev->dev);
63 if (of_id) 194 if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
65 else 196 else
66 return -EINVAL; 197 return -EINVAL;
67 198
199 if (!STM_SAI_IS_F4(sai)) {
200 sai->pclk = devm_clk_get(&pdev->dev, "pclk");
201 if (IS_ERR(sai->pclk)) {
202 dev_err(&pdev->dev, "missing bus clock pclk\n");
203 return PTR_ERR(sai->pclk);
204 }
205 }
206
68 sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); 207 sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
69 if (IS_ERR(sai->clk_x8k)) { 208 if (IS_ERR(sai->clk_x8k)) {
70 dev_err(&pdev->dev, "missing x8k parent clock\n"); 209 dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
92 reset_control_deassert(rst); 231 reset_control_deassert(rst);
93 } 232 }
94 233
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
95 sai->pdev = pdev; 239 sai->pdev = pdev;
96 platform_set_drvdata(pdev, sai); 240 platform_set_drvdata(pdev, sai);
97 241
98 return of_platform_populate(np, NULL, NULL, &pdev->dev); 242 ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
243 if (ret < 0)
244 stm32_sai_sync_del_provider(np);
245
246 return ret;
99} 247}
100 248
101static int stm32_sai_remove(struct platform_device *pdev) 249static int stm32_sai_remove(struct platform_device *pdev)
102{ 250{
103 of_platform_depopulate(&pdev->dev); 251 of_platform_depopulate(&pdev->dev);
104 252
253 stm32_sai_sync_del_provider(pdev->dev.of_node);
254
105 return 0; 255 return 0;
106} 256}
107 257
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc62d9..bb062e70de63 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
16 * details. 16 * details.
17 */ 17 */
18 18
19#include <linux/bitfield.h>
20
19/******************** SAI Register Map **************************************/ 21/******************** SAI Register Map **************************************/
20 22
21/* common register */ 23/* Global configuration register */
22#define STM_SAI_GCR 0x00 24#define STM_SAI_GCR 0x00
23 25
24/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */ 26/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
37 39
38/******************** Bit definition for SAI_GCR register *******************/ 40/******************** Bit definition for SAI_GCR register *******************/
39#define SAI_GCR_SYNCIN_SHIFT 0 41#define SAI_GCR_SYNCIN_SHIFT 0
42#define SAI_GCR_SYNCIN_WDTH 2
40#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT) 43#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
41#define SAI_GCR_SYNCIN_SET(x) ((x) << SAI_GCR_SYNCIN_SHIFT) 44#define SAI_GCR_SYNCIN_MAX FIELD_GET(SAI_GCR_SYNCIN_MASK,\
45 SAI_GCR_SYNCIN_MASK)
42 46
43#define SAI_GCR_SYNCOUT_SHIFT 4 47#define SAI_GCR_SYNCOUT_SHIFT 4
44#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT) 48#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
45#define SAI_GCR_SYNCOUT_SET(x) ((x) << SAI_GCR_SYNCOUT_SHIFT)
46 49
47/******************* Bit definition for SAI_XCR1 register *******************/ 50/******************* Bit definition for SAI_XCR1 register *******************/
48#define SAI_XCR1_RX_TX_SHIFT 0 51#define SAI_XCR1_RX_TX_SHIFT 0
@@ -231,6 +234,12 @@
231#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4) 234#define STM_SAI_IS_F4(ip) ((ip)->conf->version == SAI_STM32F4)
232#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7) 235#define STM_SAI_IS_H7(ip) ((ip)->conf->version == SAI_STM32H7)
233 236
237enum stm32_sai_syncout {
238 STM_SAI_SYNC_OUT_NONE,
239 STM_SAI_SYNC_OUT_A,
240 STM_SAI_SYNC_OUT_B,
241};
242
234enum stm32_sai_version { 243enum stm32_sai_version {
235 SAI_STM32F4, 244 SAI_STM32F4,
236 SAI_STM32H7 245 SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
247/** 256/**
248 * struct stm32_sai_data - private data of SAI instance driver 257 * struct stm32_sai_data - private data of SAI instance driver
249 * @pdev: device data pointer 258 * @pdev: device data pointer
259 * @base: common register bank virtual base address
260 * @pclk: SAI bus clock
250 * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz 261 * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
251 * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz 262 * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
252 * @version: SOC version 263 * @version: SOC version
253 * @irq: SAI interrupt line 264 * @irq: SAI interrupt line
265 * @set_sync: pointer to synchro mode configuration callback
254 */ 266 */
255struct stm32_sai_data { 267struct stm32_sai_data {
256 struct platform_device *pdev; 268 struct platform_device *pdev;
269 void __iomem *base;
270 struct clk *pclk;
257 struct clk *clk_x8k; 271 struct clk *clk_x8k;
258 struct clk *clk_x11k; 272 struct clk *clk_x11k;
259 struct stm32_sai_conf *conf; 273 struct stm32_sai_conf *conf;
260 int irq; 274 int irq;
275 int (*set_sync)(struct stm32_sai_data *sai,
276 struct device_node *np_provider, int synco, int synci);
261}; 277};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc7760f58..150ad546d8b9 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
55#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID) 55#define STM_SAI_IS_SUB_B(x) ((x)->id == STM_SAI_B_ID)
56#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B") 56#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
57 57
58#define SAI_SYNC_NONE 0x0
59#define SAI_SYNC_INTERNAL 0x1
60#define SAI_SYNC_EXTERNAL 0x2
61
62#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
63
58/** 64/**
59 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) 65 * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
60 * @pdev: device data pointer 66 * @pdev: device data pointer
@@ -65,6 +71,7 @@
65 * @cpu_dai: DAI runtime data pointer 71 * @cpu_dai: DAI runtime data pointer
66 * @substream: PCM substream data pointer 72 * @substream: PCM substream data pointer
67 * @pdata: SAI block parent data pointer 73 * @pdata: SAI block parent data pointer
74 * @np_sync_provider: synchronization provider node
68 * @sai_ck: kernel clock feeding the SAI clock generator 75 * @sai_ck: kernel clock feeding the SAI clock generator
69 * @phys_addr: SAI registers physical base address 76 * @phys_addr: SAI registers physical base address
70 * @mclk_rate: SAI block master clock frequency (Hz). set at init 77 * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
73 * @master: SAI block mode flag. (true=master, false=slave) set at init 80 * @master: SAI block mode flag. (true=master, false=slave) set at init
74 * @fmt: SAI block format. relevant only for custom protocols. set at init 81 * @fmt: SAI block format. relevant only for custom protocols. set at init
75 * @sync: SAI block synchronization mode. (none, internal or external) 82 * @sync: SAI block synchronization mode. (none, internal or external)
83 * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
84 * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
76 * @fs_length: frame synchronization length. depends on protocol settings 85 * @fs_length: frame synchronization length. depends on protocol settings
77 * @slots: rx or tx slot number 86 * @slots: rx or tx slot number
78 * @slot_width: rx or tx slot width in bits 87 * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
88 struct snd_soc_dai *cpu_dai; 97 struct snd_soc_dai *cpu_dai;
89 struct snd_pcm_substream *substream; 98 struct snd_pcm_substream *substream;
90 struct stm32_sai_data *pdata; 99 struct stm32_sai_data *pdata;
100 struct device_node *np_sync_provider;
91 struct clk *sai_ck; 101 struct clk *sai_ck;
92 dma_addr_t phys_addr; 102 dma_addr_t phys_addr;
93 unsigned int mclk_rate; 103 unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
96 bool master; 106 bool master;
97 int fmt; 107 int fmt;
98 int sync; 108 int sync;
109 int synco;
110 int synci;
99 int fs_length; 111 int fs_length;
100 int slots; 112 int slots;
101 int slot_width; 113 int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
387 fmt & SND_SOC_DAIFMT_MASTER_MASK); 399 fmt & SND_SOC_DAIFMT_MASTER_MASK);
388 return -EINVAL; 400 return -EINVAL;
389 } 401 }
402
403 /* Set slave mode if sub-block is synchronized with another SAI */
404 if (sai->sync) {
405 dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
406 cr1 |= SAI_XCR1_SLAVE;
407 sai->master = false;
408 }
409
390 cr1_mask |= SAI_XCR1_SLAVE; 410 cr1_mask |= SAI_XCR1_SLAVE;
391 411
392 /* do not generate master by default */ 412 /* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
749 if (STM_SAI_IS_CAPTURE(sai)) 769 if (STM_SAI_IS_CAPTURE(sai))
750 cr1 |= SAI_XCR1_RX_TX; 770 cr1 |= SAI_XCR1_RX_TX;
751 771
772 /* Configure synchronization */
773 if (sai->sync == SAI_SYNC_EXTERNAL) {
774 /* Configure synchro client and provider */
775 sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
776 sai->synco, sai->synci);
777 }
778
779 cr1_mask |= SAI_XCR1_SYNCEN_MASK;
780 cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
781
752 return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); 782 return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
753} 783}
754 784
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
835 struct device_node *np = pdev->dev.of_node; 865 struct device_node *np = pdev->dev.of_node;
836 struct resource *res; 866 struct resource *res;
837 void __iomem *base; 867 void __iomem *base;
868 struct of_phandle_args args;
869 int ret;
838 870
839 if (!np) 871 if (!np)
840 return -ENODEV; 872 return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
868 return -EINVAL; 900 return -EINVAL;
869 } 901 }
870 902
903 /* Get synchronization property */
904 args.np = NULL;
905 ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
906 if (ret < 0 && ret != -ENOENT) {
907 dev_err(&pdev->dev, "Failed to get st,sync property\n");
908 return ret;
909 }
910
911 sai->sync = SAI_SYNC_NONE;
912 if (args.np) {
913 if (args.np == np) {
914 dev_err(&pdev->dev, "%s sync own reference\n",
915 np->name);
916 of_node_put(args.np);
917 return -EINVAL;
918 }
919
920 sai->np_sync_provider = of_get_parent(args.np);
921 if (!sai->np_sync_provider) {
922 dev_err(&pdev->dev, "%s parent node not found\n",
923 np->name);
924 of_node_put(args.np);
925 return -ENODEV;
926 }
927
928 sai->sync = SAI_SYNC_INTERNAL;
929 if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
930 if (!STM_SAI_HAS_EXT_SYNC(sai)) {
931 dev_err(&pdev->dev,
932 "External synchro not supported\n");
933 of_node_put(args.np);
934 return -EINVAL;
935 }
936 sai->sync = SAI_SYNC_EXTERNAL;
937
938 sai->synci = args.args[0];
939 if (sai->synci < 1 ||
940 (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
941 dev_err(&pdev->dev, "Wrong SAI index\n");
942 of_node_put(args.np);
943 return -EINVAL;
944 }
945
946 if (of_property_match_string(args.np, "compatible",
947 "st,stm32-sai-sub-a") >= 0)
948 sai->synco = STM_SAI_SYNC_OUT_A;
949
950 if (of_property_match_string(args.np, "compatible",
951 "st,stm32-sai-sub-b") >= 0)
952 sai->synco = STM_SAI_SYNC_OUT_B;
953
954 if (!sai->synco) {
955 dev_err(&pdev->dev, "Unknown SAI sub-block\n");
956 of_node_put(args.np);
957 return -EINVAL;
958 }
959 }
960
961 dev_dbg(&pdev->dev, "%s synchronized with %s\n",
962 pdev->name, args.np->full_name);
963 }
964
965 of_node_put(args.np);
871 sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); 966 sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
872 if (IS_ERR(sai->sai_ck)) { 967 if (IS_ERR(sai->sai_ck)) {
873 dev_err(&pdev->dev, "Missing kernel clock sai_ck\n"); 968 dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");