.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * ALSA SoC SPDIF Audio Layer |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * Copyright 2015 Marcus Cooper <codekipper@gmail.com> |
---|
6 | 7 | * |
---|
7 | 8 | * Based on the Allwinner SDK driver, released under the GPL. |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
12 | | - * (at your option) any later version. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, |
---|
15 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
17 | | - * GNU General Public License for more details. |
---|
18 | 9 | */ |
---|
19 | 10 | |
---|
20 | 11 | #include <linux/clk.h> |
---|
.. | .. |
---|
74 | 65 | #define SUN4I_SPDIF_FCTL_TXIM BIT(2) |
---|
75 | 66 | #define SUN4I_SPDIF_FCTL_RXOM(v) ((v) << 0) |
---|
76 | 67 | #define SUN4I_SPDIF_FCTL_RXOM_MASK GENMASK(1, 0) |
---|
| 68 | + |
---|
| 69 | +#define SUN50I_H6_SPDIF_FCTL (0x14) |
---|
| 70 | + #define SUN50I_H6_SPDIF_FCTL_HUB_EN BIT(31) |
---|
| 71 | + #define SUN50I_H6_SPDIF_FCTL_FTX BIT(30) |
---|
| 72 | + #define SUN50I_H6_SPDIF_FCTL_FRX BIT(29) |
---|
| 73 | + #define SUN50I_H6_SPDIF_FCTL_TXTL(v) ((v) << 12) |
---|
| 74 | + #define SUN50I_H6_SPDIF_FCTL_TXTL_MASK GENMASK(19, 12) |
---|
| 75 | + #define SUN50I_H6_SPDIF_FCTL_RXTL(v) ((v) << 4) |
---|
| 76 | + #define SUN50I_H6_SPDIF_FCTL_RXTL_MASK GENMASK(10, 4) |
---|
| 77 | + #define SUN50I_H6_SPDIF_FCTL_TXIM BIT(2) |
---|
| 78 | + #define SUN50I_H6_SPDIF_FCTL_RXOM(v) ((v) << 0) |
---|
| 79 | + #define SUN50I_H6_SPDIF_FCTL_RXOM_MASK GENMASK(1, 0) |
---|
77 | 80 | |
---|
78 | 81 | #define SUN4I_SPDIF_FSTA (0x18) |
---|
79 | 82 | #define SUN4I_SPDIF_FSTA_TXE BIT(14) |
---|
.. | .. |
---|
161 | 164 | #define SUN4I_SPDIF_SAMFREQ_176_4KHZ 0xc |
---|
162 | 165 | #define SUN4I_SPDIF_SAMFREQ_192KHZ 0xe |
---|
163 | 166 | |
---|
| 167 | +/** |
---|
| 168 | + * struct sun4i_spdif_quirks - Differences between SoC variants. |
---|
| 169 | + * |
---|
| 170 | + * @reg_dac_txdata: TX FIFO offset for DMA config. |
---|
| 171 | + * @has_reset: SoC needs reset deasserted. |
---|
| 172 | + * @val_fctl_ftx: TX FIFO flush bitmask. |
---|
| 173 | + */ |
---|
| 174 | +struct sun4i_spdif_quirks { |
---|
| 175 | + unsigned int reg_dac_txdata; |
---|
| 176 | + bool has_reset; |
---|
| 177 | + unsigned int val_fctl_ftx; |
---|
| 178 | +}; |
---|
| 179 | + |
---|
164 | 180 | struct sun4i_spdif_dev { |
---|
165 | 181 | struct platform_device *pdev; |
---|
166 | 182 | struct clk *spdif_clk; |
---|
.. | .. |
---|
169 | 185 | struct snd_soc_dai_driver cpu_dai_drv; |
---|
170 | 186 | struct regmap *regmap; |
---|
171 | 187 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
---|
| 188 | + const struct sun4i_spdif_quirks *quirks; |
---|
172 | 189 | }; |
---|
173 | 190 | |
---|
174 | 191 | static void sun4i_spdif_configure(struct sun4i_spdif_dev *host) |
---|
175 | 192 | { |
---|
| 193 | + const struct sun4i_spdif_quirks *quirks = host->quirks; |
---|
| 194 | + |
---|
176 | 195 | /* soft reset SPDIF */ |
---|
177 | 196 | regmap_write(host->regmap, SUN4I_SPDIF_CTL, SUN4I_SPDIF_CTL_RESET); |
---|
178 | 197 | |
---|
179 | 198 | /* flush TX FIFO */ |
---|
180 | 199 | regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL, |
---|
181 | | - SUN4I_SPDIF_FCTL_FTX, SUN4I_SPDIF_FCTL_FTX); |
---|
| 200 | + quirks->val_fctl_ftx, quirks->val_fctl_ftx); |
---|
182 | 201 | |
---|
183 | 202 | /* clear TX counter */ |
---|
184 | 203 | regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0); |
---|
.. | .. |
---|
224 | 243 | static int sun4i_spdif_startup(struct snd_pcm_substream *substream, |
---|
225 | 244 | struct snd_soc_dai *cpu_dai) |
---|
226 | 245 | { |
---|
227 | | - struct snd_soc_pcm_runtime *rtd = substream->private_data; |
---|
228 | | - struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
---|
| 246 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 247 | + struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); |
---|
229 | 248 | |
---|
230 | 249 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) |
---|
231 | 250 | return -EINVAL; |
---|
.. | .. |
---|
405 | 424 | .name = "spdif", |
---|
406 | 425 | }; |
---|
407 | 426 | |
---|
408 | | -struct sun4i_spdif_quirks { |
---|
409 | | - unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ |
---|
410 | | - bool has_reset; |
---|
411 | | -}; |
---|
412 | | - |
---|
413 | 427 | static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = { |
---|
414 | 428 | .reg_dac_txdata = SUN4I_SPDIF_TXFIFO, |
---|
| 429 | + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, |
---|
415 | 430 | }; |
---|
416 | 431 | |
---|
417 | 432 | static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = { |
---|
418 | 433 | .reg_dac_txdata = SUN4I_SPDIF_TXFIFO, |
---|
| 434 | + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, |
---|
419 | 435 | .has_reset = true, |
---|
420 | 436 | }; |
---|
421 | 437 | |
---|
422 | 438 | static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = { |
---|
423 | 439 | .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, |
---|
| 440 | + .val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX, |
---|
424 | 441 | .has_reset = true, |
---|
| 442 | +}; |
---|
| 443 | + |
---|
| 444 | +static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = { |
---|
| 445 | + .reg_dac_txdata = SUN8I_SPDIF_TXFIFO, |
---|
| 446 | + .val_fctl_ftx = SUN50I_H6_SPDIF_FCTL_FTX, |
---|
| 447 | + .has_reset = true, |
---|
425 | 448 | }; |
---|
426 | 449 | |
---|
427 | 450 | static const struct of_device_id sun4i_spdif_of_match[] = { |
---|
.. | .. |
---|
436 | 459 | { |
---|
437 | 460 | .compatible = "allwinner,sun8i-h3-spdif", |
---|
438 | 461 | .data = &sun8i_h3_spdif_quirks, |
---|
| 462 | + }, |
---|
| 463 | + { |
---|
| 464 | + .compatible = "allwinner,sun50i-h6-spdif", |
---|
| 465 | + .data = &sun50i_h6_spdif_quirks, |
---|
439 | 466 | }, |
---|
440 | 467 | { /* sentinel */ } |
---|
441 | 468 | }; |
---|
.. | .. |
---|
501 | 528 | dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); |
---|
502 | 529 | return -ENODEV; |
---|
503 | 530 | } |
---|
| 531 | + host->quirks = quirks; |
---|
504 | 532 | |
---|
505 | 533 | host->regmap = devm_regmap_init_mmio(&pdev->dev, base, |
---|
506 | 534 | &sun4i_spdif_regmap_config); |
---|
.. | .. |
---|
527 | 555 | if (quirks->has_reset) { |
---|
528 | 556 | host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, |
---|
529 | 557 | NULL); |
---|
530 | | - if (IS_ERR(host->rst) && PTR_ERR(host->rst) == -EPROBE_DEFER) { |
---|
| 558 | + if (PTR_ERR(host->rst) == -EPROBE_DEFER) { |
---|
531 | 559 | ret = -EPROBE_DEFER; |
---|
532 | 560 | dev_err(&pdev->dev, "Failed to get reset: %d\n", ret); |
---|
533 | 561 | return ret; |
---|