.. | .. |
---|
7 | 7 | #include <linux/module.h> |
---|
8 | 8 | #include <linux/of_platform.h> |
---|
9 | 9 | #include <linux/regmap.h> |
---|
| 10 | +#include <linux/reset.h> |
---|
10 | 11 | #include <sound/soc.h> |
---|
11 | 12 | |
---|
12 | 13 | #include "axg-tdm-formatter.h" |
---|
.. | .. |
---|
20 | 21 | struct clk *lrclk; |
---|
21 | 22 | struct clk *sclk_sel; |
---|
22 | 23 | struct clk *lrclk_sel; |
---|
| 24 | + struct reset_control *reset; |
---|
23 | 25 | bool enabled; |
---|
24 | 26 | struct regmap *map; |
---|
25 | 27 | }; |
---|
.. | .. |
---|
28 | 30 | struct axg_tdm_stream *ts, |
---|
29 | 31 | unsigned int offset) |
---|
30 | 32 | { |
---|
31 | | - unsigned int val, ch = ts->channels; |
---|
32 | | - unsigned long mask; |
---|
33 | | - int i, j; |
---|
| 33 | + unsigned int ch = ts->channels; |
---|
| 34 | + u32 val[AXG_TDM_NUM_LANES]; |
---|
| 35 | + int i, j, k; |
---|
| 36 | + |
---|
| 37 | + /* |
---|
| 38 | + * We need to mimick the slot distribution used by the HW to keep the |
---|
| 39 | + * channel placement consistent regardless of the number of channel |
---|
| 40 | + * in the stream. This is why the odd algorithm below is used. |
---|
| 41 | + */ |
---|
| 42 | + memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES); |
---|
34 | 43 | |
---|
35 | 44 | /* |
---|
36 | 45 | * Distribute the channels of the stream over the available slots |
---|
37 | | - * of each TDM lane |
---|
| 46 | + * of each TDM lane. We need to go over the 32 slots ... |
---|
38 | 47 | */ |
---|
39 | | - for (i = 0; i < AXG_TDM_NUM_LANES; i++) { |
---|
40 | | - val = 0; |
---|
41 | | - mask = ts->mask[i]; |
---|
42 | | - |
---|
43 | | - for (j = find_first_bit(&mask, 32); |
---|
44 | | - (j < 32) && ch; |
---|
45 | | - j = find_next_bit(&mask, 32, j + 1)) { |
---|
46 | | - val |= 1 << j; |
---|
47 | | - ch -= 1; |
---|
| 48 | + for (i = 0; (i < 32) && ch; i += 2) { |
---|
| 49 | + /* ... of all the lanes ... */ |
---|
| 50 | + for (j = 0; j < AXG_TDM_NUM_LANES; j++) { |
---|
| 51 | + /* ... then distribute the channels in pairs */ |
---|
| 52 | + for (k = 0; k < 2; k++) { |
---|
| 53 | + if ((BIT(i + k) & ts->mask[j]) && ch) { |
---|
| 54 | + val[j] |= BIT(i + k); |
---|
| 55 | + ch -= 1; |
---|
| 56 | + } |
---|
| 57 | + } |
---|
48 | 58 | } |
---|
49 | | - |
---|
50 | | - regmap_write(map, offset, val); |
---|
51 | | - offset += regmap_get_reg_stride(map); |
---|
52 | 59 | } |
---|
53 | 60 | |
---|
54 | 61 | /* |
---|
.. | .. |
---|
61 | 68 | return -EINVAL; |
---|
62 | 69 | } |
---|
63 | 70 | |
---|
| 71 | + for (i = 0; i < AXG_TDM_NUM_LANES; i++) { |
---|
| 72 | + regmap_write(map, offset, val[i]); |
---|
| 73 | + offset += regmap_get_reg_stride(map); |
---|
| 74 | + } |
---|
| 75 | + |
---|
64 | 76 | return 0; |
---|
65 | 77 | } |
---|
66 | 78 | EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); |
---|
.. | .. |
---|
68 | 80 | static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) |
---|
69 | 81 | { |
---|
70 | 82 | struct axg_tdm_stream *ts = formatter->stream; |
---|
71 | | - bool invert = formatter->drv->invert_sclk; |
---|
| 83 | + bool invert; |
---|
72 | 84 | int ret; |
---|
73 | 85 | |
---|
74 | 86 | /* Do nothing if the formatter is already enabled */ |
---|
.. | .. |
---|
76 | 88 | return 0; |
---|
77 | 89 | |
---|
78 | 90 | /* |
---|
79 | | - * If sclk is inverted, invert it back and provide the inversion |
---|
80 | | - * required by the formatter |
---|
| 91 | + * On the g12a (and possibly other SoCs), when a stream using |
---|
| 92 | + * multiple lanes is restarted, it will sometimes not start |
---|
| 93 | + * from the first lane, but randomly from another used one. |
---|
| 94 | + * The result is an unexpected and random channel shift. |
---|
| 95 | + * |
---|
| 96 | + * The hypothesis is that an HW counter is not properly reset |
---|
| 97 | + * and the formatter simply starts on the lane it stopped |
---|
| 98 | + * before. Unfortunately, there does not seems to be a way to |
---|
| 99 | + * reset this through the registers of the block. |
---|
| 100 | + * |
---|
| 101 | + * However, the g12a has indenpendent reset lines for each audio |
---|
| 102 | + * devices. Using this reset before each start solves the issue. |
---|
81 | 103 | */ |
---|
82 | | - invert ^= axg_tdm_sclk_invert(ts->iface->fmt); |
---|
83 | | - ret = clk_set_phase(formatter->sclk, invert ? 180 : 0); |
---|
| 104 | + ret = reset_control_reset(formatter->reset); |
---|
| 105 | + if (ret) |
---|
| 106 | + return ret; |
---|
| 107 | + |
---|
| 108 | + /* |
---|
| 109 | + * If sclk is inverted, it means the bit should latched on the |
---|
| 110 | + * rising edge which is what our HW expects. If not, we need to |
---|
| 111 | + * invert it before the formatter. |
---|
| 112 | + */ |
---|
| 113 | + invert = axg_tdm_sclk_invert(ts->iface->fmt); |
---|
| 114 | + ret = clk_set_phase(formatter->sclk, invert ? 0 : 180); |
---|
84 | 115 | if (ret) |
---|
85 | 116 | return ret; |
---|
86 | 117 | |
---|
87 | 118 | /* Setup the stream parameter in the formatter */ |
---|
88 | | - ret = formatter->drv->ops->prepare(formatter->map, formatter->stream); |
---|
| 119 | + ret = formatter->drv->ops->prepare(formatter->map, |
---|
| 120 | + formatter->drv->quirks, |
---|
| 121 | + formatter->stream); |
---|
89 | 122 | if (ret) |
---|
90 | 123 | return ret; |
---|
91 | 124 | |
---|
.. | .. |
---|
231 | 264 | struct device *dev = &pdev->dev; |
---|
232 | 265 | const struct axg_tdm_formatter_driver *drv; |
---|
233 | 266 | struct axg_tdm_formatter *formatter; |
---|
234 | | - struct resource *res; |
---|
235 | 267 | void __iomem *regs; |
---|
236 | 268 | int ret; |
---|
237 | 269 | |
---|
.. | .. |
---|
247 | 279 | platform_set_drvdata(pdev, formatter); |
---|
248 | 280 | formatter->drv = drv; |
---|
249 | 281 | |
---|
250 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
251 | | - regs = devm_ioremap_resource(dev, res); |
---|
| 282 | + regs = devm_platform_ioremap_resource(pdev, 0); |
---|
252 | 283 | if (IS_ERR(regs)) |
---|
253 | 284 | return PTR_ERR(regs); |
---|
254 | 285 | |
---|
.. | .. |
---|
301 | 332 | ret = PTR_ERR(formatter->lrclk_sel); |
---|
302 | 333 | if (ret != -EPROBE_DEFER) |
---|
303 | 334 | dev_err(dev, "failed to get lrclk_sel: %d\n", ret); |
---|
| 335 | + return ret; |
---|
| 336 | + } |
---|
| 337 | + |
---|
| 338 | + /* Formatter dedicated reset line */ |
---|
| 339 | + formatter->reset = devm_reset_control_get_optional_exclusive(dev, NULL); |
---|
| 340 | + if (IS_ERR(formatter->reset)) { |
---|
| 341 | + ret = PTR_ERR(formatter->reset); |
---|
| 342 | + if (ret != -EPROBE_DEFER) |
---|
| 343 | + dev_err(dev, "failed to get reset: %d\n", ret); |
---|
304 | 344 | return ret; |
---|
305 | 345 | } |
---|
306 | 346 | |
---|
.. | .. |
---|
368 | 408 | /* |
---|
369 | 409 | * If the list is not empty, it would mean that one of the formatter |
---|
370 | 410 | * widget is still powered and attached to the interface while we |
---|
371 | | - * we are removing the TDM DAI. It should not be possible |
---|
| 411 | + * are removing the TDM DAI. It should not be possible |
---|
372 | 412 | */ |
---|
373 | 413 | WARN_ON(!list_empty(&ts->formatter_list)); |
---|
374 | 414 | mutex_destroy(&ts->lock); |
---|