| .. | .. |
|---|
| 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); |
|---|