blob: 4f1bcea90ce97abb6b8417754baf3e8238993d97 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From e62741891f6901b5219eacdf60835cac9beb7bae Mon Sep 17 00:00:00 2001
2From: Viorel Suman <viorel.suman@nxp.com>
3Date: Wed, 21 Nov 2018 16:09:44 +0200
4Subject: [PATCH] MLK-20328-1: ASoC: fsl_sai: map number of pins to dataline
5 masks
6
7The patch enable mapping the number of pins required to play or record
8a specific number of channels to a specific dataline mask.
9
10Three consequent elements in "fsl,dataline" and "fsl,dataline,dsd" defines a
11particular mapping, for instance for: fsl,dataline = "0 0xff 0xff 2 0x11 0x11"
12there are two mappings defined:
13
14default (0 pins) "rx" and "tx" dataline masks: 0 0xff 0xff
15 2 pins "rx" and "tx" dataline masks: 2 0x11 0x11
16
17In case if property is missing, then default value "0 0x1 0x1" is considered.
18
19Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
20---
21 sound/soc/fsl/fsl_sai.c | 227 ++++++++++++++++++++++++++++++------------------
22 sound/soc/fsl/fsl_sai.h | 16 +++-
23 2 files changed, 153 insertions(+), 90 deletions(-)
24
25--- a/sound/soc/fsl/fsl_sai.c
26+++ b/sound/soc/fsl/fsl_sai.c
27@@ -621,17 +621,35 @@ static int fsl_sai_hw_params(struct snd_
28 u32 slots = (channels == 1) ? 2 : channels;
29 u32 slot_width = word_width;
30 u32 pins, bclk;
31- int ret;
32- int i;
33- int trce_mask = 0;
34+ int ret, i, trce_mask = 0, dl_cfg_cnt, dl_cfg_idx = 0;
35+ struct fsl_sai_dl_cfg *dl_cfg;
36
37 if (sai->slots)
38 slots = sai->slots;
39
40 pins = DIV_ROUND_UP(channels, slots);
41 sai->is_dsd = fsl_is_dsd(params);
42- if (sai->is_dsd)
43+ if (sai->is_dsd) {
44 pins = channels;
45+ dl_cfg = sai->dsd_dl_cfg;
46+ dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
47+ } else {
48+ dl_cfg = sai->pcm_dl_cfg;
49+ dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
50+ }
51+
52+ for (i = 0; i < dl_cfg_cnt; i++) {
53+ if (dl_cfg[i].pins == pins) {
54+ dl_cfg_idx = i;
55+ break;
56+ }
57+ }
58+
59+ if (dl_cfg_idx >= dl_cfg_cnt) {
60+ dev_err(cpu_dai->dev, "fsl,dataline%s invalid or not provided.\n",
61+ sai->is_dsd ? ",dsd" : "");
62+ return -EINVAL;
63+ }
64
65 if (sai->slot_width)
66 slot_width = sai->slot_width;
67@@ -713,7 +731,7 @@ static int fsl_sai_hw_params(struct snd_
68
69 if (sai->soc->dataline != 0x1) {
70
71- if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
72+ if (dl_cfg[dl_cfg_idx].mask[tx] <= 1 || sai->is_multi_lane)
73 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
74 FSL_SAI_CR4_FCOMB_MASK, 0);
75 else
76@@ -724,21 +742,13 @@ static int fsl_sai_hw_params(struct snd_
77 if (tx) {
78 sai->dma_params_tx.maxburst =
79 FSL_SAI_MAXBURST_TX * pins;
80- if (sai->is_dsd)
81- sai->dma_params_tx.fifo_num = pins +
82- (sai->dataline_off_dsd[tx] << 4);
83- else
84- sai->dma_params_tx.fifo_num = pins +
85- (sai->dataline_off[tx] << 4);
86+ sai->dma_params_tx.fifo_num = pins +
87+ (dl_cfg[dl_cfg_idx].offset[tx] << 4);
88 } else {
89 sai->dma_params_rx.maxburst =
90 FSL_SAI_MAXBURST_RX * pins;
91- if (sai->is_dsd)
92- sai->dma_params_rx.fifo_num = pins +
93- (sai->dataline_off_dsd[tx] << 4);
94- else
95- sai->dma_params_rx.fifo_num = pins +
96- (sai->dataline_off[tx] << 4);
97+ sai->dma_params_rx.fifo_num = pins +
98+ (dl_cfg[dl_cfg_idx].offset[tx] << 4);
99 }
100 }
101
102@@ -746,38 +756,22 @@ static int fsl_sai_hw_params(struct snd_
103 &sai->dma_params_rx);
104 }
105
106- if (sai->is_dsd) {
107- if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
108- dev_err(cpu_dai->dev, "channel not supported\n");
109- return -EINVAL;
110- }
111- /*find a proper tcre setting*/
112- for (i = 0; i < 8; i++) {
113- trce_mask = (1 << (i + 1)) - 1;
114- if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
115- break;
116- }
117-
118- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
119- FSL_SAI_CR3_TRCE_MASK,
120- FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
121- } else {
122- if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
123- dev_err(cpu_dai->dev, "channel not supported\n");
124- return -EINVAL;
125- }
126- /*find a proper tcre setting*/
127- for (i = 0; i < 8; i++) {
128- trce_mask = (1 << (i + 1)) - 1;
129- if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
130- break;
131- }
132+ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & 0xFF) < pins) {
133+ dev_err(cpu_dai->dev, "channel not supported\n");
134+ return -EINVAL;
135+ }
136
137- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
138- FSL_SAI_CR3_TRCE_MASK,
139- FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
140+ /*find a proper tcre setting*/
141+ for (i = 0; i < 8; i++) {
142+ trce_mask = (1 << (i + 1)) - 1;
143+ if (__sw_hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
144+ break;
145 }
146
147+ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
148+ FSL_SAI_CR3_TRCE_MASK,
149+ FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
150+
151 regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
152 FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
153 FSL_SAI_CR4_CHMOD_MASK,
154@@ -820,15 +814,32 @@ static int fsl_sai_trigger(struct snd_pc
155 u32 slots = (channels == 1) ? 2 : channels;
156 u32 xcsr, count = 100;
157 u32 pins;
158- int i = 0, j = 0, k = 0;
159+ int i = 0, j = 0, k = 0, dl_cfg_cnt, dl_cfg_idx = 0;
160+ struct fsl_sai_dl_cfg *dl_cfg;
161
162 if (sai->slots)
163 slots = sai->slots;
164
165 pins = DIV_ROUND_UP(channels, slots);
166
167- if (sai->is_dsd)
168+ if (sai->is_dsd) {
169 pins = channels;
170+ dl_cfg = sai->dsd_dl_cfg;
171+ dl_cfg_cnt = sai->dsd_dl_cfg_cnt;
172+ } else {
173+ dl_cfg = sai->pcm_dl_cfg;
174+ dl_cfg_cnt = sai->pcm_dl_cfg_cnt;
175+ }
176+
177+ for (i = 0; i < dl_cfg_cnt; i++) {
178+ if (dl_cfg[i].pins == pins) {
179+ dl_cfg_idx = i;
180+ break;
181+ }
182+ }
183+
184+ i = 0;
185+
186 /*
187 * Asynchronous mode: Clear SYNC for both Tx and Rx.
188 * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
189@@ -849,7 +860,7 @@ static int fsl_sai_trigger(struct snd_pc
190 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
191
192 while (tx && i < channels) {
193- if ((sai->is_dsd ? sai->dataline_dsd[tx] : sai->dataline[tx]) & (1 << j)) {
194+ if (dl_cfg[dl_cfg_idx].mask[tx] & (1 << j)) {
195 regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
196 i++;
197 k++;
198@@ -1262,6 +1273,77 @@ static const struct of_device_id fsl_sai
199 };
200 MODULE_DEVICE_TABLE(of, fsl_sai_ids);
201
202+static unsigned int fsl_sai_calc_dl_off(unsigned int* dl_mask)
203+{
204+ int fbidx, nbidx, offset;
205+
206+ fbidx = find_first_bit((const unsigned long *)dl_mask, 8);
207+ nbidx = find_next_bit((const unsigned long *)dl_mask, 8, fbidx+1);
208+ offset = nbidx - fbidx - 1;
209+
210+ return (offset < 0 || offset >= 7 ? 0 : offset);
211+}
212+
213+static int fsl_sai_read_dlcfg(struct platform_device *pdev, char *pn,
214+ struct fsl_sai_dl_cfg **rcfg, unsigned int soc_dl)
215+{
216+ int ret, elems, i, index, num_cfg;
217+ struct device_node *np = pdev->dev.of_node;
218+ struct fsl_sai_dl_cfg *cfg;
219+ u32 rx, tx, pins;
220+
221+ *rcfg = NULL;
222+
223+ elems = of_property_count_u32_elems(np, pn);
224+
225+ /* consider default value "0 0x1 0x1" if property is missing */
226+ if (elems <= 0)
227+ elems = 3;
228+
229+ if (elems % 3) {
230+ dev_err(&pdev->dev,
231+ "Number of elements in %s must be divisible to 3.\n", pn);
232+ return -EINVAL;
233+ }
234+
235+ num_cfg = elems / 3;
236+ cfg = devm_kzalloc(&pdev->dev, num_cfg * sizeof(*cfg), GFP_KERNEL);
237+ if (cfg == NULL) {
238+ dev_err(&pdev->dev, "Cannot allocate memory for %s.\n", pn);
239+ return -ENOMEM;
240+ }
241+
242+ for (i = 0, index = 0; i < num_cfg; i++) {
243+ ret = of_property_read_u32_index(np, pn, index++, &pins);
244+ if (ret)
245+ pins = 0;
246+
247+ ret = of_property_read_u32_index(np, pn, index++, &rx);
248+ if (ret)
249+ rx = 1;
250+
251+ ret = of_property_read_u32_index(np, pn, index++, &tx);
252+ if (ret)
253+ tx = 1;
254+
255+ if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
256+ dev_err(&pdev->dev,
257+ "%s: dataline cfg[%d] setting error, mask is 0x%x\n",
258+ pn, i, soc_dl);
259+ return -EINVAL;
260+ }
261+
262+ cfg[i].pins = pins;
263+ cfg[i].mask[0] = rx;
264+ cfg[i].offset[0] = fsl_sai_calc_dl_off(&rx);
265+ cfg[i].mask[1] = tx;
266+ cfg[i].offset[1] = fsl_sai_calc_dl_off(&tx);
267+ }
268+
269+ *rcfg = cfg;
270+ return num_cfg;
271+}
272+
273 static int fsl_sai_probe(struct platform_device *pdev)
274 {
275 struct device_node *np = pdev->dev.of_node;
276@@ -1273,7 +1355,6 @@ static int fsl_sai_probe(struct platform
277 char tmp[8];
278 int irq, ret, i;
279 int index;
280- int firstbitidx, nextbitidx, offset;
281 struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
282 unsigned long irqflags = 0;
283
284@@ -1340,45 +1421,19 @@ static int fsl_sai_probe(struct platform
285 sai->is_multi_lane = true;
286
287 /*dataline mask for rx and tx*/
288- ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
289- if (ret)
290- sai->dataline[0] = 1;
291-
292- ret = of_property_read_u32_index(np, "fsl,dataline", 1, &sai->dataline[1]);
293- if (ret)
294- sai->dataline[1] = 1;
295-
296- if ((sai->dataline[0] & (~sai->soc->dataline)) || sai->dataline[1] & (~sai->soc->dataline)) {
297- dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
298- return -EINVAL;
299- }
300-
301- for (i = 0; i < 2; i++) {
302- firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
303- nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
304- offset = nextbitidx - firstbitidx - 1;
305- sai->dataline_off[i] = (offset < 0 || offset >= 7 ? 0 : offset);
306- }
307-
308- ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
309- if (ret)
310- sai->dataline_dsd[0] = 1;
311-
312- ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
313- if (ret)
314- sai->dataline_dsd[1] = 1;
315+ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline", &sai->pcm_dl_cfg,
316+ sai->soc->dataline);
317+ if (ret < 0)
318+ return ret;
319+
320+ sai->pcm_dl_cfg_cnt = ret;
321+
322+ ret = fsl_sai_read_dlcfg(pdev, "fsl,dataline,dsd", &sai->dsd_dl_cfg,
323+ sai->soc->dataline);
324+ if (ret < 0)
325+ return ret;
326
327- if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
328- dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
329- return -EINVAL;
330- }
331-
332- for (i = 0; i < 2; i++) {
333- firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
334- nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
335- offset = nextbitidx - firstbitidx - 1;
336- sai->dataline_off_dsd[i] = (offset < 0 || offset >= 7 ? 0 : offset);
337- }
338+ sai->dsd_dl_cfg_cnt = ret;
339
340 if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
341 (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
342--- a/sound/soc/fsl/fsl_sai.h
343+++ b/sound/soc/fsl/fsl_sai.h
344@@ -234,6 +234,12 @@ struct fsl_sai_param {
345 u32 dln; /* number of datalines implemented */
346 };
347
348+struct fsl_sai_dl_cfg {
349+ unsigned int pins;
350+ unsigned int mask[2];
351+ unsigned int offset[2];
352+};
353+
354 struct fsl_sai {
355 struct platform_device *pdev;
356 struct regmap *regmap;
357@@ -249,10 +255,12 @@ struct fsl_sai {
358 bool synchronous[2];
359 bool is_stream_opened[2];
360 bool is_dsd;
361- unsigned int dataline[2];
362- unsigned int dataline_dsd[2];
363- unsigned int dataline_off[2];
364- unsigned int dataline_off_dsd[2];
365+
366+ int pcm_dl_cfg_cnt;
367+ int dsd_dl_cfg_cnt;
368+ struct fsl_sai_dl_cfg *pcm_dl_cfg;
369+ struct fsl_sai_dl_cfg *dsd_dl_cfg;
370+
371 unsigned int masterflag[2];
372
373 unsigned int mclk_id[2];