History

Support HDMI audio on NVIDIA Tegra20

Merge series from Dmitry Osipenko <digetx@gmail.com>: This series revives Tegra20 S/PDIF driver which was upstreamed long time ago, but never was used. It also turns Tegra DRM HDMI driver into HDMI audio CODEC provider. Finally, HDMI audio is enabled in device-trees. For now the audio is enable only for Acer A500 tablet and Toshiba AC100 netbook because they're already supported by upstream, later on ASUS TF101 tablet will join them. I based S/PDIF patches on Arnd's Bergmann patch from a separate series [1] that removes obsolete slave_id. This eases merging of the patches by removing the merge conflict. This is a note for Mark Brown. I also based this series on top of power management series [2]. I.e. [2] should be applied first, otherwise "Add S/PDIF node to Tegra20 device-tree" patch should have merge conflict. This is a note for Thierry. [1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=273312 [2] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=274534 Changelog: v4: - Added patches that update multi_v7_defconfig with the enabled S/PDIF and APB DMA drivers. v3: - Renamed S/PDIF device-tree clocks as was suggested by Rob Herring. - Added r-bs and acks that were given by Rob Herring to v2. v2: - Corrected I2S yaml problem that was reported by the DT bot for v1 by removing the non-existent required clock-names property. - Removed assigned-clocks property from S/PDIF yaml since this property is now inherited from the clocks property. - Reordered the "tegra20: spdif: Set FIFO trigger level" patch, making it the first sound/soc patch in the series, like it was suggested by Mark Brown in the comment to v1. Also reworded commit message of this patch to *not* make it looks like it should be backported to stable kernels. Arnd Bergmann (1): ASoC: tegra20-spdif: stop setting slave_id Dmitry Osipenko (21): ASoC: dt-bindings: Add binding for Tegra20 S/PDIF ASoC: dt-bindings: tegra20-i2s: Convert to schema ASoC: dt-bindings: tegra20-i2s: Document new nvidia,fixed-parent-rate property dt-bindings: host1x: Document optional HDMI sound-dai-cells ASoC: tegra20: spdif: Set FIFO trigger level ASoC: tegra20: spdif: Support device-tree ASoC: tegra20: spdif: Improve driver's code ASoC: tegra20: spdif: Use more resource-managed helpers ASoC: tegra20: spdif: Reset hardware ASoC: tegra20: spdif: Support system suspend ASoC: tegra20: spdif: Filter out unsupported rates ASoC: tegra20: i2s: Filter out unsupported rates drm/tegra: hdmi: Unwind tegra_hdmi_init() errors drm/tegra: hdmi: Register audio CODEC on Tegra20 ARM: tegra_defconfig: Enable S/PDIF driver ARM: config: multi v7: Enable NVIDIA Tegra20 S/PDIF driver ARM: config: multi v7: Enable NVIDIA Tegra20 APB DMA driver ARM: tegra: Add S/PDIF node to Tegra20 device-tree ARM: tegra: Add HDMI audio graph to Tegra20 device-tree ARM: tegra: acer-a500: Enable S/PDIF and HDMI audio ARM: tegra: paz00: Enable S/PDIF and HDMI audio .../display/tegra/nvidia,tegra20-host1x.txt | 1 + .../bindings/sound/nvidia,tegra20-i2s.txt | 30 --- .../bindings/sound/nvidia,tegra20-i2s.yaml | 77 +++++++ .../bindings/sound/nvidia,tegra20-spdif.yaml | 85 ++++++++ .../boot/dts/tegra20-acer-a500-picasso.dts | 8 + arch/arm/boot/dts/tegra20-paz00.dts | 8 + arch/arm/boot/dts/tegra20.dtsi | 40 +++- arch/arm/configs/multi_v7_defconfig | 2 + arch/arm/configs/tegra_defconfig | 1 + drivers/gpu/drm/tegra/Kconfig | 3 + drivers/gpu/drm/tegra/hdmi.c | 168 +++++++++++++-- sound/soc/tegra/tegra20_i2s.c | 49 +++++ sound/soc/tegra/tegra20_spdif.c | 197 ++++++++++++------ sound/soc/tegra/tegra20_spdif.h | 1 + sound/soc/tegra/tegra_pcm.c | 6 + sound/soc/tegra/tegra_pcm.h | 1 + 16 files changed, 574 insertions(+), 103 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml -- 2.33.1

Mark Brown committed 4 years ago

Commit be1d03e2 parents a92c1cd bfa467125 files · +475 −150Browse files

Unified · Split

25 files
  1. Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +0 −30
  2. Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml +77 −0
  3. Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml +85 −0
  4. drivers/dma/mmp_pdma.c +0 −6
  5. drivers/dma/pxa_dma.c +0 −7
  6. drivers/dma/qcom/qcom_adm.c +49 −7
  7. drivers/dma/sh/shdma-base.c +0 −8
  8. drivers/dma/sprd-dma.c +0 −3
  9. drivers/dma/tegra20-apb-dma.c +0 −6
  10. drivers/dma/xilinx/xilinx_dpdma.c +11 −6
  11. drivers/gpu/drm/xlnx/zynqmp_disp.c +7 −2
  12. drivers/mmc/host/bcm2835.c +0 −2
  13. drivers/mtd/nand/raw/qcom_nandc.c +12 −2
  14. drivers/spi/spi-pic32.c +0 −2
  15. drivers/tty/serial/msm_serial.c +13 −2
  16. include/linux/dma/qcom_adm.h +12 −0
  17. include/linux/dma/xilinx_dpdma.h +11 −0
  18. include/linux/dmaengine.h +0 −4
  19. include/sound/dmaengine_pcm.h +0 −2
  20. sound/core/pcm_dmaengine.c +2 −3
  21. sound/soc/tegra/tegra20_i2s.c +49 −0
  22. sound/soc/tegra/tegra20_spdif.c +139 −58
  23. sound/soc/tegra/tegra20_spdif.h +1 −0
  24. sound/soc/tegra/tegra_pcm.c +6 −0
  25. sound/soc/tegra/tegra_pcm.h +1 −0
Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt+0−30
@@ -1,30 +0,0 @@
1NVIDIA Tegra 20 I2S controller
2
3Required properties:
4- compatible : "nvidia,tegra20-i2s"
5- reg : Should contain I2S registers location and length
6- interrupts : Should contain I2S interrupt
7- resets : Must contain an entry for each entry in reset-names.
8 See ../reset/reset.txt for details.
9- reset-names : Must include the following entries:
10 - i2s
11- dmas : Must contain an entry for each entry in clock-names.
12 See ../dma/dma.txt for details.
13- dma-names : Must include the following entries:
14 - rx
15 - tx
16- clocks : Must contain one entry, for the module clock.
17 See ../clocks/clock-bindings.txt for details.
18
19Example:
20
21i2s@70002800 {
22 compatible = "nvidia,tegra20-i2s";
23 reg = <0x70002800 0x200>;
24 interrupts = < 45 >;
25 clocks = <&tegra_car 11>;
26 resets = <&tegra_car 11>;
27 reset-names = "i2s";
28 dmas = <&apbdma 21>, <&apbdma 21>;
29 dma-names = "rx", "tx";
30};
Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.yaml+77−0
@@ -0,0 +1,77 @@
1# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/sound/nvidia,tegra20-i2s.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: NVIDIA Tegra20 I2S Controller
8
9description: |
10 The I2S Controller streams synchronous serial audio data between system
11 memory and an external audio device. The controller supports the I2S Left
12 Justified Mode, Right Justified Mode, and DSP mode formats.
13
14maintainers:
15 - Thierry Reding <treding@nvidia.com>
16 - Jon Hunter <jonathanh@nvidia.com>
17
18properties:
19 compatible:
20 const: nvidia,tegra20-i2s
21
22 reg:
23 maxItems: 1
24
25 resets:
26 maxItems: 1
27
28 reset-names:
29 const: i2s
30
31 interrupts:
32 maxItems: 1
33
34 clocks:
35 minItems: 1
36
37 dmas:
38 minItems: 2
39
40 dma-names:
41 items:
42 - const: rx
43 - const: tx
44
45 nvidia,fixed-parent-rate:
46 description: |
47 Specifies whether board prefers parent clock to stay at a fixed rate.
48 This allows multiple Tegra20 audio components work simultaneously by
49 limiting number of supportable audio rates.
50 type: boolean
51
52required:
53 - compatible
54 - reg
55 - resets
56 - reset-names
57 - interrupts
58 - clocks
59 - dmas
60 - dma-names
61
62additionalProperties: false
63
64examples:
65 - |
66 i2s@70002800 {
67 compatible = "nvidia,tegra20-i2s";
68 reg = <0x70002800 0x200>;
69 interrupts = <45>;
70 clocks = <&tegra_car 11>;
71 resets = <&tegra_car 11>;
72 reset-names = "i2s";
73 dmas = <&apbdma 21>, <&apbdma 21>;
74 dma-names = "rx", "tx";
75 };
76
77...
Documentation/devicetree/bindings/sound/nvidia,tegra20-spdif.yaml+85−0
@@ -0,0 +1,85 @@
1# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/sound/nvidia,tegra20-spdif.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: NVIDIA Tegra20 S/PDIF Controller
8
9description: |
10 The S/PDIF controller supports both input and output in serial audio
11 digital interface format. The input controller can digitally recover
12 a clock from the received stream. The S/PDIF controller is also used
13 to generate the embedded audio for HDMI output channel.
14
15maintainers:
16 - Thierry Reding <treding@nvidia.com>
17 - Jon Hunter <jonathanh@nvidia.com>
18
19properties:
20 compatible:
21 const: nvidia,tegra20-spdif
22
23 reg:
24 maxItems: 1
25
26 resets:
27 maxItems: 1
28
29 interrupts:
30 maxItems: 1
31
32 clocks:
33 minItems: 2
34
35 clock-names:
36 items:
37 - const: out
38 - const: in
39
40 dmas:
41 minItems: 2
42
43 dma-names:
44 items:
45 - const: rx
46 - const: tx
47
48 "#sound-dai-cells":
49 const: 0
50
51 nvidia,fixed-parent-rate:
52 description: |
53 Specifies whether board prefers parent clock to stay at a fixed rate.
54 This allows multiple Tegra20 audio components work simultaneously by
55 limiting number of supportable audio rates.
56 type: boolean
57
58required:
59 - compatible
60 - reg
61 - resets
62 - interrupts
63 - clocks
64 - clock-names
65 - dmas
66 - dma-names
67 - "#sound-dai-cells"
68
69additionalProperties: false
70
71examples:
72 - |
73 spdif@70002400 {
74 compatible = "nvidia,tegra20-spdif";
75 reg = <0x70002400 0x200>;
76 interrupts = <77>;
77 clocks = <&clk 99>, <&clk 98>;
78 clock-names = "out", "in";
79 resets = <&rst 10>;
80 dmas = <&apbdma 3>, <&apbdma 3>;
81 dma-names = "rx", "tx";
82 #sound-dai-cells = <0>;
83 };
84
85...
drivers/dma/mmp_pdma.c+0−6
@@ -727,12 +727,6 @@ static int mmp_pdma_config_write(struct dma_chan *dchan, · 726 unmodified lines
727 727
728 chan->dir = direction;728 chan->dir = direction;
729 chan->dev_addr = addr;729 chan->dev_addr = addr;
730 /* FIXME: drivers should be ported over to use the filter
731 * function. Once that's done, the following two lines can
732 * be removed.
733 */
734 if (cfg->slave_id)
735 chan->drcmr = cfg->slave_id;
736 730
737 return 0;731 return 0;
738}732}
drivers/dma/pxa_dma.c+0−7
@@ -909,13 +909,6 @@ static void pxad_get_config(struct pxad_chan *chan, · 908 unmodified lines
909 *dcmd |= PXA_DCMD_BURST16;909 *dcmd |= PXA_DCMD_BURST16;
910 else if (maxburst == 32)910 else if (maxburst == 32)
911 *dcmd |= PXA_DCMD_BURST32;911 *dcmd |= PXA_DCMD_BURST32;
912
913 /* FIXME: drivers should be ported over to use the filter
914 * function. Once that's done, the following two lines can
915 * be removed.
916 */
917 if (chan->cfg.slave_id)
918 chan->drcmr = chan->cfg.slave_id;
919}912}
920 913
921static struct dma_async_tx_descriptor *914static struct dma_async_tx_descriptor *
drivers/dma/qcom/qcom_adm.c+49−7
@@ -8,6 +8,7 @@ · 7 unmodified lines
8#include <linux/device.h>8#include <linux/device.h>
9#include <linux/dmaengine.h>9#include <linux/dmaengine.h>
10#include <linux/dma-mapping.h>10#include <linux/dma-mapping.h>
11#include <linux/dma/qcom_adm.h>
11#include <linux/init.h>12#include <linux/init.h>
12#include <linux/interrupt.h>13#include <linux/interrupt.h>
13#include <linux/io.h>14#include <linux/io.h>
@@ -140,6 +141,8 @@ struct adm_chan { · 126 unmodified lines
140 141
141 struct adm_async_desc *curr_txd;142 struct adm_async_desc *curr_txd;
142 struct dma_slave_config slave;143 struct dma_slave_config slave;
144 u32 crci;
145 u32 mux;
143 struct list_head node;146 struct list_head node;
144 147
145 int error;148 int error;
@@ -379,8 +382,8 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, · 233 unmodified lines
379 return ERR_PTR(-EINVAL);382 return ERR_PTR(-EINVAL);
380 }383 }
381 384
382 crci = achan->slave.slave_id & 0xf;385 crci = achan->crci & 0xf;
383 if (!crci || achan->slave.slave_id > 0x1f) {386 if (!crci || achan->crci > 0x1f) {
384 dev_err(adev->dev, "invalid crci value\n");387 dev_err(adev->dev, "invalid crci value\n");
385 return ERR_PTR(-EINVAL);388 return ERR_PTR(-EINVAL);
386 }389 }
@@ -403,9 +406,7 @@ static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, · 16 unmodified lines
403 if (!async_desc)406 if (!async_desc)
404 return ERR_PTR(-ENOMEM);407 return ERR_PTR(-ENOMEM);
405 408
406 if (crci)409 async_desc->mux = achan->mux ? ADM_CRCI_CTL_MUX_SEL : 0;
407 async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ?
408 ADM_CRCI_CTL_MUX_SEL : 0;
409 async_desc->crci = crci;410 async_desc->crci = crci;
410 async_desc->blk_size = blk_size;411 async_desc->blk_size = blk_size;
411 async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +412 async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +
@@ -488,10 +489,13 @@ static int adm_terminate_all(struct dma_chan *chan) · 76 unmodified lines
488static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)489static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
489{490{
490 struct adm_chan *achan = to_adm_chan(chan);491 struct adm_chan *achan = to_adm_chan(chan);
492 struct qcom_adm_peripheral_config *config = cfg->peripheral_config;
491 unsigned long flag;493 unsigned long flag;
492 494
493 spin_lock_irqsave(&achan->vc.lock, flag);495 spin_lock_irqsave(&achan->vc.lock, flag);
494 memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));496 memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));
497 if (cfg->peripheral_size == sizeof(config))
498 achan->crci = config->crci;
495 spin_unlock_irqrestore(&achan->vc.lock, flag);499 spin_unlock_irqrestore(&achan->vc.lock, flag);
496 500
497 return 0;501 return 0;
@@ -694,6 +698,45 @@ static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, · 196 unmodified lines
694 achan->vc.desc_free = adm_dma_free_desc;698 achan->vc.desc_free = adm_dma_free_desc;
695}699}
696 700
701/**
702 * adm_dma_xlate
703 * @dma_spec: pointer to DMA specifier as found in the device tree
704 * @ofdma: pointer to DMA controller data
705 *
706 * This can use either 1-cell or 2-cell formats, the first cell
707 * identifies the slave device, while the optional second cell
708 * contains the crci value.
709 *
710 * Returns pointer to appropriate dma channel on success or NULL on error.
711 */
712static struct dma_chan *adm_dma_xlate(struct of_phandle_args *dma_spec,
713 struct of_dma *ofdma)
714{
715 struct dma_device *dev = ofdma->of_dma_data;
716 struct dma_chan *chan, *candidate = NULL;
717 struct adm_chan *achan;
718
719 if (!dev || dma_spec->args_count > 2)
720 return NULL;
721
722 list_for_each_entry(chan, &dev->channels, device_node)
723 if (chan->chan_id == dma_spec->args[0]) {
724 candidate = chan;
725 break;
726 }
727
728 if (!candidate)
729 return NULL;
730
731 achan = to_adm_chan(candidate);
732 if (dma_spec->args_count == 2)
733 achan->crci = dma_spec->args[1];
734 else
735 achan->crci = 0;
736
737 return dma_get_slave_channel(candidate);
738}
739
697static int adm_dma_probe(struct platform_device *pdev)740static int adm_dma_probe(struct platform_device *pdev)
698{741{
699 struct adm_device *adev;742 struct adm_device *adev;
@@ -838,8 +881,7 @@ static int adm_dma_probe(struct platform_device *pdev) · 138 unmodified lines
838 goto err_disable_clks;881 goto err_disable_clks;
839 }882 }
840 883
841 ret = of_dma_controller_register(pdev->dev.of_node,884 ret = of_dma_controller_register(pdev->dev.of_node, adm_dma_xlate,
842 of_dma_xlate_by_chan_id,
843 &adev->common);885 &adev->common);
844 if (ret)886 if (ret)
845 goto err_unregister_dma;887 goto err_unregister_dma;
drivers/dma/sh/shdma-base.c+0−8
@@ -786,14 +786,6 @@ static int shdma_config(struct dma_chan *chan, · 785 unmodified lines
786 if (!config)786 if (!config)
787 return -EINVAL;787 return -EINVAL;
788 788
789 /*
790 * overriding the slave_id through dma_slave_config is deprecated,
791 * but possibly some out-of-tree drivers still do it.
792 */
793 if (WARN_ON_ONCE(config->slave_id &&
794 config->slave_id != schan->real_slave_id))
795 schan->real_slave_id = config->slave_id;
796
797 /*789 /*
798 * We could lock this, but you shouldn't be configuring the790 * We could lock this, but you shouldn't be configuring the
799 * channel, while using it...791 * channel, while using it...
drivers/dma/sprd-dma.c+0−3
@@ -795,9 +795,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, · 794 unmodified lines
795 return dst_datawidth;795 return dst_datawidth;
796 }796 }
797 797
798 if (slave_cfg->slave_id)
799 schan->dev_id = slave_cfg->slave_id;
800
801 hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;798 hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
802 799
803 /*800 /*
drivers/dma/tegra20-apb-dma.c+0−6
@@ -343,12 +343,6 @@ static int tegra_dma_slave_config(struct dma_chan *dc, · 342 unmodified lines
343 }343 }
344 344
345 memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));345 memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
346 if (tdc->slave_id == TEGRA_APBDMA_SLAVE_ID_INVALID &&
347 sconfig->device_fc) {
348 if (sconfig->slave_id > TEGRA_APBDMA_CSR_REQ_SEL_MASK)
349 return -EINVAL;
350 tdc->slave_id = sconfig->slave_id;
351 }
352 tdc->config_init = true;346 tdc->config_init = true;
353 347
354 return 0;348 return 0;
drivers/dma/xilinx/xilinx_dpdma.c+11−6
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/clk.h>12#include <linux/clk.h>
13#include <linux/debugfs.h>13#include <linux/debugfs.h>
14#include <linux/delay.h>14#include <linux/delay.h>
15#include <linux/dma/xilinx_dpdma.h>
15#include <linux/dmaengine.h>16#include <linux/dmaengine.h>
16#include <linux/dmapool.h>17#include <linux/dmapool.h>
17#include <linux/interrupt.h>18#include <linux/interrupt.h>
@@ -1273,6 +1274,7 @@ static int xilinx_dpdma_config(struct dma_chan *dchan, · 1255 unmodified lines
1273 struct dma_slave_config *config)1274 struct dma_slave_config *config)
1274{1275{
1275 struct xilinx_dpdma_chan *chan = to_xilinx_chan(dchan);1276 struct xilinx_dpdma_chan *chan = to_xilinx_chan(dchan);
1277 struct xilinx_dpdma_peripheral_config *pconfig;
1276 unsigned long flags;1278 unsigned long flags;
1277 1279
1278 /*1280 /*
@@ -1282,15 +1284,18 @@ static int xilinx_dpdma_config(struct dma_chan *dchan, · 3 unmodified lines
1282 * fixed both on the DPDMA side and on the DP controller side.1284 * fixed both on the DPDMA side and on the DP controller side.
1283 */1285 */
1284 1286
1285 spin_lock_irqsave(&chan->lock, flags);
1286
1287 /*1287 /*
1288 * Abuse the slave_id to indicate that the channel is part of a video1288 * Use the peripheral_config to indicate that the channel is part
1289 * group.1289 * of a video group. This requires matching use of the custom
1290 * structure in each driver.
1290 */1291 */
1291 if (chan->id <= ZYNQMP_DPDMA_VIDEO2)1292 pconfig = config->peripheral_config;
1292 chan->video_group = config->slave_id != 0;1293 if (WARN_ON(pconfig && config->peripheral_size != sizeof(*pconfig)))
1294 return -EINVAL;
1293 1295
1296 spin_lock_irqsave(&chan->lock, flags);
1297 if (chan->id <= ZYNQMP_DPDMA_VIDEO2 && pconfig)
1298 chan->video_group = pconfig->video_group;
1294 spin_unlock_irqrestore(&chan->lock, flags);1299 spin_unlock_irqrestore(&chan->lock, flags);
1295 1300
1296 return 0;1301 return 0;
drivers/gpu/drm/xlnx/zynqmp_disp.c+7−2
@@ -24,6 +24,7 @@ · 23 unmodified lines
24 24
25#include <linux/clk.h>25#include <linux/clk.h>
26#include <linux/delay.h>26#include <linux/delay.h>
27#include <linux/dma/xilinx_dpdma.h>
27#include <linux/dma-mapping.h>28#include <linux/dma-mapping.h>
28#include <linux/dmaengine.h>29#include <linux/dmaengine.h>
29#include <linux/module.h>30#include <linux/module.h>
@@ -1058,14 +1059,18 @@ static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer, · 1028 unmodified lines
1058 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);1059 zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
1059 1060
1060 /*1061 /*
1061 * Set slave_id for each DMA channel to indicate they're part of a1062 * Set pconfig for each DMA channel to indicate they're part of a
1062 * video group.1063 * video group.
1063 */1064 */
1064 for (i = 0; i < info->num_planes; i++) {1065 for (i = 0; i < info->num_planes; i++) {
1065 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1066 struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
1067 struct xilinx_dpdma_peripheral_config pconfig = {
1068 .video_group = true,
1069 };
1066 struct dma_slave_config config = {1070 struct dma_slave_config config = {
1067 .direction = DMA_MEM_TO_DEV,1071 .direction = DMA_MEM_TO_DEV,
1068 .slave_id = 1,1072 .peripheral_config = &pconfig,
1073 .peripheral_size = sizeof(pconfig),
1069 };1074 };
1070 1075
1071 dmaengine_slave_config(dma->chan, &config);1076 dmaengine_slave_config(dma->chan, &config);
drivers/mmc/host/bcm2835.c+0−2
@@ -1293,14 +1293,12 @@ static int bcm2835_add_host(struct bcm2835_host *host) · 1292 unmodified lines
1293 1293
1294 host->dma_cfg_tx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1294 host->dma_cfg_tx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1295 host->dma_cfg_tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1295 host->dma_cfg_tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1296 host->dma_cfg_tx.slave_id = 13; /* DREQ channel */
1297 host->dma_cfg_tx.direction = DMA_MEM_TO_DEV;1296 host->dma_cfg_tx.direction = DMA_MEM_TO_DEV;
1298 host->dma_cfg_tx.src_addr = 0;1297 host->dma_cfg_tx.src_addr = 0;
1299 host->dma_cfg_tx.dst_addr = host->phys_addr + SDDATA;1298 host->dma_cfg_tx.dst_addr = host->phys_addr + SDDATA;
1300 1299
1301 host->dma_cfg_rx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1300 host->dma_cfg_rx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1302 host->dma_cfg_rx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1301 host->dma_cfg_rx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1303 host->dma_cfg_rx.slave_id = 13; /* DREQ channel */
1304 host->dma_cfg_rx.direction = DMA_DEV_TO_MEM;1302 host->dma_cfg_rx.direction = DMA_DEV_TO_MEM;
1305 host->dma_cfg_rx.src_addr = host->phys_addr + SDDATA;1303 host->dma_cfg_rx.src_addr = host->phys_addr + SDDATA;
1306 host->dma_cfg_rx.dst_addr = 0;1304 host->dma_cfg_rx.dst_addr = 0;
drivers/mtd/nand/raw/qcom_nandc.c+12−2
@@ -6,6 +6,7 @@ · 5 unmodified lines
6#include <linux/clk.h>6#include <linux/clk.h>
7#include <linux/slab.h>7#include <linux/slab.h>
8#include <linux/bitops.h>8#include <linux/bitops.h>
9#include <linux/dma/qcom_adm.h>
9#include <linux/dma-mapping.h>10#include <linux/dma-mapping.h>
10#include <linux/dmaengine.h>11#include <linux/dmaengine.h>
11#include <linux/module.h>12#include <linux/module.h>
@@ -952,6 +953,7 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, · 940 unmodified lines
952 struct dma_async_tx_descriptor *dma_desc;953 struct dma_async_tx_descriptor *dma_desc;
953 struct scatterlist *sgl;954 struct scatterlist *sgl;
954 struct dma_slave_config slave_conf;955 struct dma_slave_config slave_conf;
956 struct qcom_adm_peripheral_config periph_conf = {};
955 enum dma_transfer_direction dir_eng;957 enum dma_transfer_direction dir_eng;
956 int ret;958 int ret;
957 959
@@ -983,11 +985,19 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, · 25 unmodified lines
983 if (read) {985 if (read) {
984 slave_conf.src_maxburst = 16;986 slave_conf.src_maxburst = 16;
985 slave_conf.src_addr = nandc->base_dma + reg_off;987 slave_conf.src_addr = nandc->base_dma + reg_off;
986 slave_conf.slave_id = nandc->data_crci;988 if (nandc->data_crci) {
989 periph_conf.crci = nandc->data_crci;
990 slave_conf.peripheral_config = &periph_conf;
991 slave_conf.peripheral_size = sizeof(periph_conf);
992 }
987 } else {993 } else {
988 slave_conf.dst_maxburst = 16;994 slave_conf.dst_maxburst = 16;
989 slave_conf.dst_addr = nandc->base_dma + reg_off;995 slave_conf.dst_addr = nandc->base_dma + reg_off;
990 slave_conf.slave_id = nandc->cmd_crci;996 if (nandc->cmd_crci) {
997 periph_conf.crci = nandc->cmd_crci;
998 slave_conf.peripheral_config = &periph_conf;
999 slave_conf.peripheral_size = sizeof(periph_conf);
1000 }
991 }1001 }
992 1002
993 ret = dmaengine_slave_config(nandc->chan, &slave_conf);1003 ret = dmaengine_slave_config(nandc->chan, &slave_conf);
drivers/spi/spi-pic32.c+0−2
@@ -370,7 +370,6 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width) · 369 unmodified lines
370 cfg.src_addr_width = dma_width;370 cfg.src_addr_width = dma_width;
371 cfg.dst_addr_width = dma_width;371 cfg.dst_addr_width = dma_width;
372 /* tx channel */372 /* tx channel */
373 cfg.slave_id = pic32s->tx_irq;
374 cfg.direction = DMA_MEM_TO_DEV;373 cfg.direction = DMA_MEM_TO_DEV;
375 ret = dmaengine_slave_config(master->dma_tx, &cfg);374 ret = dmaengine_slave_config(master->dma_tx, &cfg);
376 if (ret) {375 if (ret) {
@@ -378,7 +377,6 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width) · 1 unmodified line
378 return ret;377 return ret;
379 }378 }
380 /* rx channel */379 /* rx channel */
381 cfg.slave_id = pic32s->rx_irq;
382 cfg.direction = DMA_DEV_TO_MEM;380 cfg.direction = DMA_DEV_TO_MEM;
383 ret = dmaengine_slave_config(master->dma_rx, &cfg);381 ret = dmaengine_slave_config(master->dma_rx, &cfg);
384 if (ret)382 if (ret)
drivers/tty/serial/msm_serial.c+13−2
@@ -9,6 +9,7 @@ · 8 unmodified lines
9 9
10#include <linux/kernel.h>10#include <linux/kernel.h>
11#include <linux/atomic.h>11#include <linux/atomic.h>
12#include <linux/dma/qcom_adm.h>
12#include <linux/dma-mapping.h>13#include <linux/dma-mapping.h>
13#include <linux/dmaengine.h>14#include <linux/dmaengine.h>
14#include <linux/module.h>15#include <linux/module.h>
@@ -290,6 +291,7 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) · 275 unmodified lines
290{291{
291 struct device *dev = msm_port->uart.dev;292 struct device *dev = msm_port->uart.dev;
292 struct dma_slave_config conf;293 struct dma_slave_config conf;
294 struct qcom_adm_peripheral_config periph_conf = {};
293 struct msm_dma *dma;295 struct msm_dma *dma;
294 u32 crci = 0;296 u32 crci = 0;
295 int ret;297 int ret;
@@ -308,7 +310,11 @@ static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) · 12 unmodified lines
308 conf.device_fc = true;310 conf.device_fc = true;
309 conf.dst_addr = base + UARTDM_TF;311 conf.dst_addr = base + UARTDM_TF;
310 conf.dst_maxburst = UARTDM_BURST_SIZE;312 conf.dst_maxburst = UARTDM_BURST_SIZE;
311 conf.slave_id = crci;313 if (crci) {
314 conf.peripheral_config = &periph_conf;
315 conf.peripheral_size = sizeof(periph_conf);
316 periph_conf.crci = crci;
317 }
312 318
313 ret = dmaengine_slave_config(dma->chan, &conf);319 ret = dmaengine_slave_config(dma->chan, &conf);
314 if (ret)320 if (ret)
@@ -333,6 +339,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) · 18 unmodified lines
333{339{
334 struct device *dev = msm_port->uart.dev;340 struct device *dev = msm_port->uart.dev;
335 struct dma_slave_config conf;341 struct dma_slave_config conf;
342 struct qcom_adm_peripheral_config periph_conf = {};
336 struct msm_dma *dma;343 struct msm_dma *dma;
337 u32 crci = 0;344 u32 crci = 0;
338 int ret;345 int ret;
@@ -355,7 +362,11 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) · 16 unmodified lines
355 conf.device_fc = true;362 conf.device_fc = true;
356 conf.src_addr = base + UARTDM_RF;363 conf.src_addr = base + UARTDM_RF;
357 conf.src_maxburst = UARTDM_BURST_SIZE;364 conf.src_maxburst = UARTDM_BURST_SIZE;
358 conf.slave_id = crci;365 if (crci) {
366 conf.peripheral_config = &periph_conf;
367 conf.peripheral_size = sizeof(periph_conf);
368 periph_conf.crci = crci;
369 }
359 370
360 ret = dmaengine_slave_config(dma->chan, &conf);371 ret = dmaengine_slave_config(dma->chan, &conf);
361 if (ret)372 if (ret)
include/linux/dma/qcom_adm.h+12−0
@@ -0,0 +1,12 @@
1// SPDX-License-Identifier: GPL-2.0-only
2#ifndef __LINUX_DMA_QCOM_ADM_H
3#define __LINUX_DMA_QCOM_ADM_H
4
5#include <linux/types.h>
6
7struct qcom_adm_peripheral_config {
8 u32 crci;
9 u32 mux;
10};
11
12#endif /* __LINUX_DMA_QCOM_ADM_H */
include/linux/dma/xilinx_dpdma.h+11−0
@@ -0,0 +1,11 @@
1// SPDX-License-Identifier: GPL-2.0
2#ifndef __LINUX_DMA_XILINX_DPDMA_H
3#define __LINUX_DMA_XILINX_DPDMA_H
4
5#include <linux/types.h>
6
7struct xilinx_dpdma_peripheral_config {
8 bool video_group;
9};
10
11#endif /* __LINUX_DMA_XILINX_DPDMA_H */
include/linux/dmaengine.h+0−4
@@ -418,9 +418,6 @@ enum dma_slave_buswidth { · 417 unmodified lines
418 * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill418 * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill
419 * with 'true' if peripheral should be flow controller. Direction will be419 * with 'true' if peripheral should be flow controller. Direction will be
420 * selected at Runtime.420 * selected at Runtime.
421 * @slave_id: Slave requester id. Only valid for slave channels. The dma
422 * slave peripheral will have unique id as dma requester which need to be
423 * pass as slave config.
424 * @peripheral_config: peripheral configuration for programming peripheral421 * @peripheral_config: peripheral configuration for programming peripheral
425 * for dmaengine transfer422 * for dmaengine transfer
426 * @peripheral_size: peripheral configuration buffer size423 * @peripheral_size: peripheral configuration buffer size
@@ -448,7 +445,6 @@ struct dma_slave_config { · 21 unmodified lines
448 u32 src_port_window_size;445 u32 src_port_window_size;
449 u32 dst_port_window_size;446 u32 dst_port_window_size;
450 bool device_fc;447 bool device_fc;
451 unsigned int slave_id;
452 void *peripheral_config;448 void *peripheral_config;
453 size_t peripheral_size;449 size_t peripheral_size;
454};450};
include/sound/dmaengine_pcm.h+0−2
@@ -60,7 +60,6 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) · 59 unmodified lines
60 * @maxburst: Maximum number of words(note: words, as in units of the60 * @maxburst: Maximum number of words(note: words, as in units of the
61 * src_addr_width member, not bytes) that can be send to or received from the61 * src_addr_width member, not bytes) that can be send to or received from the
62 * DAI in one burst.62 * DAI in one burst.
63 * @slave_id: Slave requester id for the DMA channel.
64 * @filter_data: Custom DMA channel filter data, this will usually be used when63 * @filter_data: Custom DMA channel filter data, this will usually be used when
65 * requesting the DMA channel.64 * requesting the DMA channel.
66 * @chan_name: Custom channel name to use when requesting DMA channel.65 * @chan_name: Custom channel name to use when requesting DMA channel.
@@ -74,7 +73,6 @@ struct snd_dmaengine_dai_dma_data { · 7 unmodified lines
74 dma_addr_t addr;73 dma_addr_t addr;
75 enum dma_slave_buswidth addr_width;74 enum dma_slave_buswidth addr_width;
76 u32 maxburst;75 u32 maxburst;
77 unsigned int slave_id;
78 void *filter_data;76 void *filter_data;
79 const char *chan_name;77 const char *chan_name;
80 unsigned int fifo_size;78 unsigned int fifo_size;
sound/core/pcm_dmaengine.c+2−3
@@ -91,8 +91,8 @@ EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); · 90 unmodified lines
91 * @dma_data: DAI DMA data91 * @dma_data: DAI DMA data
92 * @slave_config: DMA slave configuration92 * @slave_config: DMA slave configuration
93 *93 *
94 * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and94 * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width
95 * slave_id fields of the DMA slave config from the same fields of the DAI DMA95 * fields of the DMA slave config from the same fields of the DAI DMA
96 * data struct. The src and dst fields will be initialized depending on the96 * data struct. The src and dst fields will be initialized depending on the
97 * direction of the substream. If the substream is a playback stream the dst97 * direction of the substream. If the substream is a playback stream the dst
98 * fields will be initialized, if it is a capture stream the src fields will be98 * fields will be initialized, if it is a capture stream the src fields will be
@@ -124,7 +124,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( · 25 unmodified lines
124 slave_config->src_addr_width = dma_data->addr_width;124 slave_config->src_addr_width = dma_data->addr_width;
125 }125 }
126 126
127 slave_config->slave_id = dma_data->slave_id;
128 slave_config->peripheral_config = dma_data->peripheral_config;127 slave_config->peripheral_config = dma_data->peripheral_config;
129 slave_config->peripheral_size = dma_data->peripheral_size;128 slave_config->peripheral_size = dma_data->peripheral_size;
130}129}
sound/soc/tegra/tegra20_i2s.c+49−0
@@ -262,10 +262,59 @@ static int tegra20_i2s_probe(struct snd_soc_dai *dai) · 261 unmodified lines
262 return 0;262 return 0;
263}263}
264 264
265static const unsigned int tegra20_i2s_rates[] = {
266 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000
267};
268
269static int tegra20_i2s_filter_rates(struct snd_pcm_hw_params *params,
270 struct snd_pcm_hw_rule *rule)
271{
272 struct snd_interval *r = hw_param_interval(params, rule->var);
273 struct snd_soc_dai *dai = rule->private;
274 struct tegra20_i2s *i2s = dev_get_drvdata(dai->dev);
275 struct clk *parent = clk_get_parent(i2s->clk_i2s);
276 long i, parent_rate, valid_rates = 0;
277
278 parent_rate = clk_get_rate(parent);
279 if (parent_rate <= 0) {
280 dev_err(dai->dev, "Can't get parent clock rate: %ld\n",
281 parent_rate);
282 return parent_rate ?: -EINVAL;
283 }
284
285 for (i = 0; i < ARRAY_SIZE(tegra20_i2s_rates); i++) {
286 if (parent_rate % (tegra20_i2s_rates[i] * 128) == 0)
287 valid_rates |= BIT(i);
288 }
289
290 /*
291 * At least one rate must be valid, otherwise the parent clock isn't
292 * audio PLL. Nothing should be filtered in this case.
293 */
294 if (!valid_rates)
295 valid_rates = BIT(ARRAY_SIZE(tegra20_i2s_rates)) - 1;
296
297 return snd_interval_list(r, ARRAY_SIZE(tegra20_i2s_rates),
298 tegra20_i2s_rates, valid_rates);
299}
300
301static int tegra20_i2s_startup(struct snd_pcm_substream *substream,
302 struct snd_soc_dai *dai)
303{
304 if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate"))
305 return 0;
306
307 return snd_pcm_hw_rule_add(substream->runtime, 0,
308 SNDRV_PCM_HW_PARAM_RATE,
309 tegra20_i2s_filter_rates, dai,
310 SNDRV_PCM_HW_PARAM_RATE, -1);
311}
312
265static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {313static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
266 .set_fmt = tegra20_i2s_set_fmt,314 .set_fmt = tegra20_i2s_set_fmt,
267 .hw_params = tegra20_i2s_hw_params,315 .hw_params = tegra20_i2s_hw_params,
268 .trigger = tegra20_i2s_trigger,316 .trigger = tegra20_i2s_trigger,
317 .startup = tegra20_i2s_startup,
269};318};
270 319
271static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {320static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
sound/soc/tegra/tegra20_spdif.c+139−58
@@ -7,12 +7,15 @@ · 6 unmodified lines
7 */7 */
8 8
9#include <linux/clk.h>9#include <linux/clk.h>
10#include <linux/delay.h>
10#include <linux/device.h>11#include <linux/device.h>
11#include <linux/io.h>12#include <linux/io.h>
12#include <linux/module.h>13#include <linux/module.h>
14#include <linux/of_device.h>
13#include <linux/platform_device.h>15#include <linux/platform_device.h>
14#include <linux/pm_runtime.h>16#include <linux/pm_runtime.h>
15#include <linux/regmap.h>17#include <linux/regmap.h>
18#include <linux/reset.h>
16#include <linux/slab.h>19#include <linux/slab.h>
17#include <sound/core.h>20#include <sound/core.h>
18#include <sound/pcm.h>21#include <sound/pcm.h>
@@ -22,12 +25,12 @@ · 3 unmodified lines
22 25
23#include "tegra20_spdif.h"26#include "tegra20_spdif.h"
24 27
25#define DRV_NAME "tegra20-spdif"
26
27static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev)28static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev)
28{29{
29 struct tegra20_spdif *spdif = dev_get_drvdata(dev);30 struct tegra20_spdif *spdif = dev_get_drvdata(dev);
30 31
32 regcache_cache_only(spdif->regmap, true);
33
31 clk_disable_unprepare(spdif->clk_spdif_out);34 clk_disable_unprepare(spdif->clk_spdif_out);
32 35
33 return 0;36 return 0;
@@ -38,23 +41,45 @@ static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev) · 4 unmodified lines
38 struct tegra20_spdif *spdif = dev_get_drvdata(dev);41 struct tegra20_spdif *spdif = dev_get_drvdata(dev);
39 int ret;42 int ret;
40 43
44 ret = reset_control_assert(spdif->reset);
45 if (ret)
46 return ret;
47
41 ret = clk_prepare_enable(spdif->clk_spdif_out);48 ret = clk_prepare_enable(spdif->clk_spdif_out);
42 if (ret) {49 if (ret) {
43 dev_err(dev, "clk_enable failed: %d\n", ret);50 dev_err(dev, "clk_enable failed: %d\n", ret);
44 return ret;51 return ret;
45 }52 }
46 53
54 usleep_range(10, 100);
55
56 ret = reset_control_deassert(spdif->reset);
57 if (ret)
58 goto disable_clocks;
59
60 regcache_cache_only(spdif->regmap, false);
61 regcache_mark_dirty(spdif->regmap);
62
63 ret = regcache_sync(spdif->regmap);
64 if (ret)
65 goto disable_clocks;
66
47 return 0;67 return 0;
68
69disable_clocks:
70 clk_disable_unprepare(spdif->clk_spdif_out);
71
72 return ret;
48}73}
49 74
50static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,75static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
51 struct snd_pcm_hw_params *params,76 struct snd_pcm_hw_params *params,
52 struct snd_soc_dai *dai)77 struct snd_soc_dai *dai)
53{78{
54 struct device *dev = dai->dev;79 struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
55 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
56 unsigned int mask = 0, val = 0;80 unsigned int mask = 0, val = 0;
57 int ret, spdifclock;81 int ret, spdifclock;
82 long rate;
58 83
59 mask |= TEGRA20_SPDIF_CTRL_PACK |84 mask |= TEGRA20_SPDIF_CTRL_PACK |
60 TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;85 TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
@@ -69,6 +94,14 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, · 8 unmodified lines
69 94
70 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val);95 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val);
71 96
97 /*
98 * FIFO trigger level must be bigger than DMA burst or equal to it,
99 * otherwise data is discarded on overflow.
100 */
101 regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_DATA_FIFO_CSR,
102 TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK,
103 TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL);
104
72 switch (params_rate(params)) {105 switch (params_rate(params)) {
73 case 32000:106 case 32000:
74 spdifclock = 4096000;107 spdifclock = 4096000;
@@ -97,10 +130,16 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, · 22 unmodified lines
97 130
98 ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);131 ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
99 if (ret) {132 if (ret) {
100 dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);133 dev_err(dai->dev, "Can't set SPDIF clock rate: %d\n", ret);
101 return ret;134 return ret;
102 }135 }
103 136
137 rate = clk_get_rate(spdif->clk_spdif_out);
138 if (rate != spdifclock)
139 dev_warn_once(dai->dev,
140 "SPDIF clock rate %d doesn't match requested rate %lu\n",
141 spdifclock, rate);
142
104 return 0;143 return 0;
105}144}
106 145
@@ -118,9 +157,9 @@ static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) · 11 unmodified lines
118}157}
119 158
120static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,159static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
121 struct snd_soc_dai *dai)160 struct snd_soc_dai *dai)
122{161{
123 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);162 struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
124 163
125 switch (cmd) {164 switch (cmd) {
126 case SNDRV_PCM_TRIGGER_START:165 case SNDRV_PCM_TRIGGER_START:
@@ -140,9 +179,62 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, · 13 unmodified lines
140 return 0;179 return 0;
141}180}
142 181
182static int tegra20_spdif_filter_rates(struct snd_pcm_hw_params *params,
183 struct snd_pcm_hw_rule *rule)
184{
185 struct snd_interval *r = hw_param_interval(params, rule->var);
186 struct snd_soc_dai *dai = rule->private;
187 struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
188 struct clk *parent = clk_get_parent(spdif->clk_spdif_out);
189 const unsigned int rates[] = { 32000, 44100, 48000 };
190 long i, parent_rate, valid_rates = 0;
191
192 parent_rate = clk_get_rate(parent);
193 if (parent_rate <= 0) {
194 dev_err(dai->dev, "Can't get parent clock rate: %ld\n",
195 parent_rate);
196 return parent_rate ?: -EINVAL;
197 }
198
199 for (i = 0; i < ARRAY_SIZE(rates); i++) {
200 if (parent_rate % (rates[i] * 128) == 0)
201 valid_rates |= BIT(i);
202 }
203
204 /*
205 * At least one rate must be valid, otherwise the parent clock isn't
206 * audio PLL. Nothing should be filtered in this case.
207 */
208 if (!valid_rates)
209 valid_rates = BIT(ARRAY_SIZE(rates)) - 1;
210
211 return snd_interval_list(r, ARRAY_SIZE(rates), rates, valid_rates);
212}
213
214static int tegra20_spdif_startup(struct snd_pcm_substream *substream,
215 struct snd_soc_dai *dai)
216{
217 if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate"))
218 return 0;
219
220 /*
221 * SPDIF and I2S share audio PLL. HDMI takes audio packets from SPDIF
222 * and audio may not work on some TVs if clock rate isn't precise.
223 *
224 * PLL rate is controlled by I2S side. Filter out audio rates that
225 * don't match PLL rate at the start of stream to allow both SPDIF
226 * and I2S work simultaneously, assuming that PLL rate won't be
227 * changed later on.
228 */
229 return snd_pcm_hw_rule_add(substream->runtime, 0,
230 SNDRV_PCM_HW_PARAM_RATE,
231 tegra20_spdif_filter_rates, dai,
232 SNDRV_PCM_HW_PARAM_RATE, -1);
233}
234
143static int tegra20_spdif_probe(struct snd_soc_dai *dai)235static int tegra20_spdif_probe(struct snd_soc_dai *dai)
144{236{
145 struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);237 struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
146 238
147 dai->capture_dma_data = NULL;239 dai->capture_dma_data = NULL;
148 dai->playback_dma_data = &spdif->playback_dma_data;240 dai->playback_dma_data = &spdif->playback_dma_data;
@@ -151,26 +243,27 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai) · 2 unmodified lines
151}243}
152 244
153static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {245static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
154 .hw_params = tegra20_spdif_hw_params,246 .hw_params = tegra20_spdif_hw_params,
155 .trigger = tegra20_spdif_trigger,247 .trigger = tegra20_spdif_trigger,
248 .startup = tegra20_spdif_startup,
156};249};
157 250
158static struct snd_soc_dai_driver tegra20_spdif_dai = {251static struct snd_soc_dai_driver tegra20_spdif_dai = {
159 .name = DRV_NAME,252 .name = "tegra20-spdif",
160 .probe = tegra20_spdif_probe,253 .probe = tegra20_spdif_probe,
161 .playback = {254 .playback = {
162 .stream_name = "Playback",255 .stream_name = "Playback",
163 .channels_min = 2,256 .channels_min = 2,
164 .channels_max = 2,257 .channels_max = 2,
165 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |258 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
166 SNDRV_PCM_RATE_48000,259 SNDRV_PCM_RATE_48000,
167 .formats = SNDRV_PCM_FMTBIT_S16_LE,260 .formats = SNDRV_PCM_FMTBIT_S16_LE,
168 },261 },
169 .ops = &tegra20_spdif_dai_ops,262 .ops = &tegra20_spdif_dai_ops,
170};263};
171 264
172static const struct snd_soc_component_driver tegra20_spdif_component = {265static const struct snd_soc_component_driver tegra20_spdif_component = {
173 .name = DRV_NAME,266 .name = "tegra20-spdif",
174};267};
175 268
176static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)269static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -251,7 +344,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = { · 74 unmodified lines
251static int tegra20_spdif_platform_probe(struct platform_device *pdev)344static int tegra20_spdif_platform_probe(struct platform_device *pdev)
252{345{
253 struct tegra20_spdif *spdif;346 struct tegra20_spdif *spdif;
254 struct resource *mem, *dmareq;347 struct resource *mem;
255 void __iomem *regs;348 void __iomem *regs;
256 int ret;349 int ret;
257 350
@@ -262,89 +355,77 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) · 4 unmodified lines
262 355
263 dev_set_drvdata(&pdev->dev, spdif);356 dev_set_drvdata(&pdev->dev, spdif);
264 357
265 spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out");358 spdif->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
359 if (IS_ERR(spdif->reset)) {
360 dev_err(&pdev->dev, "Can't retrieve spdif reset\n");
361 return PTR_ERR(spdif->reset);
362 }
363
364 spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "out");
266 if (IS_ERR(spdif->clk_spdif_out)) {365 if (IS_ERR(spdif->clk_spdif_out)) {
267 pr_err("Can't retrieve spdif clock\n");366 dev_err(&pdev->dev, "Could not retrieve spdif clock\n");
268 ret = PTR_ERR(spdif->clk_spdif_out);367 return PTR_ERR(spdif->clk_spdif_out);
269 return ret;
270 }368 }
271 369
272 regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);370 regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
273 if (IS_ERR(regs))371 if (IS_ERR(regs))
274 return PTR_ERR(regs);372 return PTR_ERR(regs);
275 373
276 dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
277 if (!dmareq) {
278 dev_err(&pdev->dev, "No DMA resource\n");
279 return -ENODEV;
280 }
281
282 spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,374 spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
283 &tegra20_spdif_regmap_config);375 &tegra20_spdif_regmap_config);
284 if (IS_ERR(spdif->regmap)) {376 if (IS_ERR(spdif->regmap)) {
285 dev_err(&pdev->dev, "regmap init failed\n");377 dev_err(&pdev->dev, "regmap init failed\n");
286 ret = PTR_ERR(spdif->regmap);378 return PTR_ERR(spdif->regmap);
287 return ret;
288 }379 }
289 380
290 spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;381 spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
291 spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;382 spdif->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
292 spdif->playback_dma_data.maxburst = 4;383 spdif->playback_dma_data.maxburst = 4;
293 spdif->playback_dma_data.slave_id = dmareq->start;
294 384
295 pm_runtime_enable(&pdev->dev);385 ret = devm_pm_runtime_enable(&pdev->dev);
386 if (ret)
387 return ret;
296 388
297 ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,389 ret = devm_snd_soc_register_component(&pdev->dev,
298 &tegra20_spdif_dai, 1);390 &tegra20_spdif_component,
391 &tegra20_spdif_dai, 1);
299 if (ret) {392 if (ret) {
300 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);393 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
301 ret = -ENOMEM;394 return ret;
302 goto err_pm_disable;
303 }395 }
304 396
305 ret = tegra_pcm_platform_register(&pdev->dev);397 ret = devm_tegra_pcm_platform_register(&pdev->dev);
306 if (ret) {398 if (ret) {
307 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);399 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
308 goto err_unregister_component;400 return ret;
309 }401 }
310 402
311 return 0;
312
313err_unregister_component:
314 snd_soc_unregister_component(&pdev->dev);
315err_pm_disable:
316 pm_runtime_disable(&pdev->dev);
317
318 return ret;
319}
320
321static int tegra20_spdif_platform_remove(struct platform_device *pdev)
322{
323 tegra_pcm_platform_unregister(&pdev->dev);
324 snd_soc_unregister_component(&pdev->dev);
325
326 pm_runtime_disable(&pdev->dev);
327
328 return 0;403 return 0;
329}404}
330 405
331static const struct dev_pm_ops tegra20_spdif_pm_ops = {406static const struct dev_pm_ops tegra20_spdif_pm_ops = {
332 SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,407 SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
333 tegra20_spdif_runtime_resume, NULL)408 tegra20_spdif_runtime_resume, NULL)
409 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
410 pm_runtime_force_resume)
334};411};
335 412
413static const struct of_device_id tegra20_spdif_of_match[] = {
414 { .compatible = "nvidia,tegra20-spdif", },
415 {},
416};
417MODULE_DEVICE_TABLE(of, tegra20_spdif_of_match);
418
336static struct platform_driver tegra20_spdif_driver = {419static struct platform_driver tegra20_spdif_driver = {
337 .driver = {420 .driver = {
338 .name = DRV_NAME,421 .name = "tegra20-spdif",
339 .pm = &tegra20_spdif_pm_ops,422 .pm = &tegra20_spdif_pm_ops,
423 .of_match_table = tegra20_spdif_of_match,
340 },424 },
341 .probe = tegra20_spdif_platform_probe,425 .probe = tegra20_spdif_platform_probe,
342 .remove = tegra20_spdif_platform_remove,
343};426};
344
345module_platform_driver(tegra20_spdif_driver);427module_platform_driver(tegra20_spdif_driver);
346 428
347MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");429MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
348MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");430MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");
349MODULE_LICENSE("GPL");431MODULE_LICENSE("GPL");
350MODULE_ALIAS("platform:" DRV_NAME);
sound/soc/tegra/tegra20_spdif.h+1−0
@@ -451,6 +451,7 @@ struct tegra20_spdif { · 450 unmodified lines
451 struct snd_dmaengine_dai_dma_data capture_dma_data;451 struct snd_dmaengine_dai_dma_data capture_dma_data;
452 struct snd_dmaengine_dai_dma_data playback_dma_data;452 struct snd_dmaengine_dai_dma_data playback_dma_data;
453 struct regmap *regmap;453 struct regmap *regmap;
454 struct reset_control *reset;
454};455};
455 456
456#endif457#endif
sound/soc/tegra/tegra_pcm.c+6−0
@@ -48,6 +48,12 @@ int tegra_pcm_platform_register(struct device *dev) · 47 unmodified lines
48}48}
49EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);49EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
50 50
51int devm_tegra_pcm_platform_register(struct device *dev)
52{
53 return devm_snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, 0);
54}
55EXPORT_SYMBOL_GPL(devm_tegra_pcm_platform_register);
56
51int tegra_pcm_platform_register_with_chan_names(struct device *dev,57int tegra_pcm_platform_register_with_chan_names(struct device *dev,
52 struct snd_dmaengine_pcm_config *config,58 struct snd_dmaengine_pcm_config *config,
53 char *txdmachan, char *rxdmachan)59 char *txdmachan, char *rxdmachan)
sound/soc/tegra/tegra_pcm.h+1−0
@@ -32,6 +32,7 @@ int tegra_pcm_hw_params(struct snd_soc_component *component, · 31 unmodified lines
32snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,32snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
33 struct snd_pcm_substream *substream);33 struct snd_pcm_substream *substream);
34int tegra_pcm_platform_register(struct device *dev);34int tegra_pcm_platform_register(struct device *dev);
35int devm_tegra_pcm_platform_register(struct device *dev);
35int tegra_pcm_platform_register_with_chan_names(struct device *dev,36int tegra_pcm_platform_register_with_chan_names(struct device *dev,
36 struct snd_dmaengine_pcm_config *config,37 struct snd_dmaengine_pcm_config *config,
37 char *txdmachan, char *rxdmachan);38 char *txdmachan, char *rxdmachan);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t