diff options
272 files changed, 12088 insertions, 6831 deletions
diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml new file mode 100644 index 000000000000..3248595dc93c --- /dev/null +++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dsp/fsl,dsp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8 DSP core + +maintainers: + - Daniel Baluta <daniel.baluta@nxp.com> + +description: | + Some boards from i.MX8 family contain a DSP core used for + advanced pre- and post- audio processing. + +properties: + compatible: + enum: + - fsl,imx8qxp-dsp + + reg: + description: Should contain register location and length + + clocks: + items: + - description: ipg clock + - description: ocram clock + - description: core clock + + clock-names: + items: + - const: ipg + - const: ocram + - const: core + + power-domains: + description: + List of phandle and PM domain specifier as documented in + Documentation/devicetree/bindings/power/power_domain.txt + maxItems: 4 + + mboxes: + description: + List of <&phandle type channel> - 2 channels for TXDB, 2 channels for RXDB + (see mailbox/fsl,mu.txt) + maxItems: 4 + + mbox-names: + items: + - const: txdb0 + - const: txdb1 + - const: rxdb0 + - const: rxdb1 + + memory-region: + description: + phandle to a node describing reserved memory (System RAM memory) + used by DSP (see bindings/reserved-memory/reserved-memory.txt) + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - mboxes + - mbox-names + - memory-region + +examples: + - | + #include <dt-bindings/firmware/imx/rsrc.h> + #include <dt-bindings/clock/imx8-clock.h> + dsp@596e8000 { + compatible = "fsl,imx8qxp-dsp"; + reg = <0x596e8000 0x88000>; + clocks = <&adma_lpcg IMX_ADMA_LPCG_DSP_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_OCRAM_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_DSP_CORE_CLK>; + clock-names = "ipg", "ocram", "core"; + power-domains = <&pd IMX_SC_R_MU_13A>, + <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_DSP>, + <&pd IMX_SC_R_DSP_RAM>; + mbox-names = "txdb0", "txdb1", "rxdb0", "rxdb1"; + mboxes = <&lsio_mu13 2 0>, <&lsio_mu13 2 1>, <&lsio_mu13 3 0>, <&lsio_mu13 3 1>; + }; diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml index e0284d8c3b63..38d4cede0860 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-spdif.yaml @@ -70,7 +70,9 @@ allOf: properties: compatible: contains: - const: allwinner,sun8i-h3-spdif + enum: + - allwinner,sun8i-h3-spdif + - allwinner,sun50i-h6-spdif then: properties: diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml new file mode 100644 index 000000000000..f290eb72a878 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/allwinner,sun50i-a64-codec-analog.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A64 Analog Codec Device Tree Bindings + +maintainers: + - Chen-Yu Tsai <wens@csie.org> + - Maxime Ripard <maxime.ripard@bootlin.com> + +properties: + compatible: + const: allwinner,sun50i-a64-codec-analog + + reg: + maxItems: 1 + + cpvdd-supply: + description: + Regulator for the headphone amplifier + +required: + - compatible + - reg + - cpvdd-supply + +additionalProperties: false + +examples: + - | + codec_analog: codec-analog@1f015c0 { + compatible = "allwinner,sun50i-a64-codec-analog"; + reg = <0x01f015c0 0x4>; + cpvdd-supply = <®_eldo1>; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml new file mode 100644 index 000000000000..5e7cc05bbff1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/allwinner,sun8i-a33-codec.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/allwinner,sun8i-a33-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A33 Codec Device Tree Bindings + +maintainers: + - Chen-Yu Tsai <wens@csie.org> + - Maxime Ripard <maxime.ripard@bootlin.com> + +properties: + "#sound-dai-cells": + const: 0 + + compatible: + const: allwinner,sun8i-a33-codec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: bus + - const: mod + +required: + - "#sound-dai-cells" + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + audio-codec@1c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = <0 29 4>; + clocks = <&ccu 47>, <&ccu 92>; + clock-names = "bus", "mod"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt index 4330fc9dca6d..3080979350a0 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt @@ -4,13 +4,18 @@ Required properties: - compatible: 'amlogic,axg-toddr' or 'amlogic,axg-toddr' or 'amlogic,g12a-frddr' or - 'amlogic,g12a-toddr' + 'amlogic,g12a-toddr' or + 'amlogic,sm1-frddr' or + 'amlogic,sm1-toddr' - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier for the fifo. - clocks: phandle to the fifo peripheral clock provided by the audio clock controller. -- resets: phandle to memory ARB line provided by the arb reset controller. +- resets: list of reset phandle, one for each entry reset-names. +- reset-names: should contain the following: + * "arb" : memory ARB line (required) + * "rst" : dedicated device reset line (optional) - #sound-dai-cells: must be 0. Example of FRDDR A on the A113 SoC: diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt index 73f473a9365f..716878107a24 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt @@ -2,7 +2,8 @@ Required properties: - compatible: 'amlogic,axg-pdm' or - 'amlogic,g12a-pdm' + 'amlogic,g12a-pdm' or + 'amlogic,sm1-pdm' - reg: physical base address of the controller and length of memory mapped region. - clocks: list of clock phandle, one for each entry clock-names. @@ -12,6 +13,9 @@ Required properties: * "sysclk" : dsp system clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the pdm input. + Example of PDM on the A113 SoC: pdm: audio-controller@ff632000 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt index 0b82504fa419..df92a4ecf288 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt @@ -2,7 +2,8 @@ Required properties: - compatible: 'amlogic,axg-spdifin' or - 'amlogic,g12a-spdifin' + 'amlogic,g12a-spdifin' or + 'amlogic,sm1-spdifin' - interrupts: interrupt specifier for the spdif input. - clocks: list of clock phandle, one for each entry clock-names. - clock-names: should contain the following: @@ -10,6 +11,9 @@ Required properties: * "refclk" : spdif input reference clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the spdif input. + Example on the A113 SoC: spdifin: audio-controller@400 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt index 826152730508..28381dd1f633 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt @@ -2,13 +2,17 @@ Required properties: - compatible: 'amlogic,axg-spdifout' or - 'amlogic,g12a-spdifout' + 'amlogic,g12a-spdifout' or + 'amlogic,sm1-spdifout' - clocks: list of clock phandle, one for each entry clock-names. - clock-names: should contain the following: * "pclk" : peripheral clock. * "mclk" : master clock - #sound-dai-cells: must be 0. +Optional property: +- resets: phandle to the dedicated reset line of the spdif output. + Example on the A113 SoC: spdifout: audio-controller@480 { diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt index 8835a43edfbb..5996c0cd89c2 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt @@ -4,7 +4,9 @@ Required properties: - compatible: 'amlogic,axg-tdmin' or 'amlogic,axg-tdmout' or 'amlogic,g12a-tdmin' or - 'amlogic,g12a-tdmout' + 'amlogic,g12a-tdmout' or + 'amlogic,sm1-tdmin' or + 'amlogic,sm1-tdmout - reg: physical base address of the controller and length of memory mapped region. - clocks: list of clock phandle, one for each entry clock-names. diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt index aa6c35570d31..4e8cd7eb7cec 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt +++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-tohdmitx.txt @@ -1,10 +1,12 @@ * Amlogic HDMI Tx control glue Required properties: -- compatible: "amlogic,g12a-tohdmitx" +- compatible: "amlogic,g12a-tohdmitx" or + "amlogic,sm1-tohdmitx" - reg: physical base address of the controller and length of memory mapped region. - #sound-dai-cells: should be 1. +- resets: phandle to the dedicated reset line of the hdmitx glue. Example on the S905X2 SoC: @@ -12,6 +14,7 @@ tohdmitx: audio-controller@744 { compatible = "amlogic,g12a-tohdmitx"; reg = <0x0 0x744 0x0 0x4>; #sound-dai-cells = <1>; + resets = <&clkc_audio AUD_RESET_TOHDMITX>; }; Example of an 'amlogic,axg-sound-card': diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.txt b/Documentation/devicetree/bindings/sound/everest,es8316.txt new file mode 100644 index 000000000000..1bf03c5f2af4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es8316.txt @@ -0,0 +1,23 @@ +Everest ES8316 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + + - compatible : should be "everest,es8316" + - reg : the I2C address of the device for I2C + +Optional properties: + + - clocks : a list of phandle, should contain entries for clock-names + - clock-names : should include as follows: + "mclk" : master clock (MCLK) of the device + +Example: + +es8316: codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + clocks = <&clks 10>; + clock-names = "mclk"; +}; diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index 5b9914367610..0e6e2166f76c 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -7,8 +7,11 @@ other DSPs. It has up to six transmitters and four receivers. Required properties: - - compatible : Compatible list, must contain "fsl,imx35-esai" or - "fsl,vf610-esai" + - compatible : Compatible list, should contain one of the following + compatibles: + "fsl,imx35-esai", + "fsl,vf610-esai", + "fsl,imx6ull-esai", - reg : Offset and length of the register set for the device. diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 2e726b983845..0dc83cc4a236 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -8,7 +8,9 @@ codec/DSP interfaces. Required properties: - compatible : Compatible list, contains "fsl,vf610-sai", - "fsl,imx6sx-sai" or "fsl,imx6ul-sai" + "fsl,imx6sx-sai", "fsl,imx6ul-sai", + "fsl,imx7ulp-sai", "fsl,imx8mq-sai" or + "fsl,imx8qm-sai". - reg : Offset and length of the register set for the device. diff --git a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt b/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt deleted file mode 100644 index 056a098495cc..000000000000 --- a/Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt +++ /dev/null @@ -1,14 +0,0 @@ -* Allwinner A64 Codec Analog Controls - -Required properties: -- compatible: must be one of the following compatibles: - - "allwinner,sun50i-a64-codec-analog" -- reg: must contain the registers location and length -- cpvdd-supply: Regulator supply for the headphone amplifier - -Example: - codec_analog: codec-analog@1f015c0 { - compatible = "allwinner,sun50i-a64-codec-analog"; - reg = <0x01f015c0 0x4>; - cpvdd-supply = <®_eldo1>; - }; diff --git a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt deleted file mode 100644 index 2ca3d138528e..000000000000 --- a/Documentation/devicetree/bindings/sound/sun8i-a33-codec.txt +++ /dev/null @@ -1,63 +0,0 @@ -Allwinner SUN8I audio codec ------------------------------------- - -On Sun8i-A33 SoCs, the audio is separated in different parts: - - A DAI driver. It uses the "sun4i-i2s" driver which is - documented here: - Documentation/devicetree/bindings/sound/sun4i-i2s.txt - - An analog part of the codec which is handled as PRCM registers. - See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt - - An digital part of the codec which is documented in this current - binding documentation. - - And finally, an audio card which links all the above components. - The simple-audio card will be used. - See Documentation/devicetree/bindings/sound/simple-card.txt - -This bindings documentation exposes Sun8i codec (digital part). - -Required properties: -- compatible: must be "allwinner,sun8i-a33-codec" -- reg: must contain the registers location and length -- interrupts: must contain the codec interrupt -- clocks: a list of phandle + clock-specifer pairs, one for each entry - in clock-names. -- clock-names: should contain followings: - - "bus": the parent APB clock for this controller - - "mod": the parent module clock - -Here is an example to add a sound card and the codec binding on sun8i SoCs that -are similar to A33 using simple-card: - - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "sun8i-a33-audio"; - simple-audio-card,format = "i2s"; - simple-audio-card,frame-master = <&link_codec>; - simple-audio-card,bitclock-master = <&link_codec>; - simple-audio-card,mclk-fs = <512>; - simple-audio-card,aux-devs = <&codec_analog>; - simple-audio-card,routing = - "Left DAC", "Digital Left DAC", - "Right DAC", "Digital Right DAC"; - - simple-audio-card,cpu { - sound-dai = <&dai>; - }; - - link_codec: simple-audio-card,codec { - sound-dai = <&codec>; - }; - - soc@1c00000 { - [...] - - audio-codec@1c22e00 { - #sound-dai-cells = <0>; - compatible = "allwinner,sun8i-a33-codec"; - reg = <0x01c22e00 0x400>; - interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; - clock-names = "bus", "mod"; - }; - }; - diff --git a/Documentation/devicetree/bindings/sound/uda1334.txt b/Documentation/devicetree/bindings/sound/uda1334.txt new file mode 100644 index 000000000000..f64071b25e8d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/uda1334.txt @@ -0,0 +1,17 @@ +UDA1334 audio CODEC + +This device uses simple GPIO pins for controlling codec settings. + +Required properties: + + - compatible : "nxp,uda1334" + - nxp,mute-gpios: a GPIO spec for the MUTE pin. + - nxp,deemph-gpios: a GPIO spec for the De-emphasis pin + +Example: + +uda1334: audio-codec { + compatible = "nxp,uda1334"; + nxp,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + nxp,deemph-gpios = <&gpio3 3 GPIO_ACTIVE_LOW>; +}; diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 612a17e375d0..4af4af55e854 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -253,24 +253,6 @@ struct hdac_ext_bus_ops { int (*hdev_detach)(struct hdac_device *hdev); }; -/* - * Lowlevel I/O operators - */ -struct hdac_io_ops { - /* mapped register accesses */ - void (*reg_writel)(u32 value, u32 __iomem *addr); - u32 (*reg_readl)(u32 __iomem *addr); - void (*reg_writew)(u16 value, u16 __iomem *addr); - u16 (*reg_readw)(u16 __iomem *addr); - void (*reg_writeb)(u8 value, u8 __iomem *addr); - u8 (*reg_readb)(u8 __iomem *addr); - /* Allocation ops */ - int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size, - struct snd_dma_buffer *buf); - void (*dma_free_pages)(struct hdac_bus *bus, - struct snd_dma_buffer *buf); -}; - #define HDA_UNSOL_QUEUE_SIZE 64 #define HDA_MAX_CODECS 8 /* limit by controller side */ @@ -304,7 +286,6 @@ struct hdac_rb { struct hdac_bus { struct device *dev; const struct hdac_bus_ops *ops; - const struct hdac_io_ops *io_ops; const struct hdac_ext_bus_ops *ext_ops; /* h/w resources */ @@ -344,6 +325,7 @@ struct hdac_bus { /* CORB/RIRB and position buffers */ struct snd_dma_buffer rb; struct snd_dma_buffer posbuf; + int dma_type; /* SNDRV_DMA_TYPE_XXX for CORB/RIRB */ /* hdac_stream linked list */ struct list_head stream_list; @@ -384,8 +366,7 @@ struct hdac_bus { }; int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops); + const struct hdac_bus_ops *ops); void snd_hdac_bus_exit(struct hdac_bus *bus); int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr, unsigned int cmd, unsigned int *res); @@ -429,21 +410,38 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus); void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus); +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask); +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, + unsigned int mask); +#define snd_hdac_reg_writeb(v, addr) snd_hdac_aligned_write(v, addr, 0xff) +#define snd_hdac_reg_writew(v, addr) snd_hdac_aligned_write(v, addr, 0xffff) +#define snd_hdac_reg_readb(addr) snd_hdac_aligned_read(addr, 0xff) +#define snd_hdac_reg_readw(addr) snd_hdac_aligned_read(addr, 0xffff) +#else /* CONFIG_SND_HDA_ALIGNED_MMIO */ +#define snd_hdac_reg_writeb(val, addr) writeb(val, addr) +#define snd_hdac_reg_writew(val, addr) writew(val, addr) +#define snd_hdac_reg_readb(addr) readb(addr) +#define snd_hdac_reg_readw(addr) readw(addr) +#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ +#define snd_hdac_reg_writel(val, addr) writel(val, addr) +#define snd_hdac_reg_readl(addr) readl(addr) + /* * macros for easy use */ #define _snd_hdac_chip_writeb(chip, reg, value) \ - ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writeb(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readb(chip, reg) \ - ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg))) + snd_hdac_reg_readb((chip)->remap_addr + (reg)) #define _snd_hdac_chip_writew(chip, reg, value) \ - ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writew(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readw(chip, reg) \ - ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg))) + snd_hdac_reg_readw((chip)->remap_addr + (reg)) #define _snd_hdac_chip_writel(chip, reg, value) \ - ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg))) + snd_hdac_reg_writel(value, (chip)->remap_addr + (reg)) #define _snd_hdac_chip_readl(chip, reg) \ - ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg))) + snd_hdac_reg_readl((chip)->remap_addr + (reg)) /* read/write a register, pass without AZX_REG_ prefix */ #define snd_hdac_chip_writel(chip, reg, value) \ @@ -548,24 +546,19 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, /* * macros for easy use */ -#define _snd_hdac_stream_write(type, dev, reg, value) \ - ((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg))) -#define _snd_hdac_stream_read(type, dev, reg) \ - ((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg))) - /* read/write a register, pass without AZX_REG_ prefix */ #define snd_hdac_stream_writel(dev, reg, value) \ - _snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writel(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_writew(dev, reg, value) \ - _snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writew(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_writeb(dev, reg, value) \ - _snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value) + snd_hdac_reg_writeb(value, (dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readl(dev, reg) \ - _snd_hdac_stream_read(l, dev, AZX_REG_ ## reg) + snd_hdac_reg_readl((dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readw(dev, reg) \ - _snd_hdac_stream_read(w, dev, AZX_REG_ ## reg) + snd_hdac_reg_readw((dev)->sd_addr + AZX_REG_ ## reg) #define snd_hdac_stream_readb(dev, reg) \ - _snd_hdac_stream_read(b, dev, AZX_REG_ ## reg) + snd_hdac_reg_readb((dev)->sd_addr + AZX_REG_ ## reg) /* update a register, pass without AZX_REG_ prefix */ #define snd_hdac_stream_updatel(dev, reg, mask, val) \ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index f34aced69ca8..ef88b20c7b0a 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -6,7 +6,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops, const struct hdac_ext_bus_ops *ext_ops); void snd_hdac_ext_bus_exit(struct hdac_bus *bus); diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index 7fea496f1f34..83b17682e01c 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -47,6 +47,9 @@ struct hdmi_codec_params { int channels; }; +typedef void (*hdmi_codec_plugged_cb)(struct device *dev, + bool plugged); + struct hdmi_codec_pdata; struct hdmi_codec_ops { /* @@ -88,6 +91,14 @@ struct hdmi_codec_ops { */ int (*get_dai_id)(struct snd_soc_component *comment, struct device_node *endpoint); + + /* + * Hook callback function to handle connector plug event. + * Optional + */ + int (*hook_plugged_cb)(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev); }; /* HDMI codec initalization data */ @@ -99,6 +110,12 @@ struct hdmi_codec_pdata { void *data; }; +struct snd_soc_component; +struct snd_soc_jack; + +int hdmi_codec_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); + #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" #endif /* __HDMI_CODEC_H__ */ diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/include/sound/intel-nhlt.h index f85fbf9c7ce4..f657fd8fc0ad 100644 --- a/sound/soc/intel/skylake/skl-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -1,18 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * skl-nhlt.h - Intel HDA Platform NHLT header + * intel-nhlt.h - Intel HDA Platform NHLT header * - * Copyright (C) 2015 Intel Corp - * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Copyright (c) 2015-2019 Intel Corporation */ -#ifndef __SKL_NHLT_H__ -#define __SKL_NHLT_H__ + +#ifndef __INTEL_NHLT_H__ +#define __INTEL_NHLT_H__ #include <linux/acpi.h> +#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) + struct wav_fmt { u16 fmt_tag; u16 channels; @@ -97,16 +96,22 @@ struct nhlt_resource_desc { #define MIC_ARRAY_2CH 2 #define MIC_ARRAY_4CH 4 -struct nhlt_tdm_config { +struct nhlt_device_specific_config { u8 virtual_slot; u8 config_type; } __packed; struct nhlt_dmic_array_config { - struct nhlt_tdm_config tdm_config; + struct nhlt_device_specific_config device_config; u8 array_type; } __packed; +struct nhlt_vendor_dmic_array_config { + struct nhlt_dmic_array_config dmic_config; + u8 nb_mics; + /* TODO add vendor mic config */ +} __packed; + enum { NHLT_MIC_ARRAY_2CH_SMALL = 0xa, NHLT_MIC_ARRAY_2CH_BIG = 0xb, @@ -116,4 +121,30 @@ enum { NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf, }; +struct nhlt_acpi_table *intel_nhlt_init(struct device *dev); + +void intel_nhlt_free(struct nhlt_acpi_table *addr); + +int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt); + +#else + +struct nhlt_acpi_table; + +static inline struct nhlt_acpi_table *intel_nhlt_init(struct device *dev) +{ + return NULL; +} + +static inline void intel_nhlt_free(struct nhlt_acpi_table *addr) +{ +} + +static inline int intel_nhlt_get_dmic_geo(struct device *dev, + struct nhlt_acpi_table *nhlt) +{ + return 0; +} +#endif + #endif diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1e9bb1c91770..bbe6eb1ff5d2 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -117,6 +117,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ #define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ #define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ +#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */ +#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */ #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ @@ -129,6 +131,9 @@ struct snd_pcm_ops { SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) #define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\ SNDRV_PCM_RATE_192000) +#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\ + SNDRV_PCM_RATE_352800|\ + SNDRV_PCM_RATE_384000) #define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt) #define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8) #define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8) diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb5e1e4ce8bf..6c9929abd90b 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,6 +25,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h new file mode 100644 index 000000000000..5d80b2eef525 --- /dev/null +++ b/include/sound/soc-component.h @@ -0,0 +1,387 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * soc-component.h + * + * Copyright (c) 2019 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __SOC_COMPONENT_H +#define __SOC_COMPONENT_H + +#include <sound/soc.h> + +/* + * Component probe and remove ordering levels for components with runtime + * dependencies. + */ +#define SND_SOC_COMP_ORDER_FIRST -2 +#define SND_SOC_COMP_ORDER_EARLY -1 +#define SND_SOC_COMP_ORDER_NORMAL 0 +#define SND_SOC_COMP_ORDER_LATE 1 +#define SND_SOC_COMP_ORDER_LAST 2 + +#define for_each_comp_order(order) \ + for (order = SND_SOC_COMP_ORDER_FIRST; \ + order <= SND_SOC_COMP_ORDER_LAST; \ + order++) + +/* component interface */ +struct snd_soc_component_driver { + const char *name; + + /* Default control and setup, added after probe() is run */ + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + + int (*probe)(struct snd_soc_component *component); + void (*remove)(struct snd_soc_component *component); + int (*suspend)(struct snd_soc_component *component); + int (*resume)(struct snd_soc_component *component); + + unsigned int (*read)(struct snd_soc_component *component, + unsigned int reg); + int (*write)(struct snd_soc_component *component, + unsigned int reg, unsigned int val); + + /* pcm creation and destruction */ + int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); + void (*pcm_free)(struct snd_pcm *pcm); + + /* component wide operations */ + int (*set_sysclk)(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out); + int (*set_jack)(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data); + + /* DT */ + int (*of_xlate_dai_name)(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); + int (*of_xlate_dai_id)(struct snd_soc_component *comment, + struct device_node *endpoint); + void (*seq_notifier)(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq); + int (*stream_event)(struct snd_soc_component *component, int event); + int (*set_bias_level)(struct snd_soc_component *component, + enum snd_soc_bias_level level); + + const struct snd_pcm_ops *ops; + const struct snd_compr_ops *compr_ops; + + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; + + /* + * signal if the module handling the component should not be removed + * if a pcm is open. Setting this would prevent the module + * refcount being incremented in probe() but allow it be incremented + * when a pcm is opened and decremented when it is closed. + */ + unsigned int module_get_upon_open:1; + + /* bits */ + unsigned int idle_bias_on:1; + unsigned int suspend_bias_off:1; + unsigned int use_pmdown_time:1; /* care pmdown_time at stop */ + unsigned int endianness:1; + unsigned int non_legacy_dai_naming:1; + + /* this component uses topology and ignore machine driver FEs */ + const char *ignore_machine; + const char *topology_name_prefix; + int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params); + bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */ + int be_pcm_base; /* base device ID for all BE PCMs */ +}; + +struct snd_soc_component { + const char *name; + int id; + const char *name_prefix; + struct device *dev; + struct snd_soc_card *card; + + unsigned int active; + + unsigned int suspended:1; /* is in suspend PM state */ + + struct list_head list; + struct list_head card_aux_list; /* for auxiliary bound components */ + struct list_head card_list; + + const struct snd_soc_component_driver *driver; + + struct list_head dai_list; + int num_dai; + + struct regmap *regmap; + int val_bytes; + + struct mutex io_mutex; + + /* attached dynamic objects */ + struct list_head dobj_list; + + /* + * DO NOT use any of the fields below in drivers, they are temporary and + * are going to be removed again soon. If you use them in driver code + * the driver will be marked as BROKEN when these fields are removed. + */ + + /* Don't use these, use snd_soc_component_get_dapm() */ + struct snd_soc_dapm_context dapm; + + /* machine specific init */ + int (*init)(struct snd_soc_component *component); + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + const char *debugfs_prefix; +#endif +}; + +#define for_each_component_dais(component, dai)\ + list_for_each_entry(dai, &(component)->dai_list, list) +#define for_each_component_dais_safe(component, dai, _dai)\ + list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) + +/** + * snd_soc_dapm_to_component() - Casts a DAPM context to the component it is + * embedded in + * @dapm: The DAPM context to cast to the component + * + * This function must only be used on DAPM contexts that are known to be part of + * a component (e.g. in a component driver). Otherwise the behavior is + * undefined. + */ +static inline struct snd_soc_component *snd_soc_dapm_to_component( + struct snd_soc_dapm_context *dapm) +{ + return container_of(dapm, struct snd_soc_component, dapm); +} + +/** + * snd_soc_component_get_dapm() - Returns the DAPM context associated with a + * component + * @component: The component for which to get the DAPM context + */ +static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( + struct snd_soc_component *component) +{ + return &component->dapm; +} + +/** + * snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level + * @component: The COMPONENT for which to initialize the DAPM bias level + * @level: The DAPM level to initialize to + * + * Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level() + */ +static inline void +snd_soc_component_init_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + snd_soc_dapm_init_bias_level( + snd_soc_component_get_dapm(component), level); +} + +/** + * snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level + * @component: The COMPONENT for which to get the DAPM bias level + * + * Returns: The current DAPM bias level of the COMPONENT. + */ +static inline enum snd_soc_bias_level +snd_soc_component_get_bias_level(struct snd_soc_component *component) +{ + return snd_soc_dapm_get_bias_level( + snd_soc_component_get_dapm(component)); +} + +/** + * snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level + * @component: The COMPONENT for which to set the level + * @level: The level to set to + * + * Forces the COMPONENT bias level to a specific state. See + * snd_soc_dapm_force_bias_level(). + */ +static inline int +snd_soc_component_force_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + return snd_soc_dapm_force_bias_level( + snd_soc_component_get_dapm(component), + level); +} + +/** + * snd_soc_dapm_kcontrol_component() - Returns the component associated to a + * kcontrol + * @kcontrol: The kcontrol + * + * This function must only be used on DAPM contexts that are known to be part of + * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined + */ +static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component( + struct snd_kcontrol *kcontrol) +{ + return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol)); +} + +/** + * snd_soc_component_cache_sync() - Sync the register cache with the hardware + * @component: COMPONENT to sync + * + * Note: This function will call regcache_sync() + */ +static inline int snd_soc_component_cache_sync( + struct snd_soc_component *component) +{ + return regcache_sync(component->regmap); +} + +/* component IO */ +int snd_soc_component_read(struct snd_soc_component *component, + unsigned int reg, unsigned int *val); +unsigned int snd_soc_component_read32(struct snd_soc_component *component, + unsigned int reg); +int snd_soc_component_write(struct snd_soc_component *component, + unsigned int reg, unsigned int val); +int snd_soc_component_update_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val); +int snd_soc_component_update_bits_async(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int val); +void snd_soc_component_async_complete(struct snd_soc_component *component); +int snd_soc_component_test_bits(struct snd_soc_component *component, + unsigned int reg, unsigned int mask, + unsigned int value); + +/* component wide operations */ +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir); +int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out); +int snd_soc_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data); + +void snd_soc_component_seq_notifier(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq); +int snd_soc_component_stream_event(struct snd_soc_component *component, + int event); +int snd_soc_component_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level); + +#ifdef CONFIG_REGMAP +void snd_soc_component_init_regmap(struct snd_soc_component *component, + struct regmap *regmap); +void snd_soc_component_exit_regmap(struct snd_soc_component *component); +#endif + +#define snd_soc_component_module_get_when_probe(component)\ + snd_soc_component_module_get(component, 0) +#define snd_soc_component_module_get_when_open(component) \ + snd_soc_component_module_get(component, 1) +int snd_soc_component_module_get(struct snd_soc_component *component, + int upon_open); +#define snd_soc_component_module_put_when_remove(component) \ + snd_soc_component_module_put(component, 0) +#define snd_soc_component_module_put_when_close(component) \ + snd_soc_component_module_put(component, 1) +void snd_soc_component_module_put(struct snd_soc_component *component, + int upon_open); + +static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, + void *data) +{ + dev_set_drvdata(c->dev, data); +} + +static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c) +{ + return dev_get_drvdata(c->dev); +} + +static inline bool snd_soc_component_is_active( + struct snd_soc_component *component) +{ + return component->active != 0; +} + +/* component pin */ +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin); + +/* component driver ops */ +int snd_soc_component_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +int snd_soc_component_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +int snd_soc_component_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +int snd_soc_component_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int snd_soc_component_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +int snd_soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd); +void snd_soc_component_suspend(struct snd_soc_component *component); +void snd_soc_component_resume(struct snd_soc_component *component); +int snd_soc_component_is_suspended(struct snd_soc_component *component); +int snd_soc_component_probe(struct snd_soc_component *component); +void snd_soc_component_remove(struct snd_soc_component *component); +int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *ep); +int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name); + +int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream); +int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); +int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long bytes); +struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, + unsigned long offset); +int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); +int snd_soc_pcm_component_new(struct snd_pcm *pcm); +void snd_soc_pcm_component_free(struct snd_pcm *pcm); + +#endif /* __SOC_COMPONENT_H */ diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f5d70041108f..939c73db6a03 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -145,6 +145,31 @@ int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, int snd_soc_dai_is_dummy(struct snd_soc_dai *dai); +int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); +int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); +void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); +int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); +int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); +int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd); +snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream); +void snd_soc_dai_suspend(struct snd_soc_dai *dai); +void snd_soc_dai_resume(struct snd_soc_dai *dai); +int snd_soc_dai_probe(struct snd_soc_dai *dai); +int snd_soc_dai_remove(struct snd_soc_dai *dai); +int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + struct snd_soc_pcm_runtime *rtd, int num); +bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream); + struct snd_soc_dai_ops { /* * DAI clocking configuration, all optional. @@ -268,8 +293,6 @@ struct snd_soc_dai_driver { /* Optional Callback used at pcm creation*/ int (*pcm_new)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai); - /* DAI is also used for the control bus */ - bool bus_control; /* ops */ const struct snd_soc_dai_ops *ops; @@ -281,6 +304,7 @@ struct snd_soc_dai_driver { unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; + unsigned int bus_control:1; /* DAI is also used for the control bus */ /* probe ordering - for components with runtime dependencies */ int probe_order; diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8a90816a6eb5..6e8a31225383 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -353,6 +353,8 @@ struct device; #define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */ #define SND_SOC_DAPM_PRE_POST_PMD \ (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD) +#define SND_SOC_DAPM_PRE_POST_PMU \ + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU) /* convenience event type detection */ #define SND_SOC_DAPM_EVENT_ON(e) \ @@ -417,6 +419,9 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, + struct snd_soc_card *card, + struct snd_soc_component *component); int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, @@ -662,8 +667,6 @@ struct snd_soc_dapm_context { unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ /* Go to BIAS_OFF in suspend if the DAPM context is idle */ unsigned int suspend_bias_off:1; - void (*seq_notifier)(struct snd_soc_dapm_context *, - enum snd_soc_dapm_type, int); struct device *dev; /* from parent - for debug */ struct snd_soc_component *component; /* parent component */ @@ -673,10 +676,6 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level target_bias_level; struct list_head list; - int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); - int (*set_bias_level)(struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level); - struct snd_soc_dapm_wcache path_sink_cache; struct snd_soc_dapm_wcache path_source_cache; diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 4be3a2b7c106..e55aeb00ce2d 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -142,9 +142,16 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream, /* internal use only */ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); -void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); int soc_dpcm_runtime_update(struct snd_soc_card *); +#ifdef CONFIG_DEBUG_FS +void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); +#else +static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) +{ +} +#endif + int dpcm_path_get(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list_); int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, diff --git a/include/sound/soc.h b/include/sound/soc.h index 4e8071269639..f264c6509f00 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -363,21 +363,6 @@ const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts) /* - * Component probe and remove ordering levels for components with runtime - * dependencies. - */ -#define SND_SOC_COMP_ORDER_FIRST -2 -#define SND_SOC_COMP_ORDER_EARLY -1 -#define SND_SOC_COMP_ORDER_NORMAL 0 -#define SND_SOC_COMP_ORDER_LATE 1 -#define SND_SOC_COMP_ORDER_LAST 2 - -#define for_each_comp_order(order) \ - for (order = SND_SOC_COMP_ORDER_FIRST; \ - order <= SND_SOC_COMP_ORDER_LAST; \ - order++) - -/* * Bias levels * * @ON: Bias is fully on for audio playback and capture operations. @@ -505,10 +490,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms); int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw); -int soc_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai); - /* Jack reporting */ int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, @@ -751,132 +732,6 @@ struct snd_soc_compr_ops { int (*trigger)(struct snd_compr_stream *); }; -/* component interface */ -struct snd_soc_component_driver { - const char *name; - - /* Default control and setup, added after probe() is run */ - const struct snd_kcontrol_new *controls; - unsigned int num_controls; - const struct snd_soc_dapm_widget *dapm_widgets; - unsigned int num_dapm_widgets; - const struct snd_soc_dapm_route *dapm_routes; - unsigned int num_dapm_routes; - - int (*probe)(struct snd_soc_component *); - void (*remove)(struct snd_soc_component *); - int (*suspend)(struct snd_soc_component *); - int (*resume)(struct snd_soc_component *); - - unsigned int (*read)(struct snd_soc_component *, unsigned int); - int (*write)(struct snd_soc_component *, unsigned int, unsigned int); - - /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *); - void (*pcm_free)(struct snd_pcm *); - - /* component wide operations */ - int (*set_sysclk)(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, unsigned int freq_out); - int (*set_jack)(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data); - - /* DT */ - int (*of_xlate_dai_name)(struct snd_soc_component *component, - struct of_phandle_args *args, - const char **dai_name); - int (*of_xlate_dai_id)(struct snd_soc_component *comment, - struct device_node *endpoint); - void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, - int subseq); - int (*stream_event)(struct snd_soc_component *, int event); - int (*set_bias_level)(struct snd_soc_component *component, - enum snd_soc_bias_level level); - - const struct snd_pcm_ops *ops; - const struct snd_compr_ops *compr_ops; - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - - /* - * signal if the module handling the component should not be removed - * if a pcm is open. Setting this would prevent the module - * refcount being incremented in probe() but allow it be incremented - * when a pcm is opened and decremented when it is closed. - */ - unsigned int module_get_upon_open:1; - - /* bits */ - unsigned int idle_bias_on:1; - unsigned int suspend_bias_off:1; - unsigned int use_pmdown_time:1; /* care pmdown_time at stop */ - unsigned int endianness:1; - unsigned int non_legacy_dai_naming:1; - - /* this component uses topology and ignore machine driver FEs */ - const char *ignore_machine; - const char *topology_name_prefix; - int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params); - bool use_dai_pcm_id; /* use the DAI link PCM ID as PCM device number */ - int be_pcm_base; /* base device ID for all BE PCMs */ -}; - -struct snd_soc_component { - const char *name; - int id; - const char *name_prefix; - struct device *dev; - struct snd_soc_card *card; - - unsigned int active; - - unsigned int suspended:1; /* is in suspend PM state */ - - struct list_head list; - struct list_head card_aux_list; /* for auxiliary bound components */ - struct list_head card_list; - - const struct snd_soc_component_driver *driver; - - struct list_head dai_list; - int num_dai; - - struct regmap *regmap; - int val_bytes; - - struct mutex io_mutex; - - /* attached dynamic objects */ - struct list_head dobj_list; - - /* - * DO NOT use any of the fields below in drivers, they are temporary and - * are going to be removed again soon. If you use them in driver code the - * driver will be marked as BROKEN when these fields are removed. - */ - - /* Don't use these, use snd_soc_component_get_dapm() */ - struct snd_soc_dapm_context dapm; - - /* machine specific init */ - int (*init)(struct snd_soc_component *component); - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; - const char *debugfs_prefix; -#endif -}; - -#define for_each_component_dais(component, dai)\ - list_for_each_entry(dai, &(component)->dai_list, list) -#define for_each_component_dais_safe(component, dai, _dai)\ - list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) - struct snd_soc_rtdcom_list { struct snd_soc_component *component; struct list_head list; /* rtd::component_list */ @@ -1086,6 +941,7 @@ struct snd_soc_dai_link { #define COMP_CPU(_dai) { .dai_name = _dai, } #define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, } #define COMP_PLATFORM(_name) { .name = _name } +#define COMP_AUX(_name) { .name = _name } #define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", } extern struct snd_soc_dai_link_component null_dailink_component[0]; @@ -1107,14 +963,11 @@ struct snd_soc_codec_conf { }; struct snd_soc_aux_dev { - const char *name; /* Codec name */ - /* * specify multi-codec either by device name, or by * DT/OF node, but not both. */ - const char *codec_name; - struct device_node *codec_of_node; + struct snd_soc_dai_link_component dlc; /* codec/machine specific init - e.g. add machine controls */ int (*init)(struct snd_soc_component *component); @@ -1135,6 +988,10 @@ struct snd_soc_card { struct mutex mutex; struct mutex dapm_mutex; + /* Mutex for PCM operations */ + struct mutex pcm_mutex; + enum snd_soc_pcm_subclass pcm_subclass; + spinlock_t dpcm_lock; bool instantiated; @@ -1203,8 +1060,6 @@ struct snd_soc_card { int num_of_dapm_routes; bool fully_routed; - struct work_struct deferred_resume_work; - /* lists of probed devices belonging to this card */ struct list_head component_dev_list; struct list_head list; @@ -1224,7 +1079,9 @@ struct snd_soc_card { #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_card_root; - struct dentry *debugfs_pop_time; +#endif +#ifdef CONFIG_PM_SLEEP + struct work_struct deferred_resume_work; #endif u32 pop_time; @@ -1234,6 +1091,10 @@ struct snd_soc_card { for ((i) = 0; \ ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ (i)++) +#define for_each_card_pre_auxs(card, i, aux) \ + for ((i) = 0; \ + ((i) < (card)->num_aux_devs) && ((aux) = &(card)->aux_dev[i]); \ + (i)++) #define for_each_card_links(card, link) \ list_for_each_entry(link, &(card)->dai_link_list, list) @@ -1245,6 +1106,12 @@ struct snd_soc_card { #define for_each_card_rtds_safe(card, rtd, _rtd) \ list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) +#define for_each_card_auxs(card, component) \ + list_for_each_entry(component, &card->aux_comp_list, card_aux_list) +#define for_each_card_auxs_safe(card, component, _comp) \ + list_for_each_entry_safe(component, _comp, \ + &card->aux_comp_list, card_aux_list) + #define for_each_card_components(card, component) \ list_for_each_entry(component, &(card)->component_dev_list, card_list) @@ -1253,8 +1120,6 @@ struct snd_soc_pcm_runtime { struct device *dev; struct snd_soc_card *card; struct snd_soc_dai_link *dai_link; - struct mutex pcm_mutex; - enum snd_soc_pcm_subclass pcm_subclass; struct snd_pcm_ops ops; unsigned int params_select; /* currently selected param for dai link */ @@ -1342,134 +1207,6 @@ struct soc_enum { struct snd_soc_dobj dobj; }; -/** - * snd_soc_dapm_to_component() - Casts a DAPM context to the component it is - * embedded in - * @dapm: The DAPM context to cast to the component - * - * This function must only be used on DAPM contexts that are known to be part of - * a component (e.g. in a component driver). Otherwise the behavior is - * undefined. - */ -static inline struct snd_soc_component *snd_soc_dapm_to_component( - struct snd_soc_dapm_context *dapm) -{ - return container_of(dapm, struct snd_soc_component, dapm); -} - -/** - * snd_soc_component_get_dapm() - Returns the DAPM context associated with a - * component - * @component: The component for which to get the DAPM context - */ -static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( - struct snd_soc_component *component) -{ - return &component->dapm; -} - -/** - * snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level - * @component: The COMPONENT for which to initialize the DAPM bias level - * @level: The DAPM level to initialize to - * - * Initializes the COMPONENT DAPM bias level. See snd_soc_dapm_init_bias_level(). - */ -static inline void -snd_soc_component_init_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - snd_soc_dapm_init_bias_level( - snd_soc_component_get_dapm(component), level); -} - -/** - * snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level - * @component: The COMPONENT for which to get the DAPM bias level - * - * Returns: The current DAPM bias level of the COMPONENT. - */ -static inline enum snd_soc_bias_level -snd_soc_component_get_bias_level(struct snd_soc_component *component) -{ - return snd_soc_dapm_get_bias_level( - snd_soc_component_get_dapm(component)); -} - -/** - * snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level - * @component: The COMPONENT for which to set the level - * @level: The level to set to - * - * Forces the COMPONENT bias level to a specific state. See - * snd_soc_dapm_force_bias_level(). - */ -static inline int -snd_soc_component_force_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - return snd_soc_dapm_force_bias_level( - snd_soc_component_get_dapm(component), - level); -} - -/** - * snd_soc_dapm_kcontrol_component() - Returns the component associated to a kcontrol - * @kcontrol: The kcontrol - * - * This function must only be used on DAPM contexts that are known to be part of - * a COMPONENT (e.g. in a COMPONENT driver). Otherwise the behavior is undefined. - */ -static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component( - struct snd_kcontrol *kcontrol) -{ - return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol)); -} - -/** - * snd_soc_component_cache_sync() - Sync the register cache with the hardware - * @component: COMPONENT to sync - * - * Note: This function will call regcache_sync() - */ -static inline int snd_soc_component_cache_sync( - struct snd_soc_component *component) -{ - return regcache_sync(component->regmap); -} - -/* component IO */ -int snd_soc_component_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val); -unsigned int snd_soc_component_read32(struct snd_soc_component *component, - unsigned int reg); -int snd_soc_component_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val); -int snd_soc_component_update_bits(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int val); -int snd_soc_component_update_bits_async(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int val); -void snd_soc_component_async_complete(struct snd_soc_component *component); -int snd_soc_component_test_bits(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int value); - -/* component wide operations */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, int dir); -int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out); -int snd_soc_component_set_jack(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data); - -#ifdef CONFIG_REGMAP - -void snd_soc_component_init_regmap(struct snd_soc_component *component, - struct regmap *regmap); -void snd_soc_component_exit_regmap(struct snd_soc_component *component); - -#endif - /* device driver data */ static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, @@ -1483,27 +1220,6 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) return card->drvdata; } -static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, - void *data) -{ - dev_set_drvdata(c->dev, data); -} - -static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c) -{ - return dev_get_drvdata(c->dev); -} - -static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) -{ - INIT_LIST_HEAD(&card->widgets); - INIT_LIST_HEAD(&card->paths); - INIT_LIST_HEAD(&card->dapm_list); - INIT_LIST_HEAD(&card->aux_comp_list); - INIT_LIST_HEAD(&card->component_dev_list); - INIT_LIST_HEAD(&card->list); -} - static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) { if (mc->reg == mc->rreg && mc->shift == mc->rshift) @@ -1540,12 +1256,6 @@ static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, return e->values[item]; } -static inline bool snd_soc_component_is_active( - struct snd_soc_component *component) -{ - return component->active != 0; -} - /** * snd_soc_kcontrol_component() - Returns the component that registered the * control @@ -1681,24 +1391,6 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) mutex_unlock(&dapm->card->dapm_mutex); } -int snd_soc_component_enable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_disable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_nc_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_get_pin_status(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_force_enable_pin(struct snd_soc_component *component, - const char *pin); -int snd_soc_component_force_enable_pin_unlocked( - struct snd_soc_component *component, - const char *pin); +#include <sound/soc-component.h> #endif diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 65e4c20e567c..5f1ef5565be6 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -76,6 +76,9 @@ struct sof_ipc_dai_ssp_params { uint16_t tdm_per_slot_padding_flag; uint32_t clks_control; uint32_t quirks; + uint32_t bclk_delay; /* guaranteed time (ms) for which BCLK + * will be driven, before sending data + */ } __packed; /* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ @@ -176,4 +179,13 @@ struct sof_ipc_dai_dmic_params { struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; } __packed; +/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */ +struct sof_ipc_dai_alh_params { + struct sof_ipc_hdr hdr; + uint32_t stream_id; + + /* reserved for future use */ + uint32_t reserved[15]; +} __packed; + #endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 5b8de1b1983c..0f1235022146 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -49,7 +49,9 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_SSP, /**< Intel SSP */ SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ SOF_DAI_INTEL_HDA, /**< Intel HD/A */ - SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */ + SOF_DAI_INTEL_ALH, /**< Intel ALH */ + SOF_DAI_IMX_SAI, /**< i.MX SAI */ + SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ }; /* general purpose DAI configuration */ @@ -70,6 +72,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_ssp_params ssp; struct sof_ipc_dai_dmic_params dmic; struct sof_ipc_dai_hda_params hda; + struct sof_ipc_dai_alh_params alh; }; } __packed; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 4a9c24434f42..a0fe0d4c4b66 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 8 +#define SOF_ABI_MINOR 10 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index dc1b27daaac6..8f996857fb24 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -75,6 +75,7 @@ #define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503 #define SOF_TKN_INTEL_SSP_QUIRKS 504 #define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505 +#define SOF_TKN_INTEL_SSP_BCLK_DELAY 506 /* DMIC */ #define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600 @@ -105,4 +106,12 @@ /* for backward compatibility */ #define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE +/* SAI */ +#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000 +/* TODO: Add SAI tokens */ + +/* ESAI */ +#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 +/* TODO: Add ESAI tokens */ + #endif diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 703857aab00f..11e653c8aa0e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2170,7 +2170,7 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 + 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000 }; const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index f6feced15f17..3d33fc1757ba 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -6,6 +6,9 @@ config SND_HDA_CORE config SND_HDA_DSP_LOADER bool +config SND_HDA_ALIGNED_MMIO + bool + config SND_HDA_COMPONENT bool @@ -29,3 +32,8 @@ config SND_HDA_PREALLOC_SIZE Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. + +config SND_INTEL_NHLT + tristate + # this config should be selected only for Intel ACPI platforms. + # A fallback is provided so that the code compiles in all cases.
\ No newline at end of file diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 2160202e2dc1..8560f6ef1b19 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o #extended hda obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ + +snd-intel-nhlt-objs := intel-nhlt.o +obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 4f9f1d2a2ec5..242306d820ec 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -17,80 +17,22 @@ MODULE_DESCRIPTION("HDA extended core"); MODULE_LICENSE("GPL v2"); -static void hdac_ext_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 hdac_ext_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void hdac_ext_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 hdac_ext_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void hdac_ext_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 hdac_ext_readb(u8 __iomem *addr) -{ - return readb(addr); -} - -static int hdac_ext_dma_alloc_pages(struct hdac_bus *bus, int type, - size_t size, struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void hdac_ext_dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - -static const struct hdac_io_ops hdac_ext_default_io = { - .reg_writel = hdac_ext_writel, - .reg_readl = hdac_ext_readl, - .reg_writew = hdac_ext_writew, - .reg_readw = hdac_ext_readw, - .reg_writeb = hdac_ext_writeb, - .reg_readb = hdac_ext_readb, - .dma_alloc_pages = hdac_ext_dma_alloc_pages, - .dma_free_pages = hdac_ext_dma_free_pages, -}; - /** * snd_hdac_ext_bus_init - initialize a HD-audio extended bus * @ebus: the pointer to extended bus object * @dev: device pointer * @ops: bus verb operators - * @io_ops: lowlevel I/O operators, can be NULL. If NULL core will use * default ops * * Returns 0 if successful, or a negative error code. */ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops, const struct hdac_ext_bus_ops *ext_ops) { int ret; - /* check if io ops are provided, if not load the defaults */ - if (io_ops == NULL) - io_ops = &hdac_ext_default_io; - - ret = snd_hdac_bus_init(bus, dev, ops, io_ops); + ret = snd_hdac_bus_init(bus, dev, ops); if (ret < 0) return ret; diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 14e57ffd5bc1..cd25e2b3f7f2 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -4,6 +4,7 @@ */ #include <linux/init.h> +#include <linux/io.h> #include <linux/device.h> #include <linux/module.h> #include <linux/export.h> @@ -19,13 +20,11 @@ static const struct hdac_bus_ops default_ops = { * snd_hdac_bus_init - initialize a HD-audio bas bus * @bus: the pointer to bus object * @ops: bus verb operators - * @io_ops: lowlevel I/O operators * * Returns 0 if successful, or a negative error code. */ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_bus_ops *ops, - const struct hdac_io_ops *io_ops) + const struct hdac_bus_ops *ops) { memset(bus, 0, sizeof(*bus)); bus->dev = dev; @@ -33,7 +32,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, bus->ops = ops; else bus->ops = &default_ops; - bus->io_ops = io_ops; + bus->dma_type = SNDRV_DMA_TYPE_DEV; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); @@ -217,3 +216,33 @@ void snd_hdac_bus_remove_device(struct hdac_bus *bus, flush_work(&bus->unsol_work); } EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device); + +#ifdef CONFIG_SND_HDA_ALIGNED_MMIO +/* Helpers for aligned read/write of mmio space, for Tegra */ +unsigned int snd_hdac_aligned_read(void __iomem *addr, unsigned int mask) +{ + void __iomem *aligned_addr = + (void __iomem *)((unsigned long)(addr) & ~0x3); + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + unsigned int v; + + v = readl(aligned_addr); + return (v >> shift) & mask; +} +EXPORT_SYMBOL_GPL(snd_hdac_aligned_read); + +void snd_hdac_aligned_write(unsigned int val, void __iomem *addr, + unsigned int mask) +{ + void __iomem *aligned_addr = + (void __iomem *)((unsigned long)(addr) & ~0x3); + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + unsigned int v; + + v = readl(aligned_addr); + v &= ~(mask << shift); + v |= val << shift; + writel(v, aligned_addr); +} +EXPORT_SYMBOL_GPL(snd_hdac_aligned_write); +#endif /* CONFIG_SND_HDA_ALIGNED_MMIO */ diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 3b0110545070..7e7be8e4dcf9 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -575,12 +575,13 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) { struct hdac_stream *s; int num_streams = 0; + int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV; int err; list_for_each_entry(s, &bus->stream_list, list) { /* allocate memory for the BDL for each stream */ - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - BDL_SIZE, &s->bdl); + err = snd_dma_alloc_pages(dma_type, bus->dev, + BDL_SIZE, &s->bdl); num_streams++; if (err < 0) return -ENOMEM; @@ -589,16 +590,15 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) if (WARN_ON(!num_streams)) return -EINVAL; /* allocate memory for the position buffer */ - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - num_streams * 8, &bus->posbuf); + err = snd_dma_alloc_pages(dma_type, bus->dev, + num_streams * 8, &bus->posbuf); if (err < 0) return -ENOMEM; list_for_each_entry(s, &bus->stream_list, list) s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8); /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, - PAGE_SIZE, &bus->rb); + return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb); } EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages); @@ -612,12 +612,12 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus) list_for_each_entry(s, &bus->stream_list, list) { if (s->bdl.area) - bus->io_ops->dma_free_pages(bus, &s->bdl); + snd_dma_free_pages(&s->bdl); } if (bus->rb.area) - bus->io_ops->dma_free_pages(bus, &bus->rb); + snd_dma_free_pages(&bus->rb); if (bus->posbuf.area) - bus->io_ops->dma_free_pages(bus, &bus->posbuf); + snd_dma_free_pages(&bus->posbuf); } EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages); diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 55d53b89ac21..fc68d4ce0a37 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -680,8 +680,8 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, azx_dev->locked = true; spin_unlock_irq(&bus->reg_lock); - err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV_SG, - byte_size, bufp); + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, + byte_size, bufp); if (err < 0) goto err_alloc; @@ -707,7 +707,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, return azx_dev->stream_tag; error: - bus->io_ops->dma_free_pages(bus, bufp); + snd_dma_free_pages(bufp); err_alloc: spin_lock_irq(&bus->reg_lock); azx_dev->locked = false; @@ -754,7 +754,7 @@ void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev, azx_dev->period_bytes = 0; azx_dev->format_val = 0; - bus->io_ops->dma_free_pages(bus, dmab); + snd_dma_free_pages(dmab); dmab->area = NULL; spin_lock_irq(&bus->reg_lock); diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c new file mode 100644 index 000000000000..daede96f28ee --- /dev/null +++ b/sound/hda/intel-nhlt.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2019 Intel Corporation + +#include <linux/acpi.h> +#include <sound/intel-nhlt.h> + +#define NHLT_ACPI_HEADER_SIG "NHLT" + +/* Unique identification for getting NHLT blobs */ +static guid_t osc_guid = + GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, + 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); + +struct nhlt_acpi_table *intel_nhlt_init(struct device *dev) +{ + acpi_handle handle; + union acpi_object *obj; + struct nhlt_resource_desc *nhlt_ptr; + struct nhlt_acpi_table *nhlt_table = NULL; + + handle = ACPI_HANDLE(dev); + if (!handle) { + dev_err(dev, "Didn't find ACPI_HANDLE\n"); + return NULL; + } + + obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); + + if (!obj) + return NULL; + + if (obj->type != ACPI_TYPE_BUFFER) { + dev_dbg(dev, "No NHLT table found\n"); + ACPI_FREE(obj); + return NULL; + } + + nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; + if (nhlt_ptr->length) + nhlt_table = (struct nhlt_acpi_table *) + memremap(nhlt_ptr->min_addr, nhlt_ptr->length, + MEMREMAP_WB); + ACPI_FREE(obj); + if (nhlt_table && + (strncmp(nhlt_table->header.signature, + NHLT_ACPI_HEADER_SIG, + strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { + memunmap(nhlt_table); + dev_err(dev, "NHLT ACPI header signature incorrect\n"); + return NULL; + } + return nhlt_table; +} +EXPORT_SYMBOL_GPL(intel_nhlt_init); + +void intel_nhlt_free(struct nhlt_acpi_table *nhlt) +{ + memunmap((void *)nhlt); +} +EXPORT_SYMBOL_GPL(intel_nhlt_free); + +int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) +{ + struct nhlt_endpoint *epnt; + struct nhlt_dmic_array_config *cfg; + struct nhlt_vendor_dmic_array_config *cfg_vendor; + unsigned int dmic_geo = 0; + u8 j; + + if (!nhlt) + return 0; + + epnt = (struct nhlt_endpoint *)nhlt->desc; + + for (j = 0; j < nhlt->endpoint_count; j++) { + if (epnt->linktype == NHLT_LINK_DMIC) { + cfg = (struct nhlt_dmic_array_config *) + (epnt->config.caps); + switch (cfg->array_type) { + case NHLT_MIC_ARRAY_2CH_SMALL: + case NHLT_MIC_ARRAY_2CH_BIG: + dmic_geo = MIC_ARRAY_2CH; + break; + + case NHLT_MIC_ARRAY_4CH_1ST_GEOM: + case NHLT_MIC_ARRAY_4CH_L_SHAPED: + case NHLT_MIC_ARRAY_4CH_2ND_GEOM: + dmic_geo = MIC_ARRAY_4CH; + break; + case NHLT_MIC_ARRAY_VENDOR_DEFINED: + cfg_vendor = (struct nhlt_vendor_dmic_array_config *)cfg; + dmic_geo = cfg_vendor->nb_mics; + break; + default: + dev_warn(dev, "undefined DMIC array_type 0x%0x\n", + cfg->array_type); + } + } + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return dmic_geo; +} +EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel NHLT driver"); diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 35d934309cb2..dae47a45b2b8 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -12,6 +12,7 @@ config SND_HDA_INTEL tristate "HD Audio PCI" depends on SND_PCI select SND_HDA + select SND_INTEL_NHLT if ACPI help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -22,10 +23,20 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. +config SND_HDA_INTEL_DETECT_DMIC + bool "DMIC detection and probe abort" + depends on SND_HDA_INTEL + help + Say Y to detect digital microphones on SKL+ devices. DMICs + cannot be handled by the HDaudio legacy driver and are + currently only supported by the SOF driver. + If unsure say N. + config SND_HDA_TEGRA tristate "NVIDIA Tegra HD Audio" depends on ARCH_TEGRA select SND_HDA + select SND_HDA_ALIGNED_MMIO help Say Y here to support the HDA controller present in NVIDIA Tegra SoCs diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 51f10ed9bc43..a2fb19129219 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -846,7 +846,13 @@ static void snd_hda_codec_dev_release(struct device *dev) snd_hda_sysfs_clear(codec); kfree(codec->modelname); kfree(codec->wcaps); - kfree(codec); + + /* + * In the case of ASoC HD-audio, hda_codec is device managed. + * It will be freed when the ASoC device is removed. + */ + if (codec->core.type == HDA_DEV_LEGACY) + kfree(codec); } #define DEV_NAME_LEN 31 diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 48d863736b3c..97a43a28b9e4 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1207,14 +1207,12 @@ void snd_hda_bus_reset(struct hda_bus *bus) } /* HD-audio bus initialization */ -int azx_bus_init(struct azx *chip, const char *model, - const struct hdac_io_ops *io_ops) +int azx_bus_init(struct azx *chip, const char *model) { struct hda_bus *bus = &chip->bus; int err; - err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops, - io_ops); + err = snd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops); if (err < 0) return err; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index f2a6df5e6bcb..82e26442724b 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -206,8 +206,7 @@ void azx_stop_chip(struct azx *chip); irqreturn_t azx_interrupt(int irq, void *dev_id); /* Codec interface */ -int azx_bus_init(struct azx *chip, const char *model, - const struct hdac_io_ops *io_ops); +int azx_bus_init(struct azx *chip, const char *model); int azx_probe_codecs(struct azx *chip, unsigned int max_slots); int azx_codec_configure(struct azx *chip); int azx_init_streams(struct azx *chip); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 99fc0917339b..2d0db3c9f335 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -46,6 +46,7 @@ #include <sound/initval.h> #include <sound/hdaudio.h> #include <sound/hda_i915.h> +#include <sound/intel-nhlt.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> #include <linux/firmware.h> @@ -125,6 +126,7 @@ static char *patch[SNDRV_CARDS]; static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = CONFIG_SND_HDA_INPUT_BEEP_MODE}; #endif +static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC); module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -159,6 +161,8 @@ module_param_array(beep_mode, bool, NULL, 0444); MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " "(0=off, 1=on) (default=1)."); #endif +module_param(dmic_detect, bool, 0444); +MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms"); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -1684,7 +1688,6 @@ static int default_bdl_pos_adj(struct azx *chip) /* * constructor */ -static const struct hdac_io_ops pci_hda_io_ops; static const struct hda_controller_ops pci_hda_ops; static int azx_create(struct snd_card *card, struct pci_dev *pci, @@ -1744,13 +1747,17 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, else chip->bdl_pos_adj = bdl_pos_adj[dev]; - err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); + err = azx_bus_init(chip, model[dev]); if (err < 0) { kfree(hda); pci_disable_device(pci); return err; } + /* use the non-cached pages in non-snoop mode */ + if (!azx_snoop(chip)) + azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_UC; + /* Workaround for a communication error on CFL (bko#199007) and CNL */ if (IS_CFL(pci) || IS_CNL(pci)) azx_bus(chip)->polling_mode = 1; @@ -1985,41 +1992,6 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) } #endif -/* - * HDA controller ops. - */ - -/* PCI register access. */ -static void pci_azx_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 pci_azx_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void pci_azx_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 pci_azx_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void pci_azx_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 pci_azx_readb(u8 __iomem *addr) -{ - return readb(addr); -} - static int disable_msi_reset_irq(struct azx *chip) { struct hdac_bus *bus = azx_bus(chip); @@ -2036,24 +2008,6 @@ static int disable_msi_reset_irq(struct azx *chip) return 0; } -/* DMA page allocation helpers. */ -static int dma_alloc_pages(struct hdac_bus *bus, - int type, - size_t size, - struct snd_dma_buffer *buf) -{ - struct azx *chip = bus_to_azx(bus); - - if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV) - type = SNDRV_DMA_TYPE_DEV_UC; - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - static void pcm_mmap_prepare(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -2065,23 +2019,31 @@ static void pcm_mmap_prepare(struct snd_pcm_substream *substream, #endif } -static const struct hdac_io_ops pci_hda_io_ops = { - .reg_writel = pci_azx_writel, - .reg_readl = pci_azx_readl, - .reg_writew = pci_azx_writew, - .reg_readw = pci_azx_readw, - .reg_writeb = pci_azx_writeb, - .reg_readb = pci_azx_readb, - .dma_alloc_pages = dma_alloc_pages, - .dma_free_pages = dma_free_pages, -}; - static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, }; +static int azx_check_dmic(struct pci_dev *pci, struct azx *chip) +{ + struct nhlt_acpi_table *nhlt; + int ret = 0; + + if (chip->driver_type == AZX_DRIVER_SKL && + pci->class != 0x040300) { + nhlt = intel_nhlt_init(&pci->dev); + if (nhlt) { + if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) { + ret = -ENODEV; + dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n"); + } + intel_nhlt_free(nhlt); + } + } + return ret; +} + static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2112,6 +2074,17 @@ static int azx_probe(struct pci_dev *pci, card->private_data = chip; hda = container_of(chip, struct hda_intel, chip); + /* + * stop probe if digital microphones detected on Skylake+ platform + * with the DSP enabled. This is an opt-in behavior defined at build + * time or at run-time with a module parameter + */ + if (dmic_detect) { + err = azx_check_dmic(pci, chip); + if (err < 0) + goto out_free; + } + pci_set_drvdata(pci, card); err = register_vga_switcheroo(chip); diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 7dbe9f39fc79..8350954b7986 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -75,88 +75,6 @@ MODULE_PARM_DESC(power_save, #define power_save 0 #endif -/* - * DMA page allocation ops. - */ -static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size, - struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - -/* - * Register access ops. Tegra HDA register access is DWORD only. - */ -static void hda_tegra_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 hda_tegra_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void hda_tegra_writew(u16 value, u16 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - v &= ~(0xffff << shift); - v |= value << shift; - writel(v, dword_addr); -} - -static u16 hda_tegra_readw(u16 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - return (v >> shift) & 0xffff; -} - -static void hda_tegra_writeb(u8 value, u8 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - v &= ~(0xff << shift); - v |= value << shift; - writel(v, dword_addr); -} - -static u8 hda_tegra_readb(u8 __iomem *addr) -{ - unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; - void __iomem *dword_addr = (void __iomem *)((unsigned long)(addr) & ~0x3); - u32 v; - - v = readl(dword_addr); - return (v >> shift) & 0xff; -} - -static const struct hdac_io_ops hda_tegra_io_ops = { - .reg_writel = hda_tegra_writel, - .reg_readl = hda_tegra_readl, - .reg_writew = hda_tegra_writew, - .reg_readw = hda_tegra_readw, - .reg_writeb = hda_tegra_writeb, - .reg_readb = hda_tegra_readb, - .dma_alloc_pages = dma_alloc_pages, - .dma_free_pages = dma_free_pages, -}; - static const struct hda_controller_ops hda_tegra_ops; /* nothing special */ static void hda_tegra_init(struct hda_tegra *hda) @@ -475,7 +393,7 @@ static int hda_tegra_create(struct snd_card *card, INIT_WORK(&hda->probe_work, hda_tegra_probe_work); - err = azx_bus_init(chip, NULL, &hda_tegra_io_ops); + err = azx_bus_init(chip, NULL); if (err < 0) return err; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index dc86e4073001..bdc305cece6e 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -51,7 +51,6 @@ source "sound/soc/dwc/Kconfig" source "sound/soc/fsl/Kconfig" source "sound/soc/hisilicon/Kconfig" source "sound/soc/jz4740/Kconfig" -source "sound/soc/nuc900/Kconfig" source "sound/soc/kirkwood/Kconfig" source "sound/soc/img/Kconfig" source "sound/soc/intel/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d90ce8a32887..861a21b79484 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o @@ -39,7 +39,6 @@ obj-$(CONFIG_SND_SOC) += intel/ obj-$(CONFIG_SND_SOC) += mediatek/ obj-$(CONFIG_SND_SOC) += meson/ obj-$(CONFIG_SND_SOC) += mxs/ -obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += qcom/ diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index d26653f81416..52225b4b6382 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1251,8 +1251,7 @@ static int acp_audio_probe(struct platform_device *pdev) if (!audio_drv_data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); + audio_drv_data->acp_mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audio_drv_data->acp_mmio)) return PTR_ERR(audio_drv_data->acp_mmio); diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06c1d5ce642c..f118c229ed82 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -12,25 +12,31 @@ if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC tristate depends on HAS_DMA - default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_PDC - tristate config SND_ATMEL_SOC_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM - default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_DMA - tristate config SND_ATMEL_SOC_SSC tristate - default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y - default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m + +config SND_ATMEL_SOC_SSC_PDC + tristate "SoC PCM DAI support for AT91 SSC controller using PDC" + depends on ATMEL_SSC + select SND_ATMEL_SOC_PDC + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in PDC mode configured using audio-graph-card in device-tree. + +config SND_ATMEL_SOC_SSC_DMA + tristate "SoC PCM DAI support for AT91 SSC controller using DMA" + depends on ATMEL_SSC + select SND_ATMEL_SOC_DMA + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in DMA mode configured using audio-graph-card in device-tree. config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 0f2c574f27f1..e98601eccfa3 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -571,11 +571,8 @@ static int atmel_classd_probe(struct platform_device *pdev) dd->pdata = pdata; dd->irq = platform_get_irq(pdev, 0); - if (dd->irq < 0) { - ret = dd->irq; - dev_err(dev, "failed to could not get irq: %d\n", ret); - return ret; - } + if (dd->irq < 0) + return dd->irq; dd->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dd->pclk)) { diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index e09c28349e0d..04ec6f0af179 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c @@ -612,11 +612,8 @@ static int atmel_pdmic_probe(struct platform_device *pdev) dd->dev = dev; dd->irq = platform_get_irq(pdev, 0); - if (dd->irq < 0) { - ret = dd->irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } + if (dd->irq < 0) + return dd->irq; dd->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dd->pclk)) { diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 6f89483ac88c..48e9eef34c0f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; int ret; - int fslen, fslen_ext; + int fslen, fslen_ext, fs_osync, fs_edge; u32 cmr_div; u32 tcmr_period; u32 rcmr_period; @@ -558,226 +558,45 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, /* * Compute SSC register settings. */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated - * from the MCK divider, and the BCLK signal - * is output on the SSC TK line. - */ + fslen_ext = (bits - 1) / 16; + fslen = (bits - 1) % 16; - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + case SND_SOC_DAIFMT_LEFT_J: + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + + rcmr = SSC_BF(RCMR_STTDLY, 0); + tcmr = SSC_BF(TCMR_STTDLY, 0); - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* I2S format, CODEC supplies BCLK and LRC clocks. */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); break; - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS: - /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */ - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + case SND_SOC_DAIFMT_I2S: + fs_osync = SSC_FSOS_NEGATIVE; + fs_edge = SSC_START_FALLING_RF; - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output - * on the SSC TK line. - */ - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, 1) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, 1) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); break; - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_A: /* - * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. + * DSP/PCM Mode A format * * Data is transferred on first BCLK after LRC pulse rising * edge.If stereo, the right channel data is contiguous with * the left channel data. */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + fslen = fslen_ext = 0; + + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); + break; default: @@ -785,6 +604,70 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->daifmt); return -EINVAL; } + + if (!atmel_ssc_cfs(ssc_p)) { + fslen = fslen_ext = 0; + rcmr_period = tcmr_period = 0; + fs_osync = SSC_FSOS_NONE; + } + + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); + + if (atmel_ssc_cbs(ssc_p)) { + /* + * SSC provides BCLK + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output + * on the SSC TK line. + */ + rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); + + tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS); + } else { + rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); + + tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE); + } + + rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING); + + tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING); + + rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, fs_osync) + | SSC_BF(RFMR_FSLEN, fslen) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, fs_osync) + | SSC_BF(TFMR_FSLEN, fslen) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + + if (fslen_ext && !ssc->pdata->has_fslen_ext) { + dev_err(dai->dev, "sample size %d is too large for SSC device\n", + bits); + return -EINVAL; + } + pr_debug("atmel_ssc_hw_params: " "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index ab7d5f98e759..befc2a3a05b0 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -392,11 +392,11 @@ static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk, } static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, - unsigned int bclk, unsigned int *mra) + unsigned int bclk, unsigned int *mra, + unsigned long *best_rate) { unsigned long clk_rate; unsigned long lcm_rate; - unsigned long best_rate = 0; unsigned long best_diff_rate = ~0; unsigned int sysclk; struct clk *best_clk = NULL; @@ -423,7 +423,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, (clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0)); clk_rate += lcm_rate) { ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate, - &best_clk, &best_rate, + &best_clk, best_rate, &best_diff_rate); if (ret) { dev_err(dev->dev, "gclk error for rate %lu: %d", @@ -437,7 +437,7 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, } ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate, - &best_clk, &best_rate, + &best_clk, best_rate, &best_diff_rate); if (ret) { dev_err(dev->dev, "pclk error for rate %lu: %d", @@ -459,33 +459,17 @@ static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n", best_clk == dev->pclk ? "pclk" : "gclk", - best_rate, best_diff_rate); - - /* set the rate */ - ret = clk_set_rate(best_clk, best_rate); - if (ret) { - dev_err(dev->dev, "unable to set rate %lu to %s: %d\n", - best_rate, best_clk == dev->pclk ? "PCLK" : "GCLK", - ret); - return ret; - } + *best_rate, best_diff_rate); /* Configure divisors */ if (dev->sysclk) - *mra |= MCHP_I2SMCC_MRA_IMCKDIV(best_rate / (2 * sysclk)); - *mra |= MCHP_I2SMCC_MRA_ISCKDIV(best_rate / (2 * bclk)); + *mra |= MCHP_I2SMCC_MRA_IMCKDIV(*best_rate / (2 * sysclk)); + *mra |= MCHP_I2SMCC_MRA_ISCKDIV(*best_rate / (2 * bclk)); - if (best_clk == dev->gclk) { + if (best_clk == dev->gclk) *mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK; - ret = clk_prepare(dev->gclk); - if (ret < 0) - dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); - else - dev->gclk_use = 1; - } else { + else *mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK; - dev->gclk_use = 0; - } return 0; } @@ -502,6 +486,7 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + unsigned long rate = 0; struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); u32 mra = 0; u32 mrb = 0; @@ -640,6 +625,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + if (set_divs) { + bclk_rate = frame_length * params_rate(params); + ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra, + &rate); + if (ret) { + dev_err(dev->dev, + "unable to configure the divisors: %d\n", ret); + return ret; + } + } + /* * If we are already running, the wanted setup must be * the same with the one that's currently ongoing @@ -656,19 +652,27 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, return 0; } - /* Save the number of channels to know what interrupts to enable */ - dev->channels = channels; - - if (set_divs) { - bclk_rate = frame_length * params_rate(params); - ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra); + if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) { + /* set the rate */ + ret = clk_set_rate(dev->gclk, rate); if (ret) { - dev_err(dev->dev, "unable to configure the divisors: %d\n", - ret); + dev_err(dev->dev, + "unable to set rate %lu to GCLK: %d\n", + rate, ret); + return ret; + } + + ret = clk_prepare(dev->gclk); + if (ret < 0) { + dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret); return ret; } + dev->gclk_use = 1; } + /* Save the number of channels to know what interrupts to enable */ + dev->channels = channels; + ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra); if (ret < 0) { if (dev->gclk_use) { diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 21e5f6aed7f3..08bc04e2da2a 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -363,7 +363,7 @@ static const struct snd_soc_component_driver au1xpsc_ac97_component = { static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; - struct resource *iores, *dmares; + struct resource *dmares; unsigned long sel; struct au1xpsc_audio_data *wd; @@ -374,8 +374,7 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev) mutex_init(&wd->lock); - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + wd->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wd->mmio)) return PTR_ERR(wd->mmio); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 076303f96b8c..767ce950d0da 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -291,7 +291,7 @@ static const struct snd_soc_component_driver au1xpsc_i2s_component = { static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) { - struct resource *iores, *dmares; + struct resource *dmares; unsigned long sel; struct au1xpsc_audio_data *wd; @@ -300,8 +300,7 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) if (!wd) return -ENOMEM; - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + wd->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wd->mmio)) return PTR_ERR(wd->mmio); diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 5ef80f3d446a..e6a12e271b07 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -828,7 +828,6 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) { struct bcm2835_i2s_dev *dev; int ret; - struct resource *mem; void __iomem *base; const __be32 *addr; dma_addr_t dma_base; @@ -848,8 +847,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) } /* Request ioarea */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 123ecf5479d7..8966b02844dc 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -639,7 +639,6 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; - int ret = 0; aio = cygnus_dai_get_dma_data(substream); dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); @@ -647,7 +646,7 @@ static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); - return ret; + return 0; } static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream) @@ -668,7 +667,6 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; unsigned long bufsize, periodsize; - int ret = 0; bool is_play; u32 start; struct ringbuf_regs *p_rbuf = NULL; @@ -693,7 +691,7 @@ static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start, periodsize, bufsize); - return ret; + return 0; } static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream) diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index b7c358b48d8d..2f9357d7da96 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1342,11 +1342,8 @@ static int cygnus_ssp_probe(struct platform_device *pdev) } cygaud->irq_num = platform_get_irq(pdev, 0); - if (cygaud->irq_num <= 0) { - dev_err(dev, "platform_get_irq failed\n"); - err = cygaud->irq_num; - return err; - } + if (cygaud->irq_num <= 0) + return cygaud->irq_num; err = audio_clk_init(pdev, cygaud); if (err) { diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index 84c967fcab6b..e21eaa1893d1 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c @@ -362,7 +362,6 @@ static const struct snd_soc_component_driver ep93xx_ac97_component = { static int ep93xx_ac97_probe(struct platform_device *pdev) { struct ep93xx_ac97_info *info; - struct resource *res; int irq; int ret; @@ -370,8 +369,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, res); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 0b4355e95f84..7d9cf67129d4 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -430,15 +430,13 @@ static const struct snd_soc_component_driver ep93xx_i2s_component = { static int ep93xx_i2s_probe(struct platform_device *pdev) { struct ep93xx_i2s_info *info; - struct resource *res; int err; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, res); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index e982722b448e..00b2c43d28a1 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -529,10 +529,6 @@ static const struct snd_kcontrol_new pm860x_snd_controls[] = { * DAPM Controls */ -/* PCM Switch / PCM Interface */ -static const struct snd_kcontrol_new pcm_switch_controls = - SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0); - /* AUX1 Switch */ static const struct snd_kcontrol_new aux1_switch_controls = SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0); @@ -549,17 +545,6 @@ static const struct snd_kcontrol_new lepa_switch_controls = static const struct snd_kcontrol_new repa_switch_controls = SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0); -/* PCM Mux / Mux7 */ -static const char *aif1_text[] = { - "PCM L", "PCM R", -}; - -static SOC_ENUM_SINGLE_DECL(aif1_enum, - PM860X_PCM_IFACE_3, 6, aif1_text); - -static const struct snd_kcontrol_new aif1_mux = - SOC_DAPM_ENUM("PCM Mux", aif1_enum); - /* I2S Mux / Mux9 */ static const char *i2s_din_text[] = { "DIN", "DIN1", diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9f89a5346299..89238343e34d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -70,10 +70,12 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS43130 if I2C select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI select SND_SOC_CS4349 if I2C + select SND_SOC_CS47L15 if MFD_CS47L15 select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CS47L35 if MFD_CS47L35 select SND_SOC_CS47L85 if MFD_CS47L85 select SND_SOC_CS47L90 if MFD_CS47L90 + select SND_SOC_CS47L92 if MFD_CS47L92 select SND_SOC_CS53L30 if I2C select SND_SOC_CX20442 if TTY select SND_SOC_CX2072X if I2C @@ -197,6 +199,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TS3A227E if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_TWL6040 if TWL6040_CORE + select SND_SOC_UDA1334 if GPIOLIB select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WCD9335 if SLIMBUS @@ -581,6 +584,9 @@ config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" depends on I2C +config SND_SOC_CS47L15 + tristate + config SND_SOC_CS47L24 tristate @@ -593,6 +599,9 @@ config SND_SOC_CS47L85 config SND_SOC_CS47L90 tristate +config SND_SOC_CS47L92 + tristate + # Cirrus Logic Quad-Channel ADC config SND_SOC_CS53L30 tristate "Cirrus Logic CS53L30 CODEC" @@ -722,12 +731,16 @@ config SND_SOC_LOCHNAGAR_SC config SND_SOC_MADERA tristate + default y if SND_SOC_CS47L15=y default y if SND_SOC_CS47L35=y default y if SND_SOC_CS47L85=y default y if SND_SOC_CS47L90=y + default y if SND_SOC_CS47L92=y + default m if SND_SOC_CS47L15=m default m if SND_SOC_CS47L35=m default m if SND_SOC_CS47L85=m default m if SND_SOC_CS47L90=m + default m if SND_SOC_CS47L92=m config SND_SOC_MAX98088 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" @@ -1195,6 +1208,14 @@ config SND_SOC_TWL4030 config SND_SOC_TWL6040 tristate +config SND_SOC_UDA1334 + tristate "NXP UDA1334 DAC" + depends on GPIOLIB + help + The UDA1334 is an NXP audio codec, supports the I2S-bus data format + and has basic features such as de-emphasis (at 44.1 kHz sampling + rate) and mute. + config SND_SOC_UDA134X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5b4bb8cf4325..c498373dcc5f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -64,10 +64,12 @@ snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs43130-objs := cs43130.o snd-soc-cs4341-objs := cs4341.o snd-soc-cs4349-objs := cs4349.o +snd-soc-cs47l15-objs := cs47l15.o snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs47l35-objs := cs47l35.o snd-soc-cs47l85-objs := cs47l85.o snd-soc-cs47l90-objs := cs47l90.o +snd-soc-cs47l92-objs := cs47l92.o snd-soc-cs53l30-objs := cs53l30.o snd-soc-cx20442-objs := cx20442.o snd-soc-cx2072x-objs := cx2072x.o @@ -210,6 +212,7 @@ snd-soc-tscs454-objs := tscs454.o snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o +snd-soc-uda1334-objs := uda1334.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o @@ -346,9 +349,11 @@ obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o +obj-$(CONFIG_SND_SOC_CS47L15) += snd-soc-cs47l15.o obj-$(CONFIG_SND_SOC_CS47L35) += snd-soc-cs47l35.o obj-$(CONFIG_SND_SOC_CS47L85) += snd-soc-cs47l85.o obj-$(CONFIG_SND_SOC_CS47L90) += snd-soc-cs47l90.o +obj-$(CONFIG_SND_SOC_CS47L92) += snd-soc-cs47l92.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o @@ -490,6 +495,7 @@ obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o +obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 80dab5df9633..980e024a5720 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -413,15 +413,10 @@ static struct snd_soc_dai_driver ad193x_no_adc_dai = { .ops = &ad193x_dai_ops, }; -struct ad193x_reg_default { - unsigned int reg; - unsigned int val; -}; - /* codec register values to set after reset */ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { - const struct ad193x_reg_default reg_init[] = { + static const struct reg_sequence reg_init[] = { { 0, 0x99 }, /* PLL_CLK_CTRL0: pll input: mclki/xi 12.288Mhz */ { 1, 0x04 }, /* PLL_CLK_CTRL1: no on-chip Vref */ { 2, 0x40 }, /* DAC_CTRL0: TDM mode */ @@ -437,21 +432,17 @@ static void ad193x_reg_default_init(struct ad193x_priv *ad193x) { 12, 0x00 }, /* DAC_L4_VOL: no attenuation */ { 13, 0x00 }, /* DAC_R4_VOL: no attenuation */ }; - const struct ad193x_reg_default reg_adc_init[] = { + static const struct reg_sequence reg_adc_init[] = { { 14, 0x03 }, /* ADC_CTRL0: high-pass filter enable */ { 15, 0x43 }, /* ADC_CTRL1: sata delay=1, adc aux mode */ { 16, 0x00 }, /* ADC_CTRL2: reset */ }; - int i; - for (i = 0; i < ARRAY_SIZE(reg_init); i++) - regmap_write(ad193x->regmap, reg_init[i].reg, reg_init[i].val); + regmap_multi_reg_write(ad193x->regmap, reg_init, ARRAY_SIZE(reg_init)); if (ad193x_has_adc(ad193x)) { - for (i = 0; i < ARRAY_SIZE(reg_adc_init); i++) { - regmap_write(ad193x->regmap, reg_adc_init[i].reg, - reg_adc_init[i].val); - } + regmap_multi_reg_write(ad193x->regmap, reg_adc_init, + ARRAY_SIZE(reg_adc_init)); } } diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 1d03a1348162..04b86a51e055 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -334,7 +334,7 @@ static struct cs4271_clk_cfg cs4271_clk_tab[] = { {0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2}, }; -#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) +#define CS4271_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) static int cs4271_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, @@ -383,13 +383,13 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream, val = CS4271_MODE1_MODE_4X; ratio = cs4271->mclk / cs4271->rate; - for (i = 0; i < CS4171_NR_RATIOS; i++) + for (i = 0; i < CS4271_NR_RATIOS; i++) if ((cs4271_clk_tab[i].master == cs4271->master) && (cs4271_clk_tab[i].speed_mode == val) && (cs4271_clk_tab[i].ratio == ratio)) break; - if (i == CS4171_NR_RATIOS) { + if (i == CS4271_NR_RATIOS) { dev_err(component->dev, "Invalid sample rate\n"); return -EINVAL; } diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index b4d7627525f9..ac569ab3d30f 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -199,14 +199,6 @@ static const struct soc_enum beep_bass_enum = SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1, ARRAY_SIZE(beep_bass_text), beep_bass_text); -static const char * const adc_swap_text[] = { - "None", "A+B/2", "A-B/2", "Swap" -}; - -static const struct soc_enum adc_swap_enum = - SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3, - ARRAY_SIZE(adc_swap_text), adc_swap_text); - static const char * const pgaa_mux_text[] = { "AIN1A", "AIN2A", "AIN3A"}; diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index a81739367109..36089f8bcf0a 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -273,12 +273,6 @@ static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, CS42L73_MIXERCTL, 4, cs42l73_spo_mixer_text); -static const struct snd_kcontrol_new vsp_output_mux = - SOC_DAPM_ENUM("Route", vsp_output_mux_enum); - -static const struct snd_kcontrol_new xsp_output_mux = - SOC_DAPM_ENUM("Route", xsp_output_mux_enum); - static const struct snd_kcontrol_new hp_amp_ctl = SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1); diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 5b049fcdba20..94b1adb088fd 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -684,6 +684,8 @@ static int cs42xx8_runtime_suspend(struct device *dev) #endif const struct dev_pm_ops cs42xx8_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) }; EXPORT_SYMBOL_GPL(cs42xx8_pm); diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c new file mode 100644 index 000000000000..ece1276f38eb --- /dev/null +++ b/sound/soc/codecs/cs47l15.c @@ -0,0 +1,1490 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC Audio driver for CS47L15 codec +// +// Copyright (C) 2016-2019 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include <linux/irqchip/irq-madera.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" +#include "wm_adsp.h" + +#define CS47L15_NUM_ADSP 1 +#define CS47L15_MONO_OUTPUTS 1 + +/* Mid-mode registers */ +#define CS47L15_ADC_INT_BIAS_MASK 0x3800 +#define CS47L15_ADC_INT_BIAS_SHIFT 11 +#define CS47L15_PGA_BIAS_SEL_MASK 0x03 +#define CS47L15_PGA_BIAS_SEL_SHIFT 0 + +#define DRV_NAME "cs47l15-codec" + +struct cs47l15 { + struct madera_priv core; + struct madera_fll fll[2]; + + bool in1_lp_mode; +}; + +static const struct wm_adsp_region cs47l15_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x080000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, + { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, + { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, +}; + +static const char * const cs47l15_outdemux_texts[] = { + "HPOUT", + "EPOUT", +}; + +static SOC_ENUM_SINGLE_DECL(cs47l15_outdemux_enum, SND_SOC_NOPM, 0, + cs47l15_outdemux_texts); + +static const struct snd_kcontrol_new cs47l15_outdemux = + SOC_DAPM_ENUM_EXT("HPOUT1 Demux", cs47l15_outdemux_enum, + madera_out1_demux_get, madera_out1_demux_put); + +static int cs47l15_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + unsigned int freq; + int ret; + + ret = regmap_read(madera->regmap, MADERA_DSP_CLOCK_2, &freq); + if (ret != 0) { + dev_err(madera->dev, + "Failed to read MADERA_DSP_CLOCK_2: %d\n", ret); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = madera_set_adsp_clk(&cs47l15->core, w->shift, freq); + if (ret) + return ret; + break; + default: + break; + } + + return wm_adsp_early_event(w, kcontrol, event); +} + +#define CS47L15_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG SPKOUTL Switch", base, 6, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) + +static int cs47l15_in1_adc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !!cs47l15->in1_lp_mode; + + return 0; +} + +static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + switch (ucontrol->value.integer.value[0]) { + case 0: + /* Set IN1 to normal mode */ + snd_soc_component_update_bits(component, MADERA_DMIC1L_CONTROL, + MADERA_IN1_OSR_MASK, + 5 << MADERA_IN1_OSR_SHIFT); + snd_soc_component_update_bits(component, CS47L15_ADC_INT_BIAS, + CS47L15_ADC_INT_BIAS_MASK, + 4 << CS47L15_ADC_INT_BIAS_SHIFT); + snd_soc_component_update_bits(component, CS47L15_PGA_BIAS_SEL, + CS47L15_PGA_BIAS_SEL_MASK, 0); + cs47l15->in1_lp_mode = false; + break; + default: + /* Set IN1 to LP mode */ + snd_soc_component_update_bits(component, MADERA_DMIC1L_CONTROL, + MADERA_IN1_OSR_MASK, + 4 << MADERA_IN1_OSR_SHIFT); + snd_soc_component_update_bits(component, CS47L15_ADC_INT_BIAS, + CS47L15_ADC_INT_BIAS_MASK, + 1 << CS47L15_ADC_INT_BIAS_SHIFT); + snd_soc_component_update_bits(component, CS47L15_PGA_BIAS_SEL, + CS47L15_PGA_BIAS_SEL_MASK, + 3 << CS47L15_PGA_BIAS_SEL_SHIFT); + cs47l15->in1_lp_mode = true; + break; + } + + return 0; +} + +static const struct snd_kcontrol_new cs47l15_snd_controls[] = { +SOC_ENUM("IN1 OSR", madera_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", madera_in_dmic_osr[1]), + +SOC_SINGLE_RANGE_TLV("IN1L Volume", MADERA_IN1L_CONTROL, + MADERA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN1R Volume", MADERA_IN1R_CONTROL, + MADERA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), + +SOC_ENUM("IN HPF Cutoff Frequency", madera_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", MADERA_IN1L_CONTROL, MADERA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", MADERA_IN1R_CONTROL, MADERA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", MADERA_IN2L_CONTROL, MADERA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", MADERA_IN2R_CONTROL, MADERA_IN2R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), + +SOC_ENUM("Input Ramp Up", madera_in_vi_ramp), +SOC_ENUM("Input Ramp Down", madera_in_vd_ramp), + +MADERA_MIXER_CONTROLS("EQ1", MADERA_EQ1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ2", MADERA_EQ2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ3", MADERA_EQ3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ4", MADERA_EQ4MIX_INPUT_1_SOURCE), + +MADERA_EQ_CONTROL("EQ1 Coefficients", MADERA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", MADERA_EQ1_1, MADERA_EQ1_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", MADERA_EQ1_1, MADERA_EQ1_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", MADERA_EQ1_1, MADERA_EQ1_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", MADERA_EQ1_2, MADERA_EQ1_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", MADERA_EQ1_2, MADERA_EQ1_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ2 Coefficients", MADERA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", MADERA_EQ2_1, MADERA_EQ2_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", MADERA_EQ2_1, MADERA_EQ2_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", MADERA_EQ2_1, MADERA_EQ2_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", MADERA_EQ2_2, MADERA_EQ2_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", MADERA_EQ2_2, MADERA_EQ2_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ3 Coefficients", MADERA_EQ3_2), +SOC_SINGLE_TLV("EQ3 B1 Volume", MADERA_EQ3_1, MADERA_EQ3_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B2 Volume", MADERA_EQ3_1, MADERA_EQ3_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B3 Volume", MADERA_EQ3_1, MADERA_EQ3_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B4 Volume", MADERA_EQ3_2, MADERA_EQ3_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B5 Volume", MADERA_EQ3_2, MADERA_EQ3_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ4 Coefficients", MADERA_EQ4_2), +SOC_SINGLE_TLV("EQ4 B1 Volume", MADERA_EQ4_1, MADERA_EQ4_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B2 Volume", MADERA_EQ4_1, MADERA_EQ4_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B3 Volume", MADERA_EQ4_1, MADERA_EQ4_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B4 Volume", MADERA_EQ4_2, MADERA_EQ4_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B5 Volume", MADERA_EQ4_2, MADERA_EQ4_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_MIXER_CONTROLS("DRC1L", MADERA_DRC1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC1R", MADERA_DRC1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2L", MADERA_DRC2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2R", MADERA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", MADERA_DRC1_CTRL1, 5, + MADERA_DRC1R_ENA | MADERA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", MADERA_DRC2_CTRL1, 5, + MADERA_DRC2R_ENA | MADERA_DRC2L_ENA), + +MADERA_MIXER_CONTROLS("LHPF1", MADERA_HPLP1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF2", MADERA_HPLP2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF3", MADERA_HPLP3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF4", MADERA_HPLP4MIX_INPUT_1_SOURCE), + +MADERA_LHPF_CONTROL("LHPF1 Coefficients", MADERA_HPLPF1_2), +MADERA_LHPF_CONTROL("LHPF2 Coefficients", MADERA_HPLPF2_2), +MADERA_LHPF_CONTROL("LHPF3 Coefficients", MADERA_HPLPF3_2), +MADERA_LHPF_CONTROL("LHPF4 Coefficients", MADERA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", madera_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", madera_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", madera_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", madera_lhpf4_mode), + +MADERA_RATE_ENUM("ISRC1 FSL", madera_isrc_fsl[0]), +MADERA_RATE_ENUM("ISRC2 FSL", madera_isrc_fsl[1]), +MADERA_RATE_ENUM("ISRC1 FSH", madera_isrc_fsh[0]), +MADERA_RATE_ENUM("ISRC2 FSH", madera_isrc_fsh[1]), + +WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + +MADERA_MIXER_CONTROLS("DSP1L", MADERA_DSP1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DSP1R", MADERA_DSP1RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, madera_noise_tlv), + +MADERA_MIXER_CONTROLS("HPOUT1L", MADERA_OUT1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT1R", MADERA_OUT1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKOUTL", MADERA_OUT4LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1L", MADERA_OUT5LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1R", MADERA_OUT5RMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", MADERA_HP1_SHORT_CIRCUIT_CTRL, + MADERA_HP1_SC_ENA_SHIFT, 1, 0), + +SOC_SINGLE("SPKDAT1 High Performance Switch", MADERA_OUTPUT_PATH_CONFIG_5L, + MADERA_OUT5_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_SINGLE("Speaker Digital Switch", MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_OUT4L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("SPKDAT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("Speaker Digital Volume", MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_OUT4L_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), + +SOC_DOUBLE("SPKDAT1 Switch", MADERA_PDM_SPK1_CTRL_1, MADERA_SPK1L_MUTE_SHIFT, + MADERA_SPK1R_MUTE_SHIFT, 1, 1), + +SOC_ENUM("Output Ramp Up", madera_out_vi_ramp), +SOC_ENUM("Output Ramp Down", madera_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_THR_SHIFT, 7, 1, madera_ng_tlv), +SOC_ENUM("Noise Gate Hold", madera_ng_hold), + +SOC_SINGLE_BOOL_EXT("IN1 LP Mode Switch", 0, + cs47l15_in1_adc_get, cs47l15_in1_adc_put), + +CS47L15_NG_SRC("HPOUT1L", MADERA_NOISE_GATE_SELECT_1L), +CS47L15_NG_SRC("HPOUT1R", MADERA_NOISE_GATE_SELECT_1R), +CS47L15_NG_SRC("SPKOUTL", MADERA_NOISE_GATE_SELECT_4L), +CS47L15_NG_SRC("SPKDAT1L", MADERA_NOISE_GATE_SELECT_5L), +CS47L15_NG_SRC("SPKDAT1R", MADERA_NOISE_GATE_SELECT_5R), + +MADERA_MIXER_CONTROLS("AIF1TX1", MADERA_AIF1TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX2", MADERA_AIF1TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX3", MADERA_AIF1TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX4", MADERA_AIF1TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX5", MADERA_AIF1TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX6", MADERA_AIF1TX6MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF2TX1", MADERA_AIF2TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX2", MADERA_AIF2TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX3", MADERA_AIF2TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX4", MADERA_AIF2TX4MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF3TX1", MADERA_AIF3TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX2", MADERA_AIF3TX2MIX_INPUT_1_SOURCE), + +MADERA_GAINMUX_CONTROLS("SPDIF1TX1", MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE), +MADERA_GAINMUX_CONTROLS("SPDIF1TX2", MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE), + +WM_ADSP_FW_CONTROL("DSP1", 0), +}; + +MADERA_MIXER_ENUMS(EQ1, MADERA_EQ1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ2, MADERA_EQ2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ3, MADERA_EQ3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ4, MADERA_EQ4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DRC1L, MADERA_DRC1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC1R, MADERA_DRC1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2L, MADERA_DRC2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2R, MADERA_DRC2RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(LHPF1, MADERA_HPLP1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF2, MADERA_HPLP2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF3, MADERA_HPLP3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF4, MADERA_HPLP4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DSP1L, MADERA_DSP1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DSP1R, MADERA_DSP1RMIX_INPUT_1_SOURCE); +MADERA_DSP_AUX_ENUMS(DSP1, MADERA_DSP1AUX1MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(PWM1, MADERA_PWM1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(PWM2, MADERA_PWM2MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(OUT1L, MADERA_OUT1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT1R, MADERA_OUT1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKOUTL, MADERA_OUT4LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1L, MADERA_OUT5LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1R, MADERA_OUT5RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF1TX1, MADERA_AIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX2, MADERA_AIF1TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX3, MADERA_AIF1TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX4, MADERA_AIF1TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX5, MADERA_AIF1TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX6, MADERA_AIF1TX6MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF2TX1, MADERA_AIF2TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX2, MADERA_AIF2TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX3, MADERA_AIF2TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX4, MADERA_AIF2TX4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF3TX1, MADERA_AIF3TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX2, MADERA_AIF3TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(SPD1TX1, MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(SPD1TX2, MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1INT1, MADERA_ISRC1INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT2, MADERA_ISRC1INT2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT3, MADERA_ISRC1INT3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT4, MADERA_ISRC1INT4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1DEC1, MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC2, MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC3, MADERA_ISRC1DEC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC4, MADERA_ISRC1DEC4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2INT1, MADERA_ISRC2INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT2, MADERA_ISRC2INT2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT3, MADERA_ISRC2INT3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT4, MADERA_ISRC2INT4MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2DEC1, MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC2, MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC3, MADERA_ISRC2DEC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC4, MADERA_ISRC2DEC4MIX_INPUT_1_SOURCE); + +static const char * const cs47l15_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "SPKOUTL", "SPKDAT1L", "SPKDAT1R", +}; + +static const unsigned int cs47l15_aec_loopback_values[] = { + 0, 1, 6, 8, 9, +}; + +static const struct soc_enum cs47l15_aec1_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l15_aec_loopback_texts), + cs47l15_aec_loopback_texts, + cs47l15_aec_loopback_values); + +static const struct soc_enum cs47l15_aec2_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_2, + MADERA_AEC2_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l15_aec_loopback_texts), + cs47l15_aec_loopback_texts, + cs47l15_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l15_aec_loopback_mux[] = { + SOC_DAPM_ENUM("AEC1 Loopback", cs47l15_aec1_loopback), + SOC_DAPM_ENUM("AEC2 Loopback", cs47l15_aec2_loopback), +}; + +static const struct snd_soc_dapm_widget cs47l15_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, + 0, madera_sysclk_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, + MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, + MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", MADERA_MIC_BIAS_CTRL_1, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1A", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1B", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1B_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1C", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1C_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("FXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_FX, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC2CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("OUTCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_OUT, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SPDCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SPD, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DSP1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF1TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF2TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF3TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF3, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("PWMCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_PWM, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), + +SND_SOC_DAPM_INPUT("IN1ALN"), +SND_SOC_DAPM_INPUT("IN1ALP"), +SND_SOC_DAPM_INPUT("IN1BLN"), +SND_SOC_DAPM_INPUT("IN1BLP"), +SND_SOC_DAPM_INPUT("IN1ARN"), +SND_SOC_DAPM_INPUT("IN1ARP"), +SND_SOC_DAPM_INPUT("IN1BRN"), +SND_SOC_DAPM_INPUT("IN1BRP"), +SND_SOC_DAPM_INPUT("IN2N"), +SND_SOC_DAPM_INPUT("IN2P"), +SND_SOC_DAPM_INPUT("SPKRXDAT"), + +SND_SOC_DAPM_MUX("IN1L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[0]), +SND_SOC_DAPM_MUX("IN1R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[1]), + +SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), +SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), + +SND_SOC_DAPM_MUX("IN2L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), +SND_SOC_DAPM_MUX("IN2R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_OUTPUT("DSP Trigger Out"), + +SND_SOC_DAPM_DEMUX("HPOUT1 Demux", SND_SOC_NOPM, 0, 0, &cs47l15_outdemux), + +SND_SOC_DAPM_PGA("PWM1 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + MADERA_OUT1L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + MADERA_OUT1R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, + MADERA_OUT4L_ENA_SHIFT, 0, NULL, 0, madera_spk_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_PGA("SPD1TX1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL1_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPD1TX2", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL2_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPD1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_ENA_SHIFT, 0, NULL, 0), + +/* + * mux_in widgets : arranged in the order of sources + * specified in MADERA_MIXER_INPUT_ROUTES + */ + +SND_SOC_DAPM_PGA("Noise Generator", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", MADERA_TONE_GENERATOR_1, + MADERA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", MADERA_TONE_GENERATOR_1, + MADERA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_MUX("AEC1 Loopback", MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_ENA_SHIFT, 0, + &cs47l15_aec_loopback_mux[0]), +SND_SOC_DAPM_MUX("AEC2 Loopback", MADERA_DAC_AEC_CONTROL_2, + MADERA_AEC2_LOOPBACK_ENA_SHIFT, 0, + &cs47l15_aec_loopback_mux[1]), + +SND_SOC_DAPM_PGA_E("IN1L", MADERA_INPUT_ENABLES, MADERA_IN1L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R", MADERA_INPUT_ENABLES, MADERA_IN1R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L", MADERA_INPUT_ENABLES, MADERA_IN2L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R", MADERA_INPUT_ENABLES, MADERA_IN2R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA("EQ1", MADERA_EQ1_1, MADERA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", MADERA_EQ2_1, MADERA_EQ2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ3", MADERA_EQ3_1, MADERA_EQ3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ4", MADERA_EQ4_1, MADERA_EQ4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", MADERA_DRC1_CTRL1, MADERA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", MADERA_DRC1_CTRL1, MADERA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", MADERA_DRC2_CTRL1, MADERA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", MADERA_DRC2_CTRL1, MADERA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", MADERA_HPLPF1_1, MADERA_LHPF1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", MADERA_HPLPF2_1, MADERA_LHPF2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", MADERA_HPLPF3_1, MADERA_LHPF3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", MADERA_HPLPF4_1, MADERA_LHPF4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC3", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC4", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1INT1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT3", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT4", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC3", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC4", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT3", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT4", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT4_ENA_SHIFT, 0, NULL, 0), + +WM_ADSP2("DSP1", 0, cs47l15_adsp_power_ev), + +/* end of ordered widget list */ + +MADERA_MIXER_WIDGETS(EQ1, "EQ1"), +MADERA_MIXER_WIDGETS(EQ2, "EQ2"), +MADERA_MIXER_WIDGETS(EQ3, "EQ3"), +MADERA_MIXER_WIDGETS(EQ4, "EQ4"), + +MADERA_MIXER_WIDGETS(DRC1L, "DRC1L"), +MADERA_MIXER_WIDGETS(DRC1R, "DRC1R"), +MADERA_MIXER_WIDGETS(DRC2L, "DRC2L"), +MADERA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +SND_SOC_DAPM_SWITCH("DRC1 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[0]), +SND_SOC_DAPM_SWITCH("DRC2 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[1]), + +MADERA_MIXER_WIDGETS(LHPF1, "LHPF1"), +MADERA_MIXER_WIDGETS(LHPF2, "LHPF2"), +MADERA_MIXER_WIDGETS(LHPF3, "LHPF3"), +MADERA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +MADERA_MIXER_WIDGETS(PWM1, "PWM1"), +MADERA_MIXER_WIDGETS(PWM2, "PWM2"), + +MADERA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +MADERA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +MADERA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"), +MADERA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), +MADERA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), + +MADERA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +MADERA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +MADERA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +MADERA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +MADERA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +MADERA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), + +MADERA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +MADERA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +MADERA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +MADERA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), + +MADERA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +MADERA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), + +MADERA_MUX_WIDGETS(SPD1TX1, "SPDIF1TX1"), +MADERA_MUX_WIDGETS(SPD1TX2, "SPDIF1TX2"), + +MADERA_DSP_WIDGETS(DSP1, "DSP1"), + +SND_SOC_DAPM_SWITCH("DSP1 Trigger Output", SND_SOC_NOPM, 0, 0, + &madera_dsp_trigger_output_mux[0]), + +MADERA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +MADERA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), +MADERA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"), +MADERA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"), + +MADERA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +MADERA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), +MADERA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"), +MADERA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"), + +MADERA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +MADERA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), +MADERA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"), +MADERA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"), + +MADERA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +MADERA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), +MADERA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"), +MADERA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"), + +SND_SOC_DAPM_OUTPUT("HPOUTL"), +SND_SOC_DAPM_OUTPUT("HPOUTR"), +SND_SOC_DAPM_OUTPUT("EPOUTP"), +SND_SOC_DAPM_OUTPUT("EPOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTP"), +SND_SOC_DAPM_OUTPUT("SPKDAT1L"), +SND_SOC_DAPM_OUTPUT("SPKDAT1R"), +SND_SOC_DAPM_OUTPUT("SPDIF1"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define MADERA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC1", "AEC1 Loopback" }, \ + { name, "AEC2", "AEC2 Loopback" }, \ + { name, "IN1L", "IN1L" }, \ + { name, "IN1R", "IN1R" }, \ + { name, "IN2L", "IN2L" }, \ + { name, "IN2R", "IN2R" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "EQ3", "EQ3" }, \ + { name, "EQ4", "EQ4" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1DEC3", "ISRC1DEC3" }, \ + { name, "ISRC1DEC4", "ISRC1DEC4" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC1INT3", "ISRC1INT3" }, \ + { name, "ISRC1INT4", "ISRC1INT4" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2DEC3", "ISRC2DEC3" }, \ + { name, "ISRC2DEC4", "ISRC2DEC4" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "ISRC2INT3", "ISRC2INT3" }, \ + { name, "ISRC2INT4", "ISRC2INT4" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" } + +static const struct snd_soc_dapm_route cs47l15_dapm_routes[] = { + /* Internal clock domains */ + { "EQ1", NULL, "FXCLK" }, + { "EQ2", NULL, "FXCLK" }, + { "EQ3", NULL, "FXCLK" }, + { "EQ4", NULL, "FXCLK" }, + { "DRC1L", NULL, "FXCLK" }, + { "DRC1R", NULL, "FXCLK" }, + { "DRC2L", NULL, "FXCLK" }, + { "DRC2R", NULL, "FXCLK" }, + { "LHPF1", NULL, "FXCLK" }, + { "LHPF2", NULL, "FXCLK" }, + { "LHPF3", NULL, "FXCLK" }, + { "LHPF4", NULL, "FXCLK" }, + { "PWM1 Mixer", NULL, "PWMCLK" }, + { "PWM2 Mixer", NULL, "PWMCLK" }, + { "OUT1L", NULL, "OUTCLK" }, + { "OUT1R", NULL, "OUTCLK" }, + { "OUT4L", NULL, "OUTCLK" }, + { "OUT5L", NULL, "OUTCLK" }, + { "OUT5R", NULL, "OUTCLK" }, + { "AIF1TX1", NULL, "AIF1TXCLK" }, + { "AIF1TX2", NULL, "AIF1TXCLK" }, + { "AIF1TX3", NULL, "AIF1TXCLK" }, + { "AIF1TX4", NULL, "AIF1TXCLK" }, + { "AIF1TX5", NULL, "AIF1TXCLK" }, + { "AIF1TX6", NULL, "AIF1TXCLK" }, + { "AIF2TX1", NULL, "AIF2TXCLK" }, + { "AIF2TX2", NULL, "AIF2TXCLK" }, + { "AIF2TX3", NULL, "AIF2TXCLK" }, + { "AIF2TX4", NULL, "AIF2TXCLK" }, + { "AIF3TX1", NULL, "AIF3TXCLK" }, + { "AIF3TX2", NULL, "AIF3TXCLK" }, + { "SPD1TX1", NULL, "SPDCLK" }, + { "SPD1TX2", NULL, "SPDCLK" }, + { "DSP1", NULL, "DSP1CLK" }, + { "ISRC1DEC1", NULL, "ISRC1CLK" }, + { "ISRC1DEC2", NULL, "ISRC1CLK" }, + { "ISRC1DEC3", NULL, "ISRC1CLK" }, + { "ISRC1DEC4", NULL, "ISRC1CLK" }, + { "ISRC1INT1", NULL, "ISRC1CLK" }, + { "ISRC1INT2", NULL, "ISRC1CLK" }, + { "ISRC1INT3", NULL, "ISRC1CLK" }, + { "ISRC1INT4", NULL, "ISRC1CLK" }, + { "ISRC2DEC1", NULL, "ISRC2CLK" }, + { "ISRC2DEC2", NULL, "ISRC2CLK" }, + { "ISRC2DEC3", NULL, "ISRC2CLK" }, + { "ISRC2DEC4", NULL, "ISRC2CLK" }, + { "ISRC2INT1", NULL, "ISRC2CLK" }, + { "ISRC2INT2", NULL, "ISRC2CLK" }, + { "ISRC2INT3", NULL, "ISRC2CLK" }, + { "ISRC2INT4", NULL, "ISRC2CLK" }, + + { "OUT1L", NULL, "CPVDD1" }, + { "OUT1R", NULL, "CPVDD1" }, + { "OUT4L", NULL, "SPKVDD" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT4L", NULL, "SYSCLK" }, + { "OUT5L", NULL, "SYSCLK" }, + { "OUT5R", NULL, "SYSCLK" }, + + { "SPD1", NULL, "SYSCLK" }, + { "SPD1", NULL, "SPD1TX1" }, + { "SPD1", NULL, "SPD1TX2" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + + { "MICBIAS1A", NULL, "MICBIAS1" }, + { "MICBIAS1B", NULL, "MICBIAS1" }, + { "MICBIAS1C", NULL, "MICBIAS1" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + + { "Audio Trace DSP", NULL, "DSP1" }, + + { "IN1L Analog Mux", "A", "IN1ALN" }, + { "IN1L Analog Mux", "A", "IN1ALP" }, + { "IN1L Analog Mux", "B", "IN1BLN" }, + { "IN1L Analog Mux", "B", "IN1BLP" }, + { "IN1R Analog Mux", "A", "IN1ARN" }, + { "IN1R Analog Mux", "A", "IN1ARP" }, + { "IN1R Analog Mux", "B", "IN1BRN" }, + { "IN1R Analog Mux", "B", "IN1BRP" }, + + { "IN1L Mode", "Analog", "IN1L Analog Mux" }, + { "IN1R Mode", "Analog", "IN1R Analog Mux" }, + + { "IN1L Mode", "Digital", "IN1ALN" }, + { "IN1L Mode", "Digital", "IN1ALP" }, + { "IN1R Mode", "Digital", "IN1ALN" }, + { "IN1R Mode", "Digital", "IN1ALP" }, + + { "IN1L", NULL, "IN1L Mode" }, + { "IN1R", NULL, "IN1R Mode" }, + + { "IN2L Mode", "Analog", "IN2N" }, + { "IN2L Mode", "Analog", "IN2P" }, + + { "IN2L Mode", "Digital", "SPKRXDAT" }, + { "IN2R Mode", "Digital", "SPKRXDAT" }, + + { "IN2L", NULL, "IN2L Mode" }, + { "IN2R", NULL, "IN2R Mode" }, + + MADERA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + MADERA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + MADERA_MIXER_ROUTES("OUT4L", "SPKOUTL"), + MADERA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), + MADERA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), + + MADERA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + MADERA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + MADERA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + MADERA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + MADERA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + MADERA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + MADERA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + MADERA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + + MADERA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + MADERA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + MADERA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + MADERA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + + MADERA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + MADERA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + + MADERA_MUX_ROUTES("SPD1TX1", "SPDIF1TX1"), + MADERA_MUX_ROUTES("SPD1TX2", "SPDIF1TX2"), + + MADERA_MIXER_ROUTES("EQ1", "EQ1"), + MADERA_MIXER_ROUTES("EQ2", "EQ2"), + MADERA_MIXER_ROUTES("EQ3", "EQ3"), + MADERA_MIXER_ROUTES("EQ4", "EQ4"), + + MADERA_MIXER_ROUTES("DRC1L", "DRC1L"), + MADERA_MIXER_ROUTES("DRC1R", "DRC1R"), + MADERA_MIXER_ROUTES("DRC2L", "DRC2L"), + MADERA_MIXER_ROUTES("DRC2R", "DRC2R"), + + MADERA_MIXER_ROUTES("LHPF1", "LHPF1"), + MADERA_MIXER_ROUTES("LHPF2", "LHPF2"), + MADERA_MIXER_ROUTES("LHPF3", "LHPF3"), + MADERA_MIXER_ROUTES("LHPF4", "LHPF4"), + + MADERA_DSP_ROUTES("DSP1"), + + { "DSP Trigger Out", NULL, "DSP1 Trigger Output" }, + + { "DSP1 Trigger Output", "Switch", "DSP1" }, + + MADERA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + MADERA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + MADERA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"), + MADERA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"), + + MADERA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + MADERA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + MADERA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"), + MADERA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"), + + MADERA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + MADERA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + MADERA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"), + MADERA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"), + + MADERA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + MADERA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + MADERA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"), + MADERA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"), + + { "AEC1 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC1 Loopback", "HPOUT1R", "OUT1R" }, + { "AEC2 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC2 Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1 Demux", NULL, "OUT1L" }, + { "HPOUT1 Demux", NULL, "OUT1R" }, + { "HPOUTL", "HPOUT", "HPOUT1 Demux" }, + { "HPOUTR", "HPOUT", "HPOUT1 Demux" }, + { "EPOUTP", "EPOUT", "HPOUT1 Demux" }, + { "EPOUTN", "EPOUT", "HPOUT1 Demux" }, + + { "AEC1 Loopback", "SPKOUTL", "OUT4L" }, + { "AEC2 Loopback", "SPKOUTL", "OUT4L" }, + { "SPKOUTN", NULL, "OUT4L" }, + { "SPKOUTP", NULL, "OUT4L" }, + + { "AEC1 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC1 Loopback", "SPKDAT1R", "OUT5R" }, + { "AEC2 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC2 Loopback", "SPKDAT1R", "OUT5R" }, + { "SPKDAT1L", NULL, "OUT5L" }, + { "SPKDAT1R", NULL, "OUT5R" }, + + { "SPDIF1", NULL, "SPD1" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1 Activity Output" }, + { "DRC2 Signal Activity", NULL, "DRC2 Activity Output" }, + { "DRC1 Activity Output", "Switch", "DRC1L" }, + { "DRC1 Activity Output", "Switch", "DRC1R" }, + { "DRC2 Activity Output", "Switch", "DRC2L" }, + { "DRC2 Activity Output", "Switch", "DRC2R" }, +}; + +static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + + switch (fll_id) { + case MADERA_FLL1_REFCLK: + return madera_set_fll_refclk(&cs47l15->fll[0], source, fref, + fout); + case MADERA_FLLAO_REFCLK: + return madera_set_fll_ao_refclk(&cs47l15->fll[1], source, fref, + fout); + case MADERA_FLL1_SYNCCLK: + return madera_set_fll_syncclk(&cs47l15->fll[0], source, fref, + fout); + default: + return -EINVAL; + } +} + +static struct snd_soc_dai_driver cs47l15_dai[] = { + { + .name = "cs47l15-aif1", + .id = 1, + .base = MADERA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-aif2", + .id = 2, + .base = MADERA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-aif3", + .id = 3, + .base = MADERA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l15-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "cs47l15-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 6, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + }, +}; + +static int cs47l15_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "cs47l15-dsp-trace") == 0) { + n_adsp = 0; + } else { + dev_err(madera->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->adsp[n_adsp], stream); +} + +static irqreturn_t cs47l15_adsp2_irq(int irq, void *data) +{ + struct cs47l15 *cs47l15 = data; + struct madera_priv *priv = &cs47l15->core; + struct madera *madera = priv->madera; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->adsp[0]); + if (ret == -ENODEV) { + dev_err(madera->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int cs47l15_component_probe(struct snd_soc_component *component) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l15->core.madera; + int ret; + + snd_soc_component_init_regmap(component, madera->regmap); + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = snd_soc_component_get_dapm(component); + mutex_unlock(&madera->dapm_ptr_lock); + + ret = madera_init_inputs(component); + if (ret) + return ret; + + ret = madera_init_outputs(component, CS47L15_MONO_OUTPUTS); + if (ret) + return ret; + + snd_soc_component_disable_pin(component, "HAPTICS"); + + ret = snd_soc_add_component_controls(component, + madera_adsp_rate_controls, + CS47L15_NUM_ADSP); + if (ret) + return ret; + + wm_adsp2_component_probe(&cs47l15->core.adsp[0], component); + + return 0; +} + +static void cs47l15_component_remove(struct snd_soc_component *component) +{ + struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l15->core.madera; + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = NULL; + mutex_unlock(&madera->dapm_ptr_lock); + + wm_adsp2_component_remove(&cs47l15->core.adsp[0], component); +} + +#define CS47L15_DIG_VU 0x0200 + +static unsigned int cs47l15_digital_vu[] = { + MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, + MADERA_DAC_DIGITAL_VOLUME_4L, + MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, +}; + +static const struct snd_compr_ops cs47l15_compr_ops = { + .open = &cs47l15_open, + .free = &wm_adsp_compr_free, + .set_params = &wm_adsp_compr_set_params, + .get_caps = &wm_adsp_compr_get_caps, + .trigger = &wm_adsp_compr_trigger, + .pointer = &wm_adsp_compr_pointer, + .copy = &wm_adsp_compr_copy, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs47l15 = { + .probe = &cs47l15_component_probe, + .remove = &cs47l15_component_remove, + .set_sysclk = &madera_set_sysclk, + .set_pll = &cs47l15_set_fll, + .name = DRV_NAME, + .compr_ops = &cs47l15_compr_ops, + .controls = cs47l15_snd_controls, + .num_controls = ARRAY_SIZE(cs47l15_snd_controls), + .dapm_widgets = cs47l15_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l15_dapm_widgets), + .dapm_routes = cs47l15_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs47l15_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static int cs47l15_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct cs47l15 *cs47l15; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l15_dai) > MADERA_MAX_DAI); + + /* quick exit if Madera irqchip driver hasn't completed probe */ + if (!madera->irq_dev) { + dev_dbg(&pdev->dev, "irqchip driver not ready\n"); + return -EPROBE_DEFER; + } + + cs47l15 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l15), + GFP_KERNEL); + if (!cs47l15) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l15); + + cs47l15->core.madera = madera; + cs47l15->core.dev = &pdev->dev; + cs47l15->core.num_inputs = 4; + + ret = madera_core_init(&cs47l15->core); + if (ret) + return ret; + + ret = madera_init_overheat(&cs47l15->core); + if (ret) + goto error_core; + + ret = madera_request_irq(madera, MADERA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l15_adsp2_irq, + cs47l15); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + goto error_overheat; + } + + ret = madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 1); + if (ret) + dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); + + cs47l15->core.adsp[0].part = "cs47l15"; + cs47l15->core.adsp[0].num = 1; + cs47l15->core.adsp[0].type = WMFW_ADSP2; + cs47l15->core.adsp[0].rev = 2; + cs47l15->core.adsp[0].dev = madera->dev; + cs47l15->core.adsp[0].regmap = madera->regmap_32bit; + + cs47l15->core.adsp[0].base = MADERA_DSP1_CONFIG_1; + cs47l15->core.adsp[0].mem = cs47l15_dsp1_regions; + cs47l15->core.adsp[0].num_mems = ARRAY_SIZE(cs47l15_dsp1_regions); + + cs47l15->core.adsp[0].lock_regions = + WM_ADSP2_REGION_1 | WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3; + + ret = wm_adsp2_init(&cs47l15->core.adsp[0]); + if (ret != 0) + goto error_dsp_irq; + + ret = madera_init_bus_error_irq(&cs47l15->core, 0, wm_adsp2_bus_error); + if (ret) + goto error_adsp; + + madera_init_fll(madera, 1, MADERA_FLL1_CONTROL_1 - 1, + &cs47l15->fll[0]); + madera_init_fll(madera, 4, MADERA_FLLAO_CONTROL_1 - 1, + &cs47l15->fll[1]); + + for (i = 0; i < ARRAY_SIZE(cs47l15_dai); i++) + madera_init_dai(&cs47l15->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l15_digital_vu); i++) + regmap_update_bits(madera->regmap, cs47l15_digital_vu[i], + CS47L15_DIG_VU, CS47L15_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_cs47l15, + cs47l15_dai, + ARRAY_SIZE(cs47l15_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + goto error_pm_runtime; + } + + return ret; + +error_pm_runtime: + pm_runtime_disable(&pdev->dev); + madera_free_bus_error_irq(&cs47l15->core, 0); +error_adsp: + wm_adsp2_remove(&cs47l15->core.adsp[0]); +error_dsp_irq: + madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(madera, MADERA_IRQ_DSP_IRQ1, cs47l15); +error_overheat: + madera_free_overheat(&cs47l15->core); +error_core: + madera_core_free(&cs47l15->core); + + return ret; +} + +static int cs47l15_remove(struct platform_device *pdev) +{ + struct cs47l15 *cs47l15 = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + madera_free_bus_error_irq(&cs47l15->core, 0); + + wm_adsp2_remove(&cs47l15->core.adsp[0]); + + madera_set_irq_wake(cs47l15->core.madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(cs47l15->core.madera, MADERA_IRQ_DSP_IRQ1, cs47l15); + madera_free_overheat(&cs47l15->core); + madera_core_free(&cs47l15->core); + + return 0; +} + +static struct platform_driver cs47l15_codec_driver = { + .driver = { + .name = "cs47l15-codec", + }, + .probe = &cs47l15_probe, + .remove = &cs47l15_remove, +}; + +module_platform_driver(cs47l15_codec_driver); + +MODULE_SOFTDEP("pre: madera irq-madera arizona-micsupp"); +MODULE_DESCRIPTION("ASoC CS47L15 driver"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); +MODULE_AUTHOR("Jaswinder Jassal <jjassal@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l15-codec"); diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index e3585c1dab3d..d396a8545d51 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -524,7 +524,7 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, 6, +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index c4ecb0e6911a..67cac60a859d 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2402,13 +2402,6 @@ static irqreturn_t cs47l90_adsp2_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t cs47l90_dsp_bus_error(int irq, void *data) -{ - struct wm_adsp *dsp = (struct wm_adsp *)data; - - return wm_adsp2_bus_error(dsp); -} - static int cs47l90_component_probe(struct snd_soc_component *component) { struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component); @@ -2558,7 +2551,7 @@ static int cs47l90_probe(struct platform_device *pdev) if (ret == 0) { ret = madera_init_bus_error_irq(&cs47l90->core, i, - cs47l90_dsp_bus_error); + wm_adsp2_bus_error); if (ret != 0) wm_adsp2_remove(&cs47l90->core.adsp[i]); } diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c new file mode 100644 index 000000000000..d50f75f3b3e4 --- /dev/null +++ b/sound/soc/codecs/cs47l92.c @@ -0,0 +1,2039 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// ALSA SoC Audio driver for CS47L92 codec +// +// Copyright (C) 2016-2019 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. +// + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include <linux/irqchip/irq-madera.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/registers.h> + +#include "madera.h" +#include "wm_adsp.h" + +#define CS47L92_NUM_ADSP 1 +#define CS47L92_MONO_OUTPUTS 3 + +#define DRV_NAME "cs47l92-codec" + +struct cs47l92 { + struct madera_priv core; + struct madera_fll fll[2]; +}; + +static const struct wm_adsp_region cs47l92_dsp1_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x080000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x0e0000 }, + { .type = WMFW_ADSP2_XM, .base = 0x0a0000 }, + { .type = WMFW_ADSP2_YM, .base = 0x0c0000 }, +}; + +static const char * const cs47l92_outdemux_texts[] = { + "HPOUT3", + "HPOUT4", +}; + +static int cs47l92_put_demux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int ep_sel, mux, change, cur; + bool out_mono; + int ret; + + if (ucontrol->value.enumerated.item[0] > e->items - 1) + return -EINVAL; + + mux = ucontrol->value.enumerated.item[0]; + + snd_soc_dapm_mutex_lock(dapm); + + ep_sel = mux << e->shift_l; + + change = snd_soc_component_test_bits(component, MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL_MASK, + ep_sel); + if (!change) + goto end; + + ret = regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &cur); + if (ret != 0) + dev_warn(madera->dev, "Failed to read outputs: %d\n", ret); + + /* EP_SEL should not be modified while HPOUT3 or 4 is enabled */ + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA | MADERA_OUT3R_ENA, 0); + if (ret) + dev_warn(madera->dev, "Failed to disable outputs: %d\n", ret); + + usleep_range(2000, 3000); /* wait for wseq to complete */ + + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL, ep_sel); + if (ret) { + dev_err(madera->dev, "Failed to set OUT3 demux: %d\n", ret); + } else { + out_mono = madera->pdata.codec.out_mono[2 + mux]; + + ret = madera_set_output_mode(component, 3, out_mono); + if (ret < 0) + dev_warn(madera->dev, + "Failed to set output mode: %d\n", ret); + } + + ret = regmap_update_bits(madera->regmap, MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA | MADERA_OUT3R_ENA, cur); + if (ret) { + dev_warn(madera->dev, "Failed to restore outputs: %d\n", ret); + } else { + /* wait for wseq */ + if (cur & (MADERA_OUT3L_ENA | MADERA_OUT3R_ENA)) + msleep(34); /* enable delay */ + else + usleep_range(2000, 3000); /* disable delay */ + } + +end: + snd_soc_dapm_mutex_unlock(dapm); + + return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); +} + +static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum, + MADERA_OUTPUT_ENABLES_1, + MADERA_EP_SEL_SHIFT, + cs47l92_outdemux_texts); + +static const struct snd_kcontrol_new cs47l92_outdemux = + SOC_DAPM_ENUM_EXT("OUT3 Demux", cs47l92_outdemux_enum, + snd_soc_dapm_get_enum_double, cs47l92_put_demux); + +static int cs47l92_adsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + unsigned int freq; + int ret; + + ret = regmap_read(madera->regmap, MADERA_DSP_CLOCK_2, &freq); + if (ret != 0) { + dev_err(madera->dev, + "Failed to read MADERA_DSP_CLOCK_2: %d\n", ret); + return ret; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = madera_set_adsp_clk(&cs47l92->core, w->shift, freq); + if (ret) + return ret; + break; + default: + break; + } + + return wm_adsp_early_event(w, kcontrol, event); +} + +#define CS47L92_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG HPOUT2L Switch", base, 2, 1, 0), \ + SOC_SINGLE(name " NG HPOUT2R Switch", base, 3, 1, 0), \ + SOC_SINGLE(name " NG HPOUT3L Switch", base, 4, 1, 0), \ + SOC_SINGLE(name " NG HPOUT3R Switch", base, 5, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \ + SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0) + +static const struct snd_kcontrol_new cs47l92_snd_controls[] = { +SOC_ENUM("IN1 OSR", madera_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", madera_in_dmic_osr[1]), +SOC_ENUM("IN3 OSR", madera_in_dmic_osr[2]), +SOC_ENUM("IN4 OSR", madera_in_dmic_osr[3]), + +SOC_SINGLE_RANGE_TLV("IN1L Volume", MADERA_IN1L_CONTROL, + MADERA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN1R Volume", MADERA_IN1R_CONTROL, + MADERA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN2L Volume", MADERA_IN2L_CONTROL, + MADERA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), +SOC_SINGLE_RANGE_TLV("IN2R Volume", MADERA_IN2R_CONTROL, + MADERA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, madera_ana_tlv), + +SOC_ENUM("IN HPF Cutoff Frequency", madera_in_hpf_cut_enum), + +SOC_SINGLE_EXT("IN1L LP Switch", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN1R LP Switch", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN2L LP Switch", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), +SOC_SINGLE_EXT("IN2R LP Switch", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN1L_LP_MODE_SHIFT, 1, 0, + snd_soc_get_volsw, madera_lp_mode_put), + +SOC_SINGLE("IN1L HPF Switch", MADERA_IN1L_CONTROL, + MADERA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", MADERA_IN1R_CONTROL, + MADERA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", MADERA_IN2L_CONTROL, + MADERA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", MADERA_IN2R_CONTROL, + MADERA_IN2R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3L HPF Switch", MADERA_IN3L_CONTROL, + MADERA_IN3L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3R HPF Switch", MADERA_IN3R_CONTROL, + MADERA_IN3R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4L HPF Switch", MADERA_IN4L_CONTROL, + MADERA_IN4L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4R HPF Switch", MADERA_IN4R_CONTROL, + MADERA_IN4R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1L, + MADERA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_1R, + MADERA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2L, + MADERA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_2R, + MADERA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN3L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_3L, + MADERA_IN3L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN3R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_3R, + MADERA_IN3R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN4L Digital Volume", MADERA_ADC_DIGITAL_VOLUME_4L, + MADERA_IN4L_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), +SOC_SINGLE_TLV("IN4R Digital Volume", MADERA_ADC_DIGITAL_VOLUME_4R, + MADERA_IN4R_DIG_VOL_SHIFT, 0xbf, 0, madera_digital_tlv), + +SOC_ENUM("Input Ramp Up", madera_in_vi_ramp), +SOC_ENUM("Input Ramp Down", madera_in_vd_ramp), + +MADERA_MIXER_CONTROLS("EQ1", MADERA_EQ1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ2", MADERA_EQ2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ3", MADERA_EQ3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("EQ4", MADERA_EQ4MIX_INPUT_1_SOURCE), + +MADERA_EQ_CONTROL("EQ1 Coefficients", MADERA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", MADERA_EQ1_1, MADERA_EQ1_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", MADERA_EQ1_1, MADERA_EQ1_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", MADERA_EQ1_1, MADERA_EQ1_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", MADERA_EQ1_2, MADERA_EQ1_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", MADERA_EQ1_2, MADERA_EQ1_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ2 Coefficients", MADERA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", MADERA_EQ2_1, MADERA_EQ2_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", MADERA_EQ2_1, MADERA_EQ2_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", MADERA_EQ2_1, MADERA_EQ2_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", MADERA_EQ2_2, MADERA_EQ2_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", MADERA_EQ2_2, MADERA_EQ2_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ3 Coefficients", MADERA_EQ3_2), +SOC_SINGLE_TLV("EQ3 B1 Volume", MADERA_EQ3_1, MADERA_EQ3_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B2 Volume", MADERA_EQ3_1, MADERA_EQ3_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B3 Volume", MADERA_EQ3_1, MADERA_EQ3_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B4 Volume", MADERA_EQ3_2, MADERA_EQ3_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ3 B5 Volume", MADERA_EQ3_2, MADERA_EQ3_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +MADERA_EQ_CONTROL("EQ4 Coefficients", MADERA_EQ4_2), +SOC_SINGLE_TLV("EQ4 B1 Volume", MADERA_EQ4_1, MADERA_EQ4_B1_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B2 Volume", MADERA_EQ4_1, MADERA_EQ4_B2_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B3 Volume", MADERA_EQ4_1, MADERA_EQ4_B3_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B4 Volume", MADERA_EQ4_2, MADERA_EQ4_B4_GAIN_SHIFT, + 24, 0, madera_eq_tlv), +SOC_SINGLE_TLV("EQ4 B5 Volume", MADERA_EQ4_2, MADERA_EQ4_B5_GAIN_SHIFT, + 24, 0, madera_eq_tlv), + +SOC_SINGLE("DAC High Performance Mode Switch", MADERA_OUTPUT_RATE_1, + MADERA_CP_DAC_MODE_SHIFT, 1, 0), + +MADERA_MIXER_CONTROLS("DRC1L", MADERA_DRC1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC1R", MADERA_DRC1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2L", MADERA_DRC2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DRC2R", MADERA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", MADERA_DRC1_CTRL1, 5, + MADERA_DRC1R_ENA | MADERA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", MADERA_DRC2_CTRL1, 5, + MADERA_DRC2R_ENA | MADERA_DRC2L_ENA), + +MADERA_MIXER_CONTROLS("LHPF1", MADERA_HPLP1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF2", MADERA_HPLP2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF3", MADERA_HPLP3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("LHPF4", MADERA_HPLP4MIX_INPUT_1_SOURCE), + +MADERA_LHPF_CONTROL("LHPF1 Coefficients", MADERA_HPLPF1_2), +MADERA_LHPF_CONTROL("LHPF2 Coefficients", MADERA_HPLPF2_2), +MADERA_LHPF_CONTROL("LHPF3 Coefficients", MADERA_HPLPF3_2), +MADERA_LHPF_CONTROL("LHPF4 Coefficients", MADERA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", madera_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", madera_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", madera_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", madera_lhpf4_mode), + +MADERA_RATE_ENUM("ISRC1 FSL", madera_isrc_fsl[0]), +MADERA_RATE_ENUM("ISRC2 FSL", madera_isrc_fsl[1]), +MADERA_RATE_ENUM("ISRC1 FSH", madera_isrc_fsh[0]), +MADERA_RATE_ENUM("ISRC2 FSH", madera_isrc_fsh[1]), +MADERA_RATE_ENUM("ASRC1 Rate 1", madera_asrc1_bidir_rate[0]), +MADERA_RATE_ENUM("ASRC1 Rate 2", madera_asrc1_bidir_rate[1]), + +WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + +MADERA_MIXER_CONTROLS("DSP1L", MADERA_DSP1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("DSP1R", MADERA_DSP1RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, madera_noise_tlv), + +MADERA_MIXER_CONTROLS("HPOUT1L", MADERA_OUT1LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT1R", MADERA_OUT1RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT2L", MADERA_OUT2LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT2R", MADERA_OUT2RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT3L", MADERA_OUT3LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("HPOUT3R", MADERA_OUT3RMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1L", MADERA_OUT5LMIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SPKDAT1R", MADERA_OUT5RMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", MADERA_HP1_SHORT_CIRCUIT_CTRL, + MADERA_HP1_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT2 SC Protect Switch", MADERA_HP2_SHORT_CIRCUIT_CTRL, + MADERA_HP2_SC_ENA_SHIFT, 1, 0), +SOC_SINGLE("HPOUT3 SC Protect Switch", MADERA_HP3_SHORT_CIRCUIT_CTRL, + MADERA_HP3_SC_ENA_SHIFT, 1, 0), + +SOC_SINGLE("SPKDAT1 High Performance Switch", MADERA_OUTPUT_PATH_CONFIG_5L, + MADERA_OUT5_OSR_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("HPOUT2 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, MADERA_OUT2L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("HPOUT3 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, MADERA_OUT3L_MUTE_SHIFT, 1, 1), +SOC_DOUBLE_R("SPKDAT1 Digital Switch", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, MADERA_OUT1L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("HPOUT2 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, MADERA_OUT2L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("HPOUT3 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, MADERA_OUT3L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), +SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, MADERA_OUT5L_VOL_SHIFT, + 0xbf, 0, madera_digital_tlv), + +SOC_DOUBLE("SPKDAT1 Switch", MADERA_PDM_SPK1_CTRL_1, MADERA_SPK1L_MUTE_SHIFT, + MADERA_SPK1R_MUTE_SHIFT, 1, 1), + +SOC_ENUM("Output Ramp Up", madera_out_vi_ramp), +SOC_ENUM("Output Ramp Down", madera_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", MADERA_NOISE_GATE_CONTROL, + MADERA_NGATE_THR_SHIFT, 7, 1, madera_ng_tlv), +SOC_ENUM("Noise Gate Hold", madera_ng_hold), + +SOC_ENUM_EXT("DFC1RX Width", madera_dfc_width[0], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1RX Type", madera_dfc_type[0], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1TX Width", madera_dfc_width[1], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC1TX Type", madera_dfc_type[1], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2RX Width", madera_dfc_width[2], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2RX Type", madera_dfc_type[2], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2TX Width", madera_dfc_width[3], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC2TX Type", madera_dfc_type[3], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3RX Width", madera_dfc_width[4], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3RX Type", madera_dfc_type[4], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3TX Width", madera_dfc_width[5], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC3TX Type", madera_dfc_type[5], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4RX Width", madera_dfc_width[6], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4RX Type", madera_dfc_type[6], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4TX Width", madera_dfc_width[7], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC4TX Type", madera_dfc_type[7], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5RX Width", madera_dfc_width[8], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5RX Type", madera_dfc_type[8], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5TX Width", madera_dfc_width[9], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC5TX Type", madera_dfc_type[9], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6RX Width", madera_dfc_width[10], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6RX Type", madera_dfc_type[10], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6TX Width", madera_dfc_width[11], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC6TX Type", madera_dfc_type[11], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7RX Width", madera_dfc_width[12], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7RX Type", madera_dfc_type[12], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7TX Width", madera_dfc_width[13], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC7TX Type", madera_dfc_type[13], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8RX Width", madera_dfc_width[14], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8RX Type", madera_dfc_type[14], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8TX Width", madera_dfc_width[15], + snd_soc_get_enum_double, madera_dfc_put), +SOC_ENUM_EXT("DFC8TX Type", madera_dfc_type[15], + snd_soc_get_enum_double, madera_dfc_put), + +CS47L92_NG_SRC("HPOUT1L", MADERA_NOISE_GATE_SELECT_1L), +CS47L92_NG_SRC("HPOUT1R", MADERA_NOISE_GATE_SELECT_1R), +CS47L92_NG_SRC("HPOUT2L", MADERA_NOISE_GATE_SELECT_2L), +CS47L92_NG_SRC("HPOUT2R", MADERA_NOISE_GATE_SELECT_2R), +CS47L92_NG_SRC("HPOUT3L", MADERA_NOISE_GATE_SELECT_3L), +CS47L92_NG_SRC("HPOUT3R", MADERA_NOISE_GATE_SELECT_3R), +CS47L92_NG_SRC("SPKDAT1L", MADERA_NOISE_GATE_SELECT_5L), +CS47L92_NG_SRC("SPKDAT1R", MADERA_NOISE_GATE_SELECT_5R), + +MADERA_MIXER_CONTROLS("AIF1TX1", MADERA_AIF1TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX2", MADERA_AIF1TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX3", MADERA_AIF1TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX4", MADERA_AIF1TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX5", MADERA_AIF1TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX6", MADERA_AIF1TX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX7", MADERA_AIF1TX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF1TX8", MADERA_AIF1TX8MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF2TX1", MADERA_AIF2TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX2", MADERA_AIF2TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX3", MADERA_AIF2TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX4", MADERA_AIF2TX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX5", MADERA_AIF2TX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX6", MADERA_AIF2TX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX7", MADERA_AIF2TX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF2TX8", MADERA_AIF2TX8MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("AIF3TX1", MADERA_AIF3TX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX2", MADERA_AIF3TX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX3", MADERA_AIF3TX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("AIF3TX4", MADERA_AIF3TX4MIX_INPUT_1_SOURCE), + +MADERA_MIXER_CONTROLS("SLIMTX1", MADERA_SLIMTX1MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX2", MADERA_SLIMTX2MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX3", MADERA_SLIMTX3MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX4", MADERA_SLIMTX4MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX5", MADERA_SLIMTX5MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX6", MADERA_SLIMTX6MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX7", MADERA_SLIMTX7MIX_INPUT_1_SOURCE), +MADERA_MIXER_CONTROLS("SLIMTX8", MADERA_SLIMTX8MIX_INPUT_1_SOURCE), + +MADERA_GAINMUX_CONTROLS("SPDIFTX1", MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE), +MADERA_GAINMUX_CONTROLS("SPDIFTX2", MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE), + +WM_ADSP_FW_CONTROL("DSP1", 0), +}; + +MADERA_MIXER_ENUMS(EQ1, MADERA_EQ1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ2, MADERA_EQ2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ3, MADERA_EQ3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(EQ4, MADERA_EQ4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DRC1L, MADERA_DRC1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC1R, MADERA_DRC1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2L, MADERA_DRC2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DRC2R, MADERA_DRC2RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(LHPF1, MADERA_HPLP1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF2, MADERA_HPLP2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF3, MADERA_HPLP3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(LHPF4, MADERA_HPLP4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(DSP1L, MADERA_DSP1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(DSP1R, MADERA_DSP1RMIX_INPUT_1_SOURCE); +MADERA_DSP_AUX_ENUMS(DSP1, MADERA_DSP1AUX1MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(PWM1, MADERA_PWM1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(PWM2, MADERA_PWM2MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(OUT1L, MADERA_OUT1LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT1R, MADERA_OUT1RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT2L, MADERA_OUT2LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT2R, MADERA_OUT2RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT3L, MADERA_OUT3LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(OUT3R, MADERA_OUT3RMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1L, MADERA_OUT5LMIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SPKDAT1R, MADERA_OUT5RMIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF1TX1, MADERA_AIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX2, MADERA_AIF1TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX3, MADERA_AIF1TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX4, MADERA_AIF1TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX5, MADERA_AIF1TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX6, MADERA_AIF1TX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX7, MADERA_AIF1TX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF1TX8, MADERA_AIF1TX8MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF2TX1, MADERA_AIF2TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX2, MADERA_AIF2TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX3, MADERA_AIF2TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX4, MADERA_AIF2TX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX5, MADERA_AIF2TX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX6, MADERA_AIF2TX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX7, MADERA_AIF2TX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF2TX8, MADERA_AIF2TX8MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(AIF3TX1, MADERA_AIF3TX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX2, MADERA_AIF3TX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX3, MADERA_AIF3TX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(AIF3TX4, MADERA_AIF3TX4MIX_INPUT_1_SOURCE); + +MADERA_MIXER_ENUMS(SLIMTX1, MADERA_SLIMTX1MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX2, MADERA_SLIMTX2MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX3, MADERA_SLIMTX3MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX4, MADERA_SLIMTX4MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX5, MADERA_SLIMTX5MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX6, MADERA_SLIMTX6MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX7, MADERA_SLIMTX7MIX_INPUT_1_SOURCE); +MADERA_MIXER_ENUMS(SLIMTX8, MADERA_SLIMTX8MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(SPD1TX1, MADERA_SPDIF1TX1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(SPD1TX2, MADERA_SPDIF1TX2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ASRC1IN1L, MADERA_ASRC1_1LMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN1R, MADERA_ASRC1_1RMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN2L, MADERA_ASRC1_2LMIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ASRC1IN2R, MADERA_ASRC1_2RMIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1INT1, MADERA_ISRC1INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1INT2, MADERA_ISRC1INT2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC1DEC1, MADERA_ISRC1DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC1DEC2, MADERA_ISRC1DEC2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2INT1, MADERA_ISRC2INT1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2INT2, MADERA_ISRC2INT2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(ISRC2DEC1, MADERA_ISRC2DEC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(ISRC2DEC2, MADERA_ISRC2DEC2MIX_INPUT_1_SOURCE); + +MADERA_MUX_ENUMS(DFC1, MADERA_DFC1MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC2, MADERA_DFC2MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC3, MADERA_DFC3MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC4, MADERA_DFC4MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC5, MADERA_DFC5MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC6, MADERA_DFC6MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC7, MADERA_DFC7MIX_INPUT_1_SOURCE); +MADERA_MUX_ENUMS(DFC8, MADERA_DFC8MIX_INPUT_1_SOURCE); + +static const char * const cs47l92_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R", + "SPKDAT1L", "SPKDAT1R", +}; + +static const unsigned int cs47l92_aec_loopback_values[] = { + 0, 1, 2, 3, 4, 5, 8, 9 +}; + +static const struct soc_enum cs47l92_aec_loopback = + SOC_VALUE_ENUM_SINGLE(MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l92_aec_loopback_texts), + cs47l92_aec_loopback_texts, + cs47l92_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l92_aec_loopback_mux = + SOC_DAPM_ENUM("AEC1 Loopback", cs47l92_aec_loopback); + +static const struct snd_soc_dapm_widget cs47l92_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", MADERA_SYSTEM_CLOCK_1, MADERA_SYSCLK_ENA_SHIFT, + 0, madera_sysclk_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_SUPPLY("ASYNCCLK", MADERA_ASYNC_CLOCK_1, + MADERA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", MADERA_OUTPUT_SYSTEM_CLOCK, + MADERA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", MADERA_OUTPUT_ASYNC_CLOCK, + MADERA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("DSPCLK", MADERA_DSP_CLOCK_1, + MADERA_DSP_CLK_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD1", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD2", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", MADERA_MIC_BIAS_CTRL_1, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", MADERA_MIC_BIAS_CTRL_2, + MADERA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS1A", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1B", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1B_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1C", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1C_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS1D", MADERA_MIC_BIAS_CTRL_5, + MADERA_MICB1D_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("MICBIAS2A", MADERA_MIC_BIAS_CTRL_6, + MADERA_MICB2A_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2B", MADERA_MIC_BIAS_CTRL_6, + MADERA_MICB2B_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("FXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_FX, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ASRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ASRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("ISRC2CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_ISRC2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("OUTCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_OUT, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SPDCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SPD, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DSP1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF1TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF1, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF2TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF2, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF3TXCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_AIF3, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("SLIMBUSCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_SLIMBUS, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("PWMCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_PWM, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("DFCCLK", SND_SOC_NOPM, + MADERA_DOM_GRP_DFC, 0, + madera_domain_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), + +SND_SOC_DAPM_INPUT("IN1ALN"), +SND_SOC_DAPM_INPUT("IN1ALP"), +SND_SOC_DAPM_INPUT("IN1BLN"), +SND_SOC_DAPM_INPUT("IN1BLP"), +SND_SOC_DAPM_INPUT("IN1ARN"), +SND_SOC_DAPM_INPUT("IN1ARP"), +SND_SOC_DAPM_INPUT("IN1BR"), +SND_SOC_DAPM_INPUT("IN2ALN"), +SND_SOC_DAPM_INPUT("IN2ALP"), +SND_SOC_DAPM_INPUT("IN2BL"), +SND_SOC_DAPM_INPUT("IN2ARN"), +SND_SOC_DAPM_INPUT("IN2ARP"), +SND_SOC_DAPM_INPUT("IN2BR"), + +SND_SOC_DAPM_MUX("IN1L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[0]), +SND_SOC_DAPM_MUX("IN1R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[1]), +SND_SOC_DAPM_MUX("IN2L Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[2]), +SND_SOC_DAPM_MUX("IN2R Analog Mux", SND_SOC_NOPM, 0, 0, &madera_inmux[3]), + +SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), +SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[0]), + +SND_SOC_DAPM_MUX("IN2L Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), +SND_SOC_DAPM_MUX("IN2R Mode", SND_SOC_NOPM, 0, 0, &madera_inmode[1]), + +SND_SOC_DAPM_DEMUX("OUT3 Demux", SND_SOC_NOPM, 0, 0, &cs47l92_outdemux), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_PGA("PWM1 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", MADERA_PWM_DRIVE_1, MADERA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, + MADERA_AIF1_TX_ENABLES, MADERA_AIF1TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX7", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX8", NULL, 0, + MADERA_AIF2_TX_ENABLES, MADERA_AIF2TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, + MADERA_SLIMBUS_TX_CHANNEL_ENABLE, + MADERA_SLIMTX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX3", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX4", NULL, 0, + MADERA_AIF3_TX_ENABLES, MADERA_AIF3TX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + MADERA_OUT1L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + MADERA_OUT1R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT2L", SND_SOC_NOPM, + MADERA_OUT2L_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT2R", SND_SOC_NOPM, + MADERA_OUT2R_ENA_SHIFT, 0, NULL, 0, madera_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT3L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT3R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT3R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5L", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5L_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT5R", MADERA_OUTPUT_ENABLES_1, + MADERA_OUT5R_ENA_SHIFT, 0, NULL, 0, madera_out_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_PGA("SPD1TX1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL1_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPD1TX2", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_VAL2_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_OUT_DRV("SPD1", MADERA_SPD1_TX_CONTROL, + MADERA_SPD1_ENA_SHIFT, 0, NULL, 0), + +/* + * mux_in widgets : arranged in the order of sources + * specified in MADERA_MIXER_INPUT_ROUTES + */ + +SND_SOC_DAPM_PGA("Noise Generator", MADERA_COMFORT_NOISE_GENERATOR, + MADERA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", MADERA_TONE_GENERATOR_1, + MADERA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", MADERA_TONE_GENERATOR_1, + MADERA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_MUX("AEC1 Loopback", MADERA_DAC_AEC_CONTROL_1, + MADERA_AEC1_LOOPBACK_ENA_SHIFT, 0, + &cs47l92_aec_loopback_mux), + +SND_SOC_DAPM_PGA_E("IN1L", MADERA_INPUT_ENABLES, MADERA_IN1L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R", MADERA_INPUT_ENABLES, MADERA_IN1R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L", MADERA_INPUT_ENABLES, MADERA_IN2L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R", MADERA_INPUT_ENABLES, MADERA_IN2R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN3L", MADERA_INPUT_ENABLES, MADERA_IN3L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN3R", MADERA_INPUT_ENABLES, MADERA_IN3R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN4L", MADERA_INPUT_ENABLES, MADERA_IN4L_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN4R", MADERA_INPUT_ENABLES, MADERA_IN4R_ENA_SHIFT, + 0, NULL, 0, madera_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, + MADERA_AIF1_RX_ENABLES, MADERA_AIF1RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX7", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX8", NULL, 0, + MADERA_AIF2_RX_ENABLES, MADERA_AIF2RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX3", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX4", NULL, 0, + MADERA_AIF3_RX_ENABLES, MADERA_AIF3RX4_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, MADERA_SLIMBUS_RX_CHANNEL_ENABLE, + MADERA_SLIMRX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA("EQ1", MADERA_EQ1_1, MADERA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", MADERA_EQ2_1, MADERA_EQ2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ3", MADERA_EQ3_1, MADERA_EQ3_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ4", MADERA_EQ4_1, MADERA_EQ4_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", MADERA_DRC1_CTRL1, MADERA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", MADERA_DRC1_CTRL1, MADERA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", MADERA_DRC2_CTRL1, MADERA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", MADERA_DRC2_CTRL1, MADERA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", MADERA_HPLPF1_1, MADERA_LHPF1_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", MADERA_HPLPF2_1, MADERA_LHPF2_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", MADERA_HPLPF3_1, MADERA_LHPF3_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", MADERA_HPLPF4_1, MADERA_LHPF4_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("ASRC1IN1L", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN1L_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN1R", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN1R_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN2L", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN2L_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ASRC1IN2R", MADERA_ASRC1_ENABLE, + MADERA_ASRC1_IN2R_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1INT1", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", MADERA_ISRC_1_CTRL_3, + MADERA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", MADERA_ISRC_2_CTRL_3, + MADERA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), + +WM_ADSP2("DSP1", 0, cs47l92_adsp_power_ev), + +/* end of ordered widget list */ + +SND_SOC_DAPM_PGA("DFC1", MADERA_DFC1_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC2", MADERA_DFC2_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC3", MADERA_DFC3_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC4", MADERA_DFC4_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC5", MADERA_DFC5_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC6", MADERA_DFC6_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC7", MADERA_DFC7_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("DFC8", MADERA_DFC8_CTRL, MADERA_DFC1_ENA_SHIFT, 0, NULL, 0), + +MADERA_MIXER_WIDGETS(EQ1, "EQ1"), +MADERA_MIXER_WIDGETS(EQ2, "EQ2"), +MADERA_MIXER_WIDGETS(EQ3, "EQ3"), +MADERA_MIXER_WIDGETS(EQ4, "EQ4"), + +MADERA_MIXER_WIDGETS(DRC1L, "DRC1L"), +MADERA_MIXER_WIDGETS(DRC1R, "DRC1R"), +MADERA_MIXER_WIDGETS(DRC2L, "DRC2L"), +MADERA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +SND_SOC_DAPM_SWITCH("DRC1 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[0]), +SND_SOC_DAPM_SWITCH("DRC2 Activity Output", SND_SOC_NOPM, 0, 0, + &madera_drc_activity_output_mux[1]), + +MADERA_MIXER_WIDGETS(LHPF1, "LHPF1"), +MADERA_MIXER_WIDGETS(LHPF2, "LHPF2"), +MADERA_MIXER_WIDGETS(LHPF3, "LHPF3"), +MADERA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +MADERA_MIXER_WIDGETS(PWM1, "PWM1"), +MADERA_MIXER_WIDGETS(PWM2, "PWM2"), + +MADERA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +MADERA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +MADERA_MIXER_WIDGETS(OUT2L, "HPOUT2L"), +MADERA_MIXER_WIDGETS(OUT2R, "HPOUT2R"), +MADERA_MIXER_WIDGETS(OUT3L, "HPOUT3L"), +MADERA_MIXER_WIDGETS(OUT3R, "HPOUT3R"), +MADERA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), +MADERA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), + +MADERA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +MADERA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +MADERA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +MADERA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +MADERA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +MADERA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), +MADERA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), +MADERA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), + +MADERA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +MADERA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +MADERA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +MADERA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +MADERA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +MADERA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), +MADERA_MIXER_WIDGETS(AIF2TX7, "AIF2TX7"), +MADERA_MIXER_WIDGETS(AIF2TX8, "AIF2TX8"), + +MADERA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +MADERA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), +MADERA_MIXER_WIDGETS(AIF3TX3, "AIF3TX3"), +MADERA_MIXER_WIDGETS(AIF3TX4, "AIF3TX4"), + +MADERA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"), +MADERA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"), +MADERA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"), +MADERA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"), +MADERA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"), +MADERA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"), +MADERA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"), +MADERA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"), + +MADERA_MUX_WIDGETS(SPD1TX1, "SPDIFTX1"), +MADERA_MUX_WIDGETS(SPD1TX2, "SPDIFTX2"), + +MADERA_MUX_WIDGETS(ASRC1IN1L, "ASRC1IN1L"), +MADERA_MUX_WIDGETS(ASRC1IN1R, "ASRC1IN1R"), +MADERA_MUX_WIDGETS(ASRC1IN2L, "ASRC1IN2L"), +MADERA_MUX_WIDGETS(ASRC1IN2R, "ASRC1IN2R"), + +MADERA_DSP_WIDGETS(DSP1, "DSP1"), + +MADERA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +MADERA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), + +MADERA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +MADERA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), + +MADERA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +MADERA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), + +MADERA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +MADERA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), + +MADERA_MUX_WIDGETS(DFC1, "DFC1"), +MADERA_MUX_WIDGETS(DFC2, "DFC2"), +MADERA_MUX_WIDGETS(DFC3, "DFC3"), +MADERA_MUX_WIDGETS(DFC4, "DFC4"), +MADERA_MUX_WIDGETS(DFC5, "DFC5"), +MADERA_MUX_WIDGETS(DFC6, "DFC6"), +MADERA_MUX_WIDGETS(DFC7, "DFC7"), +MADERA_MUX_WIDGETS(DFC8, "DFC8"), + +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("HPOUT2L"), +SND_SOC_DAPM_OUTPUT("HPOUT2R"), +SND_SOC_DAPM_OUTPUT("HPOUT3L"), +SND_SOC_DAPM_OUTPUT("HPOUT3R"), +SND_SOC_DAPM_OUTPUT("HPOUT4L"), +SND_SOC_DAPM_OUTPUT("HPOUT4R"), +SND_SOC_DAPM_OUTPUT("SPKDAT1L"), +SND_SOC_DAPM_OUTPUT("SPKDAT1R"), +SND_SOC_DAPM_OUTPUT("SPDIF1"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define MADERA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC1", "AEC1 Loopback" }, \ + { name, "IN1L", "IN1L" }, \ + { name, "IN1R", "IN1R" }, \ + { name, "IN2L", "IN2L" }, \ + { name, "IN2R", "IN2R" }, \ + { name, "IN3L", "IN3L" }, \ + { name, "IN3R", "IN3R" }, \ + { name, "IN4L", "IN4L" }, \ + { name, "IN4R", "IN4R" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF1RX7", "AIF1RX7" }, \ + { name, "AIF1RX8", "AIF1RX8" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ + { name, "AIF2RX7", "AIF2RX7" }, \ + { name, "AIF2RX8", "AIF2RX8" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "AIF3RX3", "AIF3RX3" }, \ + { name, "AIF3RX4", "AIF3RX4" }, \ + { name, "SLIMRX1", "SLIMRX1" }, \ + { name, "SLIMRX2", "SLIMRX2" }, \ + { name, "SLIMRX3", "SLIMRX3" }, \ + { name, "SLIMRX4", "SLIMRX4" }, \ + { name, "SLIMRX5", "SLIMRX5" }, \ + { name, "SLIMRX6", "SLIMRX6" }, \ + { name, "SLIMRX7", "SLIMRX7" }, \ + { name, "SLIMRX8", "SLIMRX8" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "EQ3", "EQ3" }, \ + { name, "EQ4", "EQ4" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ASRC1IN1L", "ASRC1IN1L" }, \ + { name, "ASRC1IN1R", "ASRC1IN1R" }, \ + { name, "ASRC1IN2L", "ASRC1IN2L" }, \ + { name, "ASRC1IN2R", "ASRC1IN2R" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "DSP1.1", "DSP1" }, \ + { name, "DSP1.2", "DSP1" }, \ + { name, "DSP1.3", "DSP1" }, \ + { name, "DSP1.4", "DSP1" }, \ + { name, "DSP1.5", "DSP1" }, \ + { name, "DSP1.6", "DSP1" }, \ + { name, "DFC1", "DFC1" }, \ + { name, "DFC2", "DFC2" }, \ + { name, "DFC3", "DFC3" }, \ + { name, "DFC4", "DFC4" }, \ + { name, "DFC5", "DFC5" }, \ + { name, "DFC6", "DFC6" }, \ + { name, "DFC7", "DFC7" }, \ + { name, "DFC8", "DFC8" } + +static const struct snd_soc_dapm_route cs47l92_dapm_routes[] = { + /* Internal clock domains */ + { "EQ1", NULL, "FXCLK" }, + { "EQ2", NULL, "FXCLK" }, + { "EQ3", NULL, "FXCLK" }, + { "EQ4", NULL, "FXCLK" }, + { "DRC1L", NULL, "FXCLK" }, + { "DRC1R", NULL, "FXCLK" }, + { "DRC2L", NULL, "FXCLK" }, + { "DRC2R", NULL, "FXCLK" }, + { "LHPF1", NULL, "FXCLK" }, + { "LHPF2", NULL, "FXCLK" }, + { "LHPF3", NULL, "FXCLK" }, + { "LHPF4", NULL, "FXCLK" }, + { "PWM1 Mixer", NULL, "PWMCLK" }, + { "PWM2 Mixer", NULL, "PWMCLK" }, + { "OUT1L", NULL, "OUTCLK" }, + { "OUT1R", NULL, "OUTCLK" }, + { "OUT2L", NULL, "OUTCLK" }, + { "OUT2R", NULL, "OUTCLK" }, + { "OUT3L", NULL, "OUTCLK" }, + { "OUT3R", NULL, "OUTCLK" }, + { "OUT5L", NULL, "OUTCLK" }, + { "OUT5R", NULL, "OUTCLK" }, + { "AIF1TX1", NULL, "AIF1TXCLK" }, + { "AIF1TX2", NULL, "AIF1TXCLK" }, + { "AIF1TX3", NULL, "AIF1TXCLK" }, + { "AIF1TX4", NULL, "AIF1TXCLK" }, + { "AIF1TX5", NULL, "AIF1TXCLK" }, + { "AIF1TX6", NULL, "AIF1TXCLK" }, + { "AIF1TX7", NULL, "AIF1TXCLK" }, + { "AIF1TX8", NULL, "AIF1TXCLK" }, + { "AIF2TX1", NULL, "AIF2TXCLK" }, + { "AIF2TX2", NULL, "AIF2TXCLK" }, + { "AIF2TX3", NULL, "AIF2TXCLK" }, + { "AIF2TX4", NULL, "AIF2TXCLK" }, + { "AIF2TX5", NULL, "AIF2TXCLK" }, + { "AIF2TX6", NULL, "AIF2TXCLK" }, + { "AIF2TX7", NULL, "AIF2TXCLK" }, + { "AIF2TX8", NULL, "AIF2TXCLK" }, + { "AIF3TX1", NULL, "AIF3TXCLK" }, + { "AIF3TX2", NULL, "AIF3TXCLK" }, + { "AIF3TX3", NULL, "AIF3TXCLK" }, + { "AIF3TX4", NULL, "AIF3TXCLK" }, + { "SLIMTX1", NULL, "SLIMBUSCLK" }, + { "SLIMTX2", NULL, "SLIMBUSCLK" }, + { "SLIMTX3", NULL, "SLIMBUSCLK" }, + { "SLIMTX4", NULL, "SLIMBUSCLK" }, + { "SLIMTX5", NULL, "SLIMBUSCLK" }, + { "SLIMTX6", NULL, "SLIMBUSCLK" }, + { "SLIMTX7", NULL, "SLIMBUSCLK" }, + { "SLIMTX8", NULL, "SLIMBUSCLK" }, + { "SPD1TX1", NULL, "SPDCLK" }, + { "SPD1TX2", NULL, "SPDCLK" }, + { "DSP1", NULL, "DSP1CLK" }, + { "ISRC1DEC1", NULL, "ISRC1CLK" }, + { "ISRC1DEC2", NULL, "ISRC1CLK" }, + { "ISRC1INT1", NULL, "ISRC1CLK" }, + { "ISRC1INT2", NULL, "ISRC1CLK" }, + { "ISRC2DEC1", NULL, "ISRC2CLK" }, + { "ISRC2DEC2", NULL, "ISRC2CLK" }, + { "ISRC2INT1", NULL, "ISRC2CLK" }, + { "ISRC2INT2", NULL, "ISRC2CLK" }, + { "ASRC1IN1L", NULL, "ASRC1CLK" }, + { "ASRC1IN1R", NULL, "ASRC1CLK" }, + { "ASRC1IN2L", NULL, "ASRC1CLK" }, + { "ASRC1IN2R", NULL, "ASRC1CLK" }, + { "DFC1", NULL, "DFCCLK" }, + { "DFC2", NULL, "DFCCLK" }, + { "DFC3", NULL, "DFCCLK" }, + { "DFC4", NULL, "DFCCLK" }, + { "DFC5", NULL, "DFCCLK" }, + { "DFC6", NULL, "DFCCLK" }, + { "DFC7", NULL, "DFCCLK" }, + { "DFC8", NULL, "DFCCLK" }, + + { "OUT1L", NULL, "CPVDD1" }, + { "OUT1L", NULL, "CPVDD2" }, + { "OUT1R", NULL, "CPVDD1" }, + { "OUT1R", NULL, "CPVDD2" }, + { "OUT2L", NULL, "CPVDD1" }, + { "OUT2L", NULL, "CPVDD2" }, + { "OUT2R", NULL, "CPVDD1" }, + { "OUT2R", NULL, "CPVDD2" }, + { "OUT3L", NULL, "CPVDD1" }, + { "OUT3L", NULL, "CPVDD2" }, + { "OUT3R", NULL, "CPVDD1" }, + { "OUT3R", NULL, "CPVDD2" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT2L", NULL, "SYSCLK" }, + { "OUT2R", NULL, "SYSCLK" }, + { "OUT3L", NULL, "SYSCLK" }, + { "OUT3R", NULL, "SYSCLK" }, + { "OUT5L", NULL, "SYSCLK" }, + { "OUT5R", NULL, "SYSCLK" }, + + { "SPD1", NULL, "SYSCLK" }, + { "SPD1", NULL, "SPD1TX1" }, + { "SPD1", NULL, "SPD1TX2" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + { "IN3L", NULL, "SYSCLK" }, + { "IN3R", NULL, "SYSCLK" }, + { "IN4L", NULL, "SYSCLK" }, + { "IN4R", NULL, "SYSCLK" }, + + { "ASRC1IN1L", NULL, "SYSCLK" }, + { "ASRC1IN1R", NULL, "SYSCLK" }, + { "ASRC1IN2L", NULL, "SYSCLK" }, + { "ASRC1IN2R", NULL, "SYSCLK" }, + + { "ASRC1IN1L", NULL, "ASYNCCLK" }, + { "ASRC1IN1R", NULL, "ASYNCCLK" }, + { "ASRC1IN2L", NULL, "ASYNCCLK" }, + { "ASRC1IN2R", NULL, "ASYNCCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + { "MICBIAS2", NULL, "MICVDD" }, + + { "MICBIAS1A", NULL, "MICBIAS1" }, + { "MICBIAS1B", NULL, "MICBIAS1" }, + { "MICBIAS1C", NULL, "MICBIAS1" }, + { "MICBIAS1D", NULL, "MICBIAS1" }, + + { "MICBIAS2A", NULL, "MICBIAS2" }, + { "MICBIAS2B", NULL, "MICBIAS2" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + { "AIF1 Capture", NULL, "AIF1TX7" }, + { "AIF1 Capture", NULL, "AIF1TX8" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + { "AIF1RX7", NULL, "AIF1 Playback" }, + { "AIF1RX8", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, + { "AIF2 Capture", NULL, "AIF2TX7" }, + { "AIF2 Capture", NULL, "AIF2TX8" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, + { "AIF2RX7", NULL, "AIF2 Playback" }, + { "AIF2RX8", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + { "AIF3 Capture", NULL, "AIF3TX3" }, + { "AIF3 Capture", NULL, "AIF3TX4" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + { "AIF3RX3", NULL, "AIF3 Playback" }, + { "AIF3RX4", NULL, "AIF3 Playback" }, + + { "Slim1 Capture", NULL, "SLIMTX1" }, + { "Slim1 Capture", NULL, "SLIMTX2" }, + { "Slim1 Capture", NULL, "SLIMTX3" }, + { "Slim1 Capture", NULL, "SLIMTX4" }, + + { "SLIMRX1", NULL, "Slim1 Playback" }, + { "SLIMRX2", NULL, "Slim1 Playback" }, + { "SLIMRX3", NULL, "Slim1 Playback" }, + { "SLIMRX4", NULL, "Slim1 Playback" }, + + { "Slim2 Capture", NULL, "SLIMTX5" }, + { "Slim2 Capture", NULL, "SLIMTX6" }, + + { "SLIMRX5", NULL, "Slim2 Playback" }, + { "SLIMRX6", NULL, "Slim2 Playback" }, + + { "Slim3 Capture", NULL, "SLIMTX7" }, + { "Slim3 Capture", NULL, "SLIMTX8" }, + + { "SLIMRX7", NULL, "Slim3 Playback" }, + { "SLIMRX8", NULL, "Slim3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + { "Slim1 Playback", NULL, "SYSCLK" }, + { "Slim2 Playback", NULL, "SYSCLK" }, + { "Slim3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + { "Slim1 Capture", NULL, "SYSCLK" }, + { "Slim2 Capture", NULL, "SYSCLK" }, + { "Slim3 Capture", NULL, "SYSCLK" }, + + { "Audio Trace DSP", NULL, "DSP1" }, + + { "IN1L Analog Mux", "A", "IN1ALN" }, + { "IN1L Analog Mux", "A", "IN1ALP" }, + { "IN1L Analog Mux", "B", "IN1BLN" }, + { "IN1L Analog Mux", "B", "IN1BLP" }, + { "IN1R Analog Mux", "A", "IN1ARN" }, + { "IN1R Analog Mux", "A", "IN1ARP" }, + { "IN1R Analog Mux", "B", "IN1BR" }, + { "IN1R Analog Mux", "B", "IN1ALN" }, + + { "IN1L Mode", "Analog", "IN1L Analog Mux" }, + { "IN1R Mode", "Analog", "IN1R Analog Mux" }, + + { "IN1L Mode", "Digital", "IN1ALN" }, + { "IN1L Mode", "Digital", "IN1ALP" }, + { "IN1R Mode", "Digital", "IN1ALN" }, + { "IN1R Mode", "Digital", "IN1ALP" }, + + { "IN1L", NULL, "IN1L Mode" }, + { "IN1R", NULL, "IN1R Mode" }, + + { "IN2L Analog Mux", "A", "IN2ALN" }, + { "IN2L Analog Mux", "A", "IN2ALP" }, + { "IN2L Analog Mux", "B", "IN2ALN" }, + { "IN2L Analog Mux", "B", "IN2BL" }, + { "IN2R Analog Mux", "A", "IN2ARN" }, + { "IN2R Analog Mux", "A", "IN2ARP" }, + { "IN2R Analog Mux", "B", "IN2ARN" }, + { "IN2R Analog Mux", "B", "IN2BR" }, + + { "IN2L Mode", "Analog", "IN2L Analog Mux" }, + { "IN2R Mode", "Analog", "IN2R Analog Mux" }, + + { "IN2L Mode", "Digital", "IN2ALN" }, + { "IN2L Mode", "Digital", "IN2ALP" }, + { "IN2R Mode", "Digital", "IN2ALN" }, + { "IN2R Mode", "Digital", "IN2ALP" }, + + { "IN2L", NULL, "IN2L Mode" }, + { "IN2R", NULL, "IN2R Mode" }, + + { "IN3L", NULL, "IN1ARN" }, + { "IN3L", NULL, "IN1ARP" }, + { "IN3R", NULL, "IN1ARN" }, + { "IN3R", NULL, "IN1ARP" }, + + { "IN4L", NULL, "IN2ARN" }, + { "IN4L", NULL, "IN2ARP" }, + { "IN4R", NULL, "IN2ARN" }, + { "IN4R", NULL, "IN2ARP" }, + + MADERA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + MADERA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + MADERA_MIXER_ROUTES("OUT2L", "HPOUT2L"), + MADERA_MIXER_ROUTES("OUT2R", "HPOUT2R"), + MADERA_MIXER_ROUTES("OUT3L", "HPOUT3L"), + MADERA_MIXER_ROUTES("OUT3R", "HPOUT3R"), + + MADERA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), + MADERA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), + + MADERA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + MADERA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + MADERA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + MADERA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + MADERA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + MADERA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + MADERA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + MADERA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + MADERA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), + MADERA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), + + MADERA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + MADERA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + MADERA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + MADERA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + MADERA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + MADERA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), + MADERA_MIXER_ROUTES("AIF2TX7", "AIF2TX7"), + MADERA_MIXER_ROUTES("AIF2TX8", "AIF2TX8"), + + MADERA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + MADERA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + MADERA_MIXER_ROUTES("AIF3TX3", "AIF3TX3"), + MADERA_MIXER_ROUTES("AIF3TX4", "AIF3TX4"), + + MADERA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"), + MADERA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"), + MADERA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"), + MADERA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"), + MADERA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"), + MADERA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"), + MADERA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"), + MADERA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"), + + MADERA_MUX_ROUTES("SPD1TX1", "SPDIFTX1"), + MADERA_MUX_ROUTES("SPD1TX2", "SPDIFTX2"), + + MADERA_MIXER_ROUTES("EQ1", "EQ1"), + MADERA_MIXER_ROUTES("EQ2", "EQ2"), + MADERA_MIXER_ROUTES("EQ3", "EQ3"), + MADERA_MIXER_ROUTES("EQ4", "EQ4"), + + MADERA_MIXER_ROUTES("DRC1L", "DRC1L"), + MADERA_MIXER_ROUTES("DRC1R", "DRC1R"), + MADERA_MIXER_ROUTES("DRC2L", "DRC2L"), + MADERA_MIXER_ROUTES("DRC2R", "DRC2R"), + + MADERA_MIXER_ROUTES("LHPF1", "LHPF1"), + MADERA_MIXER_ROUTES("LHPF2", "LHPF2"), + MADERA_MIXER_ROUTES("LHPF3", "LHPF3"), + MADERA_MIXER_ROUTES("LHPF4", "LHPF4"), + + MADERA_MUX_ROUTES("ASRC1IN1L", "ASRC1IN1L"), + MADERA_MUX_ROUTES("ASRC1IN1R", "ASRC1IN1R"), + MADERA_MUX_ROUTES("ASRC1IN2L", "ASRC1IN2L"), + MADERA_MUX_ROUTES("ASRC1IN2R", "ASRC1IN2R"), + + MADERA_DSP_ROUTES("DSP1"), + + MADERA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + MADERA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + + MADERA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + MADERA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + + MADERA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + MADERA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + + MADERA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + MADERA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + + { "AEC1 Loopback", "HPOUT1L", "OUT1L" }, + { "AEC1 Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1L", NULL, "OUT1L" }, + { "HPOUT1R", NULL, "OUT1R" }, + + { "AEC1 Loopback", "HPOUT2L", "OUT2L" }, + { "AEC1 Loopback", "HPOUT2R", "OUT2R" }, + { "HPOUT2L", NULL, "OUT2L" }, + { "HPOUT2R", NULL, "OUT2R" }, + + { "AEC1 Loopback", "HPOUT3L", "OUT3L" }, + { "AEC1 Loopback", "HPOUT3R", "OUT3R" }, + { "OUT3 Demux", NULL, "OUT3L" }, + { "OUT3 Demux", NULL, "OUT3R" }, + + { "HPOUT3L", "HPOUT3", "OUT3 Demux" }, + { "HPOUT3R", "HPOUT3", "OUT3 Demux" }, + { "HPOUT4L", "HPOUT4", "OUT3 Demux" }, + { "HPOUT4R", "HPOUT4", "OUT3 Demux" }, + + { "AEC1 Loopback", "SPKDAT1L", "OUT5L" }, + { "AEC1 Loopback", "SPKDAT1R", "OUT5R" }, + { "SPKDAT1L", NULL, "OUT5L" }, + { "SPKDAT1R", NULL, "OUT5R" }, + + { "SPDIF1", NULL, "SPD1" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1 Activity Output" }, + { "DRC2 Signal Activity", NULL, "DRC2 Activity Output" }, + { "DRC1 Activity Output", "Switch", "DRC1L" }, + { "DRC1 Activity Output", "Switch", "DRC1R" }, + { "DRC2 Activity Output", "Switch", "DRC2L" }, + { "DRC2 Activity Output", "Switch", "DRC2R" }, + + MADERA_MUX_ROUTES("DFC1", "DFC1"), + MADERA_MUX_ROUTES("DFC2", "DFC2"), + MADERA_MUX_ROUTES("DFC3", "DFC3"), + MADERA_MUX_ROUTES("DFC4", "DFC4"), + MADERA_MUX_ROUTES("DFC5", "DFC5"), + MADERA_MUX_ROUTES("DFC6", "DFC6"), + MADERA_MUX_ROUTES("DFC7", "DFC7"), + MADERA_MUX_ROUTES("DFC8", "DFC8"), +}; + +static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + + switch (fll_id) { + case MADERA_FLL1_REFCLK: + return madera_fllhj_set_refclk(&cs47l92->fll[0], source, fref, + fout); + case MADERA_FLL2_REFCLK: + return madera_fllhj_set_refclk(&cs47l92->fll[1], source, fref, + fout); + default: + return -EINVAL; + } +} + +static struct snd_soc_dai_driver cs47l92_dai[] = { + { + .name = "cs47l92-aif1", + .id = 1, + .base = MADERA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-aif2", + .id = 2, + .base = MADERA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-aif3", + .id = 3, + .base = MADERA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l92-slim1", + .id = 5, + .playback = { + .stream_name = "Slim1 Playback", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim1 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-slim2", + .id = 6, + .playback = { + .stream_name = "Slim2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-slim3", + .id = 7, + .playback = { + .stream_name = "Slim3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .capture = { + .stream_name = "Slim3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .ops = &madera_simple_dai_ops, + }, + { + .name = "cs47l92-cpu-trace", + .capture = { + .stream_name = "Audio Trace CPU", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "cs47l92-dsp-trace", + .capture = { + .stream_name = "Audio Trace DSP", + .channels_min = 1, + .channels_max = 2, + .rates = MADERA_RATES, + .formats = MADERA_FORMATS, + }, + }, +}; + +static int cs47l92_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "cs47l92-dsp-trace") == 0) { + n_adsp = 0; + } else { + dev_err(madera->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->adsp[n_adsp], stream); +} + +static irqreturn_t cs47l92_adsp2_irq(int irq, void *data) +{ + struct cs47l92 *cs47l92 = data; + struct madera_priv *priv = &cs47l92->core; + struct madera *madera = priv->madera; + int ret; + + ret = wm_adsp_compr_handle_irq(&priv->adsp[0]); + if (ret == -ENODEV) { + dev_err(madera->dev, "Spurious compressed data IRQ\n"); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int cs47l92_component_probe(struct snd_soc_component *component) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l92->core.madera; + int ret; + + snd_soc_component_init_regmap(component, madera->regmap); + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = snd_soc_component_get_dapm(component); + mutex_unlock(&madera->dapm_ptr_lock); + + ret = madera_init_inputs(component); + if (ret) + return ret; + + ret = madera_init_outputs(component, CS47L92_MONO_OUTPUTS); + if (ret) + return ret; + + snd_soc_component_disable_pin(component, "HAPTICS"); + + ret = snd_soc_add_component_controls(component, + madera_adsp_rate_controls, + CS47L92_NUM_ADSP); + if (ret) + return ret; + + return wm_adsp2_component_probe(&cs47l92->core.adsp[0], component); +} + +static void cs47l92_component_remove(struct snd_soc_component *component) +{ + struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); + struct madera *madera = cs47l92->core.madera; + + mutex_lock(&madera->dapm_ptr_lock); + madera->dapm = NULL; + mutex_unlock(&madera->dapm_ptr_lock); + + wm_adsp2_component_remove(&cs47l92->core.adsp[0], component); +} + +#define CS47L92_DIG_VU 0x0200 + +static unsigned int cs47l92_digital_vu[] = { + MADERA_DAC_DIGITAL_VOLUME_1L, + MADERA_DAC_DIGITAL_VOLUME_1R, + MADERA_DAC_DIGITAL_VOLUME_2L, + MADERA_DAC_DIGITAL_VOLUME_2R, + MADERA_DAC_DIGITAL_VOLUME_3L, + MADERA_DAC_DIGITAL_VOLUME_3R, + MADERA_DAC_DIGITAL_VOLUME_5L, + MADERA_DAC_DIGITAL_VOLUME_5R, +}; + +static const struct snd_compr_ops cs47l92_compr_ops = { + .open = &cs47l92_open, + .free = &wm_adsp_compr_free, + .set_params = &wm_adsp_compr_set_params, + .get_caps = &wm_adsp_compr_get_caps, + .trigger = &wm_adsp_compr_trigger, + .pointer = &wm_adsp_compr_pointer, + .copy = &wm_adsp_compr_copy, +}; + +static const struct snd_soc_component_driver soc_component_dev_cs47l92 = { + .probe = &cs47l92_component_probe, + .remove = &cs47l92_component_remove, + .set_sysclk = &madera_set_sysclk, + .set_pll = &cs47l92_set_fll, + .name = DRV_NAME, + .compr_ops = &cs47l92_compr_ops, + .controls = cs47l92_snd_controls, + .num_controls = ARRAY_SIZE(cs47l92_snd_controls), + .dapm_widgets = cs47l92_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l92_dapm_widgets), + .dapm_routes = cs47l92_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs47l92_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static int cs47l92_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct cs47l92 *cs47l92; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l92_dai) > MADERA_MAX_DAI); + + /* quick exit if Madera irqchip driver hasn't completed probe */ + if (!madera->irq_dev) { + dev_dbg(&pdev->dev, "irqchip driver not ready\n"); + return -EPROBE_DEFER; + } + + cs47l92 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l92), GFP_KERNEL); + if (!cs47l92) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l92); + + cs47l92->core.madera = madera; + cs47l92->core.dev = &pdev->dev; + cs47l92->core.num_inputs = 8; + + ret = madera_core_init(&cs47l92->core); + if (ret) + return ret; + + ret = madera_request_irq(madera, MADERA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l92_adsp2_irq, + cs47l92); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + goto error_core; + } + + ret = madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 1); + if (ret) + dev_warn(&pdev->dev, "Failed to set DSP IRQ wake: %d\n", ret); + + cs47l92->core.adsp[0].part = "cs47l92"; + cs47l92->core.adsp[0].num = 1; + cs47l92->core.adsp[0].type = WMFW_ADSP2; + cs47l92->core.adsp[0].rev = 2; + cs47l92->core.adsp[0].dev = madera->dev; + cs47l92->core.adsp[0].regmap = madera->regmap_32bit; + + cs47l92->core.adsp[0].base = MADERA_DSP1_CONFIG_1; + cs47l92->core.adsp[0].mem = cs47l92_dsp1_regions; + cs47l92->core.adsp[0].num_mems = ARRAY_SIZE(cs47l92_dsp1_regions); + + cs47l92->core.adsp[0].lock_regions = WM_ADSP2_REGION_1_9; + + ret = wm_adsp2_init(&cs47l92->core.adsp[0]); + if (ret != 0) + goto error_dsp_irq; + + ret = madera_init_bus_error_irq(&cs47l92->core, 0, wm_adsp2_bus_error); + if (ret != 0) { + wm_adsp2_remove(&cs47l92->core.adsp[0]); + goto error_adsp; + } + + madera_init_fll(madera, 1, MADERA_FLL1_CONTROL_1 - 1, + &cs47l92->fll[0]); + madera_init_fll(madera, 2, MADERA_FLL2_CONTROL_1 - 1, + &cs47l92->fll[1]); + + for (i = 0; i < ARRAY_SIZE(cs47l92_dai); i++) + madera_init_dai(&cs47l92->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l92_digital_vu); i++) + regmap_update_bits(madera->regmap, cs47l92_digital_vu[i], + CS47L92_DIG_VU, CS47L92_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_cs47l92, + cs47l92_dai, + ARRAY_SIZE(cs47l92_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + goto error_pm_runtime; + } + + return ret; + +error_pm_runtime: + pm_runtime_disable(&pdev->dev); + madera_free_bus_error_irq(&cs47l92->core, 0); +error_adsp: + wm_adsp2_remove(&cs47l92->core.adsp[0]); +error_dsp_irq: + madera_set_irq_wake(madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(madera, MADERA_IRQ_DSP_IRQ1, cs47l92); +error_core: + madera_core_free(&cs47l92->core); + + return ret; +} + +static int cs47l92_remove(struct platform_device *pdev) +{ + struct cs47l92 *cs47l92 = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + + madera_free_bus_error_irq(&cs47l92->core, 0); + wm_adsp2_remove(&cs47l92->core.adsp[0]); + + madera_set_irq_wake(cs47l92->core.madera, MADERA_IRQ_DSP_IRQ1, 0); + madera_free_irq(cs47l92->core.madera, MADERA_IRQ_DSP_IRQ1, cs47l92); + + madera_core_free(&cs47l92->core); + + return 0; +} + +static struct platform_driver cs47l92_codec_driver = { + .driver = { + .name = "cs47l92-codec", + }, + .probe = &cs47l92_probe, + .remove = &cs47l92_remove, +}; + +module_platform_driver(cs47l92_codec_driver); + +MODULE_SOFTDEP("pre: madera irq-madera arizona-micsupp"); +MODULE_DESCRIPTION("ASoC CS47L92 driver"); +MODULE_AUTHOR("Stuart Henderson <stuarth@opensource.cirrus.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l92-codec"); diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index ed2959dbe1fb..36eef1fb3d18 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/mod_devicetable.h> @@ -33,6 +34,7 @@ static const unsigned int supported_mclk_lrck_ratios[] = { struct es8316_priv { struct mutex lock; + struct clk *mclk; struct regmap *regmap; struct snd_soc_component *component; struct snd_soc_jack *jack; @@ -363,13 +365,21 @@ static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); - int i; + int i, ret; int count = 0; es8316->sysclk = freq; - if (freq == 0) + if (freq == 0) { + es8316->sysclk_constraints.list = NULL; + es8316->sysclk_constraints.count = 0; + return 0; + } + + ret = clk_set_rate(es8316->mclk, freq); + if (ret) + return ret; /* Limit supported sample rates to ones that can be autodetected * by the codec running in slave mode. @@ -444,17 +454,10 @@ static int es8316_pcm_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); - if (es8316->sysclk == 0) { - dev_err(component->dev, "No sysclk provided\n"); - return -EINVAL; - } - - /* The set of sample rates that can be supported depends on the - * MCLK supplied to the CODEC. - */ - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &es8316->sysclk_constraints); + if (es8316->sysclk_constraints.list) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &es8316->sysclk_constraints); return 0; } @@ -466,11 +469,19 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); u8 wordlen = 0; + int i; - if (!es8316->sysclk) { - dev_err(component->dev, "No MCLK configured\n"); - return -EINVAL; + /* Validate supported sample rates that are autodetected from MCLK */ + for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) { + const unsigned int ratio = supported_mclk_lrck_ratios[i]; + + if (es8316->sysclk % ratio != 0) + continue; + if (es8316->sysclk / ratio == params_rate(params)) + break; } + if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS) + return -EINVAL; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -700,9 +711,24 @@ static int es8316_set_jack(struct snd_soc_component *component, static int es8316_probe(struct snd_soc_component *component) { struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + int ret; es8316->component = component; + es8316->mclk = devm_clk_get_optional(component->dev, "mclk"); + if (IS_ERR(es8316->mclk)) { + dev_err(component->dev, "unable to get mclk\n"); + return PTR_ERR(es8316->mclk); + } + if (!es8316->mclk) + dev_warn(component->dev, "assuming static mclk\n"); + + ret = clk_prepare_enable(es8316->mclk); + if (ret) { + dev_err(component->dev, "unable to enable mclk\n"); + return ret; + } + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -725,8 +751,16 @@ static int es8316_probe(struct snd_soc_component *component) return 0; } +static void es8316_remove(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(es8316->mclk); +} + static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .remove = es8316_remove, .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 69b81e704127..fdf64c29f563 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -99,7 +99,6 @@ static SOC_ENUM_SINGLE_DECL(adcpol, static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); -static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 0bf1c8cad108..b5fd8f08726e 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/string.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -274,6 +275,8 @@ struct hdmi_codec_priv { struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; struct mutex lock; + struct snd_soc_jack *jack; + unsigned int jack_status; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -663,6 +666,49 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) return 0; } +static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, + unsigned int jack_status) +{ + if (hcp->jack && jack_status != hcp->jack_status) { + snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); + hcp->jack_status = jack_status; + } +} + +static void plugged_cb(struct device *dev, bool plugged) +{ + struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + + if (plugged) + hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); + else + hdmi_codec_jack_report(hcp, 0); +} + +/** + * hdmi_codec_set_jack_detect - register HDMI plugged callback + * @component: the hdmi-codec instance + * @jack: ASoC jack to report (dis)connection events on + */ +int hdmi_codec_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + int ret = -EOPNOTSUPP; + + if (hcp->hcd.ops->hook_plugged_cb) { + hcp->jack = jack; + ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent, + hcp->hcd.data, + plugged_cb, + component->dev); + if (ret) + hcp->jack = NULL; + } + return ret; +} +EXPORT_SYMBOL_GPL(hdmi_codec_set_jack_detect); + static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) { struct hdmi_codec_daifmt *cf = dai->playback_dma_data; diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c index 7feedbb7bbed..14d8fe1c28a4 100644 --- a/sound/soc/codecs/inno_rk3036.c +++ b/sound/soc/codecs/inno_rk3036.c @@ -405,7 +405,6 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev) { struct rk3036_codec_priv *priv; struct device_node *of_node = pdev->dev.of_node; - struct resource *res; void __iomem *base; struct regmap *grf; int ret; @@ -414,8 +413,7 @@ static int rk3036_codec_platform_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 766354c73076..2567a5d15b55 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -545,15 +545,13 @@ static int jz4725b_codec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct jz_icdc *icdc; - struct resource *mem; int ret; icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL); if (!icdc) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - icdc->base = devm_ioremap_resource(dev, mem); + icdc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(icdc->base)) return PTR_ERR(icdc->base); diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 974e17fa1911..460aa1fd1efe 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -318,7 +318,6 @@ static int jz4740_codec_probe(struct platform_device *pdev) { int ret; struct jz4740_codec *jz4740_codec; - struct resource *mem; void __iomem *base; jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec), @@ -326,8 +325,7 @@ static int jz4740_codec_probe(struct platform_device *pdev) if (!jz4740_codec) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index 1b1be19a2f99..52639811cc52 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -87,6 +87,16 @@ #define MADERA_FLLAO_MIN_N 4 #define MADERA_FLLAO_MAX_N 1023 #define MADERA_FLLAO_MAX_FBDIV 254 +#define MADERA_FLLHJ_INT_MAX_N 1023 +#define MADERA_FLLHJ_INT_MIN_N 1 +#define MADERA_FLLHJ_FRAC_MAX_N 255 +#define MADERA_FLLHJ_FRAC_MIN_N 4 +#define MADERA_FLLHJ_LOW_THRESH 192000 +#define MADERA_FLLHJ_MID_THRESH 1152000 +#define MADERA_FLLHJ_MAX_THRESH 13000000 +#define MADERA_FLLHJ_LOW_GAINS 0x23f0 +#define MADERA_FLLHJ_MID_GAINS 0x22f2 +#define MADERA_FLLHJ_HIGH_GAINS 0x21f0 #define MADERA_FLL_SYNCHRONISER_OFFS 0x10 #define CS47L35_FLL_SYNCHRONISER_OFFS 0xE @@ -96,6 +106,7 @@ #define MADERA_FLL_CONTROL_4_OFFS 0x4 #define MADERA_FLL_CONTROL_5_OFFS 0x5 #define MADERA_FLL_CONTROL_6_OFFS 0x6 +#define MADERA_FLL_GAIN_OFFS 0x8 #define MADERA_FLL_CONTROL_7_OFFS 0x9 #define MADERA_FLL_EFS_2_OFFS 0xA #define MADERA_FLL_SYNCHRONISER_1_OFFS 0x1 @@ -107,6 +118,9 @@ #define MADERA_FLL_SYNCHRONISER_7_OFFS 0x7 #define MADERA_FLL_SPREAD_SPECTRUM_OFFS 0x9 #define MADERA_FLL_GPIO_CLOCK_OFFS 0xA +#define MADERA_FLL_CONTROL_10_OFFS 0xA +#define MADERA_FLL_CONTROL_11_OFFS 0xB +#define MADERA_FLL1_DIGITAL_TEST_1_OFFS 0xD #define MADERA_FLLAO_CONTROL_1_OFFS 0x1 #define MADERA_FLLAO_CONTROL_2_OFFS 0x2 @@ -300,6 +314,100 @@ int madera_free_overheat(struct madera_priv *priv) } EXPORT_SYMBOL_GPL(madera_free_overheat); +static int madera_get_variable_u32_array(struct device *dev, + const char *propname, + u32 *dest, int n_max, + int multiple) +{ + int n, ret; + + n = device_property_count_u32(dev, propname); + if (n < 0) { + if (n == -EINVAL) + return 0; /* missing, ignore */ + + dev_warn(dev, "%s malformed (%d)\n", propname, n); + + return n; + } else if ((n % multiple) != 0) { + dev_warn(dev, "%s not a multiple of %d entries\n", + propname, multiple); + + return -EINVAL; + } + + if (n > n_max) + n = n_max; + + ret = device_property_read_u32_array(dev, propname, dest, n); + if (ret < 0) + return ret; + + return n; +} + +static void madera_prop_get_inmode(struct madera_priv *priv) +{ + struct madera *madera = priv->madera; + struct madera_codec_pdata *pdata = &madera->pdata.codec; + u32 tmp[MADERA_MAX_INPUT * MADERA_MAX_MUXED_CHANNELS]; + int n, i, in_idx, ch_idx; + + BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode) != MADERA_MAX_INPUT); + BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode[0]) != MADERA_MAX_MUXED_CHANNELS); + + n = madera_get_variable_u32_array(madera->dev, "cirrus,inmode", + tmp, ARRAY_SIZE(tmp), + MADERA_MAX_MUXED_CHANNELS); + if (n < 0) + return; + + in_idx = 0; + ch_idx = 0; + for (i = 0; i < n; ++i) { + pdata->inmode[in_idx][ch_idx] = tmp[i]; + + if (++ch_idx == MADERA_MAX_MUXED_CHANNELS) { + ch_idx = 0; + ++in_idx; + } + } +} + +static void madera_prop_get_pdata(struct madera_priv *priv) +{ + struct madera *madera = priv->madera; + struct madera_codec_pdata *pdata = &madera->pdata.codec; + u32 out_mono[ARRAY_SIZE(pdata->out_mono)]; + int i, n; + + madera_prop_get_inmode(priv); + + n = madera_get_variable_u32_array(madera->dev, "cirrus,out-mono", + out_mono, ARRAY_SIZE(out_mono), 1); + if (n > 0) + for (i = 0; i < n; ++i) + pdata->out_mono[i] = !!out_mono[i]; + + madera_get_variable_u32_array(madera->dev, + "cirrus,max-channels-clocked", + pdata->max_channels_clocked, + ARRAY_SIZE(pdata->max_channels_clocked), + 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,pdm-fmt", + pdata->pdm_fmt, + ARRAY_SIZE(pdata->pdm_fmt), 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,pdm-mute", + pdata->pdm_mute, + ARRAY_SIZE(pdata->pdm_mute), 1); + + madera_get_variable_u32_array(madera->dev, "cirrus,dmic-ref", + pdata->dmic_ref, + ARRAY_SIZE(pdata->dmic_ref), 1); +} + int madera_core_init(struct madera_priv *priv) { int i; @@ -308,6 +416,9 @@ int madera_core_init(struct madera_priv *priv) BUILD_BUG_ON(!madera_mixer_texts[MADERA_NUM_MIXER_INPUTS - 1]); BUILD_BUG_ON(!madera_mixer_values[MADERA_NUM_MIXER_INPUTS - 1]); + if (!dev_get_platdata(priv->madera->dev)) + madera_prop_get_pdata(priv); + mutex_init(&priv->rate_lock); for (i = 0; i < MADERA_MAX_HP_OUTPUT; i++) @@ -944,6 +1055,10 @@ static void madera_configure_input_mode(struct madera *madera) int max_analogue_inputs, max_dmic_sup, i; switch (madera->type) { + case CS47L15: + max_analogue_inputs = 1; + max_dmic_sup = 2; + break; case CS47L35: max_analogue_inputs = 2; max_dmic_sup = 2; @@ -1770,6 +1885,18 @@ const struct soc_enum madera_asrc1_rate[] = { }; EXPORT_SYMBOL_GPL(madera_asrc1_rate); +const struct soc_enum madera_asrc1_bidir_rate[] = { + SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1, + MADERA_ASRC1_RATE1_SHIFT, 0xf, + MADERA_RATE_ENUM_SIZE, + madera_rate_text, madera_rate_val), + SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2, + MADERA_ASRC1_RATE2_SHIFT, 0xf, + MADERA_RATE_ENUM_SIZE, + madera_rate_text, madera_rate_val), +}; +EXPORT_SYMBOL_GPL(madera_asrc1_bidir_rate); + const struct soc_enum madera_asrc2_rate[] = { SOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE1, MADERA_ASRC2_RATE1_SHIFT, 0xf, @@ -2149,6 +2276,9 @@ int madera_out_ev(struct snd_soc_dapm_widget *w, switch (madera->type) { case CS47L90: case CS47L91: + case CS42L92: + case CS47L92: + case CS47L93: out_up_delay = 6; break; default: @@ -2264,9 +2394,17 @@ int madera_hp_ev(struct snd_soc_dapm_widget *w, madera->hp_ena &= ~mask; madera->hp_ena |= val; - /* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */ - regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel); - ep_sel &= MADERA_EP_SEL_MASK; + switch (madera->type) { + case CS42L92: + case CS47L92: + case CS47L93: + break; + default: + /* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */ + regmap_read(madera->regmap, MADERA_OUTPUT_ENABLES_1, &ep_sel); + ep_sel &= MADERA_EP_SEL_MASK; + break; + } /* Force off if HPDET has disabled the clamp for this output */ if (!ep_sel && @@ -2442,6 +2580,58 @@ static int madera_get_dspclk_setting(struct madera *madera, } } +static int madera_set_outclk(struct snd_soc_component *component, + unsigned int source, unsigned int freq) +{ + int div, div_inc, rate; + + switch (source) { + case MADERA_OUTCLK_SYSCLK: + dev_dbg(component->dev, "Configured OUTCLK to SYSCLK\n"); + snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1, + MADERA_OUT_CLK_SRC_MASK, source); + return 0; + case MADERA_OUTCLK_ASYNCCLK: + dev_dbg(component->dev, "Configured OUTCLK to ASYNCCLK\n"); + snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1, + MADERA_OUT_CLK_SRC_MASK, source); + return 0; + case MADERA_OUTCLK_MCLK1: + case MADERA_OUTCLK_MCLK2: + case MADERA_OUTCLK_MCLK3: + break; + default: + return -EINVAL; + } + + if (freq % 4000) + rate = 5644800; + else + rate = 6144000; + + div = 1; + div_inc = 0; + while (div <= 8) { + if (freq / div == rate && !(freq % div)) { + dev_dbg(component->dev, "Configured %dHz OUTCLK\n", rate); + snd_soc_component_update_bits(component, + MADERA_OUTPUT_RATE_1, + MADERA_OUT_EXT_CLK_DIV_MASK | + MADERA_OUT_CLK_SRC_MASK, + (div_inc << MADERA_OUT_EXT_CLK_DIV_SHIFT) | + source); + return 0; + } + div_inc++; + div *= 2; + } + + dev_err(component->dev, + "Unable to generate %dHz OUTCLK from %dHz MCLK\n", + rate, freq); + return -EINVAL; +} + int madera_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { @@ -2478,6 +2668,8 @@ int madera_set_sysclk(struct snd_soc_component *component, int clk_id, case MADERA_CLK_OPCLK: case MADERA_CLK_ASYNC_OPCLK: return madera_set_opclk(component, clk_id, freq); + case MADERA_CLK_OUTCLK: + return madera_set_outclk(component, source, freq); default: return -EINVAL; } @@ -2691,6 +2883,10 @@ static const unsigned int madera_sr_vals[] = { #define MADERA_192K_44K1_RATE_MASK 0x003E00 #define MADERA_192K_RATE_MASK (MADERA_192K_48K_RATE_MASK | \ MADERA_192K_44K1_RATE_MASK) +#define MADERA_384K_48K_RATE_MASK 0x0F007E +#define MADERA_384K_44K1_RATE_MASK 0x007E00 +#define MADERA_384K_RATE_MASK (MADERA_384K_48K_RATE_MASK | \ + MADERA_384K_44K1_RATE_MASK) static const struct snd_pcm_hw_constraint_list madera_constraint = { .count = ARRAY_SIZE(madera_sr_vals), @@ -2703,6 +2899,7 @@ static int madera_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct madera_priv *priv = snd_soc_component_get_drvdata(component); struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1]; + struct madera *madera = priv->madera; unsigned int base_rate; if (!substream->runtime) @@ -2722,12 +2919,26 @@ static int madera_startup(struct snd_pcm_substream *substream, return 0; } - if (base_rate == 0) - dai_priv->constraint.mask = MADERA_192K_RATE_MASK; - else if (base_rate % 4000) - dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK; - else - dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK; + switch (madera->type) { + case CS42L92: + case CS47L92: + case CS47L93: + if (base_rate == 0) + dai_priv->constraint.mask = MADERA_384K_RATE_MASK; + else if (base_rate % 4000) + dai_priv->constraint.mask = MADERA_384K_44K1_RATE_MASK; + else + dai_priv->constraint.mask = MADERA_384K_48K_RATE_MASK; + break; + default: + if (base_rate == 0) + dai_priv->constraint.mask = MADERA_192K_RATE_MASK; + else if (base_rate % 4000) + dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK; + else + dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK; + break; + } return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, @@ -4048,6 +4259,308 @@ int madera_set_fll_ao_refclk(struct madera_fll *fll, int source, } EXPORT_SYMBOL_GPL(madera_set_fll_ao_refclk); +static int madera_fllhj_disable(struct madera_fll *fll) +{ + struct madera *madera = fll->madera; + bool change; + + madera_fll_dbg(fll, "Disabling FLL\n"); + + /* Disable lockdet, but don't set ctrl_upd update but. This allows the + * lock status bit to clear as normal, but should the FLL be enabled + * again due to a control clock being required, the lock won't re-assert + * as the FLL config registers are automatically applied when the FLL + * enables. + */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_MASK, 0); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, MADERA_FLL1_HOLD_MASK); + regmap_update_bits_check(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_ENA_MASK, 0, &change); + + madera_wait_for_fll(fll, false); + + /* ctrl_up gates the writes to all the fll's registers, setting it to 0 + * here ensures that after a runtime suspend/resume cycle when one + * enables the fll then ctrl_up is the last bit that is configured + * by the fll enable code rather than the cache sync operation which + * would have updated it much earlier before writing out all fll + * registers + */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + MADERA_FLL1_CTRL_UPD_MASK, 0); + + if (change) + pm_runtime_put_autosuspend(madera->dev); + + return 0; +} + +static int madera_fllhj_apply(struct madera_fll *fll, int fin) +{ + struct madera *madera = fll->madera; + int refdiv, fref, fout, lockdet_thr, fbdiv, hp, fast_clk, fllgcd; + bool frac = false; + unsigned int fll_n, min_n, max_n, ratio, theta, lambda; + unsigned int gains, val, num; + + madera_fll_dbg(fll, "fin=%d, fout=%d\n", fin, fll->fout); + + for (refdiv = 0; refdiv < 4; refdiv++) + if ((fin / (1 << refdiv)) <= MADERA_FLLHJ_MAX_THRESH) + break; + + fref = fin / (1 << refdiv); + + /* Use simple heuristic approach to find a configuration that + * should work for most input clocks. + */ + fast_clk = 0; + fout = fll->fout; + frac = fout % fref; + + if (fref < MADERA_FLLHJ_LOW_THRESH) { + lockdet_thr = 2; + gains = MADERA_FLLHJ_LOW_GAINS; + if (frac) + fbdiv = 256; + else + fbdiv = 4; + } else if (fref < MADERA_FLLHJ_MID_THRESH) { + lockdet_thr = 8; + gains = MADERA_FLLHJ_MID_GAINS; + fbdiv = 1; + } else { + lockdet_thr = 8; + gains = MADERA_FLLHJ_HIGH_GAINS; + fbdiv = 1; + /* For high speed input clocks, enable 300MHz fast oscillator + * when we're in fractional divider mode. + */ + if (frac) { + fast_clk = 0x3; + fout = fll->fout * 6; + } + } + /* Use high performance mode for fractional configurations. */ + if (frac) { + hp = 0x3; + min_n = MADERA_FLLHJ_FRAC_MIN_N; + max_n = MADERA_FLLHJ_FRAC_MAX_N; + } else { + hp = 0x0; + min_n = MADERA_FLLHJ_INT_MIN_N; + max_n = MADERA_FLLHJ_INT_MAX_N; + } + + ratio = fout / fref; + + madera_fll_dbg(fll, "refdiv=%d, fref=%d, frac:%d\n", + refdiv, fref, frac); + + while (ratio / fbdiv < min_n) { + fbdiv /= 2; + if (fbdiv < 1) { + madera_fll_err(fll, "FBDIV (%d) must be >= 1\n", fbdiv); + return -EINVAL; + } + } + while (frac && (ratio / fbdiv > max_n)) { + fbdiv *= 2; + if (fbdiv >= 1024) { + madera_fll_err(fll, "FBDIV (%u) >= 1024\n", fbdiv); + return -EINVAL; + } + } + + madera_fll_dbg(fll, "lockdet=%d, hp=0x%x, fbdiv:%d\n", + lockdet_thr, hp, fbdiv); + + /* Calculate N.K values */ + fllgcd = gcd(fout, fbdiv * fref); + num = fout / fllgcd; + lambda = (fref * fbdiv) / fllgcd; + fll_n = num / lambda; + theta = num % lambda; + + madera_fll_dbg(fll, "fll_n=%d, gcd=%d, theta=%d, lambda=%d\n", + fll_n, fllgcd, theta, lambda); + + /* Some sanity checks before any registers are written. */ + if (fll_n < min_n || fll_n > max_n) { + madera_fll_err(fll, "N not in valid %s mode range %d-%d: %d\n", + frac ? "fractional" : "integer", min_n, max_n, + fll_n); + return -EINVAL; + } + if (fbdiv < 1 || (frac && fbdiv >= 1024) || (!frac && fbdiv >= 256)) { + madera_fll_err(fll, "Invalid fbdiv for %s mode (%u)\n", + frac ? "fractional" : "integer", fbdiv); + return -EINVAL; + } + + /* clear the ctrl_upd bit to guarantee we write to it later. */ + regmap_write(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + fll_n << MADERA_FLL1_N_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_3_OFFS, + MADERA_FLL1_THETA_MASK, + theta << MADERA_FLL1_THETA_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_4_OFFS, + MADERA_FLL1_LAMBDA_MASK, + lambda << MADERA_FLL1_LAMBDA_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_5_OFFS, + MADERA_FLL1_FB_DIV_MASK, + fbdiv << MADERA_FLL1_FB_DIV_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_6_OFFS, + MADERA_FLL1_REFCLK_DIV_MASK, + refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_GAIN_OFFS, + 0xffff, + gains); + val = hp << MADERA_FLL1_HP_SHIFT; + val |= 1 << MADERA_FLL1_PHASEDET_ENA_SHIFT; + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_10_OFFS, + MADERA_FLL1_HP_MASK | MADERA_FLL1_PHASEDET_ENA_MASK, + val); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_THR_MASK, + lockdet_thr << MADERA_FLL1_LOCKDET_THR_SHIFT); + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL1_DIGITAL_TEST_1_OFFS, + MADERA_FLL1_SYNC_EFS_ENA_MASK | + MADERA_FLL1_CLK_VCO_FAST_SRC_MASK, + fast_clk); + + return 0; +} + +static int madera_fllhj_enable(struct madera_fll *fll) +{ + struct madera *madera = fll->madera; + int already_enabled = madera_is_enabled_fll(fll, fll->base); + int ret; + + if (already_enabled < 0) + return already_enabled; + + if (!already_enabled) + pm_runtime_get_sync(madera->dev); + + madera_fll_dbg(fll, "Enabling FLL, initially %s\n", + already_enabled ? "enabled" : "disabled"); + + /* FLLn_HOLD must be set before configuring any registers */ + regmap_update_bits(fll->madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, + MADERA_FLL1_HOLD_MASK); + + /* Apply refclk */ + ret = madera_fllhj_apply(fll, fll->ref_freq); + if (ret) { + madera_fll_err(fll, "Failed to set FLL: %d\n", ret); + goto out; + } + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + CS47L92_FLL1_REFCLK_SRC_MASK, + fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT); + + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_ENA_MASK, + MADERA_FLL1_ENA_MASK); + +out: + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_11_OFFS, + MADERA_FLL1_LOCKDET_MASK, + MADERA_FLL1_LOCKDET_MASK); + + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_2_OFFS, + MADERA_FLL1_CTRL_UPD_MASK, + MADERA_FLL1_CTRL_UPD_MASK); + + /* Release the hold so that flln locks to external frequency */ + regmap_update_bits(madera->regmap, + fll->base + MADERA_FLL_CONTROL_1_OFFS, + MADERA_FLL1_HOLD_MASK, + 0); + + if (!already_enabled) + madera_wait_for_fll(fll, true); + + return 0; +} + +static int madera_fllhj_validate(struct madera_fll *fll, + unsigned int ref_in, + unsigned int fout) +{ + if (fout && !ref_in) { + madera_fll_err(fll, "fllout set without valid input clk\n"); + return -EINVAL; + } + + if (fll->fout && fout != fll->fout) { + madera_fll_err(fll, "Can't change output on active FLL\n"); + return -EINVAL; + } + + if (ref_in / MADERA_FLL_MAX_REFDIV > MADERA_FLLHJ_MAX_THRESH) { + madera_fll_err(fll, "Can't scale %dMHz to <=13MHz\n", ref_in); + return -EINVAL; + } + + return 0; +} + +int madera_fllhj_set_refclk(struct madera_fll *fll, int source, + unsigned int fin, unsigned int fout) +{ + int ret = 0; + + /* To remain consistent with previous FLLs, we expect fout to be + * provided in the form of the required sysclk rate, which is + * 2x the calculated fll out. + */ + if (fout) + fout /= 2; + + if (fll->ref_src == source && fll->ref_freq == fin && + fll->fout == fout) + return 0; + + if (fin && fout && madera_fllhj_validate(fll, fin, fout)) + return -EINVAL; + + fll->ref_src = source; + fll->ref_freq = fin; + fll->fout = fout; + + if (fout) + ret = madera_fllhj_enable(fll); + else + madera_fllhj_disable(fll); + + return ret; +} +EXPORT_SYMBOL_GPL(madera_fllhj_set_refclk); + /** * madera_set_output_mode - Set the mode of the specified output * diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h index 0af66f280770..1f3e8e230cf2 100644 --- a/sound/soc/codecs/madera.h +++ b/sound/soc/codecs/madera.h @@ -47,6 +47,7 @@ #define MADERA_CLK_SYSCLK_3 6 #define MADERA_CLK_ASYNCCLK_2 7 #define MADERA_CLK_DSPCLK 8 +#define MADERA_CLK_OUTCLK 9 #define MADERA_CLK_SRC_MCLK1 0x0 #define MADERA_CLK_SRC_MCLK2 0x1 @@ -61,6 +62,12 @@ #define MADERA_CLK_SRC_AIF4BCLK 0xB #define MADERA_CLK_SRC_FLLAO 0xF +#define MADERA_OUTCLK_SYSCLK 0 +#define MADERA_OUTCLK_ASYNCCLK 1 +#define MADERA_OUTCLK_MCLK1 4 +#define MADERA_OUTCLK_MCLK2 5 +#define MADERA_OUTCLK_MCLK3 6 + #define MADERA_MIXER_VOL_MASK 0x00FE #define MADERA_MIXER_VOL_SHIFT 1 #define MADERA_MIXER_VOL_WIDTH 7 @@ -326,6 +333,7 @@ extern const struct soc_enum madera_sample_rate[]; extern const struct soc_enum madera_isrc_fsl[]; extern const struct soc_enum madera_isrc_fsh[]; extern const struct soc_enum madera_asrc1_rate[]; +extern const struct soc_enum madera_asrc1_bidir_rate[]; extern const struct soc_enum madera_asrc2_rate[]; extern const struct soc_enum madera_dfc_width[]; extern const struct soc_enum madera_dfc_type[]; @@ -403,6 +411,8 @@ int madera_set_fll_syncclk(struct madera_fll *fll, int source, unsigned int fref, unsigned int fout); int madera_set_fll_ao_refclk(struct madera_fll *fll, int source, unsigned int fin, unsigned int fout); +int madera_fllhj_set_refclk(struct madera_fll *fll, int source, + unsigned int fin, unsigned int fout); int madera_core_init(struct madera_priv *priv); int madera_core_free(struct madera_priv *priv); diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index ce801489a86d..dfee05f985bd 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -154,10 +154,6 @@ static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv, 8, 10, TLV_DB_SCALE_ITEM(400, 100, 0) ); -static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv, - 0, 11, TLV_DB_SCALE_ITEM(950, 100, 0), -); - static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1); static const struct snd_kcontrol_new max98371_snd_controls[] = { diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 8c601a3ebc27..e609abcf3220 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -12,6 +12,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_gpio.h> #include <sound/tlv.h> #include "max98373.h" @@ -901,6 +902,17 @@ static void max98373_slot_config(struct i2c_client *i2c, else max98373->i_slot = 1; + max98373->reset_gpio = of_get_named_gpio(dev->of_node, + "maxim,reset-gpio", 0); + if (!gpio_is_valid(max98373->reset_gpio)) { + dev_err(dev, "Looking up %s property in node %s failed %d\n", + "maxim,reset-gpio", dev->of_node->full_name, + max98373->reset_gpio); + } else { + dev_dbg(dev, "maxim,reset-gpio=%d", + max98373->reset_gpio); + } + if (!device_property_read_u32(dev, "maxim,spkfb-slot-no", &value)) max98373->spkfb_slot = value & 0xF; else @@ -929,7 +941,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c, else max98373->interleave_mode = false; - /* regmap initialization */ max98373->regmap = devm_regmap_init_i2c(i2c, &max98373_regmap); @@ -940,6 +951,24 @@ static int max98373_i2c_probe(struct i2c_client *i2c, return ret; } + /* voltage/current slot & gpio configuration */ + max98373_slot_config(i2c, max98373); + + /* Power on device */ + if (gpio_is_valid(max98373->reset_gpio)) { + ret = gpio_request(max98373->reset_gpio, "MAX98373_RESET"); + if (ret) { + dev_err(&i2c->dev, "%s: Failed to request gpio %d\n", + __func__, max98373->reset_gpio); + gpio_free(max98373->reset_gpio); + return -EINVAL; + } + gpio_direction_output(max98373->reset_gpio, 0); + msleep(50); + gpio_direction_output(max98373->reset_gpio, 1); + msleep(20); + } + /* Check Revision ID */ ret = regmap_read(max98373->regmap, MAX98373_R21FF_REV_ID, ®); @@ -950,9 +979,6 @@ static int max98373_i2c_probe(struct i2c_client *i2c, } dev_info(&i2c->dev, "MAX98373 revisionID: 0x%02X\n", reg); - /* voltage/current slot configuration */ - max98373_slot_config(i2c, max98373); - /* codec registeration */ ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98373, max98373_dai, ARRAY_SIZE(max98373_dai)); diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h index a59e51355a84..63dae8be7105 100644 --- a/sound/soc/codecs/max98373.h +++ b/sound/soc/codecs/max98373.h @@ -205,6 +205,7 @@ struct max98373_priv { struct regmap *regmap; + int reset_gpio; unsigned int v_slot; unsigned int i_slot; unsigned int spkfb_slot; diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index f50ee8f5fe93..6f43748f9239 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -27,19 +27,6 @@ struct max9850_priv { unsigned int sysclk; }; -/* max9850 register cache */ -static const struct reg_default max9850_reg[] = { - { 2, 0x0c }, - { 3, 0x00 }, - { 4, 0x00 }, - { 5, 0x00 }, - { 6, 0x00 }, - { 7, 0x00 }, - { 8, 0x00 }, - { 9, 0x00 }, - { 10, 0x00 }, -}; - /* these registers are not used at the moment but provided for the sake of * completeness */ static bool max9850_volatile_register(struct device *dev, unsigned int reg) diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 818c0301fb29..c4dfa8ab1d49 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -20,15 +20,6 @@ static const char * const max98926_boost_voltage_txt[] = { "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V", "6.5V" }; -static const char * const max98926_boost_current_txt[] = { - "0.6", "0.8", "1.0", "1.2", "1.4", "1.6", "1.8", "2.0", - "2.2", "2.4", "2.6", "2.8", "3.2", "3.6", "4.0", "4.4" -}; - -static const char *const max98926_dai_txt[] = { - "Left", "Right", "LeftRight", "LeftRightDiv2", -}; - static const char *const max98926_pdm_ch_text[] = { "Current", "Voltage", }; diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 3abd27893ce6..55823bc95d06 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -56,7 +56,6 @@ static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0); static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0); static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0); -static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); static const char * const ml26124_companding[] = {"16bit PCM", "u-law", "A-law"}; diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 368b6c09474b..667e9f73aba3 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1185,10 +1185,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "mbhc_switch_int"); - if (irq < 0) { - dev_err(dev, "failed to get mbhc switch irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_mbhc_switch_irq_handler, @@ -1200,10 +1198,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (priv->mbhc_btn_enabled) { irq = platform_get_irq_byname(pdev, "mbhc_but_press_det"); - if (irq < 0) { - dev_err(dev, "failed to get button press irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_press_irq_handler, @@ -1214,10 +1210,8 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) dev_err(dev, "cannot request mbhc button press irq\n"); irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det"); - if (irq < 0) { - dev_err(dev, "failed to get button release irq\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(dev, irq, NULL, mbhc_btn_release_irq_handler, diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 1db7e43ec203..9fa5d44fdc79 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1143,7 +1143,6 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) struct msm8916_wcd_digital_priv *priv; struct device *dev = &pdev->dev; void __iomem *base; - struct resource *mem_res; struct regmap *digital_map; int ret; @@ -1151,8 +1150,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index 4b3ce01c5a93..5c0536eb1044 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1066,11 +1066,6 @@ static int mt_mic_bias_2_event(struct snd_soc_dapm_widget *w, return 0; } -/* DAPM Kcontrols */ -static const struct snd_kcontrol_new mt_lineout_control = - SOC_DAPM_SINGLE("Switch", MT6351_AUDDEC_ANA_CON3, - RG_AUDLOLPWRUP_VAUDP32_BIT, 1, 0); - /* DAPM Widgets */ static const struct snd_soc_dapm_widget mt6351_dapm_widgets[] = { /* Digital Clock */ diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 50b3fc5457ea..bb737fd678cc 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -1730,6 +1730,10 @@ static int mt6358_dmic_enable(struct mt6358_priv *priv) /* UL turn on */ regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003); + + /* Prevent pop noise form dmic hw */ + msleep(100); + return 0; } @@ -2255,10 +2259,8 @@ static struct snd_soc_dai_driver mt6358_dai_driver[] = { }, }; -static int mt6358_codec_init_reg(struct mt6358_priv *priv) +static void mt6358_codec_init_reg(struct mt6358_priv *priv) { - int ret = 0; - /* Disable HeadphoneL/HeadphoneR short circuit protection */ regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT, @@ -2285,8 +2287,6 @@ static int mt6358_codec_init_reg(struct mt6358_priv *priv) /* set gpio */ playback_gpio_reset(priv); capture_gpio_reset(priv); - - return ret; } static int mt6358_codec_probe(struct snd_soc_component *cmpnt) diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index f1104d7d6426..50ed86d45c26 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -44,18 +44,25 @@ static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { "VCCDA2" }; +#define PCM3168A_DAI_DAC 0 +#define PCM3168A_DAI_ADC 1 + +/* ADC/DAC side parameters */ +struct pcm3168a_io_params { + bool master_mode; + unsigned int fmt; + int tdm_slots; + u32 tdm_mask; + int slot_width; +}; + struct pcm3168a_priv { struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; struct regmap *regmap; struct clk *scki; - bool adc_master_mode; - bool dac_master_mode; unsigned long sysclk; - unsigned int adc_fmt; - unsigned int dac_fmt; - int tdm_slots; - u32 tdm_mask[2]; - int slot_width; + + struct pcm3168a_io_params io_params[2]; }; static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; @@ -263,7 +270,7 @@ static unsigned int pcm3168a_scki_ratios[] = { #define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios) #define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2) -#define PCM1368A_MAX_SYSCLK 36864000 +#define PCM3168A_MAX_SYSCLK 36864000 static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a) { @@ -296,7 +303,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component); int ret; - if (freq > PCM1368A_MAX_SYSCLK) + if (freq > PCM3168A_MAX_SYSCLK) return -EINVAL; ret = clk_set_rate(pcm3168a->scki, freq); @@ -308,8 +315,7 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, return 0; } -static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, - unsigned int format, bool dac) +static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); @@ -356,43 +362,31 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } - if (dac) { + if (dai->id == PCM3168A_DAI_DAC) { reg = PCM3168A_DAC_PWR_MST_FMT; mask = PCM3168A_DAC_FMT_MASK; shift = PCM3168A_DAC_FMT_SHIFT; - pcm3168a->dac_master_mode = master_mode; - pcm3168a->dac_fmt = fmt; } else { reg = PCM3168A_ADC_MST_FMT; mask = PCM3168A_ADC_FMTAD_MASK; shift = PCM3168A_ADC_FMTAD_SHIFT; - pcm3168a->adc_master_mode = master_mode; - pcm3168a->adc_fmt = fmt; } + pcm3168a->io_params[dai->id].master_mode = master_mode; + pcm3168a->io_params[dai->id].fmt = fmt; + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); return 0; } -static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai, - unsigned int format) -{ - return pcm3168a_set_dai_fmt(dai, format, true); -} - -static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai, - unsigned int format) -{ - return pcm3168a_set_dai_fmt(dai, format, false); -} - static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { dev_err(component->dev, @@ -408,22 +402,13 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - if (pcm3168a->tdm_slots && pcm3168a->tdm_slots != slots) { - dev_err(component->dev, "Not matching slots %d vs %d\n", - pcm3168a->tdm_slots, slots); - return -EINVAL; - } - - if (pcm3168a->slot_width && pcm3168a->slot_width != slot_width) { - dev_err(component->dev, "Not matching slot_width %d vs %d\n", - pcm3168a->slot_width, slot_width); - return -EINVAL; - } - - pcm3168a->tdm_slots = slots; - pcm3168a->slot_width = slot_width; - pcm3168a->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; - pcm3168a->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + io_params->tdm_slots = slots; + io_params->slot_width = slot_width; + /* Ignore the not relevant mask for the DAI/direction */ + if (dai->id == PCM3168A_DAI_DAC) + io_params->tdm_mask = tx_mask; + else + io_params->tdm_mask = rx_mask; return 0; } @@ -434,7 +419,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - bool tx, master_mode; + struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; + bool master_mode; u32 val, mask, shift, reg; unsigned int rate, fmt, ratio, max_ratio; unsigned int tdm_slots; @@ -444,23 +430,21 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, ratio = pcm3168a->sysclk / rate; - tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - if (tx) { + if (dai->id == PCM3168A_DAI_DAC) { max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; reg = PCM3168A_DAC_PWR_MST_FMT; mask = PCM3168A_DAC_MSDA_MASK; shift = PCM3168A_DAC_MSDA_SHIFT; - master_mode = pcm3168a->dac_master_mode; - fmt = pcm3168a->dac_fmt; } else { max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; reg = PCM3168A_ADC_MST_FMT; mask = PCM3168A_ADC_MSAD_MASK; shift = PCM3168A_ADC_MSAD_SHIFT; - master_mode = pcm3168a->adc_master_mode; - fmt = pcm3168a->adc_fmt; } + master_mode = io_params->master_mode; + fmt = io_params->fmt; + for (i = 0; i < max_ratio; i++) { if (pcm3168a_scki_ratios[i] == ratio) break; @@ -471,8 +455,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (pcm3168a->slot_width) - slot_width = pcm3168a->slot_width; + if (io_params->slot_width) + slot_width = io_params->slot_width; else slot_width = params_width(params); @@ -497,8 +481,8 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (pcm3168a->tdm_slots) - tdm_slots = pcm3168a->tdm_slots; + if (io_params->tdm_slots) + tdm_slots = io_params->tdm_slots; else tdm_slots = params_channels(params); @@ -534,7 +518,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(pcm3168a->regmap, reg, mask, val); - if (tx) { + if (dai->id == PCM3168A_DAI_DAC) { mask = PCM3168A_DAC_FMT_MASK; shift = PCM3168A_DAC_FMT_SHIFT; } else { @@ -552,20 +536,13 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int fmt; unsigned int sample_min; unsigned int channel_max; unsigned int channel_maxs[] = { - 6, /* rx */ - 8 /* tx */ + 8, /* DAC */ + 6 /* ADC */ }; - if (tx) - fmt = pcm3168a->dac_fmt; - else - fmt = pcm3168a->adc_fmt; - /* * Available Data Bits * @@ -578,7 +555,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, * I2S * LEFT_J */ - switch (fmt) { + switch (pcm3168a->io_params[dai->id].fmt) { case PCM3168A_FMT_RIGHT_J: sample_min = 16; channel_max = 2; @@ -588,7 +565,7 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, case PCM3168A_FMT_DSP_A: case PCM3168A_FMT_DSP_B: sample_min = 24; - channel_max = channel_maxs[tx]; + channel_max = channel_maxs[dai->id]; break; default: sample_min = 24; @@ -599,32 +576,29 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, sample_min, 32); + /* Allow all channels in multi DIN/DOUT mode */ + if (pcm3168a->io_params[dai->id].tdm_slots == 2) + channel_max = channel_maxs[dai->id]; + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, channel_max); return 0; } -static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { +static const struct snd_soc_dai_ops pcm3168a_dai_ops = { .startup = pcm3168a_startup, - .set_fmt = pcm3168a_set_dai_fmt_dac, + .set_fmt = pcm3168a_set_dai_fmt, .set_sysclk = pcm3168a_set_dai_sysclk, .hw_params = pcm3168a_hw_params, .digital_mute = pcm3168a_digital_mute, .set_tdm_slot = pcm3168a_set_tdm_slot, }; -static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { - .startup = pcm3168a_startup, - .set_fmt = pcm3168a_set_dai_fmt_adc, - .set_sysclk = pcm3168a_set_dai_sysclk, - .hw_params = pcm3168a_hw_params, - .set_tdm_slot = pcm3168a_set_tdm_slot, -}; - static struct snd_soc_dai_driver pcm3168a_dais[] = { { .name = "pcm3168a-dac", + .id = PCM3168A_DAI_DAC, .playback = { .stream_name = "Playback", .channels_min = 1, @@ -632,10 +606,11 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = PCM3168A_FORMATS }, - .ops = &pcm3168a_dac_dai_ops + .ops = &pcm3168a_dai_ops }, { .name = "pcm3168a-adc", + .id = PCM3168A_DAI_ADC, .capture = { .stream_name = "Capture", .channels_min = 1, @@ -643,7 +618,7 @@ static struct snd_soc_dai_driver pcm3168a_dais[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = PCM3168A_FORMATS }, - .ops = &pcm3168a_adc_dai_ops + .ops = &pcm3168a_dai_ops }, }; diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 24f8f86d58e9..287c962ba00d 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -432,7 +432,6 @@ static int rk3328_platform_probe(struct platform_device *pdev) { struct device_node *rk3328_np = pdev->dev.of_node; struct rk3328_codec_priv *rk3328; - struct resource *res; struct regmap *grf; void __iomem *base; int ret = 0; @@ -482,8 +481,7 @@ static int rk3328_platform_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index ed28250d5e34..be1e276e3631 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -978,9 +978,6 @@ static bool rt1011_readable_register(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9435, 37, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1739, 37, 0); - static const char * const rt1011_din_source_select[] = { "Left", "Right", @@ -1029,6 +1026,8 @@ static const char * const rt1011_tdm_adc_swap_select[] = { static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc1_1_enum, RT1011_TDM1_SET_3, 6, rt1011_tdm_adc_swap_select); +static SOC_ENUM_SINGLE_DECL(rt1011_tdm_adc2_1_enum, RT1011_TDM1_SET_3, 4, + rt1011_tdm_adc_swap_select); static void rt1011_reset(struct regmap *regmap) { @@ -1223,7 +1222,10 @@ static int rt1011_bq_drc_info(struct snd_kcontrol *kcontrol, static int rt1011_r0_cali_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = 0; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1011_priv *rt1011 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt1011->cali_done; return 0; } @@ -1237,6 +1239,7 @@ static int rt1011_r0_cali_put(struct snd_kcontrol *kcontrol, if (!component->card->instantiated) return 0; + rt1011->cali_done = 0; if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF && ucontrol->value.integer.value[0]) rt1011_calibrate(rt1011, 1); @@ -1333,7 +1336,8 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { /* TDM1 Data Out Selection */ SOC_ENUM("TDM1 DOUT Source", rt1011_tdm1_adc1_dat_enum), SOC_ENUM("TDM1 DOUT Location", rt1011_tdm1_adc1_loc_enum), - SOC_ENUM("TDM1 ADCDAT Swap Select", rt1011_tdm_adc1_1_enum), + SOC_ENUM("TDM1 ADC1DAT Swap Select", rt1011_tdm_adc1_1_enum), + SOC_ENUM("TDM1 ADC2DAT Swap Select", rt1011_tdm_adc2_1_enum), /* Data Out Mode */ SOC_ENUM("I2S ADC DOUT Mode", rt1011_adc_dout_mode_enum), @@ -1355,6 +1359,10 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = { SOC_SINGLE_EXT("R0 Calibration", SND_SOC_NOPM, 0, 1, 0, rt1011_r0_cali_get, rt1011_r0_cali_put), RT1011_R0_LOAD("R0 Load Mode"), + + /* R0 temperature */ + SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP, + 2, 255, 0), }; static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, @@ -1511,7 +1519,8 @@ static const struct snd_soc_dapm_route rt1011_dapm_routes[] = { static int rt1011_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; @@ -2139,6 +2148,7 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) r0_factor = ((format / r0[0] * 100) / 128) - (r0_integer * 100); rt1011->r0_reg = r0[0]; + rt1011->cali_done = 1; dev_info(dev, "r0 resistance about %d.%02d ohm, reg=0x%X\n", r0_integer, r0_factor, r0[0]); } @@ -2189,6 +2199,13 @@ static void rt1011_calibration_work(struct work_struct *work) rt1011_calibrate(rt1011, 1); + /* + * This flag should reset after booting. + * The factory test will do calibration again and use this flag to check + * whether the calibration completed + */ + rt1011->cali_done = 0; + /* initial */ rt1011_reg_init(component); } diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index 98a38800c4df..2d65983f3d0f 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -227,6 +227,7 @@ #define RT1011_STP_CALIB_RS_TEMP 0x152a #define RT1011_INIT_RECIPROCAL_REG_24_16 0x1538 #define RT1011_INIT_RECIPROCAL_REG_15_0 0x1539 +#define RT1011_STP_INITIAL_RESISTANCE_TEMP 0x153c #define RT1011_STP_ALPHA_RECIPROCAL_MSB 0x153e #define RT1011_SPK_RESISTANCE_1 0x1544 #define RT1011_SPK_RESISTANCE_2 0x1546 @@ -665,7 +666,7 @@ struct rt1011_priv { int pll_out; int bq_drc_set; - unsigned int r0_reg; + unsigned int r0_reg, cali_done; int recv_spk_mode; }; diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 9909369483f0..e27742abfa76 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -608,7 +608,8 @@ static const struct snd_soc_dapm_route rt1305_dapm_routes[] = { static int rt1305_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index d673506c7c39..b75931a69a1c 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -1,13 +1,10 @@ -/* - * rt1308.c -- RT1308 ALSA SoC amplifier component driver - * - * Copyright 2019 Realtek Semiconductor Corp. - * Author: Derek Fang <derek.fang@realtek.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// rt1308.c -- RT1308 ALSA SoC amplifier component driver +// +// Copyright 2019 Realtek Semiconductor Corp. +// Author: Derek Fang <derek.fang@realtek.com> +// #include <linux/module.h> #include <linux/moduleparam.h> @@ -40,10 +37,10 @@ static const struct reg_sequence init_list[] = { { RT1308_VREF, 0x18100000 }, { RT1308_IV_SENSE, 0x87010000 }, { RT1308_DUMMY_REG, 0x00000200 }, - { RT1308_SIL_DET, 0x61c30000 }, + { RT1308_SIL_DET, 0xe1c30000 }, { RT1308_DC_CAL_2, 0x00ffff00 }, { RT1308_CLK_DET, 0x01000000 }, - { RT1308_POWER_STATUS, 0x00800000 }, + { RT1308_POWER_STATUS, 0x08800000 }, { RT1308_DAC_SET, 0xafaf0700 }, }; @@ -308,12 +305,13 @@ static int rt1308_classd_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: msleep(30); snd_soc_component_update_bits(component, RT1308_POWER_STATUS, - RT1308_POW_PDB_REG_BIT, RT1308_POW_PDB_REG_BIT); + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT, + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT); msleep(40); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_component_update_bits(component, RT1308_POWER_STATUS, - RT1308_POW_PDB_REG_BIT, 0); + RT1308_POW_PDB_REG_BIT | RT1308_POW_PDB_MN_BIT, 0); usleep_range(150000, 200000); break; @@ -438,7 +436,8 @@ static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { static int rt1308_get_clk_info(int sclk, int rate) { - int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; + int i; + static const int pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; if (sclk <= 0 || rate <= 0) return -EINVAL; @@ -808,33 +807,11 @@ static void rt1308_efuse(struct rt1308_priv *rt1308) { regmap_write(rt1308->regmap, RT1308_RESET, 0); - regmap_write(rt1308->regmap, RT1308_POWER, 0xff371600); - regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52100000); - regmap_write(rt1308->regmap, RT1308_I2C_I2S_SDW_SET, 0x01014005); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501); - regmap_write(rt1308->regmap, RT1308_PADS_1, 0x50150505); - regmap_write(rt1308->regmap, RT1308_VREF, 0x18100000); - regmap_write(rt1308->regmap, RT1308_IV_SENSE, 0x87010000); - regmap_write(rt1308->regmap, RT1308_DUMMY_REG, 0x00000200); - regmap_write(rt1308->regmap, RT1308_SIL_DET, 0x61c30000); - regmap_write(rt1308->regmap, RT1308_CLK_DET, 0x03700000); - regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x50022f00); regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x01800000); - regmap_write(rt1308->regmap, RT1308_DC_CAL_2, 0x00ffff00); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x607e5501); - - regmap_write(rt1308->regmap, RT1308_CLK_2, 0x0060e000); - regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x04fe0f00); msleep(100); regmap_write(rt1308->regmap, RT1308_EFUSE_1, 0x44fe0f00); msleep(20); regmap_write(rt1308->regmap, RT1308_PVDD_OFFSET_CTL, 0x10000000); - - regmap_write(rt1308->regmap, RT1308_POWER_STATUS, 0x00800000); - regmap_write(rt1308->regmap, RT1308_POWER, 0x0); - regmap_write(rt1308->regmap, RT1308_CLK_1, 0x52000000); - regmap_write(rt1308->regmap, RT1308_CLASS_D_SET_2, 0x227f5501); - regmap_write(rt1308->regmap, RT1308_SINE_TONE_GEN_1, 0x10022f00); } static int rt1308_i2c_probe(struct i2c_client *i2c, diff --git a/sound/soc/codecs/rt1308.h b/sound/soc/codecs/rt1308.h index c330aae1d527..ff7c423e879e 100644 --- a/sound/soc/codecs/rt1308.h +++ b/sound/soc/codecs/rt1308.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * RT1308.h -- RT1308 ALSA SoC amplifier component driver + * rt1308.h -- RT1308 ALSA SoC amplifier component driver * * Copyright 2019 Realtek Semiconductor Corp. * Author: Derek Fang <derek.fang@realtek.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _RT1308_H_ diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index c050d84a6916..68299ce26d3e 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -2566,7 +2566,7 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w, return 0; } -static int rt5655_set_verf(struct snd_soc_dapm_widget *w, +static int rt5665_set_verf(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); @@ -2686,11 +2686,11 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL, RT5665_PWR_MIC_DET_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + rt5665_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index c779dc3474f9..315a3d39bc09 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -691,10 +691,12 @@ static void rt5677_set_dsp_mode(struct snd_soc_component *component, bool on) struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component); if (on) { - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP, RT5677_PWR_DSP); rt5677->is_dsp_mode = true; } else { - regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, + RT5677_PWR_DSP, 0x0); rt5677->is_dsp_mode = false; } } @@ -4466,7 +4468,8 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, - 0x0055); + 5 << RT5677_LDO1_SEL_SFT | + 5 << RT5677_LDO2_SEL_SFT); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); @@ -4490,9 +4493,11 @@ static int rt5677_set_bias_level(struct snd_soc_component *component, case SND_SOC_BIAS_OFF: regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x0); regmap_write(rt5677->regmap, RT5677_PWR_DIG1, 0x0000); - regmap_write(rt5677->regmap, RT5677_PWR_DIG2, 0x0000); - regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, 0x0022); - regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); + regmap_write(rt5677->regmap, RT5677_PWR_ANLG1, + 2 << RT5677_LDO1_SEL_SFT | + 2 << RT5677_LDO2_SEL_SFT); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, + RT5677_PWR_CORE, 0); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); @@ -4719,7 +4724,8 @@ static int rt5677_probe(struct snd_soc_component *component) regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, ~RT5677_IRQ_DEBOUNCE_SEL_MASK, 0x0020); - regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); + regmap_write(rt5677->regmap, RT5677_PWR_DSP2, + RT5677_PWR_SLIM_ISO | RT5677_PWR_CORE_ISO); for (i = 0; i < RT5677_GPIO_NUM; i++) rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a6a4748c97f9..aa1f9637d895 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -31,6 +31,13 @@ #define SGTL5000_DAP_REG_OFFSET 0x0100 #define SGTL5000_MAX_REG_OFFSET 0x013A +/* Delay for the VAG ramp up */ +#define SGTL5000_VAG_POWERUP_DELAY 500 /* ms */ +/* Delay for the VAG ramp down */ +#define SGTL5000_VAG_POWERDOWN_DELAY 500 /* ms */ + +#define SGTL5000_OUTPUTS_MUTE (SGTL5000_HP_MUTE | SGTL5000_LINE_OUT_MUTE) + /* default value of sgtl5000 registers */ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_CHIP_DIG_POWER, 0x0000 }, @@ -123,6 +130,13 @@ enum { I2S_SCLK_STRENGTH_HIGH, }; +enum { + HP_POWER_EVENT, + DAC_POWER_EVENT, + ADC_POWER_EVENT, + LAST_POWER_EVENT = ADC_POWER_EVENT +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -137,8 +151,109 @@ struct sgtl5000_priv { u8 micbias_voltage; u8 lrclk_strength; u8 sclk_strength; + u16 mute_state[LAST_POWER_EVENT + 1]; }; +static inline int hp_sel_input(struct snd_soc_component *component) +{ + return (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_CTRL) & + SGTL5000_HP_SEL_MASK) >> SGTL5000_HP_SEL_SHIFT; +} + +static inline u16 mute_output(struct snd_soc_component *component, + u16 mute_mask) +{ + u16 mute_reg = snd_soc_component_read32(component, + SGTL5000_CHIP_ANA_CTRL); + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_mask); + return mute_reg; +} + +static inline void restore_output(struct snd_soc_component *component, + u16 mute_mask, u16 mute_reg) +{ + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_reg); +} + +static void vag_power_on(struct snd_soc_component *component, u32 source) +{ + if (snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) & + SGTL5000_VAG_POWERUP) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); + + /* When VAG powering on to get local loop from Line-In, the sleep + * is required to avoid loud pop. + */ + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN && + source == HP_POWER_EVENT) + msleep(SGTL5000_VAG_POWERUP_DELAY); +} + +static int vag_power_consumers(struct snd_soc_component *component, + u16 ana_pwr_reg, u32 source) +{ + int consumers = 0; + + /* count dac/adc consumers unconditional */ + if (ana_pwr_reg & SGTL5000_DAC_POWERUP) + consumers++; + if (ana_pwr_reg & SGTL5000_ADC_POWERUP) + consumers++; + + /* + * If the event comes from HP and Line-In is selected, + * current action is 'DAC to be powered down'. + * As HP_POWERUP is not set when HP muxed to line-in, + * we need to keep VAG power ON. + */ + if (source == HP_POWER_EVENT) { + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN) + consumers++; + } else { + if (ana_pwr_reg & SGTL5000_HP_POWERUP) + consumers++; + } + + return consumers; +} + +static void vag_power_off(struct snd_soc_component *component, u32 source) +{ + u16 ana_pwr = snd_soc_component_read32(component, + SGTL5000_CHIP_ANA_POWER); + + if (!(ana_pwr & SGTL5000_VAG_POWERUP)) + return; + + /* + * This function calls when any of VAG power consumers is disappearing. + * Thus, if there is more than one consumer at the moment, as minimum + * one consumer will definitely stay after the end of the current + * event. + * Don't clear VAG_POWERUP if 2 or more consumers of VAG present: + * - LINE_IN (for HP events) / HP (for DAC/ADC events) + * - DAC + * - ADC + * (the current consumer is disappearing right now) + */ + if (vag_power_consumers(component, ana_pwr, source) >= 2) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, 0); + /* In power down case, we need wait 400-1000 ms + * when VAG fully ramped down. + * As longer we wait, as smaller pop we've got. + */ + msleep(SGTL5000_VAG_POWERDOWN_DELAY); +} + /* * mic_bias power on/off share the same register bits with * output impedance of mic bias, when power on mic bias, we @@ -170,36 +285,46 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, return 0; } -/* - * As manual described, ADC/DAC only works when VAG powerup, - * So enabled VAG before ADC/DAC up. - * In power down case, we need wait 400ms when vag fully ramped down. - */ -static int power_vag_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int vag_and_mute_control(struct snd_soc_component *component, + int event, int event_source) { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP; + static const u16 mute_mask[] = { + /* + * Mask for HP_POWER_EVENT. + * Muxing Headphones have to be wrapped with mute/unmute + * headphones only. + */ + SGTL5000_HP_MUTE, + /* + * Masks for DAC_POWER_EVENT/ADC_POWER_EVENT. + * Muxing DAC or ADC block have to wrapped with mute/unmute + * both headphones and line-out. + */ + SGTL5000_OUTPUTS_MUTE, + SGTL5000_OUTPUTS_MUTE + }; + + struct sgtl5000_priv *sgtl5000 = + snd_soc_component_get_drvdata(component); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + break; case SND_SOC_DAPM_POST_PMU: - snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); - msleep(400); + vag_power_on(component, event_source); + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; - case SND_SOC_DAPM_PRE_PMD: - /* - * Don't clear VAG_POWERUP, when both DAC and ADC are - * operational to prevent inadvertently starving the - * other one of them. - */ - if ((snd_soc_component_read32(component, SGTL5000_CHIP_ANA_POWER) & - mask) != mask) { - snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, 0); - msleep(400); - } + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + vag_power_off(component, event_source); + break; + case SND_SOC_DAPM_POST_PMD: + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; default: break; @@ -208,6 +333,41 @@ static int power_vag_event(struct snd_soc_dapm_widget *w, return 0; } +/* + * Mute Headphone when power it up/down. + * Control VAG power on HP power path. + */ +static int headphone_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, HP_POWER_EVENT); +} + +/* As manual describes, ADC/DAC powering up/down requires + * to mute outputs to avoid pops. + * Control VAG power on ADC/DAC power path. + */ +static int adc_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, ADC_POWER_EVENT); +} + +static int dac_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, DAC_POWER_EVENT); +} + /* input sources for ADC */ static const char *adc_mux_text[] = { "MIC_IN", "LINE_IN" @@ -280,7 +440,10 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, + headphone_pga_event, + SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), @@ -301,11 +464,12 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { 0, SGTL5000_CHIP_DIG_POWER, 1, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), - SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), - - SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event), - SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event), + SND_SOC_DAPM_ADC_E("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0, + adc_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_DAC_E("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0, + dac_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), }; /* routes for sgtl5000 */ @@ -556,6 +720,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { SGTL5000_CHIP_ANA_ADC_CTRL, 8, 1, 0, capture_6db_attenuate), SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0), + SOC_SINGLE("Capture Switch", SGTL5000_CHIP_ANA_CTRL, 0, 1, 1), SOC_DOUBLE_TLV("Headphone Playback Volume", SGTL5000_CHIP_ANA_HP_CTRL, @@ -1173,12 +1338,17 @@ static int sgtl5000_set_power_regs(struct snd_soc_component *component) SGTL5000_INT_OSC_EN); /* Enable VDDC charge pump */ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; - } else if (vddio >= 3100 && vdda >= 3100) { + } else { ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP; - /* VDDC use VDDIO rail */ - lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; - lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << - SGTL5000_VDDC_MAN_ASSN_SHIFT; + /* + * if vddio == vdda the source of charge pump should be + * assigned manually to VDDIO + */ + if (vddio == vdda) { + lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; + lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << + SGTL5000_VDDC_MAN_ASSN_SHIFT; + } } snd_soc_component_write(component, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl); @@ -1288,6 +1458,7 @@ static int sgtl5000_probe(struct snd_soc_component *component) int ret; u16 reg; struct sgtl5000_priv *sgtl5000 = snd_soc_component_get_drvdata(component); + unsigned int zcd_mask = SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN; /* power up sgtl5000 */ ret = sgtl5000_set_power_regs(component); @@ -1296,7 +1467,7 @@ static int sgtl5000_probe(struct snd_soc_component *component) /* enable small pop, introduce 400ms delay in turning off */ snd_soc_component_update_bits(component, SGTL5000_CHIP_REF_CTRL, - SGTL5000_SMALL_POP, 1); + SGTL5000_SMALL_POP, SGTL5000_SMALL_POP); /* disable short cut detector */ snd_soc_component_write(component, SGTL5000_CHIP_SHORT_CTRL, 0); @@ -1315,9 +1486,8 @@ static int sgtl5000_probe(struct snd_soc_component *component) 0x1f); snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg); - snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL, - SGTL5000_HP_ZCD_EN | - SGTL5000_ADC_ZCD_EN); + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + zcd_mask, zcd_mask); snd_soc_component_update_bits(component, SGTL5000_CHIP_MIC_CTRL, SGTL5000_BIAS_R_MASK, diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 18cae08bbd3a..a4bf4bca95bf 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h @@ -273,7 +273,7 @@ #define SGTL5000_BIAS_CTRL_MASK 0x000e #define SGTL5000_BIAS_CTRL_SHIFT 1 #define SGTL5000_BIAS_CTRL_WIDTH 3 -#define SGTL5000_SMALL_POP 1 +#define SGTL5000_SMALL_POP 0x0001 /* * SGTL5000_CHIP_MIC_CTRL diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 9009a7407b7a..a061d78473ac 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -459,7 +459,6 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev) int ret; struct sirf_audio_codec *sirf_audio_codec; void __iomem *base; - struct resource *mem_res; sirf_audio_codec = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_codec), GFP_KERNEL); @@ -468,8 +467,7 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sirf_audio_codec); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 080a840c987a..f8e2f4b74db3 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -67,8 +67,6 @@ static SOC_ENUM_SINGLE_DECL(rec_src_enum, static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = SOC_DAPM_ENUM("Input Select", rec_src_enum); -static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, - TLV320AIC23_ANLG, 2, rec_src_text); static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, TLV320AIC23_DIGT, 1, deemph_text); diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 9b37e98da0db..df627a08def9 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -258,7 +258,6 @@ static SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, static SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text); -static SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text); static SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text); @@ -1553,7 +1552,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(aic31xx->gpio_reset)) { - dev_err(aic31xx->dev, "not able to acquire gpio\n"); + if (PTR_ERR(aic31xx->gpio_reset) != -EPROBE_DEFER) + dev_err(aic31xx->dev, "not able to acquire gpio\n"); return PTR_ERR(aic31xx->gpio_reset); } @@ -1564,7 +1564,9 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ARRAY_SIZE(aic31xx->supplies), aic31xx->supplies); if (ret) { - dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(aic31xx->dev, + "Failed to request supplies: %d\n", ret); return ret; } diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 93d84e5ae2d5..c3587af9985c 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -22,7 +22,6 @@ #include "tscs454.h" -static const unsigned int PLL_48K_RATE = (48000 * 256); static const unsigned int PLL_44_1K_RATE = (44100 * 256); #define COEFF_SIZE 3 diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 472c2fff34a8..f34637afee51 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1108,10 +1108,8 @@ static int twl6040_probe(struct snd_soc_component *component) priv->component = component; priv->plug_irq = platform_get_irq(pdev, 0); - if (priv->plug_irq < 0) { - dev_err(component->dev, "invalid irq: %d\n", priv->plug_irq); + if (priv->plug_irq < 0) return priv->plug_irq; - } INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work); diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c new file mode 100644 index 000000000000..21ab8c5487ba --- /dev/null +++ b/sound/soc/codecs/uda1334.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// uda1334.c -- UDA1334 ALSA SoC Audio driver +// +// Based on WM8523 ALSA SoC Audio driver written by Mark Brown + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio/consumer.h> +#include <linux/of_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> + +#define UDA1334_NUM_RATES 6 + +/* codec private data */ +struct uda1334_priv { + struct gpio_desc *mute; + struct gpio_desc *deemph; + unsigned int sysclk; + unsigned int rate_constraint_list[UDA1334_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; +}; + +static const struct snd_soc_dapm_widget uda1334_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("LINEVOUTL"), +SND_SOC_DAPM_OUTPUT("LINEVOUTR"), +}; + +static const struct snd_soc_dapm_route uda1334_dapm_routes[] = { + { "LINEVOUTL", NULL, "DAC" }, + { "LINEVOUTR", NULL, "DAC" }, +}; + +static int uda1334_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + int deemph = ucontrol->value.integer.value[0]; + + if (deemph > 1) + return -EINVAL; + + gpiod_set_value_cansleep(uda1334->deemph, deemph); + + return 0; +}; + +static int uda1334_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + int ret; + + ret = gpiod_get_value_cansleep(uda1334->deemph); + if (ret < 0) + return -EINVAL; + + ucontrol->value.integer.value[0] = ret; + + return 0; +}; + +static const struct snd_kcontrol_new uda1334_snd_controls[] = { + SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, + uda1334_get_deemph, uda1334_put_deemph), +}; + +static const struct { + int value; + int ratio; +} lrclk_ratios[UDA1334_NUM_RATES] = { + { 1, 128 }, + { 2, 192 }, + { 3, 256 }, + { 4, 384 }, + { 5, 512 }, + { 6, 768 }, +}; + +static int uda1334_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + /* + * The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!uda1334->sysclk) { + dev_err(component->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &uda1334->rate_constraint); + + gpiod_set_value_cansleep(uda1334->mute, 1); + + return 0; +} + +static void uda1334_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + gpiod_set_value_cansleep(uda1334->mute, 0); +} + +static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + unsigned int val; + int i, j = 0; + + uda1334->sysclk = freq; + + uda1334->rate_constraint.count = 0; + for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { + val = freq / lrclk_ratios[i].ratio; + /* + * Check that it's a standard rate since core can't + * cope with others and having the odd rates confuses + * constraint matching. + */ + + switch (val) { + case 8000: + case 32000: + case 44100: + case 48000: + case 64000: + case 88200: + case 96000: + dev_dbg(component->dev, "Supported sample rate: %dHz\n", + val); + uda1334->rate_constraint_list[j++] = val; + uda1334->rate_constraint.count++; + break; + default: + dev_dbg(component->dev, "Skipping sample rate: %dHz\n", + val); + } + } + + /* Need at least one supported rate... */ + if (uda1334->rate_constraint.count == 0) + return -EINVAL; + + return 0; +} + +static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | + SND_SOC_DAIFMT_MASTER_MASK); + + if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS)) { + dev_err(codec_dai->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static int uda1334_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(dai->component); + + if (uda1334->mute) + gpiod_set_value_cansleep(uda1334->mute, mute); + + return 0; +} + +#define UDA1334_RATES SNDRV_PCM_RATE_8000_96000 + +#define UDA1334_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops uda1334_dai_ops = { + .startup = uda1334_startup, + .shutdown = uda1334_shutdown, + .set_sysclk = uda1334_set_dai_sysclk, + .set_fmt = uda1334_set_fmt, + .mute_stream = uda1334_mute_stream, +}; + +static struct snd_soc_dai_driver uda1334_dai = { + .name = "uda1334-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = UDA1334_RATES, + .formats = UDA1334_FORMATS, + }, + .ops = &uda1334_dai_ops, +}; + +static int uda1334_probe(struct snd_soc_component *component) +{ + struct uda1334_priv *uda1334 = snd_soc_component_get_drvdata(component); + + uda1334->rate_constraint.list = &uda1334->rate_constraint_list[0]; + uda1334->rate_constraint.count = + ARRAY_SIZE(uda1334->rate_constraint_list); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_uda1334 = { + .probe = uda1334_probe, + .controls = uda1334_snd_controls, + .num_controls = ARRAY_SIZE(uda1334_snd_controls), + .dapm_widgets = uda1334_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda1334_dapm_widgets), + .dapm_routes = uda1334_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda1334_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct of_device_id uda1334_of_match[] = { + { .compatible = "nxp,uda1334" }, + { /* sentinel*/ } +}; +MODULE_DEVICE_TABLE(of, uda1334_of_match); + +static int uda1334_codec_probe(struct platform_device *pdev) +{ + struct uda1334_priv *uda1334; + int ret; + + uda1334 = devm_kzalloc(&pdev->dev, sizeof(struct uda1334_priv), + GFP_KERNEL); + if (!uda1334) + return -ENOMEM; + + platform_set_drvdata(pdev, uda1334); + + uda1334->mute = devm_gpiod_get(&pdev->dev, "nxp,mute", GPIOD_OUT_LOW); + if (IS_ERR(uda1334->mute)) { + ret = PTR_ERR(uda1334->mute); + dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret); + return ret; + } + + uda1334->deemph = devm_gpiod_get(&pdev->dev, "nxp,deemph", GPIOD_OUT_LOW); + if (IS_ERR(uda1334->deemph)) { + ret = PTR_ERR(uda1334->deemph); + dev_err(&pdev->dev, "Failed to get deemph line: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(&pdev->dev, + &soc_component_dev_uda1334, + &uda1334_dai, 1); + if (ret < 0) + dev_err(&pdev->dev, "Failed to register component: %d\n", ret); + + return ret; +} + +static struct platform_driver uda1334_codec_driver = { + .probe = uda1334_codec_probe, + .driver = { + .name = "uda1334-codec", + .of_match_table = uda1334_of_match, + }, +}; +module_platform_driver(uda1334_codec_driver); + +MODULE_DESCRIPTION("ASoC UDA1334 driver"); +MODULE_AUTHOR("Andra Danciu <andradanciu1997@gmail.com>"); +MODULE_ALIAS("platform:uda1334-codec"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index c397d713f01a..cc5a9c9b918b 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -65,7 +65,7 @@ struct wcd_clsh_ctrl { #define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 #define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) #define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) -#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(0, 3) +#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) #define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) #define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) #define WCD9XXX_HPH_CONST_SEL_BYPASS 0 diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 1bbbe421b999..03f8a94bba2f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2071,9 +2071,10 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF1_PB, .playback = { .stream_name = "AIF1 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, - .rate_max = 192000, + .rate_max = 384000, .rate_min = 8000, .channels_min = 1, .channels_max = 2, @@ -2099,10 +2100,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF2_PB, .playback = { .stream_name = "AIF2 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, @@ -2127,10 +2129,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF3_PB, .playback = { .stream_name = "AIF3 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, @@ -2155,10 +2158,11 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { .id = AIF4_PB, .playback = { .stream_name = "AIF4 Playback", - .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK | + SNDRV_PCM_RATE_384000, .formats = WCD9335_FORMATS_S16_S24_LE, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 384000, .channels_min = 1, .channels_max = 2, }, @@ -4062,7 +4066,8 @@ static int wcd9335_setup_irqs(struct wcd9335_codec *wcd) ret = devm_request_threaded_irq(wcd->dev, irq, NULL, wcd9335_irqs[i].handler, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, wcd9335_irqs[i].name, wcd); if (ret) { dev_err(wcd->dev, "Failed to request %s\n", diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 66a5f1827aa9..9c7e2892c8cb 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -140,7 +140,7 @@ struct pll_factors { * to allow rounding later */ #define FIXED_FLL_SIZE ((1 << 22) * 10) -static int wm8995_pll_factors(struct device *dev, +static int wm8955_pll_factors(struct device *dev, int Fref, int Fout, struct pll_factors *pll) { u64 Kpart; @@ -279,7 +279,7 @@ static int wm8955_configure_clocking(struct snd_soc_component *component) /* Use the last divider configuration we saw for the * sample rate. */ - ret = wm8995_pll_factors(component->dev, wm8955->mclk_rate, + ret = wm8955_pll_factors(component->dev, wm8955->mclk_rate, clock_cfgs[sr].mclk, &pll); if (ret != 0) { dev_err(component->dev, diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 25e74cf0666a..85bfd041d546 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -273,7 +273,7 @@ static const struct soc_enum wm8988_rline_enum = wm8988_line_texts, wm8988_line_values); static const struct snd_kcontrol_new wm8988_right_line_controls = - SOC_DAPM_ENUM("Route", wm8988_lline_enum); + SOC_DAPM_ENUM("Route", wm8988_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f5fbadc5e7e2..ae28d9907c30 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -4242,8 +4242,9 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp) } } -irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) +irqreturn_t wm_adsp2_bus_error(int irq, void *data) { + struct wm_adsp *dsp = (struct wm_adsp *)data; unsigned int val; struct regmap *regmap = dsp->regmap; int ret = 0; @@ -4307,8 +4308,9 @@ error: } EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); -irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp) +irqreturn_t wm_halo_bus_error(int irq, void *data) { + struct wm_adsp *dsp = (struct wm_adsp *)data; struct regmap *regmap = dsp->regmap; unsigned int fault[6]; struct reg_sequence clear[] = { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3b03d1eb986f..aa634ef6c9f5 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -171,8 +171,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); -irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp); +irqreturn_t wm_adsp2_bus_error(int irq, void *data); +irqreturn_t wm_halo_bus_error(int irq, void *data); irqreturn_t wm_halo_wdt_expire(int irq, void *data); int wm_adsp_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index cbbf6257f08a..cfa40ef6b1ca 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -885,10 +885,8 @@ static int fsl_asrc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, dev_name(&pdev->dev), asrc_priv); diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 3897a54a11fe..c7e4e9757dce 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -458,7 +458,6 @@ static int fsl_audmix_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fsl_audmix *priv; - struct resource *res; const char *mdrv; const struct of_device_id *of_id; void __iomem *regs; @@ -475,8 +474,7 @@ static int fsl_audmix_probe(struct platform_device *pdev) return -ENOMEM; /* Get the addresses */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 10d2210c91ef..a78e4ab478df 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -32,15 +32,18 @@ * @extalclk: esai clock source to derive HCK, SCK and FS * @fsysclk: system clock source to derive HCK, SCK and FS * @spbaclk: SPBA clock (optional, depending on SoC design) + * @task: tasklet to handle the reset operation * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots + * @channels: channel num for tx or rx * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads * @sck_div: if using PSR/PM dividers for SCKx clock * @slave_mode: if fully using DAI slave mode * @synchronous: if using tx/rx synchronous mode + * @reset_at_xrun: flags for enable reset operaton * @name: driver name */ struct fsl_esai { @@ -52,17 +55,20 @@ struct fsl_esai { struct clk *extalclk; struct clk *fsysclk; struct clk *spbaclk; + struct tasklet_struct task; u32 fifo_depth; u32 slot_width; u32 slots; u32 tx_mask; u32 rx_mask; + u32 channels[2]; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; bool sck_div[2]; bool slave_mode; bool synchronous; + bool reset_at_xrun; char name[32]; }; @@ -71,8 +77,16 @@ static irqreturn_t esai_isr(int irq, void *devid) struct fsl_esai *esai_priv = (struct fsl_esai *)devid; struct platform_device *pdev = esai_priv->pdev; u32 esr; + u32 saisr; regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr); + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); + + if ((saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE)) && + esai_priv->reset_at_xrun) { + dev_dbg(&pdev->dev, "reset module for xrun\n"); + tasklet_schedule(&esai_priv->task); + } if (esr & ESAI_ESR_TINIT_MASK) dev_dbg(&pdev->dev, "isr: Transmission Initialized\n"); @@ -543,64 +557,184 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_esai_hw_init(struct fsl_esai *esai_priv) +{ + struct platform_device *pdev = esai_priv->pdev; + int ret; + + /* Reset ESAI unit */ + ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR, + ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK, + ESAI_ECR_ESAIEN | ESAI_ECR_ERST); + if (ret) { + dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret); + return ret; + } + + /* + * We need to enable ESAI so as to access some of its registers. + * Otherwise, we would fail to dump regmap from user space. + */ + ret = regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR, + ESAI_ECR_ESAIEN_MASK | ESAI_ECR_ERST_MASK, + ESAI_ECR_ESAIEN); + if (ret) { + dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret); + return ret; + } + + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, 0); + + return 0; +} + +static int fsl_esai_register_restore(struct fsl_esai *esai_priv) +{ + int ret; + + /* FIFO reset for safety */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, + ESAI_xFCR_xFR, ESAI_xFCR_xFR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, + ESAI_xFCR_xFR, ESAI_xFCR_xFR); + + regcache_mark_dirty(esai_priv->regmap); + ret = regcache_sync(esai_priv->regmap); + if (ret) + return ret; + + /* FIFO reset done */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); + + return 0; +} + +static void fsl_esai_trigger_start(struct fsl_esai *esai_priv, bool tx) +{ + u8 i, channels = esai_priv->channels[tx]; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); + u32 mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); + + /* Write initial words reqiured by ESAI as normal procedure */ + for (i = 0; tx && i < channels; i++) + regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + + /* + * When set the TE/RE in the end of enablement flow, there + * will be channel swap issue for multi data line case. + * In order to workaround this issue, we switch the bit + * enablement sequence to below sequence + * 1) clear the xSMB & xSMA: which is done in probe and + * stop state. + * 2) set TE/RE + * 3) set xSMB + * 4) set xSMA: xSMA is the last one in this flow, which + * will trigger esai to start. + */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); + mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); + + /* Enable Exception interrupt */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, ESAI_xCR_xEIE); +} + +static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx) +{ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xEIE_MASK, 0); + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, 0); + + /* Disable and reset FIFO */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR, 0); +} + +static void fsl_esai_hw_reset(unsigned long arg) +{ + struct fsl_esai *esai_priv = (struct fsl_esai *)arg; + bool tx = true, rx = false, enabled[2]; + u32 tfcr, rfcr; + + /* Save the registers */ + regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); + regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); + enabled[tx] = tfcr & ESAI_xFCR_xFEN; + enabled[rx] = rfcr & ESAI_xFCR_xFEN; + + /* Stop the tx & rx */ + fsl_esai_trigger_stop(esai_priv, tx); + fsl_esai_trigger_stop(esai_priv, rx); + + /* Reset the esai, and ignore return value */ + fsl_esai_hw_init(esai_priv); + + /* Enforce ESAI personal resets for both TX and RX */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); + + /* Restore registers by regcache_sync, and ignore return value */ + fsl_esai_register_restore(esai_priv); + + /* Remove ESAI personal resets by configuring PCRC and PRRC also */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, + ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, + ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); + + /* Restart tx / rx, if they already enabled */ + if (enabled[tx]) + fsl_esai_trigger_start(esai_priv, tx); + if (enabled[rx]) + fsl_esai_trigger_start(esai_priv, rx); +} + static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u8 i, channels = substream->runtime->channels; - u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); - u32 mask; + + esai_priv->channels[tx] = substream->runtime->channels; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); - - /* Write initial words reqiured by ESAI as normal procedure */ - for (i = 0; tx && i < channels; i++) - regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); - - /* - * When set the TE/RE in the end of enablement flow, there - * will be channel swap issue for multi data line case. - * In order to workaround this issue, we switch the bit - * enablement sequence to below sequence - * 1) clear the xSMB & xSMA: which is done in probe and - * stop state. - * 2) set TE/RE - * 3) set xSMB - * 4) set xSMA: xSMA is the last one in this flow, which - * will trigger esai to start. - */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), - tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); - mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; - - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); - + fsl_esai_trigger_start(esai_priv, tx); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), - tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), - ESAI_xSMA_xS_MASK, 0); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), - ESAI_xSMB_xS_MASK, 0); - - /* Disable and reset FIFO */ - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); - regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), - ESAI_xFCR_xFR, 0); + fsl_esai_trigger_stop(esai_priv, tx); break; default: return -EINVAL; @@ -787,6 +921,10 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; snprintf(esai_priv->name, sizeof(esai_priv->name), "%pOFn", np); + if (of_device_is_compatible(np, "fsl,vf610-esai") || + of_device_is_compatible(np, "fsl,imx35-esai")) + esai_priv->reset_at_xrun = true; + /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); @@ -824,10 +962,8 @@ static int fsl_esai_probe(struct platform_device *pdev) PTR_ERR(esai_priv->spbaclk)); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0, esai_priv->name, esai_priv); @@ -866,22 +1002,9 @@ static int fsl_esai_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, esai_priv); - /* Reset ESAI unit */ - ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST); - if (ret) { - dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret); - return ret; - } - - /* - * We need to enable ESAI so as to access some of its registers. - * Otherwise, we would fail to dump regmap from user space. - */ - ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN); - if (ret) { - dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret); + ret = fsl_esai_hw_init(esai_priv); + if (ret) return ret; - } esai_priv->tx_mask = 0xFFFFFFFF; esai_priv->rx_mask = 0xFFFFFFFF; @@ -899,6 +1022,9 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + tasklet_init(&esai_priv->task, fsl_esai_hw_reset, + (unsigned long)esai_priv); + pm_runtime_enable(&pdev->dev); regcache_cache_only(esai_priv->regmap, true); @@ -912,7 +1038,10 @@ static int fsl_esai_probe(struct platform_device *pdev) static int fsl_esai_remove(struct platform_device *pdev) { + struct fsl_esai *esai_priv = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); + tasklet_kill(&esai_priv->task); return 0; } @@ -920,6 +1049,7 @@ static int fsl_esai_remove(struct platform_device *pdev) static const struct of_device_id fsl_esai_dt_ids[] = { { .compatible = "fsl,imx35-esai", }, { .compatible = "fsl,vf610-esai", }, + { .compatible = "fsl,imx6ull-esai", }, {} }; MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); @@ -955,20 +1085,10 @@ static int fsl_esai_runtime_resume(struct device *dev) regcache_cache_only(esai->regmap, false); - /* FIFO reset for safety */ - regmap_update_bits(esai->regmap, REG_ESAI_TFCR, - ESAI_xFCR_xFR, ESAI_xFCR_xFR); - regmap_update_bits(esai->regmap, REG_ESAI_RFCR, - ESAI_xFCR_xFR, ESAI_xFCR_xFR); - - ret = regcache_sync(esai->regmap); + ret = fsl_esai_register_restore(esai); if (ret) goto err_regcache_sync; - /* FIFO reset done */ - regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0); - regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0); - return 0; err_regcache_sync: @@ -991,7 +1111,6 @@ static int fsl_esai_runtime_suspend(struct device *dev) struct fsl_esai *esai = dev_get_drvdata(dev); regcache_cache_only(esai->regmap, true); - regcache_mark_dirty(esai->regmap); if (!IS_ERR(esai->fsysclk)) clk_disable_unprepare(esai->fsysclk); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d58cc3ae90d8..728307acab90 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -9,6 +9,7 @@ #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -39,6 +40,7 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; + unsigned int ofs = sai->soc_data->reg_offset; struct device *dev = &sai->pdev->dev; u32 flags, xcsr, mask; bool irq_none = true; @@ -51,7 +53,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT; /* Tx IRQ */ - regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr); + regmap_read(sai->regmap, FSL_SAI_TCSR(ofs), &xcsr); flags = xcsr & mask; if (flags) @@ -81,11 +83,11 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) xcsr &= ~FSL_SAI_CSR_xF_MASK; if (flags) - regmap_write(sai->regmap, FSL_SAI_TCSR, flags | xcsr); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), flags | xcsr); irq_rx: /* Rx IRQ */ - regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr); + regmap_read(sai->regmap, FSL_SAI_RCSR(ofs), &xcsr); flags = xcsr & mask; if (flags) @@ -115,7 +117,7 @@ irq_rx: xcsr &= ~FSL_SAI_CSR_xF_MASK; if (flags) - regmap_write(sai->regmap, FSL_SAI_RCSR, flags | xcsr); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr); out: if (irq_none) @@ -139,6 +141,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0; @@ -159,7 +162,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_MSEL_MASK, val_cr2); return 0; @@ -192,6 +195,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, unsigned int fmt, int fsl_dir) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0; @@ -286,9 +290,9 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, return -EINVAL; } - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), FSL_SAI_CR2_BCP | FSL_SAI_CR2_BCD_MSTR, val_cr2); - regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_MF | FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP | FSL_SAI_CR4_FSD_MSTR, val_cr4); @@ -315,6 +319,7 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); + unsigned int ofs = sai->soc_data->reg_offset; unsigned long clk_rate; u32 savediv = 0, ratio, savesub = freq; u32 id; @@ -377,17 +382,17 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) */ if ((sai->synchronous[TX] && !sai->synchronous[RX]) || (!tx && !sai->synchronous[RX])) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) || (tx && !sai->synchronous[TX])) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_DIV_MASK, savediv - 1); } @@ -402,6 +407,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); u32 word_width = params_width(params); @@ -454,19 +460,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, if (!sai->is_slave_mode) { if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { - regmap_update_bits(sai->regmap, FSL_SAI_TCR4, + regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_TCR5, + regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_TMR, ~0UL - ((1 << channels) - 1)); } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { - regmap_update_bits(sai->regmap, FSL_SAI_RCR4, + regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_RCR5, + regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_RMR, @@ -474,10 +480,10 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, val_cr4); - regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | FSL_SAI_CR5_FBT_MASK, val_cr5); regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1)); @@ -505,6 +511,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 xcsr, count = 100; @@ -513,9 +521,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, + regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs), FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); + regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs), FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); /* @@ -526,43 +534,44 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_FRDE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), + regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_xIE_MASK, 0); /* Check if the opposite FRDE is also disabled */ - regmap_read(sai->regmap, FSL_SAI_xCSR(!tx), &xcsr); + regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr); if (!(xcsr & FSL_SAI_CSR_FRDE)) { /* Disable both directions and reset their FIFOs */ - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_TERE, 0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_TERE, 0); /* TERE will remain set till the end of current frame */ do { udelay(10); - regmap_read(sai->regmap, FSL_SAI_xCSR(tx), &xcsr); + regmap_read(sai->regmap, + FSL_SAI_xCSR(tx, ofs), &xcsr); } while (--count && xcsr & FSL_SAI_CSR_TERE); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, + regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, + regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_FR, FSL_SAI_CSR_FR); /* @@ -574,13 +583,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, */ if (!sai->is_slave_mode) { /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, - FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, - FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), + FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), + FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); } } break; @@ -595,10 +604,12 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), + FSL_SAI_CR3_TRCE_MASK, FSL_SAI_CR3_TRCE); ret = snd_pcm_hw_constraint_list(substream->runtime, 0, @@ -611,9 +622,11 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0); + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), + FSL_SAI_CR3_TRCE_MASK, 0); } static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { @@ -630,18 +643,20 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); + unsigned int ofs = sai->soc_data->reg_offset; /* Software Reset for both Tx and Rx */ - regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); /* Clear SR bit to finish the reset */ - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); - regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, - FSL_SAI_MAXBURST_TX * 2); - regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, - FSL_SAI_MAXBURST_RX - 1); + regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs), + FSL_SAI_CR1_RFW_MASK, + sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX); + regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs), + FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_RX - 1); snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, &sai->dma_params_rx); @@ -678,41 +693,89 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", }; -static struct reg_default fsl_sai_reg_defaults[] = { - {FSL_SAI_TCR1, 0}, - {FSL_SAI_TCR2, 0}, - {FSL_SAI_TCR3, 0}, - {FSL_SAI_TCR4, 0}, - {FSL_SAI_TCR5, 0}, - {FSL_SAI_TDR, 0}, - {FSL_SAI_TMR, 0}, - {FSL_SAI_RCR1, 0}, - {FSL_SAI_RCR2, 0}, - {FSL_SAI_RCR3, 0}, - {FSL_SAI_RCR4, 0}, - {FSL_SAI_RCR5, 0}, - {FSL_SAI_RMR, 0}, +static struct reg_default fsl_sai_reg_defaults_ofs0[] = { + {FSL_SAI_TCR1(0), 0}, + {FSL_SAI_TCR2(0), 0}, + {FSL_SAI_TCR3(0), 0}, + {FSL_SAI_TCR4(0), 0}, + {FSL_SAI_TCR5(0), 0}, + {FSL_SAI_TDR0, 0}, + {FSL_SAI_TDR1, 0}, + {FSL_SAI_TDR2, 0}, + {FSL_SAI_TDR3, 0}, + {FSL_SAI_TDR4, 0}, + {FSL_SAI_TDR5, 0}, + {FSL_SAI_TDR6, 0}, + {FSL_SAI_TDR7, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1(0), 0}, + {FSL_SAI_RCR2(0), 0}, + {FSL_SAI_RCR3(0), 0}, + {FSL_SAI_RCR4(0), 0}, + {FSL_SAI_RCR5(0), 0}, + {FSL_SAI_RMR, 0}, +}; + +static struct reg_default fsl_sai_reg_defaults_ofs8[] = { + {FSL_SAI_TCR1(8), 0}, + {FSL_SAI_TCR2(8), 0}, + {FSL_SAI_TCR3(8), 0}, + {FSL_SAI_TCR4(8), 0}, + {FSL_SAI_TCR5(8), 0}, + {FSL_SAI_TDR0, 0}, + {FSL_SAI_TDR1, 0}, + {FSL_SAI_TDR2, 0}, + {FSL_SAI_TDR3, 0}, + {FSL_SAI_TDR4, 0}, + {FSL_SAI_TDR5, 0}, + {FSL_SAI_TDR6, 0}, + {FSL_SAI_TDR7, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1(8), 0}, + {FSL_SAI_RCR2(8), 0}, + {FSL_SAI_RCR3(8), 0}, + {FSL_SAI_RCR4(8), 0}, + {FSL_SAI_RCR5(8), 0}, + {FSL_SAI_RMR, 0}, }; static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) + return true; + + if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_TCR1: - case FSL_SAI_TCR2: - case FSL_SAI_TCR3: - case FSL_SAI_TCR4: - case FSL_SAI_TCR5: - case FSL_SAI_TFR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: + case FSL_SAI_TFR2: + case FSL_SAI_TFR3: + case FSL_SAI_TFR4: + case FSL_SAI_TFR5: + case FSL_SAI_TFR6: + case FSL_SAI_TFR7: case FSL_SAI_TMR: - case FSL_SAI_RCSR: - case FSL_SAI_RCR1: - case FSL_SAI_RCR2: - case FSL_SAI_RCR3: - case FSL_SAI_RCR4: - case FSL_SAI_RCR5: - case FSL_SAI_RDR: - case FSL_SAI_RFR: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: + case FSL_SAI_RDR2: + case FSL_SAI_RDR3: + case FSL_SAI_RDR4: + case FSL_SAI_RDR5: + case FSL_SAI_RDR6: + case FSL_SAI_RDR7: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: + case FSL_SAI_RFR2: + case FSL_SAI_RFR3: + case FSL_SAI_RFR4: + case FSL_SAI_RFR5: + case FSL_SAI_RFR6: + case FSL_SAI_RFR7: case FSL_SAI_RMR: return true; default: @@ -722,12 +785,37 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_RCSR: - case FSL_SAI_TFR: - case FSL_SAI_RFR: - case FSL_SAI_RDR: + case FSL_SAI_TFR0: + case FSL_SAI_TFR1: + case FSL_SAI_TFR2: + case FSL_SAI_TFR3: + case FSL_SAI_TFR4: + case FSL_SAI_TFR5: + case FSL_SAI_TFR6: + case FSL_SAI_TFR7: + case FSL_SAI_RFR0: + case FSL_SAI_RFR1: + case FSL_SAI_RFR2: + case FSL_SAI_RFR3: + case FSL_SAI_RFR4: + case FSL_SAI_RFR5: + case FSL_SAI_RFR6: + case FSL_SAI_RFR7: + case FSL_SAI_RDR0: + case FSL_SAI_RDR1: + case FSL_SAI_RDR2: + case FSL_SAI_RDR3: + case FSL_SAI_RDR4: + case FSL_SAI_RDR5: + case FSL_SAI_RDR6: + case FSL_SAI_RDR7: return true; default: return false; @@ -736,21 +824,25 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) { + struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; + + if (reg >= FSL_SAI_TCSR(ofs) && reg <= FSL_SAI_TCR5(ofs)) + return true; + + if (reg >= FSL_SAI_RCSR(ofs) && reg <= FSL_SAI_RCR5(ofs)) + return true; + switch (reg) { - case FSL_SAI_TCSR: - case FSL_SAI_TCR1: - case FSL_SAI_TCR2: - case FSL_SAI_TCR3: - case FSL_SAI_TCR4: - case FSL_SAI_TCR5: - case FSL_SAI_TDR: + case FSL_SAI_TDR0: + case FSL_SAI_TDR1: + case FSL_SAI_TDR2: + case FSL_SAI_TDR3: + case FSL_SAI_TDR4: + case FSL_SAI_TDR5: + case FSL_SAI_TDR6: + case FSL_SAI_TDR7: case FSL_SAI_TMR: - case FSL_SAI_RCSR: - case FSL_SAI_RCR1: - case FSL_SAI_RCR2: - case FSL_SAI_RCR3: - case FSL_SAI_RCR4: - case FSL_SAI_RCR5: case FSL_SAI_RMR: return true; default: @@ -758,14 +850,15 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_config fsl_sai_regmap_config = { +static struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, + .fast_io = true, .max_register = FSL_SAI_RMR, - .reg_defaults = fsl_sai_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults), + .reg_defaults = fsl_sai_reg_defaults_ofs0, + .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults_ofs0), .readable_reg = fsl_sai_readable_reg, .volatile_reg = fsl_sai_volatile_reg, .writeable_reg = fsl_sai_writeable_reg, @@ -788,10 +881,7 @@ static int fsl_sai_probe(struct platform_device *pdev) return -ENOMEM; sai->pdev = pdev; - - if (of_device_is_compatible(np, "fsl,imx6sx-sai") || - of_device_is_compatible(np, "fsl,imx6ul-sai")) - sai->sai_on_imx = true; + sai->soc_data = of_device_get_match_data(&pdev->dev); sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); @@ -800,6 +890,12 @@ static int fsl_sai_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + if (sai->soc_data->reg_offset == 8) { + fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8; + fsl_sai_regmap_config.num_reg_defaults = + ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); + } + sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, &fsl_sai_regmap_config); @@ -832,10 +928,8 @@ static int fsl_sai_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai); if (ret) { @@ -886,8 +980,8 @@ static int fsl_sai_probe(struct platform_device *pdev) MCLK_DIR(index)); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; @@ -900,7 +994,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (ret) return ret; - if (sai->sai_on_imx) + if (sai->soc_data->use_imx_pcm) return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); else return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); @@ -913,10 +1007,43 @@ static int fsl_sai_remove(struct platform_device *pdev) return 0; } +static const struct fsl_sai_soc_data fsl_sai_vf610_data = { + .use_imx_pcm = false, + .fifo_depth = 32, + .reg_offset = 0, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { + .use_imx_pcm = true, + .fifo_depth = 32, + .reg_offset = 0, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { + .use_imx_pcm = true, + .fifo_depth = 16, + .reg_offset = 8, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { + .use_imx_pcm = true, + .fifo_depth = 128, + .reg_offset = 8, +}; + +static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { + .use_imx_pcm = true, + .fifo_depth = 64, + .reg_offset = 0, +}; + static const struct of_device_id fsl_sai_ids[] = { - { .compatible = "fsl,vf610-sai", }, - { .compatible = "fsl,imx6sx-sai", }, - { .compatible = "fsl,imx6ul-sai", }, + { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, + { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, + { .compatible = "fsl,imx6ul-sai", .data = &fsl_sai_imx6sx_data }, + { .compatible = "fsl,imx7ulp-sai", .data = &fsl_sai_imx7ulp_data }, + { .compatible = "fsl,imx8mq-sai", .data = &fsl_sai_imx8mq_data }, + { .compatible = "fsl,imx8qm-sai", .data = &fsl_sai_imx8qm_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); @@ -943,6 +1070,7 @@ static int fsl_sai_runtime_suspend(struct device *dev) static int fsl_sai_runtime_resume(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); + unsigned int ofs = sai->soc_data->reg_offset; int ret; ret = clk_prepare_enable(sai->bus_clk); @@ -964,11 +1092,11 @@ static int fsl_sai_runtime_resume(struct device *dev) } regcache_cache_only(sai->regmap, false); - regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); - regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), FSL_SAI_CSR_SR); usleep_range(1000, 2000); - regmap_write(sai->regmap, FSL_SAI_TCSR, 0); - regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0); + regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0); ret = regcache_sync(sai->regmap); if (ret) diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 24cb156bf995..b89b0ca26053 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -14,33 +14,61 @@ SNDRV_PCM_FMTBIT_S32_LE) /* SAI Register Map Register */ -#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ -#define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */ -#define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */ -#define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ -#define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ -#define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ -#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ -#define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ +#define FSL_SAI_TCSR(ofs) (0x00 + ofs) /* SAI Transmit Control */ +#define FSL_SAI_TCR1(ofs) (0x04 + ofs) /* SAI Transmit Configuration 1 */ +#define FSL_SAI_TCR2(ofs) (0x08 + ofs) /* SAI Transmit Configuration 2 */ +#define FSL_SAI_TCR3(ofs) (0x0c + ofs) /* SAI Transmit Configuration 3 */ +#define FSL_SAI_TCR4(ofs) (0x10 + ofs) /* SAI Transmit Configuration 4 */ +#define FSL_SAI_TCR5(ofs) (0x14 + ofs) /* SAI Transmit Configuration 5 */ +#define FSL_SAI_TDR0 0x20 /* SAI Transmit Data 0 */ +#define FSL_SAI_TDR1 0x24 /* SAI Transmit Data 1 */ +#define FSL_SAI_TDR2 0x28 /* SAI Transmit Data 2 */ +#define FSL_SAI_TDR3 0x2C /* SAI Transmit Data 3 */ +#define FSL_SAI_TDR4 0x30 /* SAI Transmit Data 4 */ +#define FSL_SAI_TDR5 0x34 /* SAI Transmit Data 5 */ +#define FSL_SAI_TDR6 0x38 /* SAI Transmit Data 6 */ +#define FSL_SAI_TDR7 0x3C /* SAI Transmit Data 7 */ +#define FSL_SAI_TFR0 0x40 /* SAI Transmit FIFO 0 */ +#define FSL_SAI_TFR1 0x44 /* SAI Transmit FIFO 1 */ +#define FSL_SAI_TFR2 0x48 /* SAI Transmit FIFO 2 */ +#define FSL_SAI_TFR3 0x4C /* SAI Transmit FIFO 3 */ +#define FSL_SAI_TFR4 0x50 /* SAI Transmit FIFO 4 */ +#define FSL_SAI_TFR5 0x54 /* SAI Transmit FIFO 5 */ +#define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO 6 */ +#define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO 7 */ #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ -#define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ -#define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ -#define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */ -#define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ -#define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ -#define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ -#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ -#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ +#define FSL_SAI_RCSR(ofs) (0x80 + ofs) /* SAI Receive Control */ +#define FSL_SAI_RCR1(ofs) (0x84 + ofs)/* SAI Receive Configuration 1 */ +#define FSL_SAI_RCR2(ofs) (0x88 + ofs) /* SAI Receive Configuration 2 */ +#define FSL_SAI_RCR3(ofs) (0x8c + ofs) /* SAI Receive Configuration 3 */ +#define FSL_SAI_RCR4(ofs) (0x90 + ofs) /* SAI Receive Configuration 4 */ +#define FSL_SAI_RCR5(ofs) (0x94 + ofs) /* SAI Receive Configuration 5 */ +#define FSL_SAI_RDR0 0xa0 /* SAI Receive Data 0 */ +#define FSL_SAI_RDR1 0xa4 /* SAI Receive Data 1 */ +#define FSL_SAI_RDR2 0xa8 /* SAI Receive Data 2 */ +#define FSL_SAI_RDR3 0xac /* SAI Receive Data 3 */ +#define FSL_SAI_RDR4 0xb0 /* SAI Receive Data 4 */ +#define FSL_SAI_RDR5 0xb4 /* SAI Receive Data 5 */ +#define FSL_SAI_RDR6 0xb8 /* SAI Receive Data 6 */ +#define FSL_SAI_RDR7 0xbc /* SAI Receive Data 7 */ +#define FSL_SAI_RFR0 0xc0 /* SAI Receive FIFO 0 */ +#define FSL_SAI_RFR1 0xc4 /* SAI Receive FIFO 1 */ +#define FSL_SAI_RFR2 0xc8 /* SAI Receive FIFO 2 */ +#define FSL_SAI_RFR3 0xcc /* SAI Receive FIFO 3 */ +#define FSL_SAI_RFR4 0xd0 /* SAI Receive FIFO 4 */ +#define FSL_SAI_RFR5 0xd4 /* SAI Receive FIFO 5 */ +#define FSL_SAI_RFR6 0xd8 /* SAI Receive FIFO 6 */ +#define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO 7 */ #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ -#define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR) -#define FSL_SAI_xCR1(tx) (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1) -#define FSL_SAI_xCR2(tx) (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2) -#define FSL_SAI_xCR3(tx) (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3) -#define FSL_SAI_xCR4(tx) (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4) -#define FSL_SAI_xCR5(tx) (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5) -#define FSL_SAI_xDR(tx) (tx ? FSL_SAI_TDR : FSL_SAI_RDR) -#define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR) +#define FSL_SAI_xCSR(tx, ofs) (tx ? FSL_SAI_TCSR(ofs) : FSL_SAI_RCSR(ofs)) +#define FSL_SAI_xCR1(tx, ofs) (tx ? FSL_SAI_TCR1(ofs) : FSL_SAI_RCR1(ofs)) +#define FSL_SAI_xCR2(tx, ofs) (tx ? FSL_SAI_TCR2(ofs) : FSL_SAI_RCR2(ofs)) +#define FSL_SAI_xCR3(tx, ofs) (tx ? FSL_SAI_TCR3(ofs) : FSL_SAI_RCR3(ofs)) +#define FSL_SAI_xCR4(tx, ofs) (tx ? FSL_SAI_TCR4(ofs) : FSL_SAI_RCR4(ofs)) +#define FSL_SAI_xCR5(tx, ofs) (tx ? FSL_SAI_TCR5(ofs) : FSL_SAI_RCR5(ofs)) +#define FSL_SAI_xDR(tx, ofs) (tx ? FSL_SAI_TDR(ofs) : FSL_SAI_RDR(ofs)) +#define FSL_SAI_xFR(tx, ofs) (tx ? FSL_SAI_TFR(ofs) : FSL_SAI_RFR(ofs)) #define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) /* SAI Transmit/Receive Control Register */ @@ -82,6 +110,7 @@ /* SAI Transmit and Receive Configuration 3 Register */ #define FSL_SAI_CR3_TRCE BIT(16) +#define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16) #define FSL_SAI_CR3_WDFL(x) (x) #define FSL_SAI_CR3_WDFL_MASK 0x1f @@ -126,6 +155,12 @@ #define FSL_SAI_MAXBURST_TX 6 #define FSL_SAI_MAXBURST_RX 6 +struct fsl_sai_soc_data { + bool use_imx_pcm; + unsigned int fifo_depth; + unsigned int reg_offset; +}; + struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; @@ -135,7 +170,6 @@ struct fsl_sai { bool is_slave_mode; bool is_lsb_first; bool is_dsp_mode; - bool sai_on_imx; bool synchronous[2]; unsigned int mclk_id[2]; @@ -143,6 +177,7 @@ struct fsl_sai { unsigned int slots; unsigned int slot_width; + const struct fsl_sai_soc_data *soc_data; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 4842e6df9a2d..7858a5499ac5 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1248,10 +1248,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, dev_name(&pdev->dev), spdif_priv); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 085855f9b08d..537dc69256f0 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1510,10 +1510,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) } ssi->irq = platform_get_irq(pdev, 0); - if (ssi->irq < 0) { - dev_err(dev, "no irq for node %s\n", pdev->name); + if (ssi->irq < 0) return ssi->irq; - } /* Set software limitations for synchronous mode except AC97 */ if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) { diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 9e1cb18859ce..71590ca6394b 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -325,14 +325,14 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->card.num_configs = priv->num_dai_conf; priv->card.dapm_routes = priv->dapm_routes; priv->card.num_dapm_routes = priv->num_dapm_routes; - priv->card.dev = pdev->dev.parent; + priv->card.dev = &pdev->dev; priv->card.owner = THIS_MODULE; priv->card.name = "imx-audmix"; platform_set_drvdata(pdev, &priv->card); snd_soc_card_set_drvdata(&priv->card, priv); - ret = devm_snd_soc_register_card(pdev->dev.parent, &priv->card); + ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed\n"); return ret; diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 16ede3b5cb32..3ce85a43e08f 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -300,12 +300,10 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, static int imx_audmux_probe(struct platform_device *pdev) { - struct resource *res; const struct of_device_id *of_id = of_match_device(imx_audmux_dt_ids, &pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - audmux_base = devm_ioremap_resource(&pdev->dev, res); + audmux_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audmux_base)) return PTR_ERR(audmux_base); diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 9038b61317be..42031ba7da31 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -520,10 +520,8 @@ static int imx_ssi_probe(struct platform_device *pdev) } ssi->irq = platform_get_irq(pdev, 0); - if (ssi->irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", ssi->irq); + if (ssi->irq < 0) return ssi->irq; - } ssi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssi->clk)) { diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 288df245b2f0..6007e6305735 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -129,6 +129,25 @@ static int asoc_simple_parse_dai(struct device_node *ep, args.args[0] = graph_get_dai_id(ep); args.args_count = (of_graph_get_endpoint_count(node) > 1); + /* + * FIXME + * + * Here, dlc->dai_name is pointer to CPU/Codec DAI name. + * If user unbinded CPU or Codec driver, but not for Sound Card, + * dlc->dai_name is keeping unbinded CPU or Codec + * driver's pointer. + * + * If user re-bind CPU or Codec driver again, ALSA SoC will try + * to rebind Card via snd_soc_try_rebind_card(), but because of + * above reason, it might can't bind Sound Card. + * Because Sound Card is pointing to released dai_name pointer. + * + * To avoid this rebind Card issue, + * 1) It needs to alloc memory to keep dai_name eventhough + * CPU or Codec driver was unbinded, or + * 2) user need to rebind Sound Card everytime + * if he unbinded CPU or Codec. + */ ret = snd_soc_get_dai_name(&args, &dlc->dai_name); if (ret < 0) return ret; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 556b1a789629..9b794775df53 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -213,10 +213,17 @@ EXPORT_SYMBOL_GPL(asoc_simple_startup); void asoc_simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + if (dai_props->mclk_fs) { + snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); + snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); + } + asoc_simple_clk_disable(dai_props->cpu_dai); asoc_simple_clk_disable(dai_props->codec_dai); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index ef849151ba56..fc9c753db8dd 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -46,7 +46,25 @@ static int asoc_simple_parse_dai(struct device_node *node, if (ret) return ret; - /* Get dai->name */ + /* + * FIXME + * + * Here, dlc->dai_name is pointer to CPU/Codec DAI name. + * If user unbinded CPU or Codec driver, but not for Sound Card, + * dlc->dai_name is keeping unbinded CPU or Codec + * driver's pointer. + * + * If user re-bind CPU or Codec driver again, ALSA SoC will try + * to rebind Card via snd_soc_try_rebind_card(), but because of + * above reason, it might can't bind Sound Card. + * Because Sound Card is pointing to released dai_name pointer. + * + * To avoid this rebind Card issue, + * 1) It needs to alloc memory to keep dai_name eventhough + * CPU or Codec driver was unbinded, or + * 2) user need to rebind Sound Card everytime + * if he unbinded CPU or Codec. + */ ret = snd_soc_of_get_dai_name(node, &dlc->dai_name); if (ret < 0) return ret; @@ -424,7 +442,7 @@ static int simple_parse_aux_devs(struct device_node *node, aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); if (!aux_node) return -EINVAL; - card->aux_dev[i].codec_of_node = aux_node; + card->aux_dev[i].dlc.of_node = aux_node; } card->num_aux_devs = n; diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 96a00a9d4cf8..01c99750212a 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -215,6 +215,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC select SND_SOC_ACPI_INTEL_MATCH + select SND_INTEL_NHLT if ACPI help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ GeminiLake or CannonLake platform with the DSP enabled in the BIOS diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 8bd1eddcc091..74274bd38f7a 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -211,7 +211,7 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) { struct sst_byt_stream *stream; - u64 header = msg->header; + u64 header = msg->tx.header; u8 stream_id = sst_byt_header_str_id(header); u8 stream_msg = sst_byt_header_msg_id(header); @@ -240,9 +240,10 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) if (msg == NULL) return 1; + msg->rx.header = header; if (header & IPC_HEADER_LARGE(true)) { - msg->rx_size = sst_byt_header_data(header); - sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size); + msg->rx.size = sst_byt_header_data(header); + sst_dsp_inbox_read(byt->dsp, msg->rx.data, msg->rx.size); } /* update any stream states */ @@ -407,17 +408,18 @@ int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) { - struct sst_byt_alloc_params *str_req = &stream->request; - struct sst_byt_alloc_response *reply = &stream->reply; - u64 header; + struct sst_ipc_message request, reply = {0}; int ret; - header = sst_byt_header(IPC_IA_ALLOC_STREAM, - sizeof(*str_req) + sizeof(u32), + request.header = sst_byt_header(IPC_IA_ALLOC_STREAM, + sizeof(stream->request) + sizeof(u32), true, stream->str_id); - ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req, - sizeof(*str_req), - reply, sizeof(*reply)); + request.data = &stream->request; + request.size = sizeof(stream->request); + reply.data = &stream->reply; + reply.size = sizeof(stream->reply); + + ret = sst_ipc_tx_message_wait(&byt->ipc, request, &reply); if (ret < 0) { dev_err(byt->dev, "ipc: error stream commit failed\n"); return ret; @@ -430,7 +432,7 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) { - u64 header; + struct sst_ipc_message request = {0}; int ret = 0; struct sst_dsp *sst = byt->dsp; unsigned long flags; @@ -438,8 +440,9 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) if (!stream->commited) goto out; - header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); - ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0); + request.header = sst_byt_header(IPC_IA_FREE_STREAM, + 0, false, stream->str_id); + ret = sst_ipc_tx_message_wait(&byt->ipc, request, NULL); if (ret < 0) { dev_err(byt->dev, "ipc: free stream %d failed\n", stream->str_id); @@ -459,15 +462,13 @@ out: static int sst_byt_stream_operations(struct sst_byt *byt, int type, int stream_id, int wait) { - u64 header; + struct sst_ipc_message request = {0}; - header = sst_byt_header(type, 0, false, stream_id); + request.header = sst_byt_header(type, 0, false, stream_id); if (wait) - return sst_ipc_tx_message_wait(&byt->ipc, header, NULL, - 0, NULL, 0); + return sst_ipc_tx_message_wait(&byt->ipc, request, NULL); else - return sst_ipc_tx_message_nowait(&byt->ipc, header, - NULL, 0); + return sst_ipc_tx_message_nowait(&byt->ipc, request); } /* stream ALSA trigger operations */ @@ -475,19 +476,17 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, u32 start_offset) { struct sst_byt_start_stream_params start_stream; - void *tx_msg; - size_t size; - u64 header; + struct sst_ipc_message request; int ret; start_stream.byte_offset = start_offset; - header = sst_byt_header(IPC_IA_START_STREAM, + request.header = sst_byt_header(IPC_IA_START_STREAM, sizeof(start_stream) + sizeof(u32), true, stream->str_id); - tx_msg = &start_stream; - size = sizeof(start_stream); + request.data = &start_stream; + request.size = sizeof(start_stream); - ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size); + ret = sst_ipc_tx_message_nowait(&byt->ipc, request); if (ret < 0) dev_err(byt->dev, "ipc: error failed to start stream %d\n", stream->str_id); @@ -623,10 +622,10 @@ EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - if (msg->header & IPC_HEADER_LARGE(true)) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.header & IPC_HEADER_LARGE(true)) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header); + sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->tx.header); } static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text) @@ -648,9 +647,9 @@ static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { /* msg content = lower 32-bit of the header + data */ - *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1); - memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size); - msg->tx_size += sizeof(u32); + *(u32 *)msg->tx.data = (u32)(msg->tx.header & (u32)-1); + memcpy(msg->tx.data + sizeof(u32), tx_data, tx_size); + msg->tx.size += sizeof(u32); } static u64 byt_reply_msg_match(u64 header, u64 *mask) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 50bf149818b5..5c27f7ab4a5f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -256,16 +256,20 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH endif ## SND_SOC_INTEL_SKL +config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + tristate + select SND_SOC_DA7219 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton-P platforms @@ -326,10 +330,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH tristate "KBL with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC help This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for DA7219 + MAX98357A I2S audio codec. @@ -387,6 +388,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help This adds support for ASoC machine driver for Intel platforms @@ -412,4 +414,14 @@ config SND_SOC_INTEL_SOF_RT5682_MACH If unsure select "N". endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +if (SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK) + +config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH + tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + +endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index e8e9c3dc82a5..4a4d3353e26d 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -340,7 +340,6 @@ static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -355,11 +354,8 @@ static int bdw_rt5677_probe(struct platform_device *pdev) /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, - platform_name); + mach->mach_params.platform); if (ret) return ret; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index ab38ef30dfff..db7e1e87156d 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -270,18 +270,14 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; broadwell_rt286.dev = &pdev->dev; /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, - platform_name); + mach->mach_params.platform); if (ret) return ret; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c0d865a940dc..ac1dea5f9d11 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -179,10 +179,17 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) int ret; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_component *component = rtd->codec_dai->component; + int clk_freq; /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 19200000, + if (soc_intel_is_cml()) + clk_freq = 24000000; + else + clk_freq = 19200000; + + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN); + if (ret) { dev_err(rtd->dev, "can't set codec sysclk configuration\n"); return ret; @@ -683,6 +690,25 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_dais[i].cpus->dai_name = "SSP2 Pin"; } } + } else if (soc_intel_is_cml()) { + unsigned int i; + + broxton_audio_card.name = "cmlda7219max"; + + for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { + /* MAXIM_CODEC is connected to SSP1. */ + if (!strcmp(broxton_dais[i].codecs->dai_name, + BXT_MAXIM_CODEC_DAI)) { + broxton_dais[i].name = "SSP1-Codec"; + broxton_dais[i].cpus->dai_name = "SSP1 Pin"; + } + /* DIALOG_CODEC is connected to SSP0 */ + else if (!strcmp(broxton_dais[i].codecs->dai_name, + BXT_DIALOG_CODEC_DAI)) { + broxton_dais[i].name = "SSP0-Codec"; + broxton_dais[i].cpus->dai_name = "SSP0 Pin"; + } + } } /* override plaform name, if required */ @@ -700,6 +726,7 @@ static int broxton_audio_probe(struct platform_device *pdev) static const struct platform_device_id bxt_board_ids[] = { { .name = "bxt_da7219_max98357a" }, { .name = "glk_da7219_max98357a" }, + { .name = "cml_da7219_max98357a" }, { } }; @@ -720,6 +747,8 @@ MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>"); MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); +MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:bxt_da7219_max98357a"); MODULE_ALIAS("platform:glk_da7219_max98357a"); +MODULE_ALIAS("platform:cml_da7219_max98357a"); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 83b978e7b4c4..eaf3e2208a06 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -324,9 +324,8 @@ static const struct snd_soc_ops cht_be_ssp2_ops = { }; static struct snd_soc_aux_dev cht_max98090_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_AUX("i2c-104C227E:00"), .init = cht_max98090_headset_init, - .codec_name = "i2c-104C227E:00", }; SND_SOC_DAILINK_DEF(dummy, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 4d3822cff98c..3dadf9bff796 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -188,18 +188,14 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; - const char *platform_name = NULL; int ret; haswell_rt5640.dev = &pdev->dev; /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; - if (mach) /* extra check since legacy does not pass parameters */ - platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, - platform_name); + mach->mach_params.platform); if (ret) return ret; diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 55fd82e05e2c..58409b6e476e 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -147,6 +147,11 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) if (err) return err; + err = snd_jack_add_new_kctl(pcm->hdmi_jack.jack, + jack_name, SND_JACK_AVOUT); + if (err) + dev_warn(component->dev, "failed creating Jack kctl\n"); + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, &pcm->hdmi_jack); if (err < 0) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 9ed68eb4f058..1778acdc367c 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -23,6 +23,7 @@ static const struct snd_soc_dapm_widget skl_hda_widgets[] = { SND_SOC_DAPM_MIC("Alt Analog In", NULL), SND_SOC_DAPM_SPK("Digital Out", NULL), SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route skl_hda_map[] = { @@ -41,6 +42,9 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "Codec Input Pin2", NULL, "Digital In" }, { "Codec Input Pin3", NULL, "Alt Analog In" }, + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, + /* CODEC BE connections */ { "Analog Codec Playback", NULL, "Analog CPU Playback" }, { "Analog CPU Playback", NULL, "codec0_out" }, diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0b12d61cf1e7..a437567b8cee 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -91,8 +91,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { { .callback = sof_rt5682_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 56c81e20b5bf..18d9630ae9a2 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,6 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 771b0ef21051..985aa366c9e8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -19,6 +19,11 @@ static struct snd_soc_acpi_codecs cml_codecs = { .codecs = {"10EC5682"} }; +static struct snd_soc_acpi_codecs cml_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -29,6 +34,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_tplg_filename = "sof-cnl-rt274.tplg", }, { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .quirk_data = &cml_spk_codecs, + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, + { .id = "MX98357A", .drv_name = "sof_rt5682", .quirk_data = &cml_codecs, diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c new file mode 100644 index 000000000000..a1290c3fa99f --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> + +struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c new file mode 100644 index 000000000000..57a6298d6dca --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> + +struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { + { + .id = "10EC1308", + .drv_name = "tgl_rt1308", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt1308.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h index 4718fd3cf636..e6357d306cb8 100644 --- a/sound/soc/intel/common/soc-intel-quirks.h +++ b/sound/soc/intel/common/soc-intel-quirks.h @@ -36,6 +36,7 @@ SOC_INTEL_IS_CPU(byt, INTEL_FAM6_ATOM_SILVERMONT); SOC_INTEL_IS_CPU(cht, INTEL_FAM6_ATOM_AIRMONT); SOC_INTEL_IS_CPU(apl, INTEL_FAM6_ATOM_GOLDMONT); SOC_INTEL_IS_CPU(glk, INTEL_FAM6_ATOM_GOLDMONT_PLUS); +SOC_INTEL_IS_CPU(cml, INTEL_FAM6_KABYLAKE_MOBILE); static inline bool soc_intel_is_byt_cr(struct platform_device *pdev) { @@ -110,6 +111,10 @@ static inline bool soc_intel_is_glk(void) return false; } +static inline bool soc_intel_is_cml(void) +{ + return false; +} #endif #endif /* _SND_SOC_INTEL_QUIRKS_H */ diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 0e8e0a7a11df..5854868650b9 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -141,11 +141,12 @@ static int sst_acpi_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, sst_acpi); + mach->pdata = sst_pdata; /* register machine driver */ sst_acpi->pdev_mach = platform_device_register_data(dev, mach->drv_name, -1, - sst_pdata, sizeof(*sst_pdata)); + mach, sizeof(*mach)); if (IS_ERR(sst_acpi->pdev_mach)) return PTR_ERR(sst_acpi->pdev_mach); diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 3a66121ee9bb..6068bb697e22 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -43,7 +43,7 @@ static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) } static int tx_wait_done(struct sst_generic_ipc *ipc, - struct ipc_message *msg, void *rx_data) + struct ipc_message *msg, struct sst_ipc_message *reply) { unsigned long flags; int ret; @@ -62,8 +62,11 @@ static int tx_wait_done(struct sst_generic_ipc *ipc, } else { /* copy the data returned from DSP */ - if (rx_data) - memcpy(rx_data, msg->rx_data, msg->rx_size); + if (reply) { + reply->header = msg->rx.header; + if (reply->data) + memcpy(reply->data, msg->rx.data, msg->rx.size); + } ret = msg->errno; } @@ -72,9 +75,9 @@ static int tx_wait_done(struct sst_generic_ipc *ipc, return ret; } -static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, - size_t rx_bytes, int wait) +static int ipc_tx_message(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, + struct sst_ipc_message *reply, int wait) { struct ipc_message *msg; unsigned long flags; @@ -87,23 +90,24 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, return -EBUSY; } - msg->header = header; - msg->tx_size = tx_bytes; - msg->rx_size = rx_bytes; + msg->tx.header = request.header; + msg->tx.size = request.size; + msg->rx.header = 0; + msg->rx.size = reply ? reply->size : 0; msg->wait = wait; msg->errno = 0; msg->pending = false; msg->complete = false; - if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL)) - ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); + if ((request.size) && (ipc->ops.tx_data_copy != NULL)) + ipc->ops.tx_data_copy(msg, request.data, request.size); list_add_tail(&msg->list, &ipc->tx_list); schedule_work(&ipc->kwork); spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); if (wait) - return tx_wait_done(ipc, msg, rx_data); + return tx_wait_done(ipc, msg, reply); else return 0; } @@ -118,13 +122,13 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc) return -ENOMEM; for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - ipc->msg[i].tx_data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].tx_data == NULL) + ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); + if (ipc->msg[i].tx.data == NULL) goto free_mem; - ipc->msg[i].rx_data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].rx_data == NULL) { - kfree(ipc->msg[i].tx_data); + ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); + if (ipc->msg[i].rx.data == NULL) { + kfree(ipc->msg[i].tx.data); goto free_mem; } @@ -136,8 +140,8 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc) free_mem: while (i > 0) { - kfree(ipc->msg[i-1].tx_data); - kfree(ipc->msg[i-1].rx_data); + kfree(ipc->msg[i-1].tx.data); + kfree(ipc->msg[i-1].rx.data); --i; } kfree(ipc->msg); @@ -173,8 +177,8 @@ static void ipc_tx_msgs(struct work_struct *work) spin_unlock_irq(&ipc->dsp->spinlock); } -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply) { int ret; @@ -187,8 +191,7 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) return -EIO; - ret = ipc_tx_message(ipc, header, tx_data, tx_bytes, - rx_data, rx_bytes, 1); + ret = ipc_tx_message(ipc, request, reply, 1); if (ipc->ops.check_dsp_lp_on) if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) @@ -198,19 +201,17 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes) +int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, - NULL, 0, 0); + return ipc_tx_message(ipc, request, NULL, 0); } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, - rx_data, rx_bytes, 1); + return ipc_tx_message(ipc, request, reply, 1); } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); @@ -232,7 +233,7 @@ struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, } list_for_each_entry(msg, &ipc->rx_list, list) { - if ((msg->header & mask) == header) + if ((msg->tx.header & mask) == header) return msg; } @@ -306,8 +307,8 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc) if (ipc->msg) { for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - kfree(ipc->msg[i].tx_data); - kfree(ipc->msg[i].rx_data); + kfree(ipc->msg[i].tx.data); + kfree(ipc->msg[i].rx.data); } kfree(ipc->msg); } diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index c6779e2ac830..08c4831b2664 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -17,15 +17,16 @@ #define IPC_MAX_MAILBOX_BYTES 256 -struct ipc_message { - struct list_head list; +struct sst_ipc_message { u64 header; + void *data; + size_t size; +}; - /* direction wrt host CPU */ - char *tx_data; - size_t tx_size; - char *rx_data; - size_t rx_size; +struct ipc_message { + struct list_head list; + struct sst_ipc_message tx; + struct sst_ipc_message rx; wait_queue_head_t waitq; bool pending; @@ -35,6 +36,7 @@ struct ipc_message { }; struct sst_generic_ipc; +struct sst_dsp; struct sst_plat_ipc_ops { void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); @@ -65,14 +67,14 @@ struct sst_generic_ipc { struct sst_plat_ipc_ops ops; }; -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); +int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply); -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, + struct sst_ipc_message request); -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, + struct sst_ipc_message request, struct sst_ipc_message *reply); struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header); diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index a83b92d6bea8..0ff89ea96ccf 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -511,7 +511,7 @@ static void hsw_notification_work(struct work_struct *work) static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) { struct sst_hsw_stream *stream; - u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); + u32 header = msg->tx.header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); u32 stream_id = msg_get_stream_id(header); u32 stream_msg = msg_get_stream_type(header); @@ -552,6 +552,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) return -EIO; } + msg->rx.header = header; /* first process the header */ switch (reply) { case IPC_GLB_REPLY_PENDING: @@ -562,13 +563,13 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) case IPC_GLB_REPLY_SUCCESS: if (msg->pending) { trace_ipc_pending_reply("completed", header); - sst_dsp_inbox_read(hsw->dsp, msg->rx_data, - msg->rx_size); + sst_dsp_inbox_read(hsw->dsp, msg->rx.data, + msg->rx.size); hsw->ipc.pending = false; } else { /* copy data from the DSP */ - sst_dsp_outbox_read(hsw->dsp, msg->rx_data, - msg->rx_size); + sst_dsp_outbox_read(hsw->dsp, msg->rx.data, + msg->rx.size); } break; /* these will be rare - but useful for debug */ @@ -810,11 +811,13 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) int sst_hsw_fw_get_version(struct sst_hsw *hsw, struct sst_hsw_ipc_fw_version *version) { + struct sst_ipc_message request = {0}, reply = {0}; int ret; - ret = sst_ipc_tx_message_wait(&hsw->ipc, - IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), - NULL, 0, version, sizeof(*version)); + request.header = IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION); + reply.data = version; + reply.size = sizeof(*version); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) dev_err(hsw->dev, "error: get version failed\n"); @@ -840,7 +843,7 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) { struct sst_hsw_ipc_volume_req *req; - u32 header; + struct sst_ipc_message request; int ret; trace_ipc_request("set stream volume", stream->reply.stream_hw_id); @@ -848,11 +851,11 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) return -EINVAL; - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); + request.header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); + request.header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); + request.header |= (stage_id << IPC_STG_ID_SHIFT); req = &stream->vol_req; req->target_volume = volume; @@ -877,8 +880,9 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, req->channel = channel; } - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req, - sizeof(*req), NULL, 0); + request.data = req; + request.size = sizeof(*req); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: set stream volume failed\n"); return ret; @@ -905,7 +909,7 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume) { struct sst_hsw_ipc_volume_req req; - u32 header; + struct sst_ipc_message request; int ret; trace_ipc_request("set mixer volume", volume); @@ -933,18 +937,19 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, req.channel = channel; } - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); + request.header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); + request.header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); + request.header |= (stage_id << IPC_STG_ID_SHIFT); req.curve_duration = hsw->curve_duration; req.curve_type = hsw->curve_type; req.target_volume = volume; - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req, - sizeof(req), NULL, 0); + request.data = &req; + request.size = sizeof(req); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: set mixer volume failed\n"); return ret; @@ -983,7 +988,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - u32 header; + struct sst_ipc_message request; int ret = 0; struct sst_dsp *sst = hsw->dsp; unsigned long flags; @@ -1000,10 +1005,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_ipc_request("stream free", stream->host_id); stream->free_req.stream_id = stream->reply.stream_hw_id; - header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); + request.header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); + request.data = &stream->free_req; + request.size = sizeof(stream->free_req); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req, - sizeof(stream->free_req), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) { dev_err(hsw->dev, "error: free stream %d failed\n", stream->free_req.stream_id); @@ -1175,9 +1181,7 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) { - struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request; - struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply; - u32 header; + struct sst_ipc_message request, reply = {0}; int ret; if (!stream) { @@ -1192,10 +1196,13 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) trace_ipc_request("stream alloc", stream->host_id); - header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); + request.header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); + request.data = &stream->request; + request.size = sizeof(stream->request); + reply.data = &stream->reply; + reply.size = sizeof(stream->reply); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req, - sizeof(*str_req), reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "error: stream commit failed\n"); return ret; @@ -1235,23 +1242,22 @@ void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw, ABI to be opaque to client PCM drivers to cope with any future ABI changes */ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) { - struct sst_hsw_ipc_stream_info_reply *reply; - u32 header; + struct sst_ipc_message request = {0}, reply = {0}; int ret; - reply = &hsw->mixer_info; - header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); + request.header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); + reply.data = &hsw->mixer_info; + reply.size = sizeof(hsw->mixer_info); trace_ipc_request("get global mixer info", 0); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, - reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "error: get stream info failed\n"); return ret; } - trace_hsw_mixer_info_reply(reply); + trace_hsw_mixer_info_reply(&hsw->mixer_info); return 0; } @@ -1260,16 +1266,15 @@ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, int stream_id, int wait) { - u32 header; + struct sst_ipc_message request = {0}; - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type); - header |= (stream_id << IPC_STR_ID_SHIFT); + request.header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE); + request.header |= IPC_STR_TYPE(type) | (stream_id << IPC_STR_ID_SHIFT); if (wait) - return sst_ipc_tx_message_wait(&hsw->ipc, header, - NULL, 0, NULL, 0); + return sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); else - return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0); + return sst_ipc_tx_message_nowait(&hsw->ipc, request); } /* Stream ALSA trigger operations */ @@ -1377,8 +1382,8 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, enum sst_hsw_device_mode mode, u32 clock_divider) { + struct sst_ipc_message request; struct sst_hsw_ipc_device_config_req config; - u32 header; int ret; trace_ipc_request("set device config", dev); @@ -1394,10 +1399,11 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, trace_hsw_device_config_req(&config); - header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); + request.header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); + request.data = &config; + request.size = sizeof(config); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, - sizeof(config), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(hsw->dev, "error: set device formats failed\n"); @@ -1409,16 +1415,20 @@ EXPORT_SYMBOL_GPL(sst_hsw_device_set_config); int sst_hsw_dx_set_state(struct sst_hsw *hsw, enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) { - u32 header, state_; + struct sst_ipc_message request, reply = {0}; + u32 state_; int ret, item; - header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); state_ = state; + request.header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); + request.data = &state_; + request.size = sizeof(state_); + reply.data = dx; + reply.size = sizeof(*dx); trace_ipc_request("PM enter Dx state", state); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_, - sizeof(state_), dx, sizeof(*dx)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, &reply); if (ret < 0) { dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); return ret; @@ -1878,7 +1888,7 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, u32 module_id, u32 instance_id) { int ret; - u32 header = 0; + struct sst_ipc_message request; struct sst_hsw_ipc_module_config config; struct sst_module *module; struct sst_module_runtime *runtime; @@ -1907,10 +1917,10 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, return -ENXIO; } - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | IPC_MODULE_ID(module_id); - dev_dbg(dev, "module enable header: %x\n", header); + dev_dbg(dev, "module enable header: %x\n", (u32)request.header); config.map.module_entries_count = 1; config.map.module_entries[0].module_id = module->id; @@ -1932,8 +1942,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, config.scratch_mem.size, config.scratch_mem.offset, config.map.module_entries[0].entry_point); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, - &config, sizeof(config), NULL, 0); + request.data = &config; + request.size = sizeof(config); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "ipc: module enable failed - %d\n", ret); else @@ -1946,7 +1957,7 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, u32 module_id, u32 instance_id) { int ret; - u32 header; + struct sst_ipc_message request = {0}; struct sst_module *module; struct device *dev = hsw->dev; struct sst_dsp *dsp = hsw->dsp; @@ -1967,11 +1978,11 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, return -ENXIO; } - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | IPC_MODULE_ID(module_id); - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "module disable failed - %d\n", ret); else @@ -1985,15 +1996,16 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, u32 param_size, char *param) { int ret; - u32 header = 0; - u32 payload_size = 0, transfer_parameter_size = 0; + struct sst_ipc_message request = {0}; + u32 payload_size = 0; struct sst_hsw_transfer_parameter *parameter; struct device *dev = hsw->dev; - header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + request.header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | IPC_MODULE_ID(module_id); - dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); + dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", + (u32)request.header); payload_size = param_size + sizeof(struct sst_hsw_transfer_parameter) - @@ -2003,14 +2015,14 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { /* short parameter, mailbox can contain data */ - dev_dbg(dev, "transfer parameter size : %d\n", - transfer_parameter_size); + dev_dbg(dev, "transfer parameter size : %zu\n", + request.size); - transfer_parameter_size = ALIGN(payload_size, 4); - dev_dbg(dev, "transfer parameter aligned size : %d\n", - transfer_parameter_size); + request.size = ALIGN(payload_size, 4); + dev_dbg(dev, "transfer parameter aligned size : %zu\n", + request.size); - parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); + parameter = kzalloc(request.size, GFP_KERNEL); if (parameter == NULL) return -ENOMEM; @@ -2022,9 +2034,9 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, parameter->parameter_id = parameter_id; parameter->data_size = param_size; + request.data = parameter; - ret = sst_ipc_tx_message_wait(&hsw->ipc, header, - parameter, transfer_parameter_size , NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, request, NULL); if (ret < 0) dev_err(dev, "ipc: module set parameter failed - %d\n", ret); @@ -2041,8 +2053,8 @@ static struct sst_dsp_device hsw_dev = { static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { /* send the message */ - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); - sst_dsp_ipc_msg_tx(ipc->dsp, msg->header); + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); + sst_dsp_ipc_msg_tx(ipc->dsp, msg->tx.header); } static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) @@ -2063,7 +2075,7 @@ static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { - memcpy(msg->tx_data, tx_data, tx_size); + memcpy(msg->tx.data, tx_data, tx_size); } static u64 hsw_reply_msg_match(u64 header, u64 *mask) diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 86f6e1d801af..48544ff1a3e6 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o \ -skl-topology.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \ + skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o ifdef CONFIG_DEBUG_FS snd-soc-skl-objs += skl-debug.o @@ -8,13 +9,6 @@ endif obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o -# Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \ - skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \ - skl-sst-utils.o - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o - #Skylake Clock device support snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 46d5159cf905..92a82e6b5fe6 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -14,7 +14,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define BXT_BASEFW_TIMEOUT 3000 #define BXT_INIT_TIMEOUT 300 @@ -49,7 +49,7 @@ static int bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; int ret = 0, i, dma_id, stream_tag; @@ -184,7 +184,7 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) static int bxt_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret, i; if (ctx->fw == NULL) { @@ -268,7 +268,7 @@ sst_load_base_firmware_failed: */ static int bxt_d0i3_target_state(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct skl_d0i3_data *d0i3 = &skl->d0i3; if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) @@ -288,8 +288,8 @@ static void bxt_set_dsp_D0i3(struct work_struct *work) { int ret; struct skl_ipc_d0ix_msg msg; - struct skl_sst *skl = container_of(work, - struct skl_sst, d0i3.work.work); + struct skl_dev *skl = container_of(work, + struct skl_dev, d0i3.work.work); struct sst_dsp *ctx = skl->dsp; struct skl_d0i3_data *d0i3 = &skl->d0i3; int target_state; @@ -331,7 +331,7 @@ static void bxt_set_dsp_D0i3(struct work_struct *work) static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct skl_d0i3_data *d0i3 = &skl->d0i3; /* Schedule D0i3 only if the usecase ref counts are appropriate */ @@ -350,7 +350,7 @@ static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) { int ret; struct skl_ipc_d0ix_msg msg; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; dev_dbg(ctx->dev, "In %s:\n", __func__); @@ -389,7 +389,7 @@ static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret; struct skl_ipc_dxstate_info dx; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); @@ -486,7 +486,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); dx.core_mask = core_mask; @@ -548,9 +548,9 @@ static struct sst_dsp_device skl_dev = { int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp) + struct skl_dev **dsp) { - struct skl_sst *skl; + struct skl_dev *skl; struct sst_dsp *sst; int ret; @@ -591,10 +591,10 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); -int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { @@ -604,29 +604,29 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, ctx->lib_info, - ctx->lib_count); + if (skl->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; } } - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(bxt_sst_init_fw); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - skl_release_library(ctx->lib_info, ctx->lib_count); - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); - skl_freeup_uuid_list(ctx); - skl_ipc_free(&ctx->ipc); - ctx->dsp->ops->free(ctx->dsp); + skl_release_library(skl->lib_info, skl->lib_count); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); + skl_freeup_uuid_list(skl); + skl_ipc_free(&skl->ipc); + skl->dsp->ops->free(skl->dsp); } EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h index 426515faab52..7bd4d2a8fdfa 100644 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ b/sound/soc/intel/skylake/cnl-sst-dsp.h @@ -9,7 +9,6 @@ #define __CNL_SST_DSP_H__ struct sst_dsp; -struct skl_sst; struct sst_dsp_device; struct sst_generic_ipc; @@ -97,8 +96,8 @@ void cnl_ipc_free(struct sst_generic_ipc *ipc); int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); -int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); + struct skl_dev **dsp); +int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl); +void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); #endif /*__CNL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index f2c09fa6ea40..4f64f097e9ae 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -24,8 +24,7 @@ #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" #include "cnl-sst-dsp.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define CNL_FW_ROM_INIT 0x1 #define CNL_FW_INIT 0x5 @@ -109,7 +108,7 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) static int cnl_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; int ret; if (!ctx->fw) { @@ -167,7 +166,7 @@ cnl_load_base_firmware_failed: static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); struct skl_ipc_dxstate_info dx; int ret; @@ -229,7 +228,7 @@ err: static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *cnl = ctx->thread_context; + struct skl_dev *cnl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); struct skl_ipc_dxstate_info dx; int ret; @@ -293,7 +292,7 @@ static struct sst_ops cnl_ops = { static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) { struct sst_dsp *dsp = context; - struct skl_sst *cnl = sst_dsp_get_thread_context(dsp); + struct skl_dev *cnl = sst_dsp_get_thread_context(dsp); struct sst_generic_ipc *ipc = &cnl->ipc; struct skl_ipc_header header = {0}; u32 hipcida, hipctdr, hipctdd; @@ -367,10 +366,10 @@ static struct sst_dsp_device cnl_dev = { static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - if (msg->tx_size) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.size) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, header->extension); sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, @@ -386,7 +385,7 @@ static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); } -static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl) +static int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) { struct sst_generic_ipc *ipc; int err; @@ -415,9 +414,9 @@ static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl) int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp) + struct skl_dev **dsp) { - struct skl_sst *cnl; + struct skl_dev *cnl; struct sst_dsp *sst; int ret; @@ -454,12 +453,12 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); -int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; - ret = ctx->dsp->fw_ops.load_fw(sst); + ret = skl->dsp->fw_ops.load_fw(sst); if (ret < 0) { dev_err(dev, "load base fw failed: %d", ret); return ret; @@ -467,21 +466,21 @@ int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(cnl_sst_init_fw); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); - skl_freeup_uuid_list(ctx); - cnl_ipc_free(&ctx->ipc); + skl_freeup_uuid_list(skl); + cnl_ipc_free(&skl->ipc); - ctx->dsp->ops->free(ctx->dsp); + skl->dsp->ops->free(skl->dsp); } EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c index b28a9c2b0380..3466675f2678 100644 --- a/sound/soc/intel/skylake/skl-debug.c +++ b/sound/soc/intel/skylake/skl-debug.c @@ -20,7 +20,7 @@ #define FW_REG_SIZE 0x60 struct skl_debug { - struct skl *skl; + struct skl_dev *skl; struct device *dev; struct dentry *fs; @@ -66,6 +66,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct skl_module_cfg *mconfig = file->private_data; + struct skl_module *module = mconfig->module; + struct skl_module_res *res = &module->resources[mconfig->res_idx]; char *buf; ssize_t ret; @@ -79,8 +81,8 @@ static ssize_t module_read(struct file *file, char __user *user_buf, mconfig->id.pvt_id); ret += snprintf(buf + ret, MOD_BUF - ret, - "Resources:\n\tMCPS %#x\n\tIBS %#x\n\tOBS %#x\t\n", - mconfig->mcps, mconfig->ibs, mconfig->obs); + "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n", + res->cpc, res->ibs, res->obs); ret += snprintf(buf + ret, MOD_BUF - ret, "Module data:\n\tCore %d\n\tIn queue %d\n\t" @@ -162,17 +164,15 @@ void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig) { - if (!debugfs_create_file(w->name, 0444, - d->modules, mconfig, - &mcfg_fops)) - dev_err(d->dev, "%s: module debugfs init failed\n", w->name); + debugfs_create_file(w->name, 0444, d->modules, mconfig, + &mcfg_fops); } static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct skl_debug *d = file->private_data; - struct sst_dsp *sst = d->skl->skl_sst->dsp; + struct sst_dsp *sst = d->skl->dsp; size_t w0_stat_sz = sst->addr.w0_stat_sz; void __iomem *in_base = sst->mailbox.in_base; void __iomem *fw_reg_addr; @@ -213,7 +213,7 @@ static const struct file_operations soft_regs_ctrl_fops = { .llseek = default_llseek, }; -struct skl_debug *skl_debugfs_init(struct skl *skl) +struct skl_debug *skl_debugfs_init(struct skl_dev *skl) { struct skl_debug *d; @@ -222,37 +222,21 @@ struct skl_debug *skl_debugfs_init(struct skl *skl) return NULL; /* create the debugfs dir with platform component's debugfs as parent */ - d->fs = debugfs_create_dir("dsp", - skl->component->debugfs_root); - if (IS_ERR(d->fs) || !d->fs) { - dev_err(&skl->pci->dev, "debugfs root creation failed\n"); - return NULL; - } + d->fs = debugfs_create_dir("dsp", skl->component->debugfs_root); d->skl = skl; d->dev = &skl->pci->dev; /* now create the module dir */ d->modules = debugfs_create_dir("modules", d->fs); - if (IS_ERR(d->modules) || !d->modules) { - dev_err(&skl->pci->dev, "modules debugfs create failed\n"); - goto err; - } - if (!debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, - &soft_regs_ctrl_fops)) { - dev_err(d->dev, "fw soft regs control debugfs init failed\n"); - goto err; - } + debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, + &soft_regs_ctrl_fops); return d; - -err: - debugfs_remove_recursive(d->fs); - return NULL; } -void skl_debugfs_exit(struct skl *skl) +void skl_debugfs_exit(struct skl_dev *skl) { struct skl_debug *d = skl->debugfs; diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index febc070839e0..476ef1897961 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -25,29 +25,18 @@ static int skl_alloc_dma_buf(struct device *dev, struct snd_dma_buffer *dmab, size_t size) { - struct hdac_bus *bus = dev_get_drvdata(dev); - - if (!bus) - return -ENODEV; - - return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, size, dmab); + return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); } static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) { - struct hdac_bus *bus = dev_get_drvdata(dev); - - if (!bus) - return -ENODEV; - - bus->io_ops->dma_free_pages(bus, dmab); - + snd_dma_free_pages(dmab); return 0; } #define SKL_ASTATE_PARAM_ID 4 -void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data) +void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) { struct skl_ipc_large_config_msg msg = {0}; @@ -55,25 +44,7 @@ void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data) msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + sizeof(cnt)); - skl_ipc_set_large_config(&ctx->ipc, &msg, data); -} - -#define NOTIFICATION_PARAM_ID 3 -#define NOTIFICATION_MASK 0xf - -/* disable notfication for underruns/overruns from firmware module */ -void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) -{ - struct notification_mask mask; - struct skl_ipc_large_config_msg msg = {0}; - - mask.notify = NOTIFICATION_MASK; - mask.enable = enable; - - msg.large_param_id = NOTIFICATION_PARAM_ID; - msg.param_data_size = sizeof(mask); - - skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask); + skl_ipc_set_large_config(&skl->ipc, &msg, data); } static int skl_dsp_setup_spib(struct device *dev, unsigned int size, @@ -277,7 +248,7 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) return NULL; } -int skl_init_dsp(struct skl *skl) +int skl_init_dsp(struct skl_dev *skl) { void __iomem *mmio_base; struct hdac_bus *bus = skl_to_bus(skl); @@ -307,13 +278,13 @@ int skl_init_dsp(struct skl *skl) loader_ops = ops->loader_ops(); ret = ops->init(bus->dev, mmio_base, irq, skl->fw_name, loader_ops, - &skl->skl_sst); + &skl); if (ret < 0) goto unmap_mmio; - skl->skl_sst->dsp_ops = ops; - cores = &skl->skl_sst->cores; + skl->dsp_ops = ops; + cores = &skl->cores; cores->count = ops->num_cores; cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); @@ -342,21 +313,20 @@ unmap_mmio: return ret; } -int skl_free_dsp(struct skl *skl) +int skl_free_dsp(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); - struct skl_sst *ctx = skl->skl_sst; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(bus, false); - ctx->dsp_ops->cleanup(bus->dev, ctx); + skl->dsp_ops->cleanup(bus->dev, skl); - kfree(ctx->cores.state); - kfree(ctx->cores.usage_count); + kfree(skl->cores.state); + kfree(skl->cores.usage_count); - if (ctx->dsp->addr.lpe) - iounmap(ctx->dsp->addr.lpe); + if (skl->dsp->addr.lpe) + iounmap(skl->dsp->addr.lpe); return 0; } @@ -368,15 +338,14 @@ int skl_free_dsp(struct skl *skl) * mode during system suspend. In the case of normal suspend, cancel * any pending D0i3 work. */ -int skl_suspend_late_dsp(struct skl *skl) +int skl_suspend_late_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct delayed_work *dwork; - if (!ctx) + if (!skl) return 0; - dwork = &ctx->d0i3.work; + dwork = &skl->d0i3.work; if (dwork->work.func) { if (skl->supend_active) @@ -388,9 +357,8 @@ int skl_suspend_late_dsp(struct skl *skl) return 0; } -int skl_suspend_dsp(struct skl *skl) +int skl_suspend_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct hdac_bus *bus = skl_to_bus(skl); int ret; @@ -398,7 +366,7 @@ int skl_suspend_dsp(struct skl *skl) if (!bus->ppcap) return 0; - ret = skl_dsp_sleep(ctx->dsp); + ret = skl_dsp_sleep(skl->dsp); if (ret < 0) return ret; @@ -409,9 +377,8 @@ int skl_suspend_dsp(struct skl *skl) return 0; } -int skl_resume_dsp(struct skl *skl) +int skl_resume_dsp(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct hdac_bus *bus = skl_to_bus(skl); int ret; @@ -424,26 +391,24 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot) + if (skl->is_first_boot) return 0; /* * Disable dynamic clock and power gating during firmware * and library download */ - ctx->enable_miscbdcge(ctx->dev, false); - ctx->clock_power_gating(ctx->dev, false); + skl->enable_miscbdcge(skl->dev, false); + skl->clock_power_gating(skl->dev, false); - ret = skl_dsp_wake(ctx->dsp); - ctx->enable_miscbdcge(ctx->dev, true); - ctx->clock_power_gating(ctx->dev, true); + ret = skl_dsp_wake(skl->dsp); + skl->enable_miscbdcge(skl->dev, true); + skl->clock_power_gating(skl->dev, true); if (ret < 0) return ret; - skl_dsp_enable_notification(skl->skl_sst, false); - if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count, + skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, skl->cfg.astate_cfg); } return ret; @@ -476,7 +441,7 @@ enum skl_bitdepth skl_get_bit_depth(int params) * which are read from widget information passed through topology binary * This is send when we create a module with INIT_INSTANCE IPC msg */ -static void skl_set_base_module_format(struct skl_sst *ctx, +static void skl_set_base_module_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_base_cfg *base_cfg) { @@ -493,7 +458,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->audio_fmt.ch_cfg = format->ch_cfg; base_cfg->audio_fmt.sample_type = format->sample_type; - dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", + dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", format->bit_depth, format->valid_bit_depth, format->ch_cfg); @@ -501,7 +466,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->audio_fmt.interleaving = format->interleaving_style; - base_cfg->cps = res->cps; + base_cfg->cpc = res->cpc; base_cfg->ibs = res->ibs; base_cfg->obs = res->obs; base_cfg->is_pages = res->is_pages; @@ -530,7 +495,7 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, * Calculate the gatewat settings required for copier module, type of * gateway and index of gateway to use */ -static u32 skl_get_node_id(struct skl_sst *ctx, +static u32 skl_get_node_id(struct skl_dev *skl, struct skl_module_cfg *mconfig) { union skl_connector_node_id node_id = {0}; @@ -587,16 +552,15 @@ static u32 skl_get_node_id(struct skl_sst *ctx, return node_id.val; } -static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, +static void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { u32 dma_io_buf; struct skl_module_res *res; int res_idx = mconfig->res_idx; - struct skl *skl = get_skl_ctx(ctx->dev); - cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); + cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { cpr_mconfig->cpr_feature_mask = 0; @@ -627,7 +591,7 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, break; default: - dev_warn(ctx->dev, "wrong connection type: %d\n", + dev_warn(skl->dev, "wrong connection type: %d\n", mconfig->hw_conn_type); return; } @@ -653,7 +617,7 @@ skip_buf_size_calc: #define DMA_CONTROL_ID 5 #define DMA_I2S_BLOB_SIZE 21 -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id) { struct skl_dma_control *dma_ctrl; @@ -686,14 +650,14 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, memcpy(dma_ctrl->config_data, caps, caps_size); - err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); + err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); kfree(dma_ctrl); return err; } EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); -static void skl_setup_out_format(struct skl_sst *ctx, +static void skl_setup_out_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_audio_data_format *out_fmt) { @@ -711,7 +675,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, out_fmt->interleaving = format->interleaving_style; out_fmt->sample_type = format->sample_type; - dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", + dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", out_fmt->number_of_channels, format->s_freq, format->bit_depth); } @@ -720,7 +684,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, * configuration and the target frequency as extra parameter passed as src * config */ -static void skl_set_src_format(struct skl_sst *ctx, +static void skl_set_src_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_src_module_cfg *src_mconfig) { @@ -728,7 +692,7 @@ static void skl_set_src_format(struct skl_sst *ctx, struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - skl_set_base_module_format(ctx, mconfig, + skl_set_base_module_format(skl, mconfig, (struct skl_base_cfg *)src_mconfig); src_mconfig->src_cfg = fmt->s_freq; @@ -739,7 +703,7 @@ static void skl_set_src_format(struct skl_sst *ctx, * module configuration and channel configuration * It also take coefficients and now we have defaults applied here */ -static void skl_set_updown_mixer_format(struct skl_sst *ctx, +static void skl_set_updown_mixer_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_up_down_mixer_cfg *mixer_mconfig) { @@ -747,7 +711,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - skl_set_base_module_format(ctx, mconfig, + skl_set_base_module_format(skl, mconfig, (struct skl_base_cfg *)mixer_mconfig); mixer_mconfig->out_ch_cfg = fmt->ch_cfg; mixer_mconfig->ch_map = fmt->ch_map; @@ -760,17 +724,17 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, * format, gateway settings * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg */ -static void skl_set_copier_format(struct skl_sst *ctx, +static void skl_set_copier_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; - skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_set_base_module_format(skl, mconfig, base_cfg); - skl_setup_out_format(ctx, mconfig, out_fmt); - skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig); + skl_setup_out_format(skl, mconfig, out_fmt); + skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); } /* @@ -778,13 +742,13 @@ static void skl_set_copier_format(struct skl_sst *ctx, * configuration and params */ -static void skl_set_algo_format(struct skl_sst *ctx, +static void skl_set_algo_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_algo_cfg *algo_mcfg) { struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg; - skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_set_base_module_format(skl, mconfig, base_cfg); if (mconfig->formats_config.caps_size == 0) return; @@ -802,7 +766,7 @@ static void skl_set_algo_format(struct skl_sst *ctx, * Mic select module take base module configuration and out-format * configuration */ -static void skl_set_base_outfmt_format(struct skl_sst *ctx, +static void skl_set_base_outfmt_format(struct skl_dev *skl, struct skl_module_cfg *mconfig, struct skl_base_outfmt_cfg *base_outfmt_mcfg) { @@ -810,11 +774,11 @@ static void skl_set_base_outfmt_format(struct skl_sst *ctx, struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)base_outfmt_mcfg; - skl_set_base_module_format(ctx, mconfig, base_cfg); - skl_setup_out_format(ctx, mconfig, out_fmt); + skl_set_base_module_format(skl, mconfig, base_cfg); + skl_setup_out_format(skl, mconfig, out_fmt); } -static u16 skl_get_module_param_size(struct skl_sst *ctx, +static u16 skl_get_module_param_size(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u16 param_size; @@ -859,14 +823,14 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, * base module format configuration */ -static int skl_set_module_format(struct skl_sst *ctx, +static int skl_set_module_format(struct skl_dev *skl, struct skl_module_cfg *module_config, u16 *module_config_size, void **param_data) { u16 param_size; - param_size = skl_get_module_param_size(ctx, module_config); + param_size = skl_get_module_param_size(skl, module_config); *param_data = kzalloc(param_size, GFP_KERNEL); if (NULL == *param_data) @@ -876,35 +840,36 @@ static int skl_set_module_format(struct skl_sst *ctx, switch (module_config->m_type) { case SKL_MODULE_TYPE_COPIER: - skl_set_copier_format(ctx, module_config, *param_data); + skl_set_copier_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_SRCINT: - skl_set_src_format(ctx, module_config, *param_data); + skl_set_src_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_UPDWMIX: - skl_set_updown_mixer_format(ctx, module_config, *param_data); + skl_set_updown_mixer_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_ALGO: - skl_set_algo_format(ctx, module_config, *param_data); + skl_set_algo_format(skl, module_config, *param_data); break; case SKL_MODULE_TYPE_BASE_OUTFMT: case SKL_MODULE_TYPE_MIC_SELECT: case SKL_MODULE_TYPE_KPB: - skl_set_base_outfmt_format(ctx, module_config, *param_data); + skl_set_base_outfmt_format(skl, module_config, *param_data); break; default: - skl_set_base_module_format(ctx, module_config, *param_data); + skl_set_base_module_format(skl, module_config, *param_data); break; } - dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", - module_config->id.module_id, param_size); + dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", + module_config->m_type, module_config->id.module_id, + param_size); print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, *param_data, param_size, false); return 0; @@ -1004,7 +969,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max, * We first calculate the module format, based on module type and then * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper */ -int skl_init_module(struct skl_sst *ctx, +int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig) { u16 module_config_size = 0; @@ -1012,19 +977,19 @@ int skl_init_module(struct skl_sst *ctx, int ret; struct skl_ipc_init_instance_msg msg; - dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, + dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, mconfig->id.module_id, mconfig->id.pvt_id); if (mconfig->pipe->state != SKL_PIPE_CREATED) { - dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", + dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", mconfig->pipe->state, mconfig->pipe->ppl_id); return -EIO; } - ret = skl_set_module_format(ctx, mconfig, + ret = skl_set_module_format(skl, mconfig, &module_config_size, ¶m_data); if (ret < 0) { - dev_err(ctx->dev, "Failed to set module format ret=%d\n", ret); + dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); return ret; } @@ -1035,9 +1000,9 @@ int skl_init_module(struct skl_sst *ctx, msg.core_id = mconfig->core_id; msg.domain = mconfig->domain; - ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); + ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); if (ret < 0) { - dev_err(ctx->dev, "Failed to init instance ret=%d\n", ret); + dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); kfree(param_data); return ret; } @@ -1046,15 +1011,15 @@ int skl_init_module(struct skl_sst *ctx, return ret; } -static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg +static void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module) { - dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", + dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", __func__, src_module->id.module_id, src_module->id.pvt_id); - dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, + dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, dst_module->id.module_id, dst_module->id.pvt_id); - dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", + dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", src_module->m_state, dst_module->m_state); } @@ -1063,7 +1028,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg * it is already bind. * Find the pin allocated and unbind then using bind_unbind IPC */ -int skl_unbind_modules(struct skl_sst *ctx, +int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg *src_mcfg, struct skl_module_cfg *dst_mcfg) { @@ -1075,7 +1040,7 @@ int skl_unbind_modules(struct skl_sst *ctx, int out_max = src_mcfg->module->max_output_pins; int src_index, dst_index, src_pin_state, dst_pin_state; - skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + skl_dump_bind_info(skl, src_mcfg, dst_mcfg); /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); @@ -1104,7 +1069,7 @@ int skl_unbind_modules(struct skl_sst *ctx, msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = false; - ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + ret = skl_ipc_bind_unbind(&skl->ipc, &msg); if (!ret) { /* free queue only if unbind is success */ skl_free_queue(src_mcfg->m_out_pin, src_index); @@ -1142,7 +1107,7 @@ static void fill_pin_params(struct skl_audio_data_format *pin_fmt, * This function finds the pins and then sends bund_unbind IPC message to * DSP using IPC helper */ -int skl_bind_modules(struct skl_sst *ctx, +int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg *src_mcfg, struct skl_module_cfg *dst_mcfg) { @@ -1156,7 +1121,7 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module *module; struct skl_module_iface *fmt; - skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); + skl_dump_bind_info(skl, src_mcfg, dst_mcfg); if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || dst_mcfg->m_state < SKL_MODULE_INIT_DONE) @@ -1188,7 +1153,7 @@ int skl_bind_modules(struct skl_sst *ctx, format = &fmt->outputs[src_index].fmt; fill_pin_params(&(pin_fmt.dst_fmt), format); - ret = skl_set_module_params(ctx, (void *)&pin_fmt, + ret = skl_set_module_params(skl, (void *)&pin_fmt, sizeof(struct skl_cpr_pin_fmt), CPR_SINK_FMT_PARAM_ID, src_mcfg); @@ -1198,7 +1163,7 @@ int skl_bind_modules(struct skl_sst *ctx, msg.dst_queue = dst_index; - dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", + dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", msg.src_queue, msg.dst_queue); msg.module_id = src_mcfg->id.module_id; @@ -1207,7 +1172,7 @@ int skl_bind_modules(struct skl_sst *ctx, msg.dst_instance_id = dst_mcfg->id.pvt_id; msg.bind = true; - ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); + ret = skl_ipc_bind_unbind(&skl->ipc, &msg); if (!ret) { src_mcfg->m_state = SKL_MODULE_BIND_DONE; @@ -1223,12 +1188,12 @@ out: return ret; } -static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe, +static int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, enum skl_ipc_pipeline_state state) { - dev_dbg(ctx->dev, "%s: pipe_state = %d\n", __func__, state); + dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); - return skl_ipc_set_pipeline_state(&ctx->ipc, pipe->ppl_id, state); + return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); } /* @@ -1237,17 +1202,17 @@ static int skl_set_pipe_state(struct skl_sst *ctx, struct skl_pipe *pipe, * This function creates pipeline, by sending create pipeline IPC messages * to FW */ -int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); - ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, + ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, pipe->pipe_priority, pipe->ppl_id, pipe->lp_mode); if (ret < 0) { - dev_err(ctx->dev, "Failed to create pipeline\n"); + dev_err(skl->dev, "Failed to create pipeline\n"); return ret; } @@ -1262,11 +1227,11 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) * reset state. Finish the procedure by sending delete pipeline IPC. * DSP will stop the DMA engines and release resources */ -int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to delete it */ if (pipe->state < SKL_PIPE_CREATED) @@ -1274,9 +1239,9 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) /* If pipe is started, do stop the pipe in FW. */ if (pipe->state >= SKL_PIPE_STARTED) { - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_err(ctx->dev, "Failed to stop pipeline\n"); + dev_err(skl->dev, "Failed to stop pipeline\n"); return ret; } @@ -1284,17 +1249,17 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) } /* reset pipe state before deletion */ - ret = skl_set_pipe_state(ctx, pipe, PPL_RESET); + ret = skl_set_pipe_state(skl, pipe, PPL_RESET); if (ret < 0) { - dev_err(ctx->dev, "Failed to reset pipe ret=%d\n", ret); + dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); return ret; } pipe->state = SKL_PIPE_RESET; - ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); + ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); if (ret < 0) { - dev_err(ctx->dev, "Failed to delete pipeline\n"); + dev_err(skl->dev, "Failed to delete pipeline\n"); return ret; } @@ -1308,28 +1273,28 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * For processing data the pipe need to be run by sending IPC set pipe state * to DSP */ -int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to pause or delete */ if (pipe->state < SKL_PIPE_CREATED) return 0; /* Pipe has to be paused before it is started */ - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_err(ctx->dev, "Failed to pause pipe\n"); + dev_err(skl->dev, "Failed to pause pipe\n"); return ret; } pipe->state = SKL_PIPE_PAUSED; - ret = skl_set_pipe_state(ctx, pipe, PPL_RUNNING); + ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); if (ret < 0) { - dev_err(ctx->dev, "Failed to start pipe\n"); + dev_err(skl->dev, "Failed to start pipe\n"); return ret; } @@ -1342,19 +1307,19 @@ int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * Stop the pipeline by sending set pipe state IPC * DSP doesnt implement stop so we always send pause message */ -int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; - dev_dbg(ctx->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); + dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); /* If pipe was not created in FW, do not try to pause or delete */ if (pipe->state < SKL_PIPE_PAUSED) return 0; - ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); + ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); if (ret < 0) { - dev_dbg(ctx->dev, "Failed to stop pipe\n"); + dev_dbg(skl->dev, "Failed to stop pipe\n"); return ret; } @@ -1367,7 +1332,7 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) * Reset the pipeline by sending set pipe state IPC this will reset the DMA * from the DSP side */ -int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) +int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) { int ret; @@ -1375,9 +1340,9 @@ int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) if (pipe->state < SKL_PIPE_PAUSED) return 0; - ret = skl_set_pipe_state(ctx, pipe, PPL_RESET); + ret = skl_set_pipe_state(skl, pipe, PPL_RESET); if (ret < 0) { - dev_dbg(ctx->dev, "Failed to reset pipe ret=%d\n", ret); + dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); return ret; } @@ -1387,7 +1352,7 @@ int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) } /* Algo parameter set helper function */ -int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg) { struct skl_ipc_large_config_msg msg; @@ -1397,18 +1362,19 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, msg.param_data_size = size; msg.large_param_id = param_id; - return skl_ipc_set_large_config(&ctx->ipc, &msg, params); + return skl_ipc_set_large_config(&skl->ipc, &msg, params); } -int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg) { struct skl_ipc_large_config_msg msg; + size_t bytes = size; msg.module_id = mcfg->id.module_id; msg.instance_id = mcfg->id.pvt_id; msg.param_data_size = size; msg.large_param_id = param_id; - return skl_ipc_get_large_config(&ctx->ipc, &msg, params); + return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); } diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index e01815cec6fd..19f328d71f24 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -9,57 +9,10 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include <linux/pci.h> +#include <sound/intel-nhlt.h> #include "skl.h" #include "skl-i2s.h" -#define NHLT_ACPI_HEADER_SIG "NHLT" - -/* Unique identification for getting NHLT blobs */ -static guid_t osc_guid = - GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, - 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); - - -struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) -{ - acpi_handle handle; - union acpi_object *obj; - struct nhlt_resource_desc *nhlt_ptr = NULL; - struct nhlt_acpi_table *nhlt_table = NULL; - - handle = ACPI_HANDLE(dev); - if (!handle) { - dev_err(dev, "Didn't find ACPI_HANDLE\n"); - return NULL; - } - - obj = acpi_evaluate_dsm(handle, &osc_guid, 1, 1, NULL); - if (obj && obj->type == ACPI_TYPE_BUFFER) { - nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; - if (nhlt_ptr->length) - nhlt_table = (struct nhlt_acpi_table *) - memremap(nhlt_ptr->min_addr, nhlt_ptr->length, - MEMREMAP_WB); - ACPI_FREE(obj); - if (nhlt_table && (strncmp(nhlt_table->header.signature, - NHLT_ACPI_HEADER_SIG, - strlen(NHLT_ACPI_HEADER_SIG)) != 0)) { - memunmap(nhlt_table); - dev_err(dev, "NHLT ACPI header signature incorrect\n"); - return NULL; - } - return nhlt_table; - } - - dev_err(dev, "device specific method to extract NHLT blob failed\n"); - return NULL; -} - -void skl_nhlt_free(struct nhlt_acpi_table *nhlt) -{ - memunmap((void *) nhlt); -} - static struct nhlt_specific_cfg *skl_get_specific_cfg( struct device *dev, struct nhlt_fmt *fmt, u8 no_ch, u32 rate, u16 bps, u8 linktype) @@ -126,7 +79,7 @@ static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, } struct nhlt_specific_cfg -*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, +*skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn, u8 dev_type) { @@ -162,48 +115,6 @@ struct nhlt_specific_cfg return NULL; } -int skl_get_dmic_geo(struct skl *skl) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct nhlt_endpoint *epnt; - struct nhlt_dmic_array_config *cfg; - struct device *dev = &skl->pci->dev; - unsigned int dmic_geo = 0; - u8 j; - - if (!nhlt) - return 0; - - epnt = (struct nhlt_endpoint *)nhlt->desc; - - for (j = 0; j < nhlt->endpoint_count; j++) { - if (epnt->linktype == NHLT_LINK_DMIC) { - cfg = (struct nhlt_dmic_array_config *) - (epnt->config.caps); - switch (cfg->array_type) { - case NHLT_MIC_ARRAY_2CH_SMALL: - case NHLT_MIC_ARRAY_2CH_BIG: - dmic_geo |= MIC_ARRAY_2CH; - break; - - case NHLT_MIC_ARRAY_4CH_1ST_GEOM: - case NHLT_MIC_ARRAY_4CH_L_SHAPED: - case NHLT_MIC_ARRAY_4CH_2ND_GEOM: - dmic_geo |= MIC_ARRAY_4CH; - break; - - default: - dev_warn(dev, "undefined DMIC array_type 0x%0x\n", - cfg->array_type); - - } - } - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); - } - - return dmic_geo; -} - static void skl_nhlt_trim_space(char *trim) { char *s = trim; @@ -219,7 +130,7 @@ static void skl_nhlt_trim_space(char *trim) s[cnt] = '\0'; } -int skl_nhlt_update_topology_bin(struct skl *skl) +int skl_nhlt_update_topology_bin(struct skl_dev *skl) { struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; struct hdac_bus *bus = skl_to_bus(skl); @@ -243,7 +154,7 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev, { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; char platform_id[32]; @@ -257,7 +168,7 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev, static DEVICE_ATTR(platform_id, 0444, skl_nhlt_platform_id_show, NULL); -int skl_nhlt_create_sysfs(struct skl *skl) +int skl_nhlt_create_sysfs(struct skl_dev *skl) { struct device *dev = &skl->pci->dev; @@ -267,7 +178,7 @@ int skl_nhlt_create_sysfs(struct skl *skl) return 0; } -void skl_nhlt_remove_sysfs(struct skl *skl) +void skl_nhlt_remove_sysfs(struct skl_dev *skl) { struct device *dev = &skl->pci->dev; @@ -279,7 +190,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl) * stores all possible rates supported in a rate table for the corresponding * sclk/sclkfs. */ -static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, +static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_ext *i2s_config_ext; @@ -377,7 +288,7 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, } } -static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, +static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, struct nhlt_fmt *fmt, u8 id) { struct skl_i2s_config_blob_ext *i2s_config_ext; @@ -421,7 +332,7 @@ static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, mclk[id].parent_name = parent->name; } -void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks) +void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) { struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; struct nhlt_endpoint *epnt; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 760bbcf9a469..7f287424af9b 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -116,7 +116,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, { struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_soc_dapm_widget *w; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; @@ -132,7 +132,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream, int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) { struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); unsigned int format_val; struct hdac_stream *hstream; struct hdac_ext_stream *stream; @@ -224,7 +224,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -271,7 +271,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; int ret; @@ -288,7 +288,7 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, mconfig->pipe->state == SKL_PIPE_CREATED || mconfig->pipe->state == SKL_PIPE_PAUSED)) { - ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe); + ret = skl_reset_pipe(skl, mconfig->pipe); if (ret < 0) return ret; @@ -350,7 +350,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -370,9 +370,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, * CGCTL.MISCBDCGE if disabled by driver */ if (!strncmp(dai->name, "Reference Pin", 13) && - skl->skl_sst->miscbdcg_disabled) { - skl->skl_sst->enable_miscbdcge(dai->dev, true); - skl->skl_sst->miscbdcg_disabled = false; + skl->miscbdcg_disabled) { + skl->enable_miscbdcge(dai->dev, true); + skl->miscbdcg_disabled = false; } mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); @@ -387,7 +387,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, { struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; int ret; @@ -396,7 +396,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); if (mconfig) { - ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe); + ret = skl_reset_pipe(skl, mconfig->pipe); if (ret < 0) dev_err(dai->dev, "%s:Reset failed ret =%d", __func__, ret); @@ -471,8 +471,7 @@ static int skl_decoupled_trigger(struct snd_pcm_substream *substream, static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); - struct skl_sst *ctx = skl->skl_sst; + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig; struct hdac_bus *bus = get_bus_ctx(substream); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); @@ -515,7 +514,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; - return skl_run_pipe(ctx, mconfig->pipe); + return skl_run_pipe(skl, mconfig->pipe); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -526,7 +525,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, * there are no underrun/overrun in the case if there is a delay * between the two operations. */ - ret = skl_stop_pipe(ctx, mconfig->pipe); + ret = skl_stop_pipe(skl, mconfig->pipe); if (ret < 0) return ret; @@ -602,14 +601,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); if (mconfig && !mconfig->pipe->passthru && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) - skl_reset_pipe(skl->skl_sst, mconfig->pipe); + skl_reset_pipe(skl, mconfig->pipe); return 0; } @@ -1301,7 +1300,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_pcm *pcm = rtd->pcm; unsigned int size; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); if (dai->driver->playback.channels_min || dai->driver->capture.channels_min) { @@ -1318,9 +1317,9 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) +static int skl_get_module_info(struct skl_dev *skl, + struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; struct skl_module_inst_id *pin_id; guid_t *uuid_mod, *uuid_tplg; struct skl_module *skl_module; @@ -1329,12 +1328,12 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) uuid_mod = (guid_t *)mconfig->guid; - if (list_empty(&ctx->uuid_list)) { - dev_err(ctx->dev, "Module list is empty\n"); + if (list_empty(&skl->uuid_list)) { + dev_err(skl->dev, "Module list is empty\n"); return -EIO; } - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { mconfig->id.module_id = module->id; if (mconfig->module) @@ -1361,7 +1360,7 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) if (skl->nr_modules && ret) return ret; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { for (i = 0; i < MAX_IN_QUEUE; i++) { pin_id = &mconfig->m_in_pin[i].id; if (guid_equal(&pin_id->mod_uuid, &module->uuid)) @@ -1378,7 +1377,7 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) return 0; } -static int skl_populate_modules(struct skl *skl) +static int skl_populate_modules(struct skl_dev *skl) { struct skl_pipeline *p; struct skl_pipe_module *m; @@ -1393,7 +1392,7 @@ static int skl_populate_modules(struct skl *skl) ret = skl_get_module_info(skl, mconfig); if (ret < 0) { - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "query module info failed\n"); return ret; } @@ -1408,7 +1407,7 @@ static int skl_populate_modules(struct skl *skl) static int skl_platform_soc_probe(struct snd_soc_component *component) { struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); const struct skl_dsp_ops *ops; int ret; @@ -1434,22 +1433,21 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) * Disable dynamic clock and power gating during firmware * and library download */ - skl->skl_sst->enable_miscbdcge(component->dev, false); - skl->skl_sst->clock_power_gating(component->dev, false); + skl->enable_miscbdcge(component->dev, false); + skl->clock_power_gating(component->dev, false); - ret = ops->init_fw(component->dev, skl->skl_sst); - skl->skl_sst->enable_miscbdcge(component->dev, true); - skl->skl_sst->clock_power_gating(component->dev, true); + ret = ops->init_fw(component->dev, skl); + skl->enable_miscbdcge(component->dev, true); + skl->clock_power_gating(component->dev, true); if (ret < 0) { dev_err(component->dev, "Failed to boot first fw: %d\n", ret); return ret; } skl_populate_modules(skl); - skl->skl_sst->update_d0i3c = skl_update_d0i3c; - skl_dsp_enable_notification(skl->skl_sst, false); + skl->update_d0i3c = skl_update_d0i3c; if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl->skl_sst, + skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, skl->cfg.astate_cfg); } @@ -1463,7 +1461,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) static void skl_pcm_remove(struct snd_soc_component *component) { struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl_tplg_exit(component, bus); @@ -1486,7 +1484,7 @@ int skl_platform_register(struct device *dev) struct snd_soc_dai_driver *dais; int num_dais = ARRAY_SIZE(skl_platform_dai); struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), GFP_KERNEL); @@ -1520,7 +1518,7 @@ err: int skl_platform_unregister(struct device *dev) { struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_deferred_bind *modules, *tmp; if (!list_empty(&skl->bind_list)) { diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c index 5bb6e40d4d3e..1c0e5226cb5b 100644 --- a/sound/soc/intel/skylake/skl-ssp-clk.c +++ b/sound/soc/intel/skylake/skl-ssp-clk.c @@ -11,6 +11,7 @@ #include <linux/platform_device.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> +#include <sound/intel-nhlt.h> #include "skl.h" #include "skl-ssp-clk.h" #include "skl-topology.h" @@ -101,7 +102,7 @@ static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type) } /* Sends dma control IPC to turn the clock ON/OFF */ -static int skl_send_clk_dma_control(struct skl *skl, +static int skl_send_clk_dma_control(struct skl_dev *skl, struct skl_clk_rate_cfg_table *rcfg, u32 vbus_id, u8 clk_type, bool enable) @@ -152,7 +153,7 @@ static int skl_send_clk_dma_control(struct skl *skl, memcpy(i2s_config + sp_cfg->size, data, size); node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4)); - ret = skl_dsp_set_dma_control(skl->skl_sst, (u32 *)i2s_config, + ret = skl_dsp_set_dma_control(skl, (u32 *)i2s_config, i2s_config_size, node_id); kfree(i2s_config); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 36590c5b4673..225706d148d8 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -12,7 +12,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-ipc.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" /* various timeout values */ #define SKL_DSP_PU_TO 50 @@ -33,7 +33,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) */ void skl_dsp_init_core_state(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int i; skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; @@ -48,7 +48,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx) /* Get the mask for all enabled cores */ unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask, en_cores_mask; u32 val; @@ -335,7 +335,7 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) */ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; if (core_id >= skl->cores.count) { @@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(skl_dsp_get_core); int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; if (core_id >= skl->cores.count) { diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index a80219562036..cdfec0fca577 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -15,9 +15,9 @@ #include "skl-sst-cldma.h" struct sst_dsp; -struct skl_sst; struct sst_dsp_device; struct skl_lib_info; +struct skl_dev; /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 @@ -222,32 +222,31 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id); int skl_dsp_boot(struct sst_dsp *ctx); int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); + struct skl_dev **dsp); int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_sst **dsp); -int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx); -int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); + struct skl_dev **dsp); +int skl_sst_init_fw(struct device *dev, struct skl_dev *skl); +int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); +void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, unsigned int offset, int index); -int skl_get_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int instance_id); -int skl_put_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int *pvt_id); -int skl_get_pvt_instance_id_map(struct skl_sst *ctx, +int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id); +int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id); +int skl_get_pvt_instance_id_map(struct skl_dev *skl, int module_id, int instance_id); -void skl_freeup_uuid_list(struct skl_sst *ctx); +void skl_freeup_uuid_list(struct skl_dev *skl); int skl_dsp_strip_extended_manifest(struct firmware *fw); -void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); -void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data); +void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data); int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, struct sst_dsp_device *skl_dev); -int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, +int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, struct firmware *stripped_fw, unsigned int hdr_offset, int index); void skl_release_library(struct skl_lib_info *linfo, int lib_count); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 2cc8f7d2d319..667cdddc289f 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -281,7 +281,7 @@ void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, size_t tx_size) { if (tx_size) - memcpy(msg->tx_data, tx_data, tx_size); + memcpy(msg->tx.data, tx_data, tx_size); } static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) @@ -295,10 +295,10 @@ static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) /* Lock to be held by caller */ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) { - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - if (msg->tx_size) - sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + if (msg->tx.size) + sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, header->extension); sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, @@ -345,7 +345,7 @@ out: int skl_ipc_process_notification(struct sst_generic_ipc *ipc, struct skl_ipc_header header) { - struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { @@ -436,7 +436,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, struct ipc_message *msg; u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u64 *ipc_header = (u64 *)(&header); - struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); unsigned long flags; spin_lock_irqsave(&ipc->dsp->spinlock, flags); @@ -447,11 +447,12 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, return; } + msg->rx.header = *ipc_header; /* first process the header */ if (reply == IPC_GLB_REPLY_SUCCESS) { dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); /* copy the rx data from the mailbox */ - sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); + sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size); switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { case IPC_GLB_LOAD_MULTIPLE_MODS: case IPC_GLB_LOAD_LIBRARY: @@ -488,7 +489,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) { struct sst_dsp *dsp = context; - struct skl_sst *skl = sst_dsp_get_thread_context(dsp); + struct skl_dev *skl = sst_dsp_get_thread_context(dsp); struct sst_generic_ipc *ipc = &skl->ipc; struct skl_ipc_header header = {0}; u32 hipcie, hipct, hipcte; @@ -595,7 +596,7 @@ bool skl_ipc_int_status(struct sst_dsp *ctx) SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; } -int skl_ipc_init(struct device *dev, struct skl_sst *skl) +int skl_ipc_init(struct device *dev, struct skl_dev *skl) { struct sst_generic_ipc *ipc; int err; @@ -635,7 +636,7 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -646,9 +647,10 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); header.extension = IPC_PPL_LP_MODE(lp_mode); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); return ret; @@ -661,16 +663,17 @@ EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); header.primary |= IPC_INSTANCE_ID(instance_id); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); return ret; @@ -684,7 +687,7 @@ int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, u8 instance_id, enum skl_ipc_pipeline_state state) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -692,9 +695,10 @@ int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); header.primary |= IPC_INSTANCE_ID(instance_id); header.primary |= IPC_PPL_STATE(state); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); return ret; @@ -707,7 +711,7 @@ int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -716,8 +720,10 @@ skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) header.primary |= IPC_INSTANCE_ID(instance_id); header.extension = IPC_DMA_ID(dma_id); + request.header = *(u64 *)(&header); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); return ret; @@ -730,16 +736,17 @@ EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); header.primary |= IPC_INSTANCE_ID(instance_id); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); return ret; @@ -753,7 +760,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); @@ -762,10 +769,13 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, header.primary |= IPC_MOD_INSTANCE_ID(instance_id); header.primary |= IPC_MOD_ID(module_id); + request.header = *(u64 *)(&header); + request.data = dx; + request.size = sizeof(*dx); + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - dx, sizeof(*dx), NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); return ret; @@ -779,7 +789,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, struct skl_ipc_init_instance_msg *msg, void *param_data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; u32 *buffer = (u32 *)param_data; /* param_block_size must be in dwords */ @@ -799,10 +809,13 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); header.extension |= IPC_DOMAIN(msg->domain); + request.header = *(u64 *)(&header); + request.data = param_data; + request.size = msg->param_data_size; + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, - msg->param_data_size, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: init instance failed\n"); @@ -817,7 +830,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, struct skl_ipc_bind_unbind_msg *msg) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; int ret; @@ -831,10 +844,11 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); header.extension |= IPC_DST_QUEUE(msg->dst_queue); header.extension |= IPC_SRC_QUEUE(msg->src_queue); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: bind/unbind failed\n"); return ret; @@ -854,7 +868,7 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, u8 module_cnt, void *data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -862,8 +876,11 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt)); + request.header = *(u64 *)(&header); + request.data = data; + request.size = sizeof(u16) * module_cnt; + + ret = sst_ipc_tx_message_nowait(ipc, request); if (ret < 0) dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); @@ -875,7 +892,7 @@ int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, void *data) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -883,8 +900,11 @@ int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt), NULL, 0); + request.header = *(u64 *)(&header); + request.data = data; + request.size = sizeof(u16) * module_cnt; + + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); @@ -896,7 +916,7 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request; int ret = 0; size_t sz_remaining, tx_size, data_offset; @@ -923,9 +943,11 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, header.primary, header.extension); dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", (unsigned)data_offset, (unsigned)tx_size); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - ((char *)param) + data_offset, - tx_size, NULL, 0); + + request.header = *(u64 *)(&header); + request.data = ((char *)param) + data_offset; + request.size = tx_size; + ret = sst_ipc_tx_message_wait(ipc, request, NULL); if (ret < 0) { dev_err(ipc->dev, "ipc: set large config fail, err: %d\n", ret); @@ -947,12 +969,17 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param) + struct skl_ipc_large_config_msg *msg, + u32 **payload, size_t *bytes) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); - int ret = 0; - size_t sz_remaining, rx_size, data_offset; + struct sst_ipc_message request, reply = {0}; + unsigned int *buf; + int ret; + + reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL); + if (!reply.data) + return -ENOMEM; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); @@ -965,33 +992,21 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, header.extension |= IPC_FINAL_BLOCK(1); header.extension |= IPC_INITIAL_BLOCK(1); - sz_remaining = msg->param_data_size; - data_offset = 0; + request.header = *(u64 *)&header; + request.data = *payload; + request.size = *bytes; + reply.size = SKL_ADSP_W1_SZ; - while (sz_remaining != 0) { - rx_size = sz_remaining > SKL_ADSP_W1_SZ - ? SKL_ADSP_W1_SZ : sz_remaining; - if (rx_size == sz_remaining) - header.extension |= IPC_FINAL_BLOCK(1); - - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, - ((char *)param) + data_offset, - msg->param_data_size); - if (ret < 0) { - dev_err(ipc->dev, - "ipc: get large config fail, err: %d\n", ret); - return ret; - } - sz_remaining -= rx_size; - data_offset = msg->param_data_size - sz_remaining; + ret = sst_ipc_tx_message_wait(ipc, request, &reply); + if (ret < 0) + dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); - /* clear the fields */ - header.extension &= IPC_INITIAL_BLOCK_CLEAR; - header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; - /* fill the fields */ - header.extension |= IPC_INITIAL_BLOCK(1); - header.extension |= IPC_DATA_OFFSET_SZ(data_offset); - } + reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK; + buf = krealloc(reply.data, reply.size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + *payload = buf; + *bytes = reply.size; return ret; } @@ -1001,7 +1016,7 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id, bool wait) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret = 0; header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); @@ -1009,12 +1024,12 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); header.primary |= IPC_MOD_INSTANCE_ID(table_id); header.primary |= IPC_MOD_ID(dma_id); + request.header = *(u64 *)(&header); if (wait) - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(ipc, request, NULL); else - ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, NULL, 0); + ret = sst_ipc_tx_message_nowait(ipc, request); if (ret < 0) dev_err(ipc->dev, "ipc: load lib failed\n"); @@ -1026,7 +1041,7 @@ EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) { struct skl_ipc_header header = {0}; - u64 *ipc_header = (u64 *)(&header); + struct sst_ipc_message request = {0}; int ret; header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); @@ -1037,6 +1052,7 @@ int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) header.extension = IPC_D0IX_WAKE(msg->wake); header.extension |= IPC_D0IX_STREAMING(msg->streaming); + request.header = *(u64 *)(&header); dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, header.primary, header.extension); @@ -1044,7 +1060,7 @@ int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) /* * Use the nopm IPC here as we dont want it checking for D0iX */ - ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_nopm(ipc, request, NULL); if (ret < 0) dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 9c31a48e99dd..08ac31778325 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -10,9 +10,9 @@ #include <linux/irqreturn.h> #include "../common/sst-ipc.h" +#include "skl-sst-dsp.h" struct sst_dsp; -struct skl_sst; struct sst_generic_ipc; enum skl_ipc_pipeline_state { @@ -67,54 +67,6 @@ struct skl_lib_info { const struct firmware *fw; }; -struct skl_sst { - struct device *dev; - struct sst_dsp *dsp; - - /* boot */ - wait_queue_head_t boot_wait; - bool boot_complete; - - /* module load */ - wait_queue_head_t mod_load_wait; - bool mod_load_complete; - bool mod_load_status; - - /* IPC messaging */ - struct sst_generic_ipc ipc; - - /* callback for miscbdge */ - void (*enable_miscbdcge)(struct device *dev, bool enable); - /* Is CGCTL.MISCBDCGE disabled */ - bool miscbdcg_disabled; - - /* Populate module information */ - struct list_head uuid_list; - - /* Is firmware loaded */ - bool fw_loaded; - - /* first boot ? */ - bool is_first_boot; - - /* multi-core */ - struct skl_dsp_cores cores; - - /* library info */ - struct skl_lib_info lib_info[SKL_MAX_LIB]; - int lib_count; - - /* Callback to update D0i3C register */ - void (*update_d0i3c)(struct device *dev, bool enable); - - struct skl_d0i3_data d0i3; - - const struct skl_dsp_ops *dsp_ops; - - /* Callback to update dynamic clock and power gating registers */ - void (*clock_power_gating)(struct device *dev, bool enable); -}; - struct skl_ipc_init_instance_msg { u32 module_id; u32 instance_id; @@ -187,7 +139,8 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param); + struct skl_ipc_large_config_msg *msg, + u32 **payload, size_t *bytes); int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id, bool wait); @@ -204,7 +157,7 @@ void skl_ipc_int_disable(struct sst_dsp *dsp); bool skl_ipc_int_status(struct sst_dsp *dsp); void skl_ipc_free(struct sst_generic_ipc *ipc); -int skl_ipc_init(struct device *dev, struct skl_sst *skl); +int skl_ipc_init(struct device *dev, struct skl_dev *skl); void skl_clear_module_cnt(struct sst_dsp *ctx); void skl_ipc_process_reply(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 928c677b506c..d43cbf4a71ef 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -8,10 +8,9 @@ #include <linux/device.h> #include <linux/slab.h> #include <linux/uuid.h> -#include "skl-sst-dsp.h" #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define DEFAULT_HASH_SHA256_LEN 32 @@ -99,12 +98,12 @@ static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) return -EINVAL; } -int skl_get_pvt_instance_id_map(struct skl_sst *ctx, +int skl_get_pvt_instance_id_map(struct skl_dev *skl, int module_id, int instance_id) { struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (module->id == module_id) return skl_get_pvtid_map(module, instance_id); } @@ -163,19 +162,19 @@ static inline int skl_pvtid_128(struct uuid_module *module) /** * skl_get_pvt_id: generate a private id for use as module id * - * @ctx: driver context + * @skl: driver context * @uuid_mod: module's uuid * @instance_id: module's instance id * * This generates a 128 bit private unique id for a module TYPE so that * module instance is unique */ -int skl_get_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int instance_id) +int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id) { struct uuid_module *module; int pvt_id; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { pvt_id = skl_pvtid_128(module); @@ -194,18 +193,18 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); /** * skl_put_pvt_id: free up the private id allocated * - * @ctx: driver context + * @skl: driver context * @uuid_mod: module's uuid * @pvt_id: module pvt id * * This frees a 128 bit private unique id previously generated */ -int skl_put_pvt_id(struct skl_sst *ctx, guid_t *uuid_mod, int *pvt_id) +int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id) { int i; struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid_mod, &module->uuid)) { if (*pvt_id != 0) @@ -234,7 +233,7 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, struct adsp_module_entry *mod_entry; int i, num_entry, size; const char *buf; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct uuid_module *module; struct firmware stripped_fw; unsigned int safe_file; @@ -317,11 +316,11 @@ free_uuid_list: return ret; } -void skl_freeup_uuid_list(struct skl_sst *ctx) +void skl_freeup_uuid_list(struct skl_dev *skl) { struct uuid_module *uuid, *_uuid; - list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { + list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) { list_del(&uuid->list); kfree(uuid); } @@ -355,16 +354,12 @@ int skl_dsp_strip_extended_manifest(struct firmware *fw) } int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp, + struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, struct sst_dsp_device *skl_dev) { - struct skl_sst *skl; + struct skl_dev *skl = *dsp; struct sst_dsp *sst; - skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); - if (skl == NULL) - return -ENOMEM; - skl->dev = dev; skl_dev->thread_context = skl; INIT_LIST_HEAD(&skl->uuid_list); @@ -381,13 +376,11 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, INIT_LIST_HEAD(&sst->module_list); skl->is_first_boot = true; - if (dsp) - *dsp = skl; return 0; } -int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, +int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, struct firmware *stripped_fw, unsigned int hdr_offset, int index) { diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 70c3a604c381..61a8e4756a2b 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -16,7 +16,7 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" -#include "skl-sst-ipc.h" +#include "skl.h" #define SKL_BASEFW_TIMEOUT 300 #define SKL_INIT_TIMEOUT 1000 @@ -66,7 +66,7 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, static int skl_load_base_firmware(struct sst_dsp *ctx) { int ret = 0, i; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; u32 reg; @@ -161,7 +161,7 @@ static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); /* If core0 is being turned on, we need to load the FW */ @@ -215,7 +215,7 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) { int ret; struct skl_ipc_dxstate_info dx; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); dx.core_mask = core_mask; @@ -332,7 +332,7 @@ static int skl_transfer_module(struct sst_dsp *ctx, const void *data, u32 size, u16 mod_id, u8 table_id, bool is_module) { int ret, bytes_left, curr_pos; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; skl->mod_load_complete = false; bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); @@ -384,7 +384,7 @@ out: static int skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; struct firmware stripped_fw; int ret, i; @@ -413,8 +413,7 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) int ret = 0; char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ - snprintf(mod_name, sizeof(mod_name), "%s%pUL%s", - "intel/dsp_fw_", guid, ".bin"); + snprintf(mod_name, sizeof(mod_name), "intel/dsp_fw_%pUL.bin", guid); module_entry = skl_module_get_from_id(ctx, mod_id); if (module_entry == NULL) { @@ -443,7 +442,7 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) { int usage_cnt; - struct skl_sst *skl = ctx->thread_context; + struct skl_dev *skl = ctx->thread_context; int ret = 0; usage_cnt = skl_put_module(ctx, mod_id); @@ -518,9 +517,10 @@ static struct sst_dsp_device skl_dev = { }; int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_dev **dsp) { - struct skl_sst *skl; + struct skl_dev *skl; struct sst_dsp *sst; int ret; @@ -554,10 +554,10 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); -int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) +int skl_sst_init_fw(struct device *dev, struct skl_dev *skl) { int ret; - struct sst_dsp *sst = ctx->dsp; + struct sst_dsp *sst = skl->dsp; ret = sst->fw_ops.load_fw(sst); if (ret < 0) { @@ -567,32 +567,32 @@ int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) skl_dsp_init_core_state(sst); - if (ctx->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, ctx->lib_info, - ctx->lib_count); + if (skl->lib_count > 1) { + ret = sst->fw_ops.load_library(sst, skl->lib_info, + skl->lib_count); if (ret < 0) { dev_err(dev, "Load Library failed : %x\n", ret); return ret; } } - ctx->is_first_boot = false; + skl->is_first_boot = false; return 0; } EXPORT_SYMBOL_GPL(skl_sst_init_fw); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) { - if (ctx->dsp->fw) - release_firmware(ctx->dsp->fw); - skl_clear_module_table(ctx->dsp); - skl_freeup_uuid_list(ctx); - skl_ipc_free(&ctx->ipc); - ctx->dsp->ops->free(ctx->dsp); - if (ctx->boot_complete) { - ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); - skl_cldma_int_disable(ctx->dsp); + if (skl->dsp->fw) + release_firmware(skl->dsp->fw); + skl_clear_module_table(skl->dsp); + skl_freeup_uuid_list(skl); + skl_ipc_free(&skl->ipc); + skl->dsp->ops->free(skl->dsp); + if (skl->boot_complete) { + skl->dsp->cl_dev.ops.cl_cleanup_controller(skl->dsp); + skl_cldma_int_disable(skl->dsp); } } EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 6241e35213af..69cd7a81bf2a 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -12,6 +12,7 @@ #include <linux/types.h> #include <linux/firmware.h> #include <linux/uuid.h> +#include <sound/intel-nhlt.h> #include <sound/soc.h> #include <sound/soc-topology.h> #include <uapi/sound/snd_sst_tokens.h> @@ -45,9 +46,9 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = { #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) -void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -64,9 +65,9 @@ void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) } } -void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) { - struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + struct skl_d0i3_data *d0i3 = &skl->d0i3; switch (caps) { case SKL_D0I3_NONE: @@ -109,118 +110,23 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, } } -/* - * Each pipelines needs memory to be allocated. Check if we have free memory - * from available pool. - */ -static bool skl_is_pipe_mem_avail(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_sst *ctx = skl->skl_sst; - - if (skl->resource.mem + mconfig->pipe->memory_pages > - skl->resource.max_mem) { - dev_err(ctx->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, - mconfig->id.instance_id); - dev_err(ctx->dev, - "exceeds ppl memory available %d mem %d\n", - skl->resource.max_mem, skl->resource.mem); - return false; - } else { - return true; - } -} - -/* - * Add the mem to the mem pool. This is freed when pipe is deleted. - * Note: DSP does actual memory management we only keep track for complete - * pool - */ -static void skl_tplg_alloc_pipe_mem(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - skl->resource.mem += mconfig->pipe->memory_pages; -} - -/* - * Pipeline needs needs DSP CPU resources for computation, this is - * quantified in MCPS (Million Clocks Per Second) required for module/pipe - * - * Each pipelines needs mcps to be allocated. Check if we have mcps for this - * pipe. - */ - -static bool skl_is_pipe_mcps_avail(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_sst *ctx = skl->skl_sst; - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - if (skl->resource.mcps + res->cps > skl->resource.max_mcps) { - dev_err(ctx->dev, - "%s: module_id %d instance %d\n", __func__, - mconfig->id.module_id, mconfig->id.instance_id); - dev_err(ctx->dev, - "exceeds ppl mcps available %d > mem %d\n", - skl->resource.max_mcps, skl->resource.mcps); - return false; - } else { - return true; - } -} - -static void skl_tplg_alloc_pipe_mcps(struct skl *skl, - struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps += res->cps; -} - -/* - * Free the mcps when tearing down - */ -static void -skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) -{ - u8 res_idx = mconfig->res_idx; - struct skl_module_res *res = &mconfig->module->resources[res_idx]; - - skl->resource.mcps -= res->cps; -} - -/* - * Free the memory when tearing down - */ -static void -skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) -{ - skl->resource.mem -= mconfig->pipe->memory_pages; -} - - -static void skl_dump_mconfig(struct skl_sst *ctx, - struct skl_module_cfg *mcfg) +static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) { struct skl_module_iface *iface = &mcfg->module->formats[0]; - dev_dbg(ctx->dev, "Dumping config\n"); - dev_dbg(ctx->dev, "Input Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + dev_dbg(skl->dev, "Dumping config\n"); + dev_dbg(skl->dev, "Input Format:\n"); + dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); + dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); + dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); + dev_dbg(skl->dev, "valid bit depth = %d\n", iface->inputs[0].fmt.valid_bit_depth); - dev_dbg(ctx->dev, "Output Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(ctx->dev, "valid bit depth = %d\n", + dev_dbg(skl->dev, "Output Format:\n"); + dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); + dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); + dev_dbg(skl->dev, "valid bit depth = %d\n", iface->outputs[0].fmt.valid_bit_depth); - dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); + dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); } static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) @@ -322,7 +228,7 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, * params, so once we have calculate params, we need buffer calculation as * well. */ -static void skl_tplg_update_buffer_size(struct skl_sst *ctx, +static void skl_tplg_update_buffer_size(struct skl_dev *skl, struct skl_module_cfg *mcfg) { int multiplier = 1; @@ -374,13 +280,12 @@ static u8 skl_tplg_be_dev_type(int dev_type) } static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; int link_type, dir; u32 ch, s_freq, s_fmt; struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(ctx->dev); u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); int fmt_idx = m_cfg->fmt_idx; struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; @@ -389,7 +294,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, if (m_cfg->formats_config.caps_size > 0) return 0; - dev_dbg(ctx->dev, "Applying default cfg blob\n"); + dev_dbg(skl->dev, "Applying default cfg blob\n"); switch (m_cfg->dev_type) { case SKL_DEVICE_DMIC: link_type = NHLT_LINK_DMIC; @@ -425,9 +330,9 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, m_cfg->formats_config.caps_size = cfg->size; m_cfg->formats_config.caps = (u32 *) &cfg->caps; } else { - dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n", + dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", m_cfg->vbus_id, link_type, dir); - dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n", + dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n", ch, s_freq, s_fmt); return -EIO; } @@ -436,7 +341,7 @@ static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, } static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { struct skl_module_cfg *m_cfg = w->priv; struct skl_pipe_params *params = m_cfg->pipe->p_params; @@ -446,10 +351,10 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, if (!m_cfg->params_fixup) return; - dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) is_fe = true; @@ -457,12 +362,12 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, is_fe = false; skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(ctx, m_cfg); + skl_tplg_update_buffer_size(skl, m_cfg); - dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n", + dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", w->name); - skl_dump_mconfig(ctx, m_cfg); + skl_dump_mconfig(skl, m_cfg); } /* @@ -471,7 +376,7 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, * set module params will be done after module is initialised. */ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, - struct skl_sst *ctx) + struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -483,7 +388,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_SET) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -497,7 +402,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(ctx, + ret = skl_set_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); if (ret < 0) @@ -542,15 +447,15 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) return 0; } -static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, +static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) { switch (mcfg->dev_type) { case SKL_DEVICE_HDAHOST: - return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params); + return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params); + return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); } return 0; @@ -562,12 +467,11 @@ static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe, * skl_init_module() routine, so invoke that for all modules in a pipeline */ static int -skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) +skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { struct skl_pipe_module *w_module; struct snd_soc_dapm_widget *w; struct skl_module_cfg *mconfig; - struct skl_sst *ctx = skl->skl_sst; u8 cfg_idx; int ret = 0; @@ -578,7 +482,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) /* check if module ids are populated */ if (mconfig->id.module_id < 0) { - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "module %pUL id not populated\n", (guid_t *)mconfig->guid); return -EIO; @@ -588,12 +492,8 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -ENOMEM; - - if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) { - ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, + if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { + ret = skl->dsp->fw_ops.load_mod(skl->dsp, mconfig->id.module_id, mconfig->guid); if (ret < 0) return ret; @@ -602,50 +502,50 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) } /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig); + ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); if (ret < 0) return ret; /* update blob if blob is null for be with default value */ - skl_tplg_update_be_blob(w, ctx); + skl_tplg_update_be_blob(w, skl); /* * apply fix/conversion to module params based on * FE/BE params */ - skl_tplg_update_module_params(w, ctx); + skl_tplg_update_module_params(w, skl); uuid_mod = (guid_t *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, + mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, mconfig->id.instance_id); if (mconfig->id.pvt_id < 0) return ret; skl_tplg_set_module_init_data(w); - ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id); + ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); if (ret < 0) { - dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n", + dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", mconfig->core_id, ret); return ret; } - ret = skl_init_module(ctx, mconfig); + ret = skl_init_module(skl, mconfig); if (ret < 0) { - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); goto err; } - skl_tplg_alloc_pipe_mcps(skl, mconfig); - ret = skl_tplg_set_module_params(w, ctx); + + ret = skl_tplg_set_module_params(w, skl); if (ret < 0) goto err; } return 0; err: - skl_dsp_put_core(ctx->dsp, mconfig->core_id); + skl_dsp_put_core(skl->dsp, mconfig->core_id); return ret; } -static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, +static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) { int ret = 0; @@ -657,19 +557,19 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, mconfig = w_module->w->priv; uuid_mod = (guid_t *)mconfig->guid; - if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod && + if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod && mconfig->m_state > SKL_MODULE_UNINIT) { - ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, + ret = skl->dsp->fw_ops.unload_mod(skl->dsp, mconfig->id.module_id); if (ret < 0) return -EIO; } - skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); + skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id); + ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); if (ret < 0) { /* don't return; continue with other modules */ - dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n", + dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", mconfig->core_id, ret); } } @@ -686,9 +586,8 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, * 0th configuratation by default for such pipes. */ static int -skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) +skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) { - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *pipe = mconfig->pipe; struct skl_pipe_params *params = pipe->p_params; struct skl_path_config *pconfig = &pipe->configs[0]; @@ -702,7 +601,7 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) } if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) { - dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n"); + dev_dbg(skl->dev, "No conn_type detected, take 0th config\n"); pipe->cur_config_idx = 0; pipe->memory_pages = pconfig->mem_pages; @@ -726,13 +625,13 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) fmt->channels, fmt->freq, fmt->bps)) { pipe->cur_config_idx = i; pipe->memory_pages = pconfig->mem_pages; - dev_dbg(ctx->dev, "Using pipe config: %d\n", i); + dev_dbg(skl->dev, "Using pipe config: %d\n", i); return 0; } } - dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", + dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); return -EINVAL; } @@ -740,44 +639,32 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig) /* * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we * need create the pipeline. So we do following: - * - check the resources * - Create the pipeline * - Initialize the modules in pipeline * - finally bind all modules together */ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { int ret; struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_pipe *s_pipe = mconfig->pipe; struct skl_module_cfg *src_module = NULL, *dst_module, *module; - struct skl_sst *ctx = skl->skl_sst; struct skl_module_deferred_bind *modules; ret = skl_tplg_get_pipe_config(skl, mconfig); if (ret < 0) return ret; - /* check resource available */ - if (!skl_is_pipe_mcps_avail(skl, mconfig)) - return -EBUSY; - - if (!skl_is_pipe_mem_avail(skl, mconfig)) - return -ENOMEM; - /* * Create a list of modules for pipe. * This list contains modules from source to sink */ - ret = skl_create_pipeline(ctx, mconfig->pipe); + ret = skl_create_pipeline(skl, mconfig->pipe); if (ret < 0) return ret; - skl_tplg_alloc_pipe_mem(skl, mconfig); - skl_tplg_alloc_pipe_mcps(skl, mconfig); - /* Init all pipe modules from source to sink */ ret = skl_tplg_init_pipe_modules(skl, s_pipe); if (ret < 0) @@ -792,7 +679,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, continue; } - ret = skl_bind_modules(ctx, src_module, dst_module); + ret = skl_bind_modules(skl, src_module, dst_module); if (ret < 0) return ret; @@ -810,7 +697,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, list_for_each_entry(modules, &skl->bind_list, node) { module = w_module->w->priv; if (modules->dst == module) - skl_bind_modules(ctx, modules->src, + skl_bind_modules(skl, modules->src, modules->dst); } } @@ -818,7 +705,7 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } -static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, +static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, int size, struct skl_module_cfg *mcfg) { int i, pvt_id; @@ -829,7 +716,7 @@ static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, struct skl_mod_inst_map *inst = kpb_params->u.map; for (i = 0; i < kpb_params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id, + pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, inst->inst_id); if (pvt_id < 0) return -EINVAL; @@ -849,7 +736,7 @@ static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, * send params after binding */ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mcfg, struct skl_sst *ctx) + struct skl_module_cfg *mcfg, struct skl_dev *skl) { int i, ret; struct skl_module_cfg *mconfig = w->priv; @@ -876,7 +763,7 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, if (mconfig->formats_config.caps_size > 0 && mconfig->formats_config.set_params == SKL_PARAM_BIND) { sp_cfg = &mconfig->formats_config; - ret = skl_set_module_params(ctx, sp_cfg->caps, + ret = skl_set_module_params(skl, sp_cfg->caps, sp_cfg->caps_size, sp_cfg->param_id, mconfig); if (ret < 0) @@ -894,10 +781,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, if (!params) return -ENOMEM; - skl_fill_sink_instance_id(ctx, params, bc->max, + skl_fill_sink_instance_id(skl, params, bc->max, mconfig); - ret = skl_set_module_params(ctx, params, + ret = skl_set_module_params(skl, params, bc->max, bc->param_id, mconfig); kfree(params); @@ -910,11 +797,11 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, return 0; } -static int skl_get_module_id(struct skl_sst *ctx, guid_t *uuid) +static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) { struct uuid_module *module; - list_for_each_entry(module, &ctx->uuid_list, list) { + list_for_each_entry(module, &skl->uuid_list, list) { if (guid_equal(uuid, &module->uuid)) return module->id; } @@ -922,7 +809,7 @@ static int skl_get_module_id(struct skl_sst *ctx, guid_t *uuid) return -EINVAL; } -static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, +static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, const struct snd_kcontrol_new *k) { struct soc_bytes_ext *sb = (void *) k->private_value; @@ -942,7 +829,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, params->num_modules = uuid_params->num_modules; for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl->skl_sst, + module_id = skl_get_module_id(skl, &uuid_params->u.map_uuid[i].mod_uuid); if (module_id < 0) { devm_kfree(bus->dev, params); @@ -966,7 +853,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl, * Retrieve the module id from UUID mentioned in the * post bind params */ -void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, +void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, struct snd_soc_dapm_widget *w) { struct skl_module_cfg *mconfig = w->priv; @@ -985,12 +872,12 @@ void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && (skl_tplg_find_moduleid_from_uuid(skl, &w->kcontrol_news[i]) < 0)) - dev_err(skl->skl_sst->dev, + dev_err(skl->dev, "%s: invalid kpb post bind params\n", __func__); } -static int skl_tplg_module_add_deferred_bind(struct skl *skl, +static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, struct skl_module_cfg *src, struct skl_module_cfg *dst) { struct skl_module_deferred_bind *m_list, *modules; @@ -1028,26 +915,27 @@ static int skl_tplg_module_add_deferred_bind(struct skl *skl, } static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl *skl, + struct skl_dev *skl, struct snd_soc_dapm_widget *src_w, struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; struct skl_module_cfg *sink_mconfig; - struct skl_sst *ctx = skl->skl_sst; int ret; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (!p->connect) continue; - dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); - dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); + dev_dbg(skl->dev, + "%s: src widget=%s\n", __func__, w->name); + dev_dbg(skl->dev, + "%s: sink widget=%s\n", __func__, p->sink->name); next_sink = p->sink; - if (!is_skl_dsp_widget_type(p->sink, ctx->dev)) + if (!is_skl_dsp_widget_type(p->sink, skl->dev)) return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); /* @@ -1056,7 +944,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, * they are ones used for SKL so check that first */ if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, ctx->dev)) { + is_skl_dsp_widget_type(p->sink, skl->dev)) { sink = p->sink; sink_mconfig = sink->priv; @@ -1088,19 +976,21 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, continue; /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); if (ret) return ret; /* set module params after bind */ - skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + skl_tplg_set_module_bind_params(src_w, + src_mconfig, skl); + skl_tplg_set_module_bind_params(sink, + sink_mconfig, skl); /* Start sinks pipe first */ if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(ctx, + ret = skl_run_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1125,10 +1015,9 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, * - Then run current pipe */ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig; - struct skl_sst *ctx = skl->skl_sst; int ret = 0; src_mconfig = w->priv; @@ -1144,25 +1033,24 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, /* Start source pipe last after starting all sinks */ if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(ctx, src_mconfig->pipe); + return skl_run_pipe(skl, src_mconfig->pipe); return 0; } static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( - struct snd_soc_dapm_widget *w, struct skl *skl) + struct snd_soc_dapm_widget *w, struct skl_dev *skl) { struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *src_w = NULL; - struct skl_sst *ctx = skl->skl_sst; snd_soc_dapm_widget_for_each_source_path(w, p) { src_w = p->source; if (!p->connect) continue; - dev_dbg(ctx->dev, "sink widget=%s\n", w->name); - dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + dev_dbg(skl->dev, "sink widget=%s\n", w->name); + dev_dbg(skl->dev, "src widget=%s\n", p->source->name); /* * here we will check widgets in sink pipelines, so that can @@ -1170,7 +1058,7 @@ static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( * ones used for SKL so check that first */ if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, ctx->dev)) { + is_skl_dsp_widget_type(p->source, skl->dev)) { return p->source; } } @@ -1191,12 +1079,11 @@ static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( * - start this pipeline */ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { int ret = 0; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - struct skl_sst *ctx = skl->skl_sst; int src_pipe_started = 0; sink = w; @@ -1222,16 +1109,16 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, } if (src_pipe_started) { - ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); + ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); if (ret) return ret; /* set module params after bind */ - skl_tplg_set_module_bind_params(source, src_mconfig, ctx); - skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx); + skl_tplg_set_module_bind_params(source, src_mconfig, skl); + skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + ret = skl_run_pipe(skl, sink_mconfig->pipe); } return ret; @@ -1244,16 +1131,15 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, * - unbind with source pipelines if still connected */ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; sink_mconfig = w->priv; /* Stop the pipe */ - ret = skl_stop_pipe(ctx, sink_mconfig->pipe); + ret = skl_stop_pipe(skl, sink_mconfig->pipe); if (ret) return ret; @@ -1263,7 +1149,7 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, if (!src_mconfig) continue; - ret = skl_unbind_modules(ctx, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1273,28 +1159,22 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, /* * in the Post-PMD event of mixer we need to do following: - * - Free the mcps used - * - Free the mem used * - Unbind the modules within the pipeline * - Delete the pipeline (modules are not required to be explicitly * deleted, pipeline delete is enough here */ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *mconfig = w->priv; struct skl_pipe_module *w_module; struct skl_module_cfg *src_module = NULL, *dst_module; - struct skl_sst *ctx = skl->skl_sst; struct skl_pipe *s_pipe = mconfig->pipe; struct skl_module_deferred_bind *modules, *tmp; if (s_pipe->state == SKL_PIPE_INVALID) return -EINVAL; - skl_tplg_free_pipe_mcps(skl, mconfig); - skl_tplg_free_pipe_mem(skl, mconfig); - list_for_each_entry(w_module, &s_pipe->w_list, node) { if (list_empty(&skl->bind_list)) break; @@ -1307,7 +1187,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * modules from deferred bind list. */ if (modules->dst == src_module) { - skl_unbind_modules(ctx, modules->src, + skl_unbind_modules(skl, modules->src, modules->dst); } @@ -1327,44 +1207,40 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; - if (mconfig->m_state >= SKL_MODULE_INIT_DONE) - skl_tplg_free_pipe_mcps(skl, dst_module); if (src_module == NULL) { src_module = dst_module; continue; } - skl_unbind_modules(ctx, src_module, dst_module); + skl_unbind_modules(skl, src_module, dst_module); src_module = dst_module; } - skl_delete_pipe(ctx, mconfig->pipe); + skl_delete_pipe(skl, mconfig->pipe); list_for_each_entry(w_module, &s_pipe->w_list, node) { src_module = w_module->w->priv; src_module->m_state = SKL_MODULE_UNINIT; } - return skl_tplg_unload_pipe_modules(ctx, s_pipe); + return skl_tplg_unload_pipe_modules(skl, s_pipe); } /* * in the Post-PMD event of PGA we need to do following: - * - Free the mcps used * - Stop the pipeline * - In source pipe is connected, unbind with source pipelines */ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl *skl) + struct skl_dev *skl) { struct skl_module_cfg *src_mconfig, *sink_mconfig; int ret = 0, i; - struct skl_sst *ctx = skl->skl_sst; src_mconfig = w->priv; /* Stop the pipe since this is a mixin module */ - ret = skl_stop_pipe(ctx, src_mconfig->pipe); + ret = skl_stop_pipe(skl, src_mconfig->pipe); if (ret) return ret; @@ -1377,7 +1253,7 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, * This is a connecter and if path is found that means * unbind between source and sink has not happened yet */ - ret = skl_unbind_modules(ctx, src_mconfig, + ret = skl_unbind_modules(skl, src_mconfig, sink_mconfig); } } @@ -1395,7 +1271,7 @@ static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1425,7 +1301,7 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, { struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); + struct skl_dev *skl = get_skl_ctx(dapm->dev); switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -1446,10 +1322,10 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); struct skl_module_cfg *mconfig = w->priv; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (w->power) - skl_get_module_params(skl->skl_sst, (u32 *)bc->params, + skl_get_module_params(skl, (u32 *)bc->params, bc->size, bc->param_id, mconfig); /* decrement size for TLV header */ @@ -1481,7 +1357,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *sb = (struct soc_bytes_ext *)kcontrol->private_value; struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; - struct skl *skl = get_skl_ctx(w->dapm->dev); + struct skl_dev *skl = get_skl_ctx(w->dapm->dev); if (ac->params) { /* @@ -1498,7 +1374,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, return -EFAULT; if (w->power) - return skl_set_module_params(skl->skl_sst, + return skl_set_module_params(skl, (u32 *)ac->params, ac->size, ac->param_id, mconfig); } @@ -1659,7 +1535,7 @@ int skl_tplg_update_pipe_params(struct device *dev, struct skl_pipe_params *params) { struct skl_module_res *res = &mconfig->module->resources[0]; - struct skl *skl = get_skl_ctx(dev); + struct skl_dev *skl = get_skl_ctx(dev); struct skl_module_fmt *format = NULL; u8 cfg_idx = mconfig->pipe->cur_config_idx; @@ -1856,7 +1732,7 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, struct skl_pipe_params *params) { struct nhlt_specific_cfg *cfg; - struct skl *skl = get_skl_ctx(dai->dev); + struct skl_dev *skl = get_skl_ctx(dai->dev); int link_type = skl_tplg_be_link_type(mconfig->dev_type); u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); @@ -2070,7 +1946,7 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev, * Return an existing pipe if the pipe already exists. */ static int skl_tplg_add_pipe(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, + struct skl_module_cfg *mconfig, struct skl_dev *skl, struct snd_soc_tplg_vendor_value_elem *tkn_elem) { struct skl_pipeline *ppl; @@ -2330,10 +2206,6 @@ static int skl_tplg_fill_res_tkn(struct device *dev, return -EINVAL; switch (tkn_elem->token) { - case SKL_TKN_MM_U32_CPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_DMA_SIZE: res->dma_buffer_size = tkn_elem->value; break; @@ -2354,10 +2226,6 @@ static int skl_tplg_fill_res_tkn(struct device *dev, res->ibs = tkn_elem->value; break; - case SKL_TKN_U32_MAX_MCPS: - res->cps = tkn_elem->value; - break; - case SKL_TKN_MM_U32_RES_PIN_ID: case SKL_TKN_MM_U32_PIN_BUF: ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, @@ -2366,6 +2234,11 @@ static int skl_tplg_fill_res_tkn(struct device *dev, return ret; break; + case SKL_TKN_MM_U32_CPS: + case SKL_TKN_U32_MAX_MCPS: + /* ignore unused tokens */ + break; + default: dev_err(dev, "Not a res type token: %d", tkn_elem->token); return -EINVAL; @@ -2381,7 +2254,7 @@ static int skl_tplg_fill_res_tkn(struct device *dev, */ static int skl_tplg_get_token(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl, struct skl_module_cfg *mconfig) + struct skl_dev *skl, struct skl_module_cfg *mconfig) { int tkn_count = 0; int ret; @@ -2631,7 +2504,7 @@ static int skl_tplg_get_token(struct device *dev, * module private data */ static int skl_tplg_get_tokens(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, struct skl_module_cfg *mconfig, int block_size) { struct snd_soc_tplg_vendor_array *array; @@ -2727,8 +2600,8 @@ static int skl_tplg_get_desc_blocks(struct device *dev, * Otherwise we create a new instance and add into driver list */ static int skl_tplg_add_pipe_v4(struct device *dev, - struct skl_module_cfg *mconfig, struct skl *skl, - struct skl_dfw_v4_pipe *dfw_pipe) + struct skl_module_cfg *mconfig, struct skl_dev *skl, + struct skl_dfw_v4_pipe *dfw_pipe) { struct skl_pipeline *ppl; struct skl_pipe *pipe; @@ -2804,7 +2677,7 @@ static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, } static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct skl_dfw_v4_module *dfw = @@ -2818,7 +2691,7 @@ static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, return ret; mconfig->id.module_id = -1; mconfig->id.instance_id = dfw->instance_id; - mconfig->module->resources[0].cps = dfw->max_mcps; + mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; mconfig->module->resources[0].ibs = dfw->ibs; mconfig->module->resources[0].obs = dfw->obs; mconfig->core_id = dfw->core_id; @@ -2886,7 +2759,7 @@ static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, * for the type and size of the suceeding data block. */ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl *skl, struct device *dev, + struct skl_dev *skl, struct device *dev, struct skl_module_cfg *mconfig) { struct snd_soc_tplg_vendor_array *array; @@ -2981,9 +2854,8 @@ static void skl_clear_pin_config(struct snd_soc_component *component, } } -void skl_cleanup_resources(struct skl *skl) +void skl_cleanup_resources(struct skl_dev *skl) { - struct skl_sst *ctx = skl->skl_sst; struct snd_soc_component *soc_component = skl->component; struct snd_soc_dapm_widget *w; struct snd_soc_card *card; @@ -2995,15 +2867,12 @@ void skl_cleanup_resources(struct skl *skl) if (!card || !card->instantiated) return; - skl->resource.mem = 0; - skl->resource.mcps = 0; - list_for_each_entry(w, &card->widgets, list) { - if (is_skl_dsp_widget_type(w, ctx->dev) && w->priv != NULL) + if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) skl_clear_pin_config(soc_component, w); } - skl_clear_module_cnt(ctx->dsp); + skl_clear_module_cnt(skl->dsp); } /* @@ -3019,7 +2888,7 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, { int ret; struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_module_cfg *mconfig; if (!tplg_w->priv.size) @@ -3163,21 +3032,21 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, static int skl_tplg_fill_str_mfest_tkn(struct device *dev, struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0; static int ref_count; switch (str_elem->token) { case SKL_TKN_STR_LIB_NAME: - if (ref_count > skl->skl_sst->lib_count - 1) { + if (ref_count > skl->lib_count - 1) { ref_count = 0; return -EINVAL; } - strncpy(skl->skl_sst->lib_info[ref_count].name, + strncpy(skl->lib_info[ref_count].name, str_elem->string, - ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name)); + ARRAY_SIZE(skl->lib_info[ref_count].name)); ref_count++; break; @@ -3192,7 +3061,7 @@ static int skl_tplg_fill_str_mfest_tkn(struct device *dev, static int skl_tplg_get_str_tkn(struct device *dev, struct snd_soc_tplg_vendor_array *array, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0, ret; struct snd_soc_tplg_vendor_string_elem *str_elem; @@ -3299,7 +3168,7 @@ static int skl_tplg_fill_mod_info(struct device *dev, static int skl_tplg_get_int_tkn(struct device *dev, struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl *skl) + struct skl_dev *skl) { int tkn_count = 0, ret; static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; @@ -3319,7 +3188,7 @@ static int skl_tplg_get_int_tkn(struct device *dev, switch (tkn_elem->token) { case SKL_TKN_U32_LIB_COUNT: - skl->skl_sst->lib_count = tkn_elem->value; + skl->lib_count = tkn_elem->value; break; case SKL_TKN_U8_NUM_MOD: @@ -3465,35 +3334,17 @@ static int skl_tplg_get_int_tkn(struct device *dev, return tkn_count; } -static int skl_tplg_get_manifest_uuid(struct device *dev, - struct skl *skl, - struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) -{ - static int ref_count; - struct skl_module *mod; - - if (uuid_tkn->token == SKL_TKN_UUID) { - mod = skl->modules[ref_count]; - guid_copy(&mod->uuid, (guid_t *)&uuid_tkn->uuid); - ref_count++; - } else { - dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); - return -EINVAL; - } - - return 0; -} - /* * Fill the manifest structure by parsing the tokens based on the * type. */ static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl *skl, + char *pvt_data, struct skl_dev *skl, int block_size) { int tkn_count = 0, ret; int off = 0, tuple_size = 0; + u8 uuid_index = 0; struct snd_soc_tplg_vendor_array *array; struct snd_soc_tplg_vendor_value_elem *tkn_elem; @@ -3516,9 +3367,17 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, continue; case SND_SOC_TPLG_TUPLE_TYPE_UUID: - ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid); - if (ret < 0) - return ret; + if (array->uuid->token != SKL_TKN_UUID) { + dev_err(dev, "Not an UUID token: %d\n", + array->uuid->token); + return -EINVAL; + } + if (uuid_index >= skl->nr_modules) { + dev_err(dev, "Too many UUID tokens\n"); + return -EINVAL; + } + guid_copy(&skl->modules[uuid_index++]->uuid, + (guid_t *)&array->uuid->uuid); tuple_size += sizeof(*array->uuid); continue; @@ -3550,7 +3409,7 @@ static int skl_tplg_get_manifest_tkn(struct device *dev, * preceded by descriptors for type and size of data block. */ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl *skl) + struct device *dev, struct skl_dev *skl) { struct snd_soc_tplg_vendor_array *array; int num_blocks, block_size = 0, block_type, off = 0; @@ -3612,7 +3471,7 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, struct snd_soc_tplg_manifest *manifest) { struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); /* proceed only if we have private data defined */ if (manifest->priv.size == 0) @@ -3620,9 +3479,9 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, skl_tplg_get_manifest_data(manifest, bus->dev, skl); - if (skl->skl_sst->lib_count > SKL_MAX_LIB) { + if (skl->lib_count > SKL_MAX_LIB) { dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - skl->skl_sst->lib_count); + skl->lib_count); return -EINVAL; } @@ -3671,7 +3530,7 @@ static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) return 0; } -static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) +static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) { struct skl_pipe_module *w_module; struct snd_soc_dapm_widget *w; @@ -3694,10 +3553,6 @@ static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) pipe->passthru = false; } -/* This will be read from topology manifest, currently defined here */ -#define SKL_MAX_MCPS 30000000 -#define SKL_FW_MAX_MEM 1000000 - /* * SKL topology init routine */ @@ -3705,7 +3560,7 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) { int ret; const struct firmware *fw; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl; ret = request_firmware(&fw, skl->tplg_name, bus->dev); @@ -3724,31 +3579,30 @@ int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) * The complete tplg for SKL is loaded as index 0, we don't use * any other index */ - ret = snd_soc_tplg_component_load(component, - &skl_tplg_ops, fw, 0); + ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0); if (ret < 0) { dev_err(bus->dev, "tplg component load failed%d\n", ret); - release_firmware(fw); - return -EINVAL; + goto err; } - skl->resource.max_mcps = SKL_MAX_MCPS; - skl->resource.max_mem = SKL_FW_MAX_MEM; - - skl->tplg = fw; ret = skl_tplg_create_pipe_widget_list(component); - if (ret < 0) - return ret; + if (ret < 0) { + dev_err(bus->dev, "tplg create pipe widget list failed%d\n", + ret); + goto err; + } list_for_each_entry(ppl, &skl->ppl_list, node) skl_tplg_set_pipe_type(skl, ppl->pipe); - return 0; +err: + release_firmware(fw); + return ret; } void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct skl_pipeline *ppl, *tmp; if (!list_empty(&skl->ppl_list)) @@ -3757,6 +3611,4 @@ void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) /* clean up topology */ snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); - - release_firmware(skl->tplg); } diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 665e35cee50d..e967800dbb62 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -101,7 +101,7 @@ struct skl_audio_data_format { } __packed; struct skl_base_cfg { - u32 cps; + u32 cpc; u32 ibs; u32 obs; u32 is_pages; @@ -140,11 +140,6 @@ struct skl_src_module_cfg { enum skl_s_freq src_cfg; } __packed; -struct notification_mask { - u32 notify; - u32 enable; -} __packed; - struct skl_up_down_mixer_cfg { struct skl_base_cfg base_cfg; enum skl_ch_cfg out_ch_cfg; @@ -348,7 +343,6 @@ struct skl_module_pin_resources { struct skl_module_res { u8 id; u32 is_pages; - u32 cps; u32 ibs; u32 obs; u32 dma_buffer_size; @@ -389,9 +383,6 @@ struct skl_module_cfg { u8 out_queue_mask; u8 in_queue; u8 out_queue; - u32 mcps; - u32 ibs; - u32 obs; u8 is_loadable; u8 core_id; u8 dev_type; @@ -447,7 +438,7 @@ enum skl_channel { SKL_CH_QUATRO = 4, }; -static inline struct skl *get_skl_ctx(struct device *dev) +static inline struct skl_dev *get_skl_ctx(struct device *dev) { struct hdac_bus *bus = dev_get_drvdata(dev); @@ -456,7 +447,7 @@ static inline struct skl *get_skl_ctx(struct device *dev) int skl_tplg_be_update_params(struct snd_soc_dai *dai, struct skl_pipe_params *params); -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id); void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, struct skl_pipe_params *params, int stream); @@ -469,32 +460,32 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module( int skl_tplg_update_pipe_params(struct device *dev, struct skl_module_cfg *mconfig, struct skl_pipe_params *params); -void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); -void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps); -int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_pause_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_pause_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); +int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe); -int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); +int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *module_config); -int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg +int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); -int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg +int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); -int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); -int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, +int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, u32 param_id, struct skl_module_cfg *mcfg); struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, @@ -508,6 +499,6 @@ int skl_pcm_link_dma_prepare(struct device *dev, int skl_dai_load(struct snd_soc_component *cmp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai); -void skl_tplg_add_moduleid_in_bind_params(struct skl *skl, +void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, struct snd_soc_dapm_widget *w); #endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3362e71b4563..141dbbf975ac 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,9 +26,11 @@ #include <sound/hdaudio.h> #include <sound/hda_i915.h> #include <sound/hda_codec.h> +#include <sound/intel-nhlt.h> #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" + #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) #include "../../../soc/codecs/hdac_hda.h" #endif @@ -50,7 +52,7 @@ static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, pci_write_config_byte(pci, reg, data); } -static void skl_init_pci(struct skl *skl) +static void skl_init_pci(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); @@ -132,7 +134,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) /* Reset stream-to-link mapping */ list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); skl_enable_miscbdcge(bus->dev, true); @@ -252,7 +254,7 @@ static irqreturn_t skl_threaded_handler(int irq, void *dev_id) static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); int ret; ret = request_threaded_irq(skl->pci->irq, skl_interrupt, @@ -276,7 +278,7 @@ static int skl_suspend_late(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); return skl_suspend_late_dsp(skl); } @@ -284,7 +286,7 @@ static int skl_suspend_late(struct device *dev) #ifdef CONFIG_PM static int _skl_suspend(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct pci_dev *pci = to_pci_dev(bus->dev); int ret; @@ -307,7 +309,7 @@ static int _skl_suspend(struct hdac_bus *bus) static int _skl_resume(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl_init_pci(skl); skl_dum_set(bus); @@ -325,7 +327,7 @@ static int skl_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); int ret; /* @@ -345,7 +347,7 @@ static int skl_suspend(struct device *dev) ret = _skl_suspend(bus); if (ret < 0) return ret; - skl->skl_sst->fw_loaded = false; + skl->fw_loaded = false; } return 0; @@ -355,7 +357,7 @@ static int skl_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct hdac_ext_link *hlink = NULL; int ret; @@ -430,7 +432,7 @@ static const struct dev_pm_ops skl_pm = { */ static int skl_free(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); skl->init_done = 0; /* to be sure */ @@ -475,7 +477,7 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; -static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, +static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl, struct snd_soc_acpi_mach *machines) { struct hdac_bus *bus = skl_to_bus(skl); @@ -494,7 +496,7 @@ static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, return mach; } -static int skl_find_machine(struct skl *skl, void *driver_data) +static int skl_find_machine(struct skl_dev *skl, void *driver_data) { struct hdac_bus *bus = skl_to_bus(skl); struct snd_soc_acpi_mach *mach = driver_data; @@ -516,13 +518,15 @@ static int skl_find_machine(struct skl *skl, void *driver_data) if (pdata) { skl->use_tplg_pcm = pdata->use_tplg_pcm; - mach->mach_params.dmic_num = skl_get_dmic_geo(skl); + mach->mach_params.dmic_num = + intel_nhlt_get_dmic_geo(&skl->pci->dev, + skl->nhlt); } return 0; } -static int skl_machine_device_register(struct skl *skl) +static int skl_machine_device_register(struct skl_dev *skl) { struct snd_soc_acpi_mach *mach = skl->mach; struct hdac_bus *bus = skl_to_bus(skl); @@ -558,13 +562,13 @@ static int skl_machine_device_register(struct skl *skl) return 0; } -static void skl_machine_device_unregister(struct skl *skl) +static void skl_machine_device_unregister(struct skl_dev *skl) { if (skl->i2s_dev) platform_device_unregister(skl->i2s_dev); } -static int skl_dmic_device_register(struct skl *skl) +static int skl_dmic_device_register(struct skl_dev *skl) { struct hdac_bus *bus = skl_to_bus(skl); struct platform_device *pdev; @@ -588,7 +592,7 @@ static int skl_dmic_device_register(struct skl *skl) return 0; } -static void skl_dmic_device_unregister(struct skl *skl) +static void skl_dmic_device_unregister(struct skl_dev *skl) { if (skl->dmic_dev) platform_device_unregister(skl->dmic_dev); @@ -626,7 +630,7 @@ static void init_skl_xtal_rate(int pci_id) } } -static int skl_clock_device_register(struct skl *skl) +static int skl_clock_device_register(struct skl_dev *skl) { struct platform_device_info pdevinfo = {NULL}; struct skl_clk_pdata *clk_pdata; @@ -656,7 +660,7 @@ static int skl_clock_device_register(struct skl *skl) return PTR_ERR_OR_ZERO(skl->clk_dev); } -static void skl_clock_device_unregister(struct skl *skl) +static void skl_clock_device_unregister(struct skl_dev *skl) { if (skl->clk_dev) platform_device_unregister(skl->clk_dev); @@ -692,7 +696,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) struct hdac_hda_priv *hda_codec; int err; @@ -792,7 +796,7 @@ static int skl_i915_init(struct hdac_bus *bus) static void skl_probe_work(struct work_struct *work) { - struct skl *skl = container_of(work, struct skl, probe_work); + struct skl_dev *skl = container_of(work, struct skl_dev, probe_work); struct hdac_bus *bus = skl_to_bus(skl); struct hdac_ext_link *hlink = NULL; int err; @@ -854,11 +858,10 @@ out_err: * constructor */ static int skl_create(struct pci_dev *pci, - const struct hdac_io_ops *io_ops, - struct skl **rskl) + struct skl_dev **rskl) { struct hdac_ext_bus_ops *ext_ops = NULL; - struct skl *skl; + struct skl_dev *skl; struct hdac_bus *bus; struct hda_bus *hbus; int err; @@ -884,7 +887,7 @@ static int skl_create(struct pci_dev *pci, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) ext_ops = snd_soc_hdac_hda_get_ops(); #endif - snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); + snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, ext_ops); bus->use_posbuf = 1; skl->pci = pci; INIT_WORK(&skl->probe_work, skl_probe_work); @@ -902,7 +905,7 @@ static int skl_create(struct pci_dev *pci, static int skl_first_init(struct hdac_bus *bus) { - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); struct pci_dev *pci = skl->pci; int err; unsigned short gcap; @@ -978,7 +981,7 @@ static int skl_first_init(struct hdac_bus *bus) static int skl_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - struct skl *skl; + struct skl_dev *skl; struct hdac_bus *bus = NULL; int err; @@ -1013,7 +1016,7 @@ static int skl_probe(struct pci_dev *pci, } /* we use ext core ops, so provide NULL for ops here */ - err = skl_create(pci, NULL, &skl); + err = skl_create(pci, &skl); if (err < 0) return err; @@ -1029,7 +1032,7 @@ static int skl_probe(struct pci_dev *pci, device_disable_async_suspend(bus->dev); - skl->nhlt = skl_nhlt_init(bus->dev); + skl->nhlt = intel_nhlt_init(bus->dev); if (skl->nhlt == NULL) { #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) @@ -1071,8 +1074,8 @@ static int skl_probe(struct pci_dev *pci, dev_dbg(bus->dev, "error failed to register dsp\n"); goto out_nhlt_free; } - skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; - skl->skl_sst->clock_power_gating = skl_clock_power_gating; + skl->enable_miscbdcge = skl_enable_miscbdcge; + skl->clock_power_gating = skl_clock_power_gating; if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -1095,7 +1098,7 @@ out_dsp_free: out_clk_free: skl_clock_device_unregister(skl); out_nhlt_free: - skl_nhlt_free(skl->nhlt); + intel_nhlt_free(skl->nhlt); out_free: skl_free(bus); @@ -1107,7 +1110,7 @@ static void skl_shutdown(struct pci_dev *pci) struct hdac_bus *bus = pci_get_drvdata(pci); struct hdac_stream *s; struct hdac_ext_stream *stream; - struct skl *skl; + struct skl_dev *skl; if (!bus) return; @@ -1129,7 +1132,7 @@ static void skl_shutdown(struct pci_dev *pci) static void skl_remove(struct pci_dev *pci) { struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl *skl = bus_to_skl(bus); + struct skl_dev *skl = bus_to_skl(bus); cancel_work_sync(&skl->probe_work); @@ -1144,7 +1147,7 @@ static void skl_remove(struct pci_dev *pci) skl_dmic_device_unregister(skl); skl_clock_device_unregister(skl); skl_nhlt_remove_sysfs(skl); - skl_nhlt_free(skl->nhlt); + intel_nhlt_free(skl->nhlt); skl_free(bus); dev_set_drvdata(&pci->dev, NULL); } diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 6070666a6392..2bfbf59277c4 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -16,8 +16,8 @@ #include <sound/hdaudio_ext.h> #include <sound/hda_codec.h> #include <sound/soc.h> -#include "skl-nhlt.h" #include "skl-ssp-clk.h" +#include "skl-sst-ipc.h" #define SKL_SUSPEND_DELAY 2000 @@ -40,13 +40,6 @@ #define AZX_VS_EM2_DUM BIT(23) #define AZX_REG_VS_EM2_L1SEN BIT(13) -struct skl_dsp_resource { - u32 max_mcps; - u32 max_mem; - u32 mcps; - u32 mem; -}; - struct skl_debug; struct skl_astate_param { @@ -63,7 +56,7 @@ struct skl_fw_config { struct skl_astate_config *astate_cfg; }; -struct skl { +struct skl_dev { struct hda_bus hbus; struct pci_dev *pci; @@ -75,16 +68,13 @@ struct skl { struct snd_soc_dai_driver *dais; struct nhlt_acpi_table *nhlt; /* nhlt ptr */ - struct skl_sst *skl_sst; /* sst skl ctx */ - struct skl_dsp_resource resource; struct list_head ppl_list; struct list_head bind_list; const char *fw_name; char tplg_name[64]; unsigned short pci_id; - const struct firmware *tplg; int supend_active; @@ -96,13 +86,59 @@ struct skl { bool use_tplg_pcm; struct skl_fw_config cfg; struct snd_soc_acpi_mach *mach; + + struct device *dev; + struct sst_dsp *dsp; + + /* boot */ + wait_queue_head_t boot_wait; + bool boot_complete; + + /* module load */ + wait_queue_head_t mod_load_wait; + bool mod_load_complete; + bool mod_load_status; + + /* IPC messaging */ + struct sst_generic_ipc ipc; + + /* callback for miscbdge */ + void (*enable_miscbdcge)(struct device *dev, bool enable); + /* Is CGCTL.MISCBDCGE disabled */ + bool miscbdcg_disabled; + + /* Populate module information */ + struct list_head uuid_list; + + /* Is firmware loaded */ + bool fw_loaded; + + /* first boot ? */ + bool is_first_boot; + + /* multi-core */ + struct skl_dsp_cores cores; + + /* library info */ + struct skl_lib_info lib_info[SKL_MAX_LIB]; + int lib_count; + + /* Callback to update D0i3C register */ + void (*update_d0i3c)(struct device *dev, bool enable); + + struct skl_d0i3_data d0i3; + + const struct skl_dsp_ops *dsp_ops; + + /* Callback to update dynamic clock and power gating registers */ + void (*clock_power_gating)(struct device *dev, bool enable); }; #define skl_to_bus(s) (&(s)->hbus.core) -#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core) +#define bus_to_skl(bus) container_of(bus, struct skl_dev, hbus.core) #define skl_to_hbus(s) (&(s)->hbus) -#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus)) +#define hbus_to_skl(hbus) container_of((hbus), struct skl_dev, (hbus)) /* to pass dai dma data */ struct skl_dma_params { @@ -121,52 +157,49 @@ struct skl_dsp_ops { int (*init)(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops loader_ops, - struct skl_sst **skl_sst); - int (*init_fw)(struct device *dev, struct skl_sst *ctx); - void (*cleanup)(struct device *dev, struct skl_sst *ctx); + struct skl_dev **skl_sst); + int (*init_fw)(struct device *dev, struct skl_dev *skl); + void (*cleanup)(struct device *dev, struct skl_dev *skl); }; int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); -struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); -void skl_nhlt_free(struct nhlt_acpi_table *addr); -struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, +struct nhlt_specific_cfg *skl_get_ep_blob(struct skl_dev *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn, u8 dev_type); -int skl_get_dmic_geo(struct skl *skl); -int skl_nhlt_update_topology_bin(struct skl *skl); -int skl_init_dsp(struct skl *skl); -int skl_free_dsp(struct skl *skl); -int skl_suspend_late_dsp(struct skl *skl); -int skl_suspend_dsp(struct skl *skl); -int skl_resume_dsp(struct skl *skl); -void skl_cleanup_resources(struct skl *skl); +int skl_nhlt_update_topology_bin(struct skl_dev *skl); +int skl_init_dsp(struct skl_dev *skl); +int skl_free_dsp(struct skl_dev *skl); +int skl_suspend_late_dsp(struct skl_dev *skl); +int skl_suspend_dsp(struct skl_dev *skl); +int skl_resume_dsp(struct skl_dev *skl); +void skl_cleanup_resources(struct skl_dev *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); void skl_update_d0i3c(struct device *dev, bool enable); -int skl_nhlt_create_sysfs(struct skl *skl); -void skl_nhlt_remove_sysfs(struct skl *skl); -void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks); +int skl_nhlt_create_sysfs(struct skl_dev *skl); +void skl_nhlt_remove_sysfs(struct skl_dev *skl); +void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks); struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id); -int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps, +int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, u32 caps_size, u32 node_id); struct skl_module_cfg; #ifdef CONFIG_DEBUG_FS -struct skl_debug *skl_debugfs_init(struct skl *skl); -void skl_debugfs_exit(struct skl *skl); +struct skl_debug *skl_debugfs_init(struct skl_dev *skl); +void skl_debugfs_exit(struct skl_dev *skl); void skl_debug_init_module(struct skl_debug *d, struct snd_soc_dapm_widget *w, struct skl_module_cfg *mconfig); #else -static inline struct skl_debug *skl_debugfs_init(struct skl *skl) +static inline struct skl_debug *skl_debugfs_init(struct skl_dev *skl) { return NULL; } -static inline void skl_debugfs_exit(struct skl *skl) +static inline void skl_debugfs_exit(struct skl_dev *skl) {} static inline void skl_debug_init_module(struct skl_debug *d, diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 3446a113f482..61226fefe1c4 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -523,7 +523,6 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data; struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai; struct kirkwood_dma_data *priv; - struct resource *mem; struct device_node *np = pdev->dev.of_node; int err; @@ -533,16 +532,13 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->io = devm_ioremap_resource(&pdev->dev, mem); + priv->io = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->io)) return PTR_ERR(priv->io); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "platform_get_irq failed: %d\n", priv->irq); + if (priv->irq < 0) return priv->irq; - } if (np) { priv->burst = 128; /* might be 32 or 128 */ diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index c7a81c4be068..d00608c73c6e 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1335,10 +1335,8 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) /* irq */ irq_id = platform_get_irq(pdev, 0); - if (irq_id <= 0) { - dev_err(dev, "%pOFn no irq found\n", dev->of_node); + if (irq_id <= 0) return irq_id < 0 ? irq_id : -ENXIO; - } ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler, IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle", diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h index d44faba27d3c..32bef5e2a56d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-common.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -63,27 +63,6 @@ enum audio_base_clock { MT2701_BASE_CLK_NUM, }; -static const unsigned int mt2701_afe_backup_list[] = { - AUDIO_TOP_CON0, - AUDIO_TOP_CON4, - AUDIO_TOP_CON5, - ASYS_TOP_CON, - AFE_CONN0, - AFE_CONN1, - AFE_CONN2, - AFE_CONN3, - AFE_CONN15, - AFE_CONN16, - AFE_CONN17, - AFE_CONN18, - AFE_CONN19, - AFE_CONN20, - AFE_CONN21, - AFE_CONN22, - AFE_DAC_CON0, - AFE_MEMIF_PBUF_SIZE, -}; - struct mt2701_i2s_data { int i2s_ctrl_reg; int i2s_asrc_fs_shift; diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 7064a9fd6f74..76502ba261c8 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -60,6 +60,27 @@ static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = { { .rate = 352800, .regvalue = 24 }, }; +static const unsigned int mt2701_afe_backup_list[] = { + AUDIO_TOP_CON0, + AUDIO_TOP_CON4, + AUDIO_TOP_CON5, + ASYS_TOP_CON, + AFE_CONN0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN3, + AFE_CONN15, + AFE_CONN16, + AFE_CONN17, + AFE_CONN18, + AFE_CONN19, + AFE_CONN20, + AFE_CONN21, + AFE_CONN22, + AFE_DAC_CON0, + AFE_MEMIF_PBUF_SIZE, +}; + static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num) { struct mt2701_afe_private *afe_priv = afe->platform_priv; @@ -796,14 +817,6 @@ static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), }; -static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = { - SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), -}; - -static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = { - SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), -}; - static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0), }; @@ -832,11 +845,6 @@ static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = { PWR2_TOP_CON, 18, 1, 0), }; -static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = { - SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S4 Out Switch", - PWR2_TOP_CON, 19, 1, 0), -}; - static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = { /* inter-connections */ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -1342,10 +1350,8 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) return -ENOMEM; irq_id = platform_get_irq_byname(pdev, "asys"); - if (irq_id < 0) { - dev_err(dev, "unable to get ASYS IRQ\n"); + if (irq_id < 0) return irq_id; - } ret = devm_request_irq(dev, irq_id, mt2701_asys_isr, IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index 08a6532da322..e52c032d53aa 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -749,7 +749,6 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt6797_afe_private *afe_priv; - struct resource *res; struct device *dev; int i, irq_id, ret; @@ -774,9 +773,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev) } /* regmap init */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 0382896c162e..0ee29255e731 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1056,7 +1056,6 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) int irq_id; struct mtk_base_afe *afe; struct mt8173_afe_private *afe_priv; - struct resource *res; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); if (ret) @@ -1075,10 +1074,8 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) afe->dev = &pdev->dev; irq_id = platform_get_irq(pdev, 0); - if (irq_id <= 0) { - dev_err(afe->dev, "np %pOFn no irq\n", afe->dev->of_node); + if (irq_id <= 0) return irq_id < 0 ? irq_id : -ENXIO; - } ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); if (ret) { @@ -1086,8 +1083,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - afe->base_addr = devm_ioremap_resource(&pdev->dev, res); + afe->base_addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 59076e21cb47..43f99e59a078 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -116,15 +116,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static const struct snd_soc_dapm_widget -mt8183_da7219_max98357_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("IT6505_8CH"), -}; - -static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = { - {"IT6505_8CH", NULL, "TDM"}, -}; - /* FE */ SND_SOC_DAILINK_DEFS(playback1, DAILINK_COMP_ARRAY(COMP_CPU("DL1")), @@ -370,7 +361,7 @@ static int mt8183_da7219_max98357_headset_init(struct snd_soc_component *component); static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_EMPTY(), .init = mt8183_da7219_max98357_headset_init, }; @@ -436,10 +427,10 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) dai_link->platforms->of_node = platform_node; } - mt8183_da7219_max98357_headset_dev.codec_of_node = + mt8183_da7219_max98357_headset_dev.dlc.of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); - if (!mt8183_da7219_max98357_headset_dev.codec_of_node) { + if (!mt8183_da7219_max98357_headset_dev.dlc.of_node) { dev_err(&pdev->dev, "Property 'mediatek,headset-codec' missing/invalid\n"); return -EINVAL; diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c index 8983d54a9b67..0d69cf440407 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -15,7 +15,9 @@ struct mtk_afe_tdm_priv { int bck_id; int bck_rate; - + int tdm_out_mode; + int bck_invert; + int lck_invert; int mclk_id; int mclk_multiple; /* according to sample rate */ int mclk_rate; @@ -23,6 +25,21 @@ struct mtk_afe_tdm_priv { }; enum { + TDM_OUT_I2S = 0, + TDM_OUT_TDM = 1, +}; + +enum { + TDM_BCK_NON_INV = 0, + TDM_BCK_INV = 1, +}; + +enum { + TDM_LCK_NON_INV = 0, + TDM_LCK_INV = 1, +}; + +enum { TDM_WLEN_16_BIT = 1, TDM_WLEN_32_BIT = 2, }; @@ -93,6 +110,25 @@ static unsigned int get_tdm_ch(unsigned int ch) } } +static unsigned int get_tdm_ch_fixup(unsigned int channels) +{ + if (channels > 4) + return 8; + else if (channels > 2) + return 4; + else + return 2; +} + +static unsigned int get_tdm_ch_per_sdata(unsigned int mode, + unsigned int channels) +{ + if (mode == TDM_OUT_TDM) + return get_tdm_ch_fixup(channels); + else + return 2; +} + /* interconnection */ enum { HDMI_CONN_CH0 = 0, @@ -433,8 +469,11 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, struct mt8183_afe_private *afe_priv = afe->platform_priv; int tdm_id = dai->id; struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int tdm_out_mode = tdm_priv->tdm_out_mode; unsigned int rate = params_rate(params); unsigned int channels = params_channels(params); + unsigned int out_channels_per_sdata = + get_tdm_ch_per_sdata(tdm_out_mode, channels); snd_pcm_format_t format = params_format(params); unsigned int tdm_con = 0; @@ -448,7 +487,7 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, /* calculate bck */ tdm_priv->bck_rate = rate * - channels * + out_channels_per_sdata * snd_pcm_format_physical_width(format); if (tdm_priv->bck_rate > tdm_priv->mclk_rate) @@ -461,50 +500,72 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, __func__, tdm_id, rate, channels, format, tdm_priv->mclk_rate, tdm_priv->bck_rate); + dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n", + __func__, out_channels_per_sdata); /* set tdm */ - tdm_con = 1 << BCK_INVERSE_SFT; - tdm_con |= 1 << LRCK_INVERSE_SFT; - tdm_con |= 1 << DELAY_DATA_SFT; + if (tdm_priv->bck_invert) + regmap_update_bits(afe->regmap, AUDIO_TOP_CON3, + BCK_INVERSE_MASK_SFT, + 0x1 << BCK_INVERSE_SFT); + + if (tdm_priv->lck_invert) + tdm_con |= 1 << LRCK_INVERSE_SFT; + + if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) { + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + } else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) { + tdm_con |= 0 << DELAY_DATA_SFT; + tdm_con |= 0 << LRCK_TDM_WIDTH_SFT; + } + tdm_con |= 1 << LEFT_ALIGN_SFT; tdm_con |= get_tdm_wlen(format) << WLEN_SFT; - tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT; tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; - tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); - switch (channels) { - case 1: - case 2: + if (out_channels_per_sdata == 2) { + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + } else { tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 3: - case 4: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 5: - case 6: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; - break; - case 7: - case 8: - tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; - tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; - tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; - tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; - break; - default: - tdm_con = 0; } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, @@ -573,10 +634,58 @@ static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); } +static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + /* DAI mode*/ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_priv->tdm_out_mode = TDM_OUT_TDM; + break; + default: + tdm_priv->tdm_out_mode = TDM_OUT_I2S; + } + + /* DAI clock inversion*/ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + tdm_priv->bck_invert = TDM_BCK_NON_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_NON_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + default: + tdm_priv->bck_invert = TDM_BCK_INV; + tdm_priv->lck_invert = TDM_LCK_INV; + break; + } + + return 0; +} + static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { .hw_params = mtk_dai_tdm_hw_params, .trigger = mtk_dai_tdm_trigger, .set_sysclk = mtk_dai_tdm_set_sysclk, + .set_fmt = mtk_dai_tdm_set_fmt, }; /* dai driver */ diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 887c932229d0..bb9cdc0d6552 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -15,7 +15,22 @@ #include "mt8183-afe-common.h" #include "../../codecs/ts3a227e.h" -static struct snd_soc_jack headset_jack; +enum PINCTRL_PIN_STATE { + PIN_STATE_DEFAULT = 0, + PIN_TDM_OUT_ON, + PIN_TDM_OUT_OFF, + PIN_STATE_MAX +}; + +static const char * const mt8183_pin_str[PIN_STATE_MAX] = { + "default", "aud_tdm_out_on", "aud_tdm_out_off", +}; + +struct mt8183_mt6358_ts3a227_max98357_priv { + struct pinctrl *pinctrl; + struct pinctrl_state *pin_states[PIN_STATE_MAX]; + struct snd_soc_jack headset_jack; +}; static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -46,16 +61,6 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static const struct snd_soc_dapm_widget -mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = { - SND_SOC_DAPM_OUTPUT("IT6505_8CH"), -}; - -static const struct snd_soc_dapm_route -mt8183_mt6358_ts3a227_max98357_dapm_routes[] = { - {"IT6505_8CH", NULL, "TDM"}, -}; - static int mt8183_mt6358_ts3a227_max98357_bt_sco_startup( struct snd_pcm_substream *substream) @@ -183,6 +188,47 @@ SND_SOC_DAILINK_DEFS(tdm, DAILINK_COMP_ARRAY(COMP_DUMMY()), DAILINK_COMP_ARRAY(COMP_EMPTY())); +static int mt8183_mt6358_tdm_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + if (IS_ERR(priv->pin_states[PIN_TDM_OUT_ON])) + return PTR_ERR(priv->pin_states[PIN_TDM_OUT_ON]); + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_ON]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); + + return ret; +} + +static void mt8183_mt6358_tdm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(rtd->card); + int ret; + + if (IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF])) + return; + + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_OFF]); + if (ret) + dev_err(rtd->card->dev, "%s failed to select state %d\n", + __func__, ret); +} + +static struct snd_soc_ops mt8183_mt6358_tdm_ops = { + .startup = mt8183_mt6358_tdm_startup, + .shutdown = mt8183_mt6358_tdm_shutdown, +}; + static struct snd_soc_dai_link mt8183_mt6358_ts3a227_max98357_dai_links[] = { /* FE */ @@ -333,33 +379,30 @@ mt8183_mt6358_ts3a227_max98357_dai_links[] = { { .name = "TDM", .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_IF | + SND_SOC_DAIFMT_CBM_CFM, .dpcm_playback = 1, .ignore_suspend = 1, + .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, + .ops = &mt8183_mt6358_tdm_ops, SND_SOC_DAILINK_REG(tdm), }, }; -static int -mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *cpnt); - -static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { - .name = "Headset Chip", - .init = mt8183_mt6358_ts3a227_max98357_headset_init, -}; - static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { .name = "mt8183_mt6358_ts3a227_max98357", .owner = THIS_MODULE, .dai_link = mt8183_mt6358_ts3a227_max98357_dai_links, .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dai_links), - .aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev, - .num_aux_devs = 1, }; static int mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) { int ret; + struct mt8183_mt6358_ts3a227_max98357_priv *priv = + snd_soc_card_get_drvdata(component->card); /* Enable Headset and 4 Buttons Jack detection */ ret = snd_soc_card_jack_new(&mt8183_mt6358_ts3a227_max98357_card, @@ -367,23 +410,29 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &headset_jack, + &priv->headset_jack, NULL, 0); if (ret) return ret; - ret = ts3a227e_enable_jack_detect(component, &headset_jack); + ret = ts3a227e_enable_jack_detect(component, &priv->headset_jack); return ret; } +static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { + .dlc = COMP_EMPTY(), + .init = mt8183_mt6358_ts3a227_max98357_headset_init, +}; + static int mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8183_mt6358_ts3a227_max98357_card; struct device_node *platform_node; struct snd_soc_dai_link *dai_link; - struct pinctrl *default_pins; + struct mt8183_mt6358_ts3a227_max98357_priv *priv; + int ret; int i; card->dev = &pdev->dev; @@ -401,21 +450,53 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) dai_link->platforms->of_node = platform_node; } - mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node = + mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node = of_parse_phandle(pdev->dev.of_node, "mediatek,headset-codec", 0); - if (!mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) { - dev_err(&pdev->dev, - "Property 'mediatek,headset-codec' missing/invalid\n"); - return -EINVAL; + if (mt8183_mt6358_ts3a227_max98357_headset_dev.dlc.of_node) { + card->aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev; + card->num_aux_devs = 1; } - default_pins = - devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT); - if (IS_ERR(default_pins)) { - dev_err(&pdev->dev, "%s set pins failed\n", + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, priv); + + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(priv->pinctrl)) { + dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n", __func__); - return PTR_ERR(default_pins); + return PTR_ERR(priv->pinctrl); + } + + for (i = 0; i < PIN_STATE_MAX; i++) { + priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl, + mt8183_pin_str[i]); + if (IS_ERR(priv->pin_states[i])) { + ret = PTR_ERR(priv->pin_states[i]); + dev_info(&pdev->dev, "%s Can't find pin state %s %d\n", + __func__, mt8183_pin_str[i], ret); + } + } + + if (!IS_ERR(priv->pin_states[PIN_TDM_OUT_OFF])) { + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_TDM_OUT_OFF]); + if (ret) + dev_info(&pdev->dev, + "%s failed to select state %d\n", + __func__, ret); + } + + if (!IS_ERR(priv->pin_states[PIN_STATE_DEFAULT])) { + ret = pinctrl_select_state(priv->pinctrl, + priv->pin_states[PIN_STATE_DEFAULT]); + if (ret) + dev_info(&pdev->dev, + "%s failed to select state %d\n", + __func__, ret); } return devm_snd_soc_register_card(&pdev->dev, card); @@ -445,4 +526,3 @@ MODULE_DESCRIPTION("MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver"); MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("mt8183_mt6358_ts3a227_max98357 soc card"); - diff --git a/sound/soc/mediatek/mt8183/mt8183-reg.h b/sound/soc/mediatek/mt8183/mt8183-reg.h index e0482f2826da..e544a09e1913 100644 --- a/sound/soc/mediatek/mt8183/mt8183-reg.h +++ b/sound/soc/mediatek/mt8183/mt8183-reg.h @@ -413,6 +413,11 @@ #define AFE_MAX_REGISTER AFE_GENERAL2_ASRC_2CH_CON13 #define AFE_IRQ_STATUS_BITS 0x1fff +/* AUDIO_TOP_CON3 */ +#define BCK_INVERSE_SFT 3 +#define BCK_INVERSE_MASK 0x1 +#define BCK_INVERSE_MASK_SFT (0x1 << 3) + /* AFE_DAC_CON0 */ #define AWB2_ON_SFT 29 #define AWB2_ON_MASK 0x1 @@ -1596,9 +1601,6 @@ #define TDM_EN_SFT 0 #define TDM_EN_MASK 0x1 #define TDM_EN_MASK_SFT (0x1 << 0) -#define BCK_INVERSE_SFT 1 -#define BCK_INVERSE_MASK 0x1 -#define BCK_INVERSE_MASK_SFT (0x1 << 1) #define LRCK_INVERSE_SFT 2 #define LRCK_INVERSE_MASK 0x1 #define LRCK_INVERSE_MASK_SFT (0x1 << 2) diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 14a8321744da..1f698adde506 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -111,6 +111,7 @@ static void axg_card_clean_references(struct axg_card *priv) struct snd_soc_card *card = &priv->card; struct snd_soc_dai_link *link; struct snd_soc_dai_link_component *codec; + struct snd_soc_aux_dev *aux; int i, j; if (card->dai_link) { @@ -123,8 +124,8 @@ static void axg_card_clean_references(struct axg_card *priv) } if (card->aux_dev) { - for (i = 0; i < card->num_aux_devs; i++) - of_node_put(card->aux_dev[i].codec_of_node); + for_each_card_pre_auxs(card, i, aux) + of_node_put(aux->dlc.of_node); } kfree(card->dai_link); @@ -157,10 +158,10 @@ static int axg_card_add_aux_devices(struct snd_soc_card *card) card->aux_dev = aux; card->num_aux_devs = num; - for (i = 0; i < card->num_aux_devs; i++, aux++) { - aux->codec_of_node = + for_each_card_pre_auxs(card, i, aux) { + aux->dlc.of_node = of_parse_phandle(node, "audio-aux-devs", i); - if (!aux->codec_of_node) + if (!aux->dlc.of_node) return -EINVAL; } diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 01c1c7db2510..5a3749938900 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -306,7 +306,7 @@ static const struct regmap_config axg_fifo_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = FIFO_INIT_ADDR, + .max_register = FIFO_CTRL2, }; int axg_fifo_probe(struct platform_device *pdev) @@ -314,7 +314,6 @@ int axg_fifo_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct axg_fifo_match_data *data; struct axg_fifo *fifo; - struct resource *res; void __iomem *regs; data = of_device_get_match_data(dev); @@ -328,8 +327,7 @@ int axg_fifo_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, fifo); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h index 5caf81241dfe..bb1e2ce50256 100644 --- a/sound/soc/meson/axg-fifo.h +++ b/sound/soc/meson/axg-fifo.h @@ -61,6 +61,7 @@ struct snd_soc_pcm_runtime; #define STATUS1_INT_STS(x) ((x) << 0) #define FIFO_STATUS2 0x18 #define FIFO_INIT_ADDR 0x24 +#define FIFO_CTRL2 0x28 struct axg_fifo { struct regmap *map; diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 2b8807737b2b..6ab111c31b28 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -23,6 +23,12 @@ #define CTRL0_SEL3_SHIFT 8 #define CTRL0_SEL3_EN_SHIFT 11 #define CTRL1_FRDDR_FORCE_FINISH BIT(12) +#define CTRL2_SEL1_SHIFT 0 +#define CTRL2_SEL1_EN_SHIFT 4 +#define CTRL2_SEL2_SHIFT 8 +#define CTRL2_SEL2_EN_SHIFT 12 +#define CTRL2_SEL3_SHIFT 16 +#define CTRL2_SEL3_EN_SHIFT 20 static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -104,7 +110,7 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = { }; static const char * const axg_frddr_sel_texts[] = { - "OUT 0", "OUT 1", "OUT 2", "OUT 3" + "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7", }; static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, @@ -120,6 +126,10 @@ static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = { @@ -128,6 +138,10 @@ static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = { { "OUT 1", "OUT 1", "SINK SEL" }, { "OUT 2", "OUT 2", "SINK SEL" }, { "OUT 3", "OUT 3", "SINK SEL" }, + { "OUT 4", "OUT 4", "SINK SEL" }, + { "OUT 5", "OUT 5", "SINK SEL" }, + { "OUT 6", "OUT 6", "SINK SEL" }, + { "OUT 7", "OUT 7", "SINK SEL" }, }; static const struct snd_soc_component_driver axg_frddr_component_drv = { @@ -162,16 +176,12 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = { .pcm_new = axg_frddr_pcm_new, }; -static const char * const g12a_frddr_sel_texts[] = { - "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", -}; - static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT, - g12a_frddr_sel_texts); + axg_frddr_sel_texts); static const struct snd_kcontrol_new g12a_frddr_out1_demux = SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum); @@ -211,6 +221,9 @@ static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { @@ -228,16 +241,25 @@ static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { { "OUT 2", "OUT 2", "SINK 1 SEL" }, { "OUT 3", "OUT 3", "SINK 1 SEL" }, { "OUT 4", "OUT 4", "SINK 1 SEL" }, + { "OUT 5", "OUT 5", "SINK 1 SEL" }, + { "OUT 6", "OUT 6", "SINK 1 SEL" }, + { "OUT 7", "OUT 7", "SINK 1 SEL" }, { "OUT 0", "OUT 0", "SINK 2 SEL" }, { "OUT 1", "OUT 1", "SINK 2 SEL" }, { "OUT 2", "OUT 2", "SINK 2 SEL" }, { "OUT 3", "OUT 3", "SINK 2 SEL" }, { "OUT 4", "OUT 4", "SINK 2 SEL" }, + { "OUT 5", "OUT 5", "SINK 2 SEL" }, + { "OUT 6", "OUT 6", "SINK 2 SEL" }, + { "OUT 7", "OUT 7", "SINK 2 SEL" }, { "OUT 0", "OUT 0", "SINK 3 SEL" }, { "OUT 1", "OUT 1", "SINK 3 SEL" }, { "OUT 2", "OUT 2", "SINK 3 SEL" }, { "OUT 3", "OUT 3", "SINK 3 SEL" }, { "OUT 4", "OUT 4", "SINK 3 SEL" }, + { "OUT 5", "OUT 5", "SINK 3 SEL" }, + { "OUT 6", "OUT 6", "SINK 3 SEL" }, + { "OUT 7", "OUT 7", "SINK 3 SEL" }, }; static const struct snd_soc_component_driver g12a_frddr_component_drv = { @@ -253,6 +275,70 @@ static const struct axg_fifo_match_data g12a_frddr_match_data = { .dai_drv = &g12a_frddr_dai_drv }; +/* On SM1, the output selection in on CTRL2 */ +static const struct snd_kcontrol_new sm1_frddr_out1_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL1_EN_SHIFT, 1, 0); +static const struct snd_kcontrol_new sm1_frddr_out2_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL2_EN_SHIFT, 1, 0); +static const struct snd_kcontrol_new sm1_frddr_out3_enable = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2, + CTRL2_SEL3_EN_SHIFT, 1, 0); + +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT, + axg_frddr_sel_texts); +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT, + axg_frddr_sel_texts); +static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT, + axg_frddr_sel_texts); + +static const struct snd_kcontrol_new sm1_frddr_out1_demux = + SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum); +static const struct snd_kcontrol_new sm1_frddr_out2_demux = + SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum); +static const struct snd_kcontrol_new sm1_frddr_out3_demux = + SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum); + +static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out1_enable), + SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out2_enable), + SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out3_enable), + SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out1_demux), + SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out2_demux), + SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, + &sm1_frddr_out3_demux), + SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_component_driver sm1_frddr_component_drv = { + .dapm_widgets = sm1_frddr_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets), + .dapm_routes = g12a_frddr_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), + .ops = &g12a_fifo_pcm_ops +}; + +static const struct axg_fifo_match_data sm1_frddr_match_data = { + .component_drv = &sm1_frddr_component_drv, + .dai_drv = &g12a_frddr_dai_drv +}; + static const struct of_device_id axg_frddr_of_match[] = { { .compatible = "amlogic,axg-frddr", @@ -260,6 +346,9 @@ static const struct of_device_id axg_frddr_of_match[] = { }, { .compatible = "amlogic,g12a-frddr", .data = &g12a_frddr_match_data, + }, { + .compatible = "amlogic,sm1-frddr", + .data = &sm1_frddr_match_data, }, {} }; MODULE_DEVICE_TABLE(of, axg_frddr_of_match); diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c index 9d5684493ffc..bfd37d49a73e 100644 --- a/sound/soc/meson/axg-pdm.c +++ b/sound/soc/meson/axg-pdm.c @@ -585,7 +585,6 @@ static int axg_pdm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct axg_pdm *priv; - struct resource *res; void __iomem *regs; int ret; @@ -600,8 +599,7 @@ static int axg_pdm_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c index 01b2035fa841..d0d09f945b48 100644 --- a/sound/soc/meson/axg-spdifin.c +++ b/sound/soc/meson/axg-spdifin.c @@ -453,7 +453,6 @@ static int axg_spdifin_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axg_spdifin *priv; struct snd_soc_dai_driver *dai_drv; - struct resource *res; void __iomem *regs; int ret; @@ -468,8 +467,7 @@ static int axg_spdifin_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c index 9dea528053ad..7ce6aa97ddf7 100644 --- a/sound/soc/meson/axg-spdifout.c +++ b/sound/soc/meson/axg-spdifout.c @@ -401,7 +401,6 @@ static int axg_spdifout_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct axg_spdifout *priv; - struct resource *res; void __iomem *regs; int ret; @@ -410,8 +409,7 @@ static int axg_spdifout_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, priv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 1a0bf9d3836d..358c8c0d861c 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -253,7 +253,6 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct axg_tdm_formatter_driver *drv; struct axg_tdm_formatter *formatter; - struct resource *res; void __iomem *regs; int ret; @@ -269,8 +268,7 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) platform_set_drvdata(pdev, formatter); formatter->drv = drv; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c index cb87f17f3e95..973d4c02ef8d 100644 --- a/sound/soc/meson/axg-tdmin.c +++ b/sound/soc/meson/axg-tdmin.c @@ -43,7 +43,8 @@ static const struct regmap_config axg_tdmin_regmap_cfg = { }; static const char * const axg_tdmin_sel_texts[] = { - "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7", + "IN 8", "IN 9", "IN 10", "IN 11", "IN 12", "IN 13", "IN 14", "IN 15", }; /* Change to special mux control to reset dapm */ @@ -164,12 +165,22 @@ static int axg_tdmin_prepare(struct regmap *map, } static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = { - SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 11", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 12", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 13", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 14", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 15", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmin_in_mux), SND_SOC_DAPM_PGA_E("DEC", SND_SOC_NOPM, 0, 0, NULL, 0, axg_tdm_formatter_event, @@ -178,12 +189,22 @@ static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = { }; static const struct snd_soc_dapm_route axg_tdmin_dapm_routes[] = { - { "SRC SEL", "IN 0", "IN 0" }, - { "SRC SEL", "IN 1", "IN 1" }, - { "SRC SEL", "IN 2", "IN 2" }, - { "SRC SEL", "IN 3", "IN 3" }, - { "SRC SEL", "IN 4", "IN 4" }, - { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, + { "SRC SEL", "IN 8", "IN 8" }, + { "SRC SEL", "IN 9", "IN 9" }, + { "SRC SEL", "IN 10", "IN 10" }, + { "SRC SEL", "IN 11", "IN 11" }, + { "SRC SEL", "IN 12", "IN 12" }, + { "SRC SEL", "IN 13", "IN 13" }, + { "SRC SEL", "IN 14", "IN 14" }, + { "SRC SEL", "IN 15", "IN 15" }, { "DEC", NULL, "SRC SEL" }, { "OUT", NULL, "DEC" }, }; diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c index 86537fc0ecb5..418ec314b37d 100644 --- a/sound/soc/meson/axg-tdmout.c +++ b/sound/soc/meson/axg-tdmout.c @@ -24,6 +24,7 @@ #define TDMOUT_CTRL1 0x04 #define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4) #define TDMOUT_CTRL1_TYPE(x) ((x) << 4) +#define SM1_TDMOUT_CTRL1_GAIN_EN 7 #define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8) #define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8) #define TDMOUT_CTRL1_SEL_SHIFT 24 @@ -51,25 +52,6 @@ static const struct regmap_config axg_tdmout_regmap_cfg = { .max_register = TDMOUT_MASK_VAL, }; -static const struct snd_kcontrol_new axg_tdmout_controls[] = { - SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), - SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), - SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), - SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), - SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, - TDMOUT_CTRL1_GAIN_EN, 1, 0), -}; - -static const char * const tdmout_sel_texts[] = { - "IN 0", "IN 1", "IN 2", -}; - -static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, - TDMOUT_CTRL1_SEL_SHIFT, tdmout_sel_texts); - -static const struct snd_kcontrol_new axg_tdmout_in_mux = - SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); - static struct snd_soc_dai * axg_tdmout_get_be(struct snd_soc_dapm_widget *w) { @@ -197,6 +179,25 @@ static int axg_tdmout_prepare(struct regmap *map, return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0); } +static const struct snd_kcontrol_new axg_tdmout_controls[] = { + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, + TDMOUT_CTRL1_GAIN_EN, 1, 0), +}; + +static const char * const axg_tdmout_sel_texts[] = { + "IN 0", "IN 1", "IN 2", +}; + +static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1, + TDMOUT_CTRL1_SEL_SHIFT, axg_tdmout_sel_texts); + +static const struct snd_kcontrol_new axg_tdmout_in_mux = + SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum); + static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), @@ -252,6 +253,67 @@ static const struct axg_tdm_formatter_driver g12a_tdmout_drv = { }, }; +static const struct snd_kcontrol_new sm1_tdmout_controls[] = { + SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0), + SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0), + SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0), + SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0), + SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1, + SM1_TDMOUT_CTRL1_GAIN_EN, 1, 0), +}; + +static const char * const sm1_tdmout_sel_texts[] = { + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", +}; + +static SOC_ENUM_SINGLE_DECL(sm1_tdmout_sel_enum, TDMOUT_CTRL1, + TDMOUT_CTRL1_SEL_SHIFT, sm1_tdmout_sel_texts); + +static const struct snd_kcontrol_new sm1_tdmout_in_mux = + SOC_DAPM_ENUM("Input Source", sm1_tdmout_sel_enum); + +static const struct snd_soc_dapm_widget sm1_tdmout_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_tdmout_in_mux), + SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0, + axg_tdm_formatter_event, + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), + SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sm1_tdmout_dapm_routes[] = { + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "ENC", NULL, "SRC SEL" }, + { "OUT", NULL, "ENC" }, +}; + +static const struct snd_soc_component_driver sm1_tdmout_component_drv = { + .controls = sm1_tdmout_controls, + .num_controls = ARRAY_SIZE(sm1_tdmout_controls), + .dapm_widgets = sm1_tdmout_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_tdmout_dapm_widgets), + .dapm_routes = sm1_tdmout_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sm1_tdmout_dapm_routes), +}; + +static const struct axg_tdm_formatter_driver sm1_tdmout_drv = { + .component_drv = &sm1_tdmout_component_drv, + .regmap_cfg = &axg_tdmout_regmap_cfg, + .ops = &axg_tdmout_ops, + .quirks = &(const struct axg_tdm_formatter_hw) { + .invert_sclk = true, + .skew_offset = 2, + }, +}; + static const struct of_device_id axg_tdmout_of_match[] = { { .compatible = "amlogic,axg-tdmout", @@ -259,6 +321,9 @@ static const struct of_device_id axg_tdmout_of_match[] = { }, { .compatible = "amlogic,g12a-tdmout", .data = &g12a_tdmout_drv, + }, { + .compatible = "amlogic,sm1-tdmout", + .data = &sm1_tdmout_drv, }, {} }; MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c index 4f63e434fad4..c8ea2145f576 100644 --- a/sound/soc/meson/axg-toddr.c +++ b/sound/soc/meson/axg-toddr.c @@ -25,6 +25,7 @@ #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) #define CTRL1_TODDR_FORCE_FINISH BIT(25) +#define CTRL1_SEL_SHIFT 28 #define TODDR_MSB_POS 31 @@ -142,16 +143,11 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = { }; static const char * const axg_toddr_sel_texts[] = { - "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 6" + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7" }; -static const unsigned int axg_toddr_sel_values[] = { - 0, 1, 2, 3, 4, 6 -}; - -static SOC_VALUE_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0, - CTRL0_SEL_SHIFT, CTRL0_SEL_MASK, - axg_toddr_sel_texts, axg_toddr_sel_values); +static SOC_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, + axg_toddr_sel_texts); static const struct snd_kcontrol_new axg_toddr_in_mux = SOC_DAPM_ENUM("Input Source", axg_toddr_sel_enum); @@ -163,7 +159,9 @@ static const struct snd_soc_dapm_widget axg_toddr_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = { @@ -173,7 +171,9 @@ static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = { { "SRC SEL", "IN 2", "IN 2" }, { "SRC SEL", "IN 3", "IN 3" }, { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, }; static const struct snd_soc_component_driver axg_toddr_component_drv = { @@ -222,6 +222,70 @@ static const struct axg_fifo_match_data g12a_toddr_match_data = { .dai_drv = &g12a_toddr_dai_drv }; +static const char * const sm1_toddr_sel_texts[] = { + "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5", "IN 6", "IN 7", + "IN 8", "IN 9", "IN 10", "IN 11", "IN 12", "IN 13", "IN 14", "IN 15" +}; + +static SOC_ENUM_SINGLE_DECL(sm1_toddr_sel_enum, FIFO_CTRL1, CTRL1_SEL_SHIFT, + sm1_toddr_sel_texts); + +static const struct snd_kcontrol_new sm1_toddr_in_mux = + SOC_DAPM_ENUM("Input Source", sm1_toddr_sel_enum); + +static const struct snd_soc_dapm_widget sm1_toddr_dapm_widgets[] = { + SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &sm1_toddr_in_mux), + SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 11", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 12", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 13", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 14", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("IN 15", NULL, 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sm1_toddr_dapm_routes[] = { + { "Capture", NULL, "SRC SEL" }, + { "SRC SEL", "IN 0", "IN 0" }, + { "SRC SEL", "IN 1", "IN 1" }, + { "SRC SEL", "IN 2", "IN 2" }, + { "SRC SEL", "IN 3", "IN 3" }, + { "SRC SEL", "IN 4", "IN 4" }, + { "SRC SEL", "IN 5", "IN 5" }, + { "SRC SEL", "IN 6", "IN 6" }, + { "SRC SEL", "IN 7", "IN 7" }, + { "SRC SEL", "IN 8", "IN 8" }, + { "SRC SEL", "IN 9", "IN 9" }, + { "SRC SEL", "IN 10", "IN 10" }, + { "SRC SEL", "IN 11", "IN 11" }, + { "SRC SEL", "IN 12", "IN 12" }, + { "SRC SEL", "IN 13", "IN 13" }, + { "SRC SEL", "IN 14", "IN 14" }, + { "SRC SEL", "IN 15", "IN 15" }, +}; + +static const struct snd_soc_component_driver sm1_toddr_component_drv = { + .dapm_widgets = sm1_toddr_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sm1_toddr_dapm_widgets), + .dapm_routes = sm1_toddr_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sm1_toddr_dapm_routes), + .ops = &g12a_fifo_pcm_ops +}; + +static const struct axg_fifo_match_data sm1_toddr_match_data = { + .component_drv = &sm1_toddr_component_drv, + .dai_drv = &g12a_toddr_dai_drv +}; + static const struct of_device_id axg_toddr_of_match[] = { { .compatible = "amlogic,axg-toddr", @@ -229,6 +293,9 @@ static const struct of_device_id axg_toddr_of_match[] = { }, { .compatible = "amlogic,g12a-toddr", .data = &g12a_toddr_match_data, + }, { + .compatible = "amlogic,sm1-toddr", + .data = &sm1_toddr_match_data, }, {} }; MODULE_DEVICE_TABLE(of, axg_toddr_of_match); diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c index 707ccb192e4c..9cfbd343a00c 100644 --- a/sound/soc/meson/g12a-tohdmitx.c +++ b/sound/soc/meson/g12a-tohdmitx.c @@ -28,7 +28,7 @@ #define CTRL0_SPDIF_CLK_SEL BIT(0) struct g12a_tohdmitx_input { - struct snd_pcm_hw_params params; + struct snd_soc_pcm_stream params; unsigned int fmt; }; @@ -225,26 +225,17 @@ static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, { struct g12a_tohdmitx_input *data = dai->playback_dma_data; - /* Save the stream params for the downstream link */ - memcpy(&data->params, params, sizeof(*params)); + data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); + data->params.rate_min = params_rate(params); + data->params.rate_max = params_rate(params); + data->params.formats = 1 << params_format(params); + data->params.channels_min = params_channels(params); + data->params.channels_max = params_channels(params); + data->params.sig_bits = dai->driver->playback.sig_bits; return 0; } -static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct g12a_tohdmitx_input *in_data = - g12a_tohdmitx_get_input_data(dai->capture_widget); - - if (!in_data) - return -ENODEV; - - memcpy(params, &in_data->params, sizeof(*params)); - - return 0; -} static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) @@ -266,6 +257,14 @@ static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, if (!in_data) return -ENODEV; + if (WARN_ON(!rtd->dai_link->params)) { + dev_warn(dai->dev, "codec2codec link expected\n"); + return -EINVAL; + } + + /* Replace link params with the input params */ + rtd->dai_link->params = &in_data->params; + if (!in_data->fmt) return 0; @@ -278,7 +277,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { }; static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { - .hw_params = g12a_tohdmitx_output_hw_params, .startup = g12a_tohdmitx_output_startup, }; @@ -378,12 +376,10 @@ MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match); static int g12a_tohdmitx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; void __iomem *regs; struct regmap *map; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 269b6d6df250..1e38ce858326 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -732,7 +732,6 @@ static int mxs_saif_mclk_init(struct platform_device *pdev) static int mxs_saif_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *iores; struct mxs_saif *saif; int irq, ret = 0; struct device_node *master; @@ -786,19 +785,13 @@ static int mxs_saif_probe(struct platform_device *pdev) return ret; } - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - saif->base = devm_ioremap_resource(&pdev->dev, iores); + saif->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(saif->base)) return PTR_ERR(saif->base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(&pdev->dev, "failed to get irq resource: %d\n", - ret); - return ret; - } + if (irq < 0) + return irq; saif->dev = &pdev->dev; ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig deleted file mode 100644 index e1b22fbcb159..000000000000 --- a/sound/soc/nuc900/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -## -## NUC900 series AC97 API -## -config SND_SOC_NUC900 - tristate "SoC Audio for NUC900 series" - depends on ARCH_W90X900 - select SND_SOC_NUC900_AC97 - help - This option enables support for AC97 mode on the NUC900 SoC. - -config SND_SOC_NUC900_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_NUC900EVB - tristate "NUC900 AC97 support for demo board" - depends on SND_SOC_NUC900 - select SND_SOC_NUC900_AC97 - select SND_SOC_AC97_CODEC - help - Select this option to enable audio (AC97) on the - NUC900 demoboard. diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile deleted file mode 100644 index c7ba2b9549d2..000000000000 --- a/sound/soc/nuc900/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# NUC900 series audio -snd-soc-nuc900-pcm-objs := nuc900-pcm.o -snd-soc-nuc900-ac97-objs := nuc900-ac97.o - -obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o -obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o - -# Boards -snd-soc-nuc900-audio-objs := nuc900-audio.o - -obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c deleted file mode 100644 index 5f2e5c069377..000000000000 --- a/sound/soc/nuc900/nuc900-ac97.c +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2009-2010 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/suspend.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/soc.h> -#include <linux/clk.h> - -#include <mach/mfp.h> - -#include "nuc900-audio.h" - -static DEFINE_MUTEX(ac97_mutex); -struct nuc900_audio *nuc900_ac97_data; -EXPORT_SYMBOL_GPL(nuc900_ac97_data); - -static int nuc900_checkready(void) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - - if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY)) - return -EPERM; - - return 0; -} - -/* AC97 controller reads codec register */ -static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long timeout = 0x10000, val; - - mutex_lock(&ac97_mutex); - - val = nuc900_checkready(); - if (val) { - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - goto out; - } - - /* set the R_WB bit and write register index */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg); - - /* set the valid frame bit and valid slots */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - val |= (VALID_FRAME | SLOT1_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); - - udelay(100); - - /* polling the AC_R_FINISH */ - while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH) - && --timeout) - mdelay(1); - - if (!timeout) { - dev_err(nuc900_audio->dev, "AC97 read register time out !\n"); - val = -EPERM; - goto out; - } - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ; - val &= ~SLOT1_VALID; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val); - - if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) { - dev_err(nuc900_audio->dev, - "R_INDEX of REG_ACTL_ACIS1 not match!\n"); - } - - udelay(100); - val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF); - -out: - mutex_unlock(&ac97_mutex); - return val; -} - -/* AC97 controller writes to codec register */ -static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long tmp, timeout = 0x10000; - - mutex_lock(&ac97_mutex); - - tmp = nuc900_checkready(); - if (tmp) - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - - /* clear the R_WB bit and write register index */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg); - - /* write register value */ - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val); - - /* set the valid frame bit and valid slots */ - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - udelay(100); - - /* polling the AC_W_FINISH */ - while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH) - && --timeout) - mdelay(1); - - if (!timeout) - dev_err(nuc900_audio->dev, "AC97 write register time out !\n"); - - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp &= ~(SLOT1_VALID | SLOT2_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - mutex_unlock(&ac97_mutex); - -} - -static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* warm reset AC 97 */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val |= AC_W_RES; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - udelay(100); - - val = nuc900_checkready(); - if (val) - dev_err(nuc900_audio->dev, "AC97 codec is not ready\n"); - - mutex_unlock(&ac97_mutex); -} - -static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* reset Audio Controller */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val |= ACTL_RESET_BIT; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val &= (~ACTL_RESET_BIT); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - /* reset AC-link interface */ - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val |= AC_RESET; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - val &= ~AC_RESET; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - /* cold reset AC 97 */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val |= AC_C_RES; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON); - val &= (~AC_C_RES); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val); - - udelay(100); - - mutex_unlock(&ac97_mutex); - -} - -/* AC97 controller operations */ -static struct snd_ac97_bus_ops nuc900_ac97_ops = { - .read = nuc900_ac97_read, - .write = nuc900_ac97_write, - .reset = nuc900_ac97_cold_reset, - .warm_reset = nuc900_ac97_warm_reset, -}; - -static int nuc900_ac97_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - int ret; - unsigned long val, tmp; - - ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); - tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp); - val |= AC_PLAY; - } else { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); - tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ); - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp); - val |= AC_RECORD; - } - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0); - tmp &= ~(SLOT3_VALID | SLOT4_VALID); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp); - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR); - val &= ~AC_PLAY; - } else { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR); - val &= ~AC_RECORD; - } - - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int nuc900_ac97_probe(struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - unsigned long val; - - mutex_lock(&ac97_mutex); - - /* enable unit clock */ - clk_enable(nuc900_audio->clk); - - /* enable audio controller and AC-link interface */ - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val |= (IIS_AC_PIN_SEL | ACLINK_EN); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); - - mutex_unlock(&ac97_mutex); - - return 0; -} - -static int nuc900_ac97_remove(struct snd_soc_dai *dai) -{ - struct nuc900_audio *nuc900_audio = nuc900_ac97_data; - - clk_disable(nuc900_audio->clk); - return 0; -} - -static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = { - .trigger = nuc900_ac97_trigger, -}; - -static struct snd_soc_dai_driver nuc900_ac97_dai = { - .probe = nuc900_ac97_probe, - .remove = nuc900_ac97_remove, - .bus_control = true, - .playback = { - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .channels_min = 1, - .channels_max = 2, - }, - .capture = { - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .channels_min = 1, - .channels_max = 2, - }, - .ops = &nuc900_ac97_dai_ops, -}; - -static const struct snd_soc_component_driver nuc900_ac97_component = { - .name = "nuc900-ac97", -}; - -static int nuc900_ac97_drvprobe(struct platform_device *pdev) -{ - struct nuc900_audio *nuc900_audio; - int ret; - - if (nuc900_ac97_data) - return -EBUSY; - - nuc900_audio = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_audio), - GFP_KERNEL); - if (!nuc900_audio) - return -ENOMEM; - - spin_lock_init(&nuc900_audio->lock); - - nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev, - nuc900_audio->res); - if (IS_ERR(nuc900_audio->mmio)) - return PTR_ERR(nuc900_audio->mmio); - - nuc900_audio->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(nuc900_audio->clk)) { - ret = PTR_ERR(nuc900_audio->clk); - goto out; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto out; - nuc900_audio->irq_num = ret; - - nuc900_ac97_data = nuc900_audio; - - ret = snd_soc_set_ac97_ops(&nuc900_ac97_ops); - if (ret) - goto out; - - ret = devm_snd_soc_register_component(&pdev->dev, &nuc900_ac97_component, - &nuc900_ac97_dai, 1); - if (ret) - goto out; - - /* enbale ac97 multifunction pin */ - mfp_set_groupg(nuc900_audio->dev, NULL); - - return 0; - -out: - snd_soc_set_ac97_ops(NULL); - return ret; -} - -static int nuc900_ac97_drvremove(struct platform_device *pdev) -{ - nuc900_ac97_data = NULL; - snd_soc_set_ac97_ops(NULL); - - return 0; -} - -static struct platform_driver nuc900_ac97_driver = { - .driver = { - .name = "nuc900-ac97", - }, - .probe = nuc900_ac97_drvprobe, - .remove = nuc900_ac97_drvremove, -}; - -module_platform_driver(nuc900_ac97_driver); - -MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("NUC900 AC97 SoC driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-ac97"); diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c deleted file mode 100644 index 19146690d514..000000000000 --- a/sound/soc/nuc900/nuc900-audio.c +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> - -#include "nuc900-audio.h" - -SND_SOC_DAILINK_DEFS(ac97, - DAILINK_COMP_ARRAY(COMP_CPU("nuc900-ac97")), - DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("nuc900-pcm-audio"))); - -static struct snd_soc_dai_link nuc900evb_ac97_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - SND_SOC_DAILINK_REG(ac97), -}; - -static struct snd_soc_card nuc900evb_audio_machine = { - .name = "NUC900EVB_AC97", - .owner = THIS_MODULE, - .dai_link = &nuc900evb_ac97_dai, - .num_links = 1, -}; - -static struct platform_device *nuc900evb_asoc_dev; - -static int __init nuc900evb_audio_init(void) -{ - int ret; - - ret = -ENOMEM; - nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1); - if (!nuc900evb_asoc_dev) - goto out; - - /* nuc900 board audio device */ - platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine); - - ret = platform_device_add(nuc900evb_asoc_dev); - - if (ret) { - platform_device_put(nuc900evb_asoc_dev); - nuc900evb_asoc_dev = NULL; - } - -out: - return ret; -} - -static void __exit nuc900evb_audio_exit(void) -{ - platform_device_unregister(nuc900evb_asoc_dev); -} - -module_init(nuc900evb_audio_init); -module_exit(nuc900evb_audio_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("NUC900 Series ASoC audio support"); -MODULE_AUTHOR("Wan ZongShun"); diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h deleted file mode 100644 index 90ffa7bbce01..000000000000 --- a/sound/soc/nuc900/nuc900-audio.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - */ - -#ifndef _NUC900_AUDIO_H -#define _NUC900_AUDIO_H - -#include <linux/io.h> - -/* Audio Control Registers */ -#define ACTL_CON 0x00 -#define ACTL_RESET 0x04 -#define ACTL_RDSTB 0x08 -#define ACTL_RDST_LENGTH 0x0C -#define ACTL_RDSTC 0x10 -#define ACTL_RSR 0x14 -#define ACTL_PDSTB 0x18 -#define ACTL_PDST_LENGTH 0x1C -#define ACTL_PDSTC 0x20 -#define ACTL_PSR 0x24 -#define ACTL_IISCON 0x28 -#define ACTL_ACCON 0x2C -#define ACTL_ACOS0 0x30 -#define ACTL_ACOS1 0x34 -#define ACTL_ACOS2 0x38 -#define ACTL_ACIS0 0x3C -#define ACTL_ACIS1 0x40 -#define ACTL_ACIS2 0x44 -#define ACTL_COUNTER 0x48 - -/* bit definition of REG_ACTL_CON register */ -#define R_DMA_IRQ 0x1000 -#define T_DMA_IRQ 0x0800 -#define IIS_AC_PIN_SEL 0x0100 -#define FIFO_TH 0x0080 -#define ADC_EN 0x0010 -#define M80_EN 0x0008 -#define ACLINK_EN 0x0004 -#define IIS_EN 0x0002 - -/* bit definition of REG_ACTL_RESET register */ -#define W5691_PLAY 0x20000 -#define ACTL_RESET_BIT 0x10000 -#define RECORD_RIGHT_CHNNEL 0x08000 -#define RECORD_LEFT_CHNNEL 0x04000 -#define PLAY_RIGHT_CHNNEL 0x02000 -#define PLAY_LEFT_CHNNEL 0x01000 -#define DAC_PLAY 0x00800 -#define ADC_RECORD 0x00400 -#define M80_PLAY 0x00200 -#define AC_RECORD 0x00100 -#define AC_PLAY 0x00080 -#define IIS_RECORD 0x00040 -#define IIS_PLAY 0x00020 -#define DAC_RESET 0x00010 -#define ADC_RESET 0x00008 -#define M80_RESET 0x00004 -#define AC_RESET 0x00002 -#define IIS_RESET 0x00001 - -/* bit definition of REG_ACTL_ACCON register */ -#define AC_BCLK_PU_EN 0x20 -#define AC_R_FINISH 0x10 -#define AC_W_FINISH 0x08 -#define AC_W_RES 0x04 -#define AC_C_RES 0x02 - -/* bit definition of ACTL_RSR register */ -#define R_FIFO_EMPTY 0x04 -#define R_DMA_END_IRQ 0x02 -#define R_DMA_MIDDLE_IRQ 0x01 - -/* bit definition of ACTL_PSR register */ -#define P_FIFO_EMPTY 0x04 -#define P_DMA_END_IRQ 0x02 -#define P_DMA_MIDDLE_IRQ 0x01 - -/* bit definition of ACTL_ACOS0 register */ -#define SLOT1_VALID 0x01 -#define SLOT2_VALID 0x02 -#define SLOT3_VALID 0x04 -#define SLOT4_VALID 0x08 -#define VALID_FRAME 0x10 - -/* bit definition of ACTL_ACOS1 register */ -#define R_WB 0x80 - -#define CODEC_READY 0x10 -#define RESET_PRSR 0x00 -#define AUDIO_WRITE(addr, val) __raw_writel(val, addr) -#define AUDIO_READ(addr) __raw_readl(addr) - -struct nuc900_audio { - void __iomem *mmio; - spinlock_t lock; - unsigned long irq_num; - struct resource *res; - struct clk *clk; - struct device *dev; - -}; - -extern struct nuc900_audio *nuc900_ac97_data; - -#endif /*end _NUC900_AUDIO_H */ diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c deleted file mode 100644 index 4442a26e9502..000000000000 --- a/sound/soc/nuc900/nuc900-pcm.c +++ /dev/null @@ -1,321 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2010 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include <mach/hardware.h> - -#include "nuc900-audio.h" - -static const struct snd_pcm_hardware nuc900_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .buffer_bytes_max = 4*1024, - .period_bytes_min = 1*1024, - .period_bytes_max = 4*1024, - .periods_min = 1, - .periods_max = 1024, -}; - -static int nuc900_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); -} - -static void nuc900_update_dma_register(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - void __iomem *mmio_addr, *mmio_len; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - mmio_addr = nuc900_audio->mmio + ACTL_PDSTB; - mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH; - } else { - mmio_addr = nuc900_audio->mmio + ACTL_RDSTB; - mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH; - } - - AUDIO_WRITE(mmio_addr, runtime->dma_addr); - AUDIO_WRITE(mmio_len, runtime->dma_bytes); -} - -static void nuc900_dma_start(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long val; - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val |= (T_DMA_IRQ | R_DMA_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); -} - -static void nuc900_dma_stop(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long val; - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - val &= ~(T_DMA_IRQ | R_DMA_IRQ); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val); -} - -static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id) -{ - struct snd_pcm_substream *substream = dev_id; - struct nuc900_audio *nuc900_audio = substream->runtime->private_data; - unsigned long val; - - spin_lock(&nuc900_audio->lock); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON); - - if (val & R_DMA_IRQ) { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR); - - if (val & R_DMA_MIDDLE_IRQ) { - val |= R_DMA_MIDDLE_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); - } - - if (val & R_DMA_END_IRQ) { - val |= R_DMA_END_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val); - } - } else if (val & T_DMA_IRQ) { - AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR); - - if (val & P_DMA_MIDDLE_IRQ) { - val |= P_DMA_MIDDLE_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); - } - - if (val & P_DMA_END_IRQ) { - val |= P_DMA_END_IRQ; - AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val); - } - } else { - dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n"); - spin_unlock(&nuc900_audio->lock); - return IRQ_HANDLED; - } - - spin_unlock(&nuc900_audio->lock); - - snd_pcm_period_elapsed(substream); - - return IRQ_HANDLED; -} - -static int nuc900_dma_hw_free(struct snd_pcm_substream *substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int nuc900_dma_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - unsigned long flags, val; - int ret = 0; - - spin_lock_irqsave(&nuc900_audio->lock, flags); - - nuc900_update_dma_register(substream); - - val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET); - - switch (runtime->channels) { - case 1: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); - val |= PLAY_RIGHT_CHNNEL; - } else { - val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); - val |= RECORD_RIGHT_CHNNEL; - } - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - break; - case 2: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL); - else - val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL); - AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val); - break; - default: - ret = -EINVAL; - } - spin_unlock_irqrestore(&nuc900_audio->lock, flags); - return ret; -} - -static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - nuc900_dma_start(substream); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - nuc900_dma_stop(substream); - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int nuc900_dma_getposition(struct snd_pcm_substream *substream, - dma_addr_t *src, dma_addr_t *dst) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - - if (src != NULL) - *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC); - - if (dst != NULL) - *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC); - - return 0; -} - -static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - dma_addr_t src, dst; - unsigned long res; - - nuc900_dma_getposition(substream, &src, &dst); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - res = dst - runtime->dma_addr; - else - res = src - runtime->dma_addr; - - return bytes_to_frames(substream->runtime, res); -} - -static int nuc900_dma_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio; - - snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware); - - nuc900_audio = nuc900_ac97_data; - - if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt, - 0, "nuc900-dma", substream)) - return -EBUSY; - - runtime->private_data = nuc900_audio; - - return 0; -} - -static int nuc900_dma_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct nuc900_audio *nuc900_audio = runtime->private_data; - - free_irq(nuc900_audio->irq_num, substream); - - return 0; -} - -static int nuc900_dma_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area, - runtime->dma_addr, runtime->dma_bytes); -} - -static const struct snd_pcm_ops nuc900_dma_ops = { - .open = nuc900_dma_open, - .close = nuc900_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = nuc900_dma_hw_params, - .hw_free = nuc900_dma_hw_free, - .prepare = nuc900_dma_prepare, - .trigger = nuc900_dma_trigger, - .pointer = nuc900_dma_pointer, - .mmap = nuc900_dma_mmap, -}; - -static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - int ret; - - ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - card->dev, 4 * 1024, (4 * 1024) - 1); - - return 0; -} - -static const struct snd_soc_component_driver nuc900_soc_component = { - .ops = &nuc900_dma_ops, - .pcm_new = nuc900_dma_new, -}; - -static int nuc900_soc_platform_probe(struct platform_device *pdev) -{ - return devm_snd_soc_register_component(&pdev->dev, &nuc900_soc_component, - NULL, 0); -} - -static struct platform_driver nuc900_pcm_driver = { - .driver = { - .name = "nuc900-pcm-audio", - }, - - .probe = nuc900_soc_platform_probe, -}; - -module_platform_driver(nuc900_pcm_driver); - -MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("nuc900 Audio DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 72f4364b2d20..e3e5425b5c62 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -399,7 +399,6 @@ static const struct snd_soc_component_driver mmp_sspa_component = { static int asoc_mmp_sspa_probe(struct platform_device *pdev) { struct sspa_priv *priv; - struct resource *res; priv = devm_kzalloc(&pdev->dev, sizeof(struct sspa_priv), GFP_KERNEL); @@ -417,8 +416,7 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev) if (priv->dma_params == NULL) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res); + priv->sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->sspa->mmio_base)) return PTR_ERR(priv->sspa->mmio_base); diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 2c7348ddbbb3..6c20bdd850f3 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -53,12 +53,18 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link->num_cpus = 1; link->num_platforms = 1; + ret = of_property_read_string(np, "link-name", &link->name); + if (ret) { + dev_err(card->dev, "error getting codec dai_link name\n"); + goto err; + } + cpu = of_get_child_by_name(np, "cpu"); platform = of_get_child_by_name(np, "platform"); codec = of_get_child_by_name(np, "codec"); if (!cpu) { - dev_err(dev, "Can't find cpu DT node\n"); + dev_err(dev, "%s: Can't find cpu DT node\n", link->name); ret = -EINVAL; goto err; } @@ -66,7 +72,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = of_parse_phandle_with_args(cpu, "sound-dai", "#sound-dai-cells", 0, &args); if (ret) { - dev_err(card->dev, "error getting cpu phandle\n"); + dev_err(card->dev, "%s: error getting cpu phandle\n", link->name); goto err; } link->cpus->of_node = args.np; @@ -74,7 +80,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name); if (ret) { - dev_err(card->dev, "error getting cpu dai name\n"); + dev_err(card->dev, "%s: error getting cpu dai name\n", link->name); goto err; } @@ -83,14 +89,14 @@ int qcom_snd_parse_of(struct snd_soc_card *card) "sound-dai", 0); if (!link->platforms->of_node) { - dev_err(card->dev, "platform dai not found\n"); + dev_err(card->dev, "%s: platform dai not found\n", link->name); ret = -EINVAL; goto err; } ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { - dev_err(card->dev, "codec dai not found\n"); + dev_err(card->dev, "%s: codec dai not found\n", link->name); goto err; } link->no_pcm = 1; @@ -110,12 +116,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) } link->ignore_suspend = 1; - ret = of_property_read_string(np, "link-name", &link->name); - if (ret) { - dev_err(card->dev, "error getting codec dai_link name\n"); - goto err; - } - link->nonatomic = 1; link->dpcm_playback = 1; link->dpcm_capture = 1; diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index cf7a299f4547..4c745baa39f7 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -564,11 +564,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev) int ret; drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif"); - if (drvdata->lpaif_irq < 0) { - dev_err(&pdev->dev, "error getting irq handle: %d\n", - drvdata->lpaif_irq); + if (drvdata->lpaif_irq < 0) return -ENODEV; - } /* ensure audio hardware is disabled */ ret = regmap_write(drvdata->lpaif_map, diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 88ebaf6e1880..af2d5a6124c8 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -419,6 +419,9 @@ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, struct rk_i2s_dev *i2s = to_info(cpu_dai); int ret; + if (freq == 0) + return 0; + ret = clk_set_rate(i2s->mclk, freq); if (ret) dev_err(i2s->dev, "Fail to set mclk %d\n", ret); diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index d54f672d38d8..0097df1fae66 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -45,7 +45,6 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { static const struct snd_soc_dapm_route rk_audio_map[] = { {"IN34", NULL, "Headset Mic"}, - {"IN34", NULL, "MICBIAS"}, {"Headset Mic", NULL, "MICBIAS"}, {"DMICL", NULL, "Int Mic"}, {"Headphone", NULL, "HPL"}, @@ -172,7 +171,7 @@ static struct snd_soc_dai_link rk_dailink = { static int rk_98090_headset_init(struct snd_soc_component *component); static struct snd_soc_aux_dev rk_98090_headset_dev = { - .name = "Headset Chip", + .dlc = COMP_EMPTY(), .init = rk_98090_headset_init, }; @@ -238,9 +237,9 @@ static int snd_rk_mc_probe(struct platform_device *pdev) rk_dailink.platforms->of_node = rk_dailink.cpus->of_node; - rk_98090_headset_dev.codec_of_node = of_parse_phandle(np, + rk_98090_headset_dev.dlc.of_node = of_parse_phandle(np, "rockchip,headset-codec", 0); - if (!rk_98090_headset_dev.codec_of_node) { + if (!rk_98090_headset_dev.dlc.of_node) { dev_err(&pdev->dev, "Property 'rockchip,headset-codec' missing/invalid\n"); return -EINVAL; diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 396776ffd670..38f536bafa09 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -297,8 +297,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { static struct snd_soc_aux_dev neo1973_aux_devs[] = { { - .name = "dfbmcs320", - .codec_name = "dfbmcs320.0", + .dlc = COMP_AUX("dfbmcs320.0"), }, }; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 51e4c976c8be..9e58cbed942a 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -240,8 +240,7 @@ static int speyside_wm9081_init(struct snd_soc_component *component) static struct snd_soc_aux_dev speyside_aux_dev[] = { { - .name = "wm9081", - .codec_name = "wm9081.1-006c", + .dlc = COMP_AUX("wm9081.1-006c"), .init = speyside_wm9081_init, }, }; diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index c091033d17ad..bb9910d4cbe2 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -307,7 +307,6 @@ static struct snd_soc_aux_dev tm2_speaker_amp_dev; static int tm2_late_probe(struct snd_soc_card *card) { struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link_component dlc = { 0 }; unsigned int ch_map[] = { 0, 1 }; struct snd_soc_dai *amp_pdm_dai; struct snd_soc_pcm_runtime *rtd; @@ -334,8 +333,7 @@ static int tm2_late_probe(struct snd_soc_card *card) return ret; } - dlc.of_node = tm2_speaker_amp_dev.codec_of_node; - amp_pdm_dai = snd_soc_find_dai(&dlc); + amp_pdm_dai = snd_soc_find_dai(&tm2_speaker_amp_dev.dlc); if (!amp_pdm_dai) return -ENODEV; @@ -532,9 +530,9 @@ static int tm2_probe(struct platform_device *pdev) return ret; } - card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node, + card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, "audio-amplifier", 0); - if (!card->aux_dev[0].codec_of_node) { + if (!card->aux_dev[0].dlc.of_node) { dev_err(dev, "audio-amplifier property invalid or missing\n"); return -EINVAL; } @@ -623,7 +621,7 @@ dai_node_put: of_node_put(cpu_dai_node[i]); } - of_node_put(card->aux_dev[0].codec_of_node); + of_node_put(card->aux_dev[0].dlc.of_node); return ret; } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 56e8dae9a15c..bda5b958d0dc 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1421,6 +1421,20 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(hw_params)); } +static int rsnd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + int ret; + + ret = rsnd_dai_call(hw_free, io, substream); + if (ret) + return ret; + + return snd_pcm_lib_free_pages(substream); +} + static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); @@ -1436,7 +1450,7 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) static const struct snd_pcm_ops rsnd_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, .hw_params = rsnd_hw_params, - .hw_free = snd_pcm_lib_free_pages, + .hw_free = rsnd_hw_free, .pointer = rsnd_pointer, }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7727add3eb1a..ea6cbaa9743e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -327,6 +327,9 @@ struct rsnd_mod_ops { int (*cleanup)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*hw_free)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream); u32 *(*get_status)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); @@ -351,12 +354,12 @@ struct rsnd_mod { * * B 0: init 1: quit * C 0: start 1: stop + * D 0: hw_params 1: hw_free * * H is always called (see __rsnd_mod_call) * H 0: probe 1: remove * H 0: pcm_new * H 0: fallback - * H 0: hw_params * H 0: pointer * H 0: prepare * H 0: cleanup @@ -365,12 +368,13 @@ struct rsnd_mod { #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_hw_params 12 +#define __rsnd_mod_shift_hw_free 12 #define __rsnd_mod_shift_probe 28 /* always called */ #define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ -#define __rsnd_mod_shift_hw_params 28 /* always called */ #define __rsnd_mod_shift_pointer 28 /* always called */ #define __rsnd_mod_shift_prepare 28 /* always called */ #define __rsnd_mod_shift_cleanup 28 /* always called */ @@ -383,10 +387,11 @@ struct rsnd_mod { #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 #define __rsnd_mod_add_stop -1 +#define __rsnd_mod_add_hw_params 1 +#define __rsnd_mod_add_hw_free -1 #define __rsnd_mod_add_irq 0 #define __rsnd_mod_add_pcm_new 0 #define __rsnd_mod_add_fallback 0 -#define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_add_pointer 0 #define __rsnd_mod_call_probe 0 @@ -402,6 +407,7 @@ struct rsnd_mod { #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 #define __rsnd_mod_call_pointer 0 +#define __rsnd_mod_call_hw_free 1 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 8bab119c753a..2af0c6f14ee6 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -359,7 +359,6 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev) int ret; struct sirf_usp *usp; void __iomem *base; - struct resource *mem_res; usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp), GFP_KERNEL); @@ -368,8 +367,7 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, usp); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem_res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); usp->regmap = devm_regmap_init_mmio(&pdev->dev, base, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c new file mode 100644 index 000000000000..79ffc2820ba9 --- /dev/null +++ b/sound/soc/soc-component.c @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// soc-component.c +// +// Copyright (C) 2019 Renesas Electronics Corp. +// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +// +#include <linux/module.h> +#include <sound/soc.h> + +/** + * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. + * @component: COMPONENT + * @clk_id: DAI specific clock ID + * @source: Source for the clock + * @freq: new clock frequency in Hz + * @dir: new clock direction - input/output. + * + * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. + */ +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) +{ + if (component->driver->set_sysclk) + return component->driver->set_sysclk(component, clk_id, source, + freq, dir); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); + +/* + * snd_soc_component_set_pll - configure component PLL. + * @component: COMPONENT + * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL + * @freq_in: PLL input clock frequency in Hz + * @freq_out: requested PLL output clock frequency in Hz + * + * Configures and enables PLL to generate output clock based on input clock. + */ +int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) +{ + if (component->driver->set_pll) + return component->driver->set_pll(component, pll_id, source, + freq_in, freq_out); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); + +void snd_soc_component_seq_notifier(struct snd_soc_component *component, + enum snd_soc_dapm_type type, int subseq) +{ + if (component->driver->seq_notifier) + component->driver->seq_notifier(component, type, subseq); +} + +int snd_soc_component_stream_event(struct snd_soc_component *component, + int event) +{ + if (component->driver->stream_event) + return component->driver->stream_event(component, event); + + return 0; +} + +int snd_soc_component_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + if (component->driver->set_bias_level) + return component->driver->set_bias_level(component, level); + + return 0; +} + +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); + +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); + +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); + +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); + +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); + +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); + +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_get_pin_status(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_get_pin_status(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); + +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); + +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); + +/** + * snd_soc_component_set_jack - configure component jack. + * @component: COMPONENTs + * @jack: structure to use for the jack + * @data: can be used if codec driver need extra data for configuring jack + * + * Configures and enables jack detection function. + */ +int snd_soc_component_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (component->driver->set_jack) + return component->driver->set_jack(component, jack, data); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); + +int snd_soc_component_module_get(struct snd_soc_component *component, + int upon_open) +{ + if (component->driver->module_get_upon_open == !!upon_open && + !try_module_get(component->dev->driver->owner)) + return -ENODEV; + + return 0; +} + +void snd_soc_component_module_put(struct snd_soc_component *component, + int upon_open) +{ + if (component->driver->module_get_upon_open == !!upon_open) + module_put(component->dev->driver->owner); +} + +int snd_soc_component_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->open) + return component->driver->ops->open(substream); + + return 0; +} + +int snd_soc_component_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->close) + return component->driver->ops->close(substream); + + return 0; +} + +int snd_soc_component_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->prepare) + return component->driver->ops->prepare(substream); + + return 0; +} + +int snd_soc_component_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + if (component->driver->ops && + component->driver->ops->hw_params) + return component->driver->ops->hw_params(substream, params); + + return 0; +} + +int snd_soc_component_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + if (component->driver->ops && + component->driver->ops->hw_free) + return component->driver->ops->hw_free(substream); + + return 0; +} + +int snd_soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) +{ + if (component->driver->ops && + component->driver->ops->trigger) + return component->driver->ops->trigger(substream, cmd); + + return 0; +} + +void snd_soc_component_suspend(struct snd_soc_component *component) +{ + if (component->driver->suspend) + component->driver->suspend(component); + component->suspended = 1; +} + +void snd_soc_component_resume(struct snd_soc_component *component) +{ + if (component->driver->resume) + component->driver->resume(component); + component->suspended = 0; +} + +int snd_soc_component_is_suspended(struct snd_soc_component *component) +{ + return component->suspended; +} + +int snd_soc_component_probe(struct snd_soc_component *component) +{ + if (component->driver->probe) + return component->driver->probe(component); + + return 0; +} + +void snd_soc_component_remove(struct snd_soc_component *component) +{ + if (component->driver->remove) + component->driver->remove(component); +} + +int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, + struct device_node *ep) +{ + if (component->driver->of_xlate_dai_id) + return component->driver->of_xlate_dai_id(component, ep); + + return -ENOTSUPP; +} + +int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name) +{ + if (component->driver->of_xlate_dai_name) + return component->driver->of_xlate_dai_name(component, + args, dai_name); + return -ENOTSUPP; +} + +int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME: use 1st pointer */ + if (component->driver->ops && + component->driver->ops->pointer) + return component->driver->ops->pointer(substream); + } + + return 0; +} + +int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + struct snd_soc_rtdcom_list *rtdcom; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME: use 1st ioctl */ + if (component->driver->ops && + component->driver->ops->ioctl) + return component->driver->ops->ioctl(substream, + cmd, arg); + } + + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st copy now */ + if (component->driver->ops && + component->driver->ops->copy_user) + return component->driver->ops->copy_user( + substream, channel, pos, buf, bytes); + } + + return -EINVAL; +} + +struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + struct page *page; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st page now */ + if (component->driver->ops && + component->driver->ops->page) { + page = component->driver->ops->page(substream, offset); + if (page) + return page; + } + } + + return NULL; +} + +int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* FIXME. it returns 1st mmap now */ + if (component->driver->ops && + component->driver->ops->mmap) + return component->driver->ops->mmap(substream, vma); + } + + return -EINVAL; +} + +int snd_soc_pcm_component_new(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->pcm_new) { + ret = component->driver->pcm_new(rtd); + if (ret < 0) + return ret; + } + } + + return 0; +} + +void snd_soc_pcm_component_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->pcm_free) + component->driver->pcm_free(pcm); + } +} diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index ddef4ff677ce..9e54d8ae6d2c 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -80,7 +80,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); @@ -108,7 +108,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) snd_soc_runtime_activate(rtd, cstream->direction); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; @@ -118,7 +118,7 @@ machine_err: if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -224,7 +224,7 @@ static void close_delayed_work(struct work_struct *work) container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dai; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); dev_dbg(rtd->dev, "Compress ASoC: pop wq checking: %s status: %s waiting: %s\n", @@ -239,7 +239,7 @@ static void close_delayed_work(struct work_struct *work) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); } static int soc_compr_free(struct snd_compr_stream *cstream) @@ -249,7 +249,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) struct snd_soc_dai *codec_dai = rtd->codec_dai; int stream; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -292,7 +292,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; } @@ -375,7 +375,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); ret = soc_compr_components_trigger(cstream, cmd); if (ret < 0) @@ -394,7 +394,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) } out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -480,7 +480,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* * First we call set_params for the CPU DAI, then the component @@ -514,14 +514,14 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, /* cancel any delayed stream shutdown that is pending */ rtd->pop_wait = 0; - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); cancel_delayed_work_sync(&rtd->delayed_work); return 0; err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -593,7 +593,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); @@ -613,7 +613,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, } err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -625,7 +625,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -638,7 +638,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -650,7 +650,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -664,7 +664,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -676,7 +676,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); @@ -697,7 +697,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) } err: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -710,7 +710,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); @@ -726,7 +726,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -738,7 +738,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -751,7 +751,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, break; } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -872,14 +872,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) } /* check client and interface hw capabilities */ - if (codec_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) playback = 1; - if (codec_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) capture = 1; - capture = capture && cpu_dai->driver->capture.channels_min; - playback = playback && cpu_dai->driver->playback.channels_min; - /* * Compress devices are unidirectional so only one of the directions * should be set, check for that (xor) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 44f899b970c2..35f48e9c5ead 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -73,6 +73,7 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); +#ifdef CONFIG_DMI /* * If a DMI filed contain strings in this blacklist (e.g. * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken @@ -87,6 +88,7 @@ static const char * const dmi_blacklist[] = { "Board Product Name", NULL, /* terminator */ }; +#endif static ssize_t pmdown_time_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -165,20 +167,16 @@ static void soc_init_component_debugfs(struct snd_soc_component *component) component->card->debugfs_card_root); } - if (IS_ERR(component->debugfs_root)) { - dev_warn(component->dev, - "ASoC: Failed to create component debugfs directory: %ld\n", - PTR_ERR(component->debugfs_root)); - return; - } - snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), component->debugfs_root); } static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { + if (!component->debugfs_root) + return; debugfs_remove_recursive(component->debugfs_root); + component->debugfs_root = NULL; } static int dai_list_show(struct seq_file *m, void *v) @@ -215,32 +213,17 @@ DEFINE_SHOW_ATTRIBUTE(component_list); static void soc_init_card_debugfs(struct snd_soc_card *card) { - if (!snd_soc_debugfs_root) - return; - card->debugfs_card_root = debugfs_create_dir(card->name, snd_soc_debugfs_root); - if (IS_ERR(card->debugfs_card_root)) { - dev_warn(card->dev, - "ASoC: Failed to create card debugfs directory: %ld\n", - PTR_ERR(card->debugfs_card_root)); - card->debugfs_card_root = NULL; - return; - } - card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, - card->debugfs_card_root, - &card->pop_time); - if (IS_ERR(card->debugfs_pop_time)) - dev_warn(card->dev, - "ASoC: Failed to create pop time debugfs file: %ld\n", - PTR_ERR(card->debugfs_pop_time)); + debugfs_create_u32("dapm_pop_time", 0644, card->debugfs_card_root, + &card->pop_time); + + snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) { - if (!card->debugfs_card_root) - return; debugfs_remove_recursive(card->debugfs_card_root); card->debugfs_card_root = NULL; } @@ -248,19 +231,12 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) static void snd_soc_debugfs_init(void) { snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR_OR_NULL(snd_soc_debugfs_root)) { - pr_warn("ASoC: Failed to create debugfs directory\n"); - snd_soc_debugfs_root = NULL; - return; - } - if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, - &dai_list_fops)) - pr_warn("ASoC: Failed to create DAI list debugfs file\n"); + debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, + &dai_list_fops); - if (!debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, - &component_list_fops)) - pr_warn("ASoC: Failed to create component list debugfs file\n"); + debugfs_create_file("components", 0444, snd_soc_debugfs_root, NULL, + &component_list_fops); } static void snd_soc_debugfs_exit(void) @@ -302,7 +278,6 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_rtdcom_list *new_rtdcom; for_each_rtdcom(rtd, rtdcom) { /* already connected */ @@ -310,14 +285,14 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, return 0; } - new_rtdcom = kmalloc(sizeof(*new_rtdcom), GFP_KERNEL); - if (!new_rtdcom) + rtdcom = kmalloc(sizeof(*rtdcom), GFP_KERNEL); + if (!rtdcom) return -ENOMEM; - new_rtdcom->component = component; - INIT_LIST_HEAD(&new_rtdcom->list); + rtdcom->component = component; + INIT_LIST_HEAD(&rtdcom->list); - list_add_tail(&new_rtdcom->list, &rtd->component_list); + list_add_tail(&rtdcom->list, &rtd->component_list); return 0; } @@ -340,6 +315,14 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, if (!driver_name) return NULL; + /* + * NOTE + * + * snd_soc_rtdcom_lookup() will find component from rtd by using + * specified driver name. + * But, if many components which have same driver name are connected + * to 1 rtd, this function will return 1st found component. + */ for_each_rtdcom(rtd, rtdcom) { const char *component_name = rtdcom->component->driver->name; @@ -408,6 +391,7 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) static void soc_add_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { + /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); rtd->num = card->num_rtd; card->num_rtd++; @@ -447,16 +431,6 @@ static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) flush_delayed_work(&rtd->delayed_work); } -static void codec2codec_close_delayed_work(struct work_struct *work) -{ - /* - * Currently nothing to do for c2c links - * Since c2c links are internal nodes in the DAPM graph and - * don't interface with the outside world or application layer - * we don't have to do any special handling on close. - */ -} - #ifdef CONFIG_PM_SLEEP /* powers down audio subsystem for suspend */ int snd_soc_suspend(struct device *dev) @@ -487,10 +461,9 @@ int snd_soc_suspend(struct device *dev) continue; for_each_rtd_codec_dai(rtd, i, dai) { - struct snd_soc_dai_driver *drv = dai->driver; - - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 1); + if (dai->playback_active) + snd_soc_dai_digital_mute(dai, 1, + SNDRV_PCM_STREAM_PLAYBACK); } } @@ -511,8 +484,8 @@ int snd_soc_suspend(struct device *dev) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) - cpu_dai->driver->suspend(cpu_dai); + if (!cpu_dai->driver->bus_control) + snd_soc_dai_suspend(cpu_dai); } /* close any waiting streams */ @@ -545,7 +518,7 @@ int snd_soc_suspend(struct device *dev) * If there are paths active then the COMPONENT will be held * with bias _ON and should not be suspended. */ - if (!component->suspended) { + if (!snd_soc_component_is_suspended(component)) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* @@ -562,9 +535,7 @@ int snd_soc_suspend(struct device *dev) /* fall through */ case SND_SOC_BIAS_OFF: - if (component->driver->suspend) - component->driver->suspend(component); - component->suspended = 1; + snd_soc_component_suspend(component); if (component->regmap) regcache_mark_dirty(component->regmap); /* deactivate pins to sleep state */ @@ -584,8 +555,8 @@ int snd_soc_suspend(struct device *dev) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) - cpu_dai->driver->suspend(cpu_dai); + if (cpu_dai->driver->bus_control) + snd_soc_dai_suspend(cpu_dai); /* deactivate pins to sleep state */ pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -631,16 +602,13 @@ static void soc_resume_deferred(struct work_struct *work) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) - cpu_dai->driver->resume(cpu_dai); + if (cpu_dai->driver->bus_control) + snd_soc_dai_resume(cpu_dai); } for_each_card_components(card, component) { - if (component->suspended) { - if (component->driver->resume) - component->driver->resume(component); - component->suspended = 0; - } + if (snd_soc_component_is_suspended(component)) + snd_soc_component_resume(component); } for_each_card_rtds(card, rtd) { @@ -665,10 +633,9 @@ static void soc_resume_deferred(struct work_struct *work) continue; for_each_rtd_codec_dai(rtd, i, dai) { - struct snd_soc_dai_driver *drv = dai->driver; - - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 0); + if (dai->playback_active) + snd_soc_dai_digital_mute(dai, 0, + SNDRV_PCM_STREAM_PLAYBACK); } } @@ -678,8 +645,8 @@ static void soc_resume_deferred(struct work_struct *work) if (rtd->dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) - cpu_dai->driver->resume(cpu_dai); + if (!cpu_dai->driver->bus_control) + snd_soc_dai_resume(cpu_dai); } if (card->resume_post) @@ -744,9 +711,18 @@ int snd_soc_resume(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(snd_soc_resume); + +static void soc_resume_init(struct snd_soc_card *card) +{ + /* deferred resume work */ + INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); +} #else #define snd_soc_suspend NULL #define snd_soc_resume NULL +static inline void soc_resume_init(struct snd_soc_card *card) +{ +} #endif static const struct snd_soc_dai_ops null_dai_ops = { @@ -861,11 +837,11 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int id, const char *name, const char *stream_name) { - struct snd_soc_dai_link *link, *_link; + struct snd_soc_dai_link *link; lockdep_assert_held(&client_mutex); - for_each_card_links_safe(card, link, _link) { + for_each_card_links(card, link) { if (link->id != id) continue; @@ -962,15 +938,51 @@ _err_defer: return -EPROBE_DEFER; } +static void soc_set_of_name_prefix(struct snd_soc_component *component) +{ + struct device_node *of_node = soc_component_to_node(component); + const char *str; + int ret; + + ret = of_property_read_string(of_node, "sound-name-prefix", &str); + if (!ret) + component->name_prefix = str; +} + +static void soc_set_name_prefix(struct snd_soc_card *card, + struct snd_soc_component *component) +{ + int i; + + for (i = 0; i < card->num_configs && card->codec_conf; i++) { + struct snd_soc_codec_conf *map = &card->codec_conf[i]; + struct device_node *of_node = soc_component_to_node(component); + + if (map->of_node && of_node != map->of_node) + continue; + if (map->dev_name && strcmp(component->name, map->dev_name)) + continue; + component->name_prefix = map->name_prefix; + return; + } + + /* + * If there is no configuration table or no match in the table, + * check if a prefix is provided in the node + */ + soc_set_of_name_prefix(component); +} + static void soc_cleanup_component(struct snd_soc_component *component) { + /* For framework level robustness */ snd_soc_component_set_jack(component, NULL, NULL); + list_del(&component->card_list); snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - if (!component->driver->module_get_upon_open) - module_put(component->dev->driver->owner); + snd_soc_component_module_put_when_remove(component); } static void soc_remove_component(struct snd_soc_component *component) @@ -978,12 +990,105 @@ static void soc_remove_component(struct snd_soc_component *component) if (!component->card) return; - if (component->driver->remove) - component->driver->remove(component); + snd_soc_component_remove(component); soc_cleanup_component(component); } +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_dai *dai; + int ret; + + if (!strcmp(component->name, "snd-soc-dummy")) + return 0; + + if (component->card) { + if (component->card != card) { + dev_err(component->dev, + "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", + card->name, component->card->name); + return -ENODEV; + } + return 0; + } + + ret = snd_soc_component_module_get_when_probe(component); + if (ret < 0) + return ret; + + component->card = card; + soc_set_name_prefix(card, component); + + soc_init_component_debugfs(component); + + snd_soc_dapm_init(dapm, card, component); + + ret = snd_soc_dapm_new_controls(dapm, + component->driver->dapm_widgets, + component->driver->num_dapm_widgets); + + if (ret != 0) { + dev_err(component->dev, + "Failed to create new controls %d\n", ret); + goto err_probe; + } + + for_each_component_dais(component, dai) { + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + goto err_probe; + } + } + + ret = snd_soc_component_probe(component); + if (ret < 0) { + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); + goto err_probe; + } + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); + + /* machine specific init */ + if (component->init) { + ret = component->init(component); + if (ret < 0) { + dev_err(component->dev, + "Failed to do machine specific init %d\n", ret); + goto err_probe; + } + } + + ret = snd_soc_add_component_controls(component, + component->driver->controls, + component->driver->num_controls); + if (ret < 0) + goto err_probe; + + ret = snd_soc_dapm_add_routes(dapm, + component->driver->dapm_routes, + component->driver->num_dapm_routes); + if (ret < 0) + goto err_probe; + + /* see for_each_card_components */ + list_add(&component->card_list, &card->component_dev_list); + +err_probe: + if (ret < 0) + soc_cleanup_component(component); + + return ret; +} + static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; @@ -992,65 +1097,141 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) dai->driver->remove_order != order) return; - if (dai->driver->remove) { - err = dai->driver->remove(dai); - if (err < 0) - dev_err(dai->dev, - "ASoC: failed to remove %s: %d\n", - dai->name, err); - } + err = snd_soc_dai_remove(dai); + if (err < 0) + dev_err(dai->dev, + "ASoC: failed to remove %s: %d\n", + dai->name, err); + dai->probed = 0; } -static void soc_remove_link_dais(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static int soc_probe_dai(struct snd_soc_dai *dai, int order) +{ + int ret; + + if (dai->probed || + dai->driver->probe_order != order) + return 0; + + ret = snd_soc_dai_probe(dai); + if (ret < 0) { + dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", + dai->name, ret); + return ret; + } + + dai->probed = 1; + + return 0; +} + +static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ +static void soc_remove_link_dais(struct snd_soc_card *card) { int i; struct snd_soc_dai *codec_dai; + struct snd_soc_pcm_runtime *rtd; + int order; - /* unregister the rtd device */ - if (rtd->dev_registered) { - device_unregister(rtd->dev); - rtd->dev_registered = 0; + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + + /* finalize rtd device */ + soc_rtd_free(rtd); + + /* remove the CODEC DAI */ + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_remove_dai(codec_dai, order); + + soc_remove_dai(rtd->cpu_dai, order); + } } +} - /* remove the CODEC DAI */ - for_each_rtd_codec_dai(rtd, i, codec_dai) - soc_remove_dai(codec_dai, order); +static int soc_probe_link_dais(struct snd_soc_card *card) +{ + struct snd_soc_dai *codec_dai; + struct snd_soc_pcm_runtime *rtd; + int i, order, ret; - soc_remove_dai(rtd->cpu_dai, order); + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + + dev_dbg(card->dev, + "ASoC: probe %s dai link %d late %d\n", + card->name, rtd->num, order); + + ret = soc_probe_dai(rtd->cpu_dai, order); + if (ret) + return ret; + + /* probe the CODEC DAI */ + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); + if (ret) + return ret; + } + } + } + + return 0; } -static void soc_remove_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static void soc_remove_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_rtdcom_list *rtdcom; + int order; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (component->driver->remove_order != order) + continue; - if (component->driver->remove_order == order) - soc_remove_component(component); + soc_remove_component(component); + } + } } } -static void soc_remove_dai_links(struct snd_soc_card *card) +static int soc_probe_link_components(struct snd_soc_card *card) { - int order; + struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link *link, *_link; + struct snd_soc_rtdcom_list *rtdcom; + int ret, order; for_each_comp_order(order) { - for_each_card_rtds(card, rtd) - soc_remove_link_dais(card, rtd, order); - } + for_each_card_rtds(card, rtd) { + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) - soc_remove_link_components(card, rtd, order); + if (component->driver->probe_order != order) + continue; + + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; + } + } } + return 0; +} + +static void soc_remove_dai_links(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link, *_link; + + soc_remove_link_dais(card); + + soc_remove_link_components(card); + for_each_card_links_safe(card, link, _link) { if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) dev_warn(card->dev, "Topology forgot to remove link %s?\n", @@ -1197,6 +1378,7 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->add_dai_link) card->add_dai_link(card, dai_link); + /* see for_each_card_links */ list_add_tail(&dai_link->list, &card->dai_link_list); return 0; @@ -1216,8 +1398,6 @@ EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link *link, *_link; - if (dai_link->dobj.type && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { dev_err(card->dev, "Invalid dai link type %d\n", @@ -1233,155 +1413,25 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->remove_dai_link) card->remove_dai_link(card, dai_link); - for_each_card_links_safe(card, link, _link) { - if (link == dai_link) { - list_del(&link->list); - return; - } - } + list_del(&dai_link->list); } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); -static void soc_set_of_name_prefix(struct snd_soc_component *component) +static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) { - struct device_node *component_of_node = soc_component_to_node(component); - const char *str; - int ret; - - ret = of_property_read_string(component_of_node, "sound-name-prefix", - &str); - if (!ret) - component->name_prefix = str; -} - -static void soc_set_name_prefix(struct snd_soc_card *card, - struct snd_soc_component *component) -{ - int i; - - for (i = 0; i < card->num_configs && card->codec_conf; i++) { - struct snd_soc_codec_conf *map = &card->codec_conf[i]; - struct device_node *component_of_node = soc_component_to_node(component); - - if (map->of_node && component_of_node != map->of_node) - continue; - if (map->dev_name && strcmp(component->name, map->dev_name)) - continue; - component->name_prefix = map->name_prefix; - return; - } - - /* - * If there is no configuration table or no match in the table, - * check if a prefix is provided in the node - */ - soc_set_of_name_prefix(component); -} - -static int soc_probe_component(struct snd_soc_card *card, - struct snd_soc_component *component) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - struct snd_soc_dai *dai; - int ret; - - if (!strcmp(component->name, "snd-soc-dummy")) - return 0; - - if (component->card) { - if (component->card != card) { - dev_err(component->dev, - "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", - card->name, component->card->name); - return -ENODEV; - } - return 0; - } - - if (!component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) - return -ENODEV; - - component->card = card; - dapm->card = card; - INIT_LIST_HEAD(&component->card_list); - INIT_LIST_HEAD(&dapm->list); - soc_set_name_prefix(card, component); - - soc_init_component_debugfs(component); - - if (component->driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(dapm, - component->driver->dapm_widgets, - component->driver->num_dapm_widgets); - - if (ret != 0) { - dev_err(component->dev, - "Failed to create new controls %d\n", ret); - goto err_probe; - } - } - - for_each_component_dais(component, dai) { - ret = snd_soc_dapm_new_dai_widgets(dapm, dai); - if (ret != 0) { - dev_err(component->dev, - "Failed to create DAI widgets %d\n", ret); - goto err_probe; - } - } - - if (component->driver->probe) { - ret = component->driver->probe(component); - if (ret < 0) { - dev_err(component->dev, - "ASoC: failed to probe component %d\n", ret); - goto err_probe; - } - } - WARN(dapm->idle_bias_off && - dapm->bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias with idle_bias_off==1\n", - component->name); - - /* machine specific init */ - if (component->init) { - ret = component->init(component); - if (ret < 0) { - dev_err(component->dev, - "Failed to do machine specific init %d\n", ret); - goto err_probe; - } + if (rtd->dev_registered) { + /* we don't need to call kfree() for rtd->dev */ + device_unregister(rtd->dev); + rtd->dev_registered = 0; } - - if (component->driver->controls) - snd_soc_add_component_controls(component, - component->driver->controls, - component->driver->num_controls); - if (component->driver->dapm_routes) - snd_soc_dapm_add_routes(dapm, - component->driver->dapm_routes, - component->driver->num_dapm_routes); - - list_add(&dapm->list, &card->dapm_list); - /* see for_each_card_components */ - list_add(&component->card_list, &card->component_dev_list); - -err_probe: - if (ret < 0) - soc_cleanup_component(component); - - return ret; } -static void rtd_release(struct device *dev) +static void soc_rtd_release(struct device *dev) { kfree(dev); } -static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, - const char *name) +static int soc_rtd_init(struct snd_soc_pcm_runtime *rtd, const char *name) { int ret = 0; @@ -1389,18 +1439,16 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (!rtd->dev) return -ENOMEM; - device_initialize(rtd->dev); rtd->dev->parent = rtd->card->dev; - rtd->dev->release = rtd_release; + rtd->dev->release = soc_rtd_release; rtd->dev->groups = soc_dev_attr_groups; dev_set_name(rtd->dev, "%s", name); dev_set_drvdata(rtd->dev, rtd); - mutex_init(&rtd->pcm_mutex); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); - ret = device_add(rtd->dev); + ret = device_register(rtd->dev); if (ret < 0) { /* calling put_device() here to free the rtd->dev */ put_device(rtd->dev); @@ -1412,47 +1460,6 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, return 0; } -static int soc_probe_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) -{ - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; - int ret; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; - } - } - - return 0; -} - -static int soc_probe_dai(struct snd_soc_dai *dai, int order) -{ - if (dai->probed || - dai->driver->probe_order != order) - return 0; - - if (dai->driver->probe) { - int ret = dai->driver->probe(dai); - - if (ret < 0) { - dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", - dai->name, ret); - return ret; - } - } - - dai->probed = 1; - - return 0; -} - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { @@ -1474,37 +1481,18 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, int order) +static int soc_link_init(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - struct snd_soc_dai *codec_dai; - int i, ret, num; - - dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", - card->name, rtd->num, order); + int ret, num; /* set default power off timeout */ rtd->pmdown_time = pmdown_time; - ret = soc_probe_dai(cpu_dai, order); - if (ret) - return ret; - - /* probe the CODEC DAI */ - for_each_rtd_codec_dai(rtd, i, codec_dai) { - ret = soc_probe_dai(codec_dai, order); - if (ret) - return ret; - } - - /* complete DAI probe during last probe */ - if (order != SND_SOC_COMP_ORDER_LAST) - return 0; - /* do machine specific initialization */ if (dai_link->init) { ret = dai_link->init(rtd); @@ -1521,15 +1509,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; } - ret = soc_post_component_init(rtd, dai_link->name); + ret = soc_rtd_init(rtd, dai_link->name); if (ret) return ret; -#ifdef CONFIG_DEBUG_FS /* add DPCM sysfs entries */ - if (dai_link->dynamic) - soc_dpcm_debugfs_add(rtd); -#endif + soc_dpcm_debugfs_add(rtd); num = rtd->num; @@ -1550,73 +1535,57 @@ static int soc_probe_link_dais(struct snd_soc_card *card, num = rtd->dai_link->id; } - if (cpu_dai->driver->compress_new) { - /* create compress_device" */ - ret = cpu_dai->driver->compress_new(rtd, num); - if (ret < 0) { + /* create compress_device if possible */ + ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); + if (ret != -ENOTSUPP) { + if (ret < 0) dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); - return ret; - } - } else if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + return ret; } - return 0; + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; + } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + return ret; +} + +static void soc_unbind_aux_dev(struct snd_soc_card *card) +{ + struct snd_soc_component *component, *_component; + + for_each_card_auxs_safe(card, component, _component) { + component->init = NULL; + list_del(&component->card_aux_list); + } } -static int soc_bind_aux_dev(struct snd_soc_card *card, int num) +static int soc_bind_aux_dev(struct snd_soc_card *card) { - struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; struct snd_soc_component *component; - struct snd_soc_dai_link_component dlc; + struct snd_soc_aux_dev *aux; + int i; - if (aux_dev->codec_of_node || aux_dev->codec_name) { + for_each_card_pre_auxs(card, i, aux) { /* codecs, usually analog devices */ - dlc.name = aux_dev->codec_name; - dlc.of_node = aux_dev->codec_of_node; - component = soc_find_component(&dlc); - if (!component) { - if (dlc.of_node) - dlc.name = of_node_full_name(dlc.of_node); - goto err_defer; - } - } else if (aux_dev->name) { - /* generic components */ - dlc.name = aux_dev->name; - dlc.of_node = NULL; - component = soc_find_component(&dlc); + component = soc_find_component(&aux->dlc); if (!component) - goto err_defer; - } else { - dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); - return -EINVAL; - } - - component->init = aux_dev->init; - list_add(&component->card_aux_list, &card->aux_comp_list); + return -EPROBE_DEFER; + component->init = aux->init; + /* see for_each_card_auxs */ + list_add(&component->card_aux_list, &card->aux_comp_list); + } return 0; - -err_defer: - dev_err(card->dev, "ASoC: %s not registered\n", dlc.name); - return -EPROBE_DEFER; } static int soc_probe_aux_devices(struct snd_soc_card *card) @@ -1626,7 +1595,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) int ret; for_each_comp_order(order) { - list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { + for_each_card_auxs(card, comp) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); if (ret < 0) { @@ -1648,14 +1617,9 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) int order; for_each_comp_order(order) { - list_for_each_entry_safe(comp, _comp, - &card->aux_comp_list, card_aux_list) { - - if (comp->driver->remove_order == order) { + for_each_card_auxs_safe(card, comp, _comp) { + if (comp->driver->remove_order == order) soc_remove_component(comp); - /* remove it from the card's aux_comp_list */ - list_del(&comp->card_aux_list); - } } } } @@ -1954,7 +1918,7 @@ match: } } -static int soc_cleanup_card_resources(struct snd_soc_card *card) +static void soc_cleanup_card_resources(struct snd_soc_card *card) { /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { @@ -1968,6 +1932,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove auxiliary devices */ soc_remove_aux_devices(card); + soc_unbind_aux_dev(card); snd_soc_dapm_free(&card->dapm); soc_cleanup_card_debugfs(card); @@ -1975,15 +1940,13 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove the card */ if (card->remove) card->remove(card); - - return 0; } static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *dai_link; - int ret, i, order; + int ret, i; mutex_lock(&client_mutex); for_each_card_prelinks(card, i, dai_link) { @@ -1997,10 +1960,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); + snd_soc_dapm_init(&card->dapm, card, NULL); /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); @@ -2013,15 +1973,16 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* bind aux_devs too */ - for (i = 0; i < card->num_aux_devs; i++) { - ret = soc_bind_aux_dev(card, i); - if (ret != 0) - goto probe_end; - } + ret = soc_bind_aux_dev(card); + if (ret < 0) + goto probe_end; /* add predefined DAI links to the list */ - for_each_card_prelinks(card, i, dai_link) - snd_soc_add_dai_link(card, dai_link); + for_each_card_prelinks(card, i, dai_link) { + ret = snd_soc_add_dai_link(card, dai_link); + if (ret < 0) + goto probe_end; + } /* card bind complete so register a sound card */ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -2035,22 +1996,17 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_init_card_debugfs(card); -#ifdef CONFIG_DEBUG_FS - snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); -#endif + soc_resume_init(card); -#ifdef CONFIG_PM_SLEEP - /* deferred resume work */ - INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); -#endif - - if (card->dapm_widgets) - snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, - card->num_dapm_widgets); + ret = snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, + card->num_dapm_widgets); + if (ret < 0) + goto probe_end; - if (card->of_dapm_widgets) - snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, - card->num_of_dapm_widgets); + ret = snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets, + card->num_of_dapm_widgets); + if (ret < 0) + goto probe_end; /* initialise the sound card only once */ if (card->probe) { @@ -2060,16 +2016,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all components used by DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - ret = soc_probe_link_components(card, rtd, order); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to instantiate card %d\n", - ret); - goto probe_end; - } - } + ret = soc_probe_link_components(card); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", ret); + goto probe_end; } /* probe auxiliary components */ @@ -2094,32 +2045,33 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - ret = soc_probe_link_dais(card, rtd, order); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to instantiate card %d\n", - ret); - goto probe_end; - } - } + ret = soc_probe_link_dais(card); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to instantiate card %d\n", ret); + goto probe_end; } + for_each_card_rtds(card, rtd) + soc_link_init(card, rtd); + snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); - if (card->controls) - snd_soc_add_card_controls(card, card->controls, - card->num_controls); + ret = snd_soc_add_card_controls(card, card->controls, + card->num_controls); + if (ret < 0) + goto probe_end; - if (card->dapm_routes) - snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, - card->num_dapm_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, + card->num_dapm_routes); + if (ret < 0) + goto probe_end; - if (card->of_dapm_routes) - snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, - card->num_of_dapm_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes, + card->num_of_dapm_routes); + if (ret < 0) + goto probe_end; /* try to set some sane longname if DMI is available */ snd_soc_set_dmi_name(card, NULL); @@ -2397,293 +2349,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); -/** - * snd_soc_dai_set_sysclk - configure DAI system or master clock. - * @dai: DAI - * @clk_id: DAI specific clock ID - * @freq: new clock frequency in Hz - * @dir: new clock direction - input/output. - * - * Configures the DAI master (MCLK) or system (SYSCLK) clocking. - */ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - if (dai->driver->ops->set_sysclk) - return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); - - return snd_soc_component_set_sysclk(dai->component, clk_id, 0, - freq, dir); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); - -/** - * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. - * @component: COMPONENT - * @clk_id: DAI specific clock ID - * @source: Source for the clock - * @freq: new clock frequency in Hz - * @dir: new clock direction - input/output. - * - * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. - */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, - int clk_id, int source, unsigned int freq, - int dir) -{ - if (component->driver->set_sysclk) - return component->driver->set_sysclk(component, clk_id, source, - freq, dir); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); - -/** - * snd_soc_dai_set_clkdiv - configure DAI clock dividers. - * @dai: DAI - * @div_id: DAI specific clock divider ID - * @div: new clock divisor. - * - * Configures the clock dividers. This is used to derive the best DAI bit and - * frame clocks from the system or master clock. It's best to set the DAI bit - * and frame clocks as low as possible to save system power. - */ -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div) -{ - if (dai->driver->ops->set_clkdiv) - return dai->driver->ops->set_clkdiv(dai, div_id, div); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); - -/** - * snd_soc_dai_set_pll - configure DAI PLL. - * @dai: DAI - * @pll_id: DAI specific PLL ID - * @source: DAI specific source for the PLL - * @freq_in: PLL input clock frequency in Hz - * @freq_out: requested PLL output clock frequency in Hz - * - * Configures and enables PLL to generate output clock based on input clock. - */ -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, - unsigned int freq_in, unsigned int freq_out) -{ - if (dai->driver->ops->set_pll) - return dai->driver->ops->set_pll(dai, pll_id, source, - freq_in, freq_out); - - return snd_soc_component_set_pll(dai->component, pll_id, source, - freq_in, freq_out); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); - -/* - * snd_soc_component_set_pll - configure component PLL. - * @component: COMPONENT - * @pll_id: DAI specific PLL ID - * @source: DAI specific source for the PLL - * @freq_in: PLL input clock frequency in Hz - * @freq_out: requested PLL output clock frequency in Hz - * - * Configures and enables PLL to generate output clock based on input clock. - */ -int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, - int source, unsigned int freq_in, - unsigned int freq_out) -{ - if (component->driver->set_pll) - return component->driver->set_pll(component, pll_id, source, - freq_in, freq_out); - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); - -/** - * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. - * @dai: DAI - * @ratio: Ratio of BCLK to Sample rate. - * - * Configures the DAI for a preset BCLK to sample rate ratio. - */ -int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) -{ - if (dai->driver->ops->set_bclk_ratio) - return dai->driver->ops->set_bclk_ratio(dai, ratio); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); - -/** - * snd_soc_dai_set_fmt - configure DAI hardware audio format. - * @dai: DAI - * @fmt: SND_SOC_DAIFMT_* format value. - * - * Configures the DAI hardware format and clocking. - */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - if (dai->driver->ops->set_fmt == NULL) - return -ENOTSUPP; - return dai->driver->ops->set_fmt(dai, fmt); -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); - -/** - * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. - * @slots: Number of slots in use. - * @tx_mask: bitmask representing active TX slots. - * @rx_mask: bitmask representing active RX slots. - * - * Generates the TDM tx and rx slot default masks for DAI. - */ -static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask) -{ - if (*tx_mask || *rx_mask) - return 0; - - if (!slots) - return -EINVAL; - - *tx_mask = (1 << slots) - 1; - *rx_mask = (1 << slots) - 1; - - return 0; -} - -/** - * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation - * @dai: The DAI to configure - * @tx_mask: bitmask representing active TX slots. - * @rx_mask: bitmask representing active RX slots. - * @slots: Number of slots in use. - * @slot_width: Width in bits for each slot. - * - * This function configures the specified DAI for TDM operation. @slot contains - * the total number of slots of the TDM stream and @slot_with the width of each - * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the - * active slots of the TDM stream for the specified DAI, i.e. which slots the - * DAI should write to or read from. If a bit is set the corresponding slot is - * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to - * the first slot, bit 1 to the second slot and so on. The first active slot - * maps to the first channel of the DAI, the second active slot to the second - * channel and so on. - * - * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, - * @rx_mask and @slot_width will be ignored. - * - * Returns 0 on success, a negative error code otherwise. - */ -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) -{ - if (dai->driver->ops->xlate_tdm_slot_mask) - dai->driver->ops->xlate_tdm_slot_mask(slots, - &tx_mask, &rx_mask); - else - snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); - - dai->tx_mask = tx_mask; - dai->rx_mask = rx_mask; - - if (dai->driver->ops->set_tdm_slot) - return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, - slots, slot_width); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); - -/** - * snd_soc_dai_set_channel_map - configure DAI audio channel map - * @dai: DAI - * @tx_num: how many TX channels - * @tx_slot: pointer to an array which imply the TX slot number channel - * 0~num-1 uses - * @rx_num: how many RX channels - * @rx_slot: pointer to an array which imply the RX slot number channel - * 0~num-1 uses - * - * configure the relationship between channel number and TDM slot number. - */ -int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, unsigned int *tx_slot, - unsigned int rx_num, unsigned int *rx_slot) -{ - if (dai->driver->ops->set_channel_map) - return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, - rx_num, rx_slot); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); - -/** - * snd_soc_dai_get_channel_map - Get DAI audio channel map - * @dai: DAI - * @tx_num: how many TX channels - * @tx_slot: pointer to an array which imply the TX slot number channel - * 0~num-1 uses - * @rx_num: how many RX channels - * @rx_slot: pointer to an array which imply the RX slot number channel - * 0~num-1 uses - */ -int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, - unsigned int *tx_num, unsigned int *tx_slot, - unsigned int *rx_num, unsigned int *rx_slot) -{ - if (dai->driver->ops->get_channel_map) - return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, - rx_num, rx_slot); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); - -/** - * snd_soc_dai_set_tristate - configure DAI system or master clock. - * @dai: DAI - * @tristate: tristate enable - * - * Tristates the DAI so that others can use it. - */ -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) -{ - if (dai->driver->ops->set_tristate) - return dai->driver->ops->set_tristate(dai, tristate); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); - -/** - * snd_soc_dai_digital_mute - configure DAI system or master clock. - * @dai: DAI - * @mute: mute enable - * @direction: stream to mute - * - * Mutes the DAI DAC. - */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, - int direction) -{ - if (dai->driver->ops->mute_stream) - return dai->driver->ops->mute_stream(dai, mute, direction); - else if (direction == SNDRV_PCM_STREAM_PLAYBACK && - dai->driver->ops->digital_mute) - return dai->driver->ops->digital_mute(dai, mute); - else - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); - static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2724,18 +2389,22 @@ int snd_soc_register_card(struct snd_soc_card *card) dev_set_drvdata(card->dev, card); - snd_soc_initialize_card_lists(card); - + INIT_LIST_HEAD(&card->widgets); + INIT_LIST_HEAD(&card->paths); + INIT_LIST_HEAD(&card->dapm_list); + INIT_LIST_HEAD(&card->aux_comp_list); + INIT_LIST_HEAD(&card->component_dev_list); + INIT_LIST_HEAD(&card->list); INIT_LIST_HEAD(&card->dai_link_list); - INIT_LIST_HEAD(&card->rtd_list); - card->num_rtd = 0; - INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); + + card->num_rtd = 0; card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); + mutex_init(&card->pcm_mutex); spin_lock_init(&card->dpcm_lock); return snd_soc_bind_card(card); @@ -2744,20 +2413,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { - struct snd_soc_pcm_runtime *rtd; - int order; - if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); /* remove all components used by DAI links on this card */ - for_each_comp_order(order) { - for_each_card_rtds(card, rtd) { - soc_remove_link_components(card, rtd, order); - } - } + soc_remove_link_components(card); soc_cleanup_card_resources(card); if (!unregister) @@ -2994,34 +2656,13 @@ int snd_soc_register_dai(struct snd_soc_component *component, } EXPORT_SYMBOL_GPL(snd_soc_register_dai); -static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, - enum snd_soc_dapm_type type, int subseq) -{ - struct snd_soc_component *component = dapm->component; - - component->driver->seq_notifier(component, type, subseq); -} - -static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, - int event) -{ - struct snd_soc_component *component = dapm->component; - - return component->driver->stream_event(component, event); -} - -static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) -{ - struct snd_soc_component *component = dapm->component; - - return component->driver->set_bias_level(component, level); -} - static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { - struct snd_soc_dapm_context *dapm; + INIT_LIST_HEAD(&component->dai_list); + INIT_LIST_HEAD(&component->dobj_list); + INIT_LIST_HEAD(&component->card_list); + mutex_init(&component->io_mutex); component->name = fmt_single_name(dev, &component->id); if (!component->name) { @@ -3032,22 +2673,6 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; - dapm = snd_soc_component_get_dapm(component); - dapm->dev = dev; - dapm->component = component; - dapm->bias_level = SND_SOC_BIAS_OFF; - dapm->idle_bias_off = !driver->idle_bias_on; - dapm->suspend_bias_off = driver->suspend_bias_off; - if (driver->seq_notifier) - dapm->seq_notifier = snd_soc_component_seq_notifier; - if (driver->stream_event) - dapm->stream_event = snd_soc_component_stream_event; - if (driver->set_bias_level) - dapm->set_bias_level = snd_soc_component_set_bias_level; - - INIT_LIST_HEAD(&component->dai_list); - mutex_init(&component->io_mutex); - return 0; } @@ -3115,7 +2740,6 @@ static void snd_soc_component_add(struct snd_soc_component *component) /* see for_each_component */ list_add(&component->list, &component_list); - INIT_LIST_HEAD(&component->dobj_list); mutex_unlock(&client_mutex); } @@ -3175,12 +2799,9 @@ static void snd_soc_try_rebind_card(void) { struct snd_soc_card *card, *c; - if (!list_empty(&unbind_card_list)) { - list_for_each_entry_safe(card, c, &unbind_card_list, list) { - if (!snd_soc_bind_card(card)) - list_del(&card->list); - } - } + list_for_each_entry_safe(card, c, &unbind_card_list, list) + if (!snd_soc_bind_card(card)) + list_del(&card->list); } int snd_soc_add_component(struct device *dev, @@ -3682,9 +3303,8 @@ int snd_soc_get_dai_id(struct device_node *ep) ret = -ENOTSUPP; mutex_lock(&client_mutex); component = soc_find_component(&dlc); - if (component && - component->driver->of_xlate_dai_id) - ret = component->driver->of_xlate_dai_id(component, ep); + if (component) + ret = snd_soc_component_of_xlate_dai_id(component, ep); mutex_unlock(&client_mutex); of_node_put(dlc.of_node); @@ -3707,11 +3327,8 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, if (component_of_node != args->np) continue; - if (pos->driver->of_xlate_dai_name) { - ret = pos->driver->of_xlate_dai_name(pos, - args, - dai_name); - } else { + ret = snd_soc_component_of_xlate_dai_name(pos, args, dai_name); + if (ret == -ENOTSUPP) { struct snd_soc_dai *dai; int id = -1; diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c new file mode 100644 index 000000000000..1c7f63871c1d --- /dev/null +++ b/sound/soc/soc-dai.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// soc-dai.c +// +// Copyright (C) 2019 Renesas Electronics Corp. +// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +// + +#include <sound/soc.h> +#include <sound/soc-dai.h> + +/** + * snd_soc_dai_set_sysclk - configure DAI system or master clock. + * @dai: DAI + * @clk_id: DAI specific clock ID + * @freq: new clock frequency in Hz + * @dir: new clock direction - input/output. + * + * Configures the DAI master (MCLK) or system (SYSCLK) clocking. + */ +int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + if (dai->driver->ops->set_sysclk) + return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); + + return snd_soc_component_set_sysclk(dai->component, clk_id, 0, + freq, dir); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); + +/** + * snd_soc_dai_set_clkdiv - configure DAI clock dividers. + * @dai: DAI + * @div_id: DAI specific clock divider ID + * @div: new clock divisor. + * + * Configures the clock dividers. This is used to derive the best DAI bit and + * frame clocks from the system or master clock. It's best to set the DAI bit + * and frame clocks as low as possible to save system power. + */ +int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, + int div_id, int div) +{ + if (dai->driver->ops->set_clkdiv) + return dai->driver->ops->set_clkdiv(dai, div_id, div); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); + +/** + * snd_soc_dai_set_pll - configure DAI PLL. + * @dai: DAI + * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL + * @freq_in: PLL input clock frequency in Hz + * @freq_out: requested PLL output clock frequency in Hz + * + * Configures and enables PLL to generate output clock based on input clock. + */ +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + if (dai->driver->ops->set_pll) + return dai->driver->ops->set_pll(dai, pll_id, source, + freq_in, freq_out); + + return snd_soc_component_set_pll(dai->component, pll_id, source, + freq_in, freq_out); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); + +/** + * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. + * @dai: DAI + * @ratio: Ratio of BCLK to Sample rate. + * + * Configures the DAI for a preset BCLK to sample rate ratio. + */ +int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + if (dai->driver->ops->set_bclk_ratio) + return dai->driver->ops->set_bclk_ratio(dai, ratio); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); + +/** + * snd_soc_dai_set_fmt - configure DAI hardware audio format. + * @dai: DAI + * @fmt: SND_SOC_DAIFMT_* format value. + * + * Configures the DAI hardware format and clocking. + */ +int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + if (dai->driver->ops->set_fmt == NULL) + return -ENOTSUPP; + return dai->driver->ops->set_fmt(dai, fmt); +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); + +/** + * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. + * @slots: Number of slots in use. + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * + * Generates the TDM tx and rx slot default masks for DAI. + */ +static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, + unsigned int *tx_mask, + unsigned int *rx_mask) +{ + if (*tx_mask || *rx_mask) + return 0; + + if (!slots) + return -EINVAL; + + *tx_mask = (1 << slots) - 1; + *rx_mask = (1 << slots) - 1; + + return 0; +} + +/** + * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation + * @dai: The DAI to configure + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. + * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. + * + * This function configures the specified DAI for TDM operation. @slot contains + * the total number of slots of the TDM stream and @slot_with the width of each + * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the + * active slots of the TDM stream for the specified DAI, i.e. which slots the + * DAI should write to or read from. If a bit is set the corresponding slot is + * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to + * the first slot, bit 1 to the second slot and so on. The first active slot + * maps to the first channel of the DAI, the second active slot to the second + * channel and so on. + * + * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask, + * @rx_mask and @slot_width will be ignored. + * + * Returns 0 on success, a negative error code otherwise. + */ +int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + if (dai->driver->ops->xlate_tdm_slot_mask) + dai->driver->ops->xlate_tdm_slot_mask(slots, + &tx_mask, &rx_mask); + else + snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + + dai->tx_mask = tx_mask; + dai->rx_mask = rx_mask; + + if (dai->driver->ops->set_tdm_slot) + return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); + +/** + * snd_soc_dai_set_channel_map - configure DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + * + * configure the relationship between channel number and TDM slot number. + */ +int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + if (dai->driver->ops->set_channel_map) + return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); + +/** + * snd_soc_dai_get_channel_map - Get DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + */ +int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + if (dai->driver->ops->get_channel_map) + return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map); + +/** + * snd_soc_dai_set_tristate - configure DAI system or master clock. + * @dai: DAI + * @tristate: tristate enable + * + * Tristates the DAI so that others can use it. + */ +int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + if (dai->driver->ops->set_tristate) + return dai->driver->ops->set_tristate(dai, tristate); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); + +/** + * snd_soc_dai_digital_mute - configure DAI system or master clock. + * @dai: DAI + * @mute: mute enable + * @direction: stream to mute + * + * Mutes the DAI DAC. + */ +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, + int direction) +{ + if (dai->driver->ops->mute_stream) + return dai->driver->ops->mute_stream(dai, mute, direction); + else if (direction == SNDRV_PCM_STREAM_PLAYBACK && + dai->driver->ops->digital_mute) + return dai->driver->ops->digital_mute(dai, mute); + else + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); + +int snd_soc_dai_hw_params(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + /* perform any topology hw_params fixups before DAI */ + if (rtd->dai_link->be_hw_params_fixup) { + ret = rtd->dai_link->be_hw_params_fixup(rtd, params); + if (ret < 0) { + dev_err(rtd->dev, + "ASoC: hw_params topology fixup failed %d\n", + ret); + return ret; + } + } + + if (dai->driver->ops->hw_params) { + ret = dai->driver->ops->hw_params(substream, params, dai); + if (ret < 0) { + dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", + dai->name, ret); + return ret; + } + } + + return 0; +} + +void snd_soc_dai_hw_free(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + if (dai->driver->ops->hw_free) + dai->driver->ops->hw_free(substream, dai); +} + +int snd_soc_dai_startup(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int ret = 0; + + if (dai->driver->ops->startup) + ret = dai->driver->ops->startup(substream, dai); + + return ret; +} + +void snd_soc_dai_shutdown(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + if (dai->driver->ops->shutdown) + dai->driver->ops->shutdown(substream, dai); +} + +int snd_soc_dai_prepare(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int ret = 0; + + if (dai->driver->ops->prepare) + ret = dai->driver->ops->prepare(substream, dai); + + return ret; +} + +int snd_soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (dai->driver->ops->trigger) + ret = dai->driver->ops->trigger(substream, cmd, dai); + + return ret; +} + +int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (dai->driver->ops->bespoke_trigger) + ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai); + + return ret; +} + +snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream) +{ + int delay = 0; + + if (dai->driver->ops->delay) + delay = dai->driver->ops->delay(substream, dai); + + return delay; +} + +void snd_soc_dai_suspend(struct snd_soc_dai *dai) +{ + if (dai->driver->suspend) + dai->driver->suspend(dai); +} + +void snd_soc_dai_resume(struct snd_soc_dai *dai) +{ + if (dai->driver->resume) + dai->driver->resume(dai); +} + +int snd_soc_dai_probe(struct snd_soc_dai *dai) +{ + if (dai->driver->probe) + return dai->driver->probe(dai); + return 0; +} + +int snd_soc_dai_remove(struct snd_soc_dai *dai) +{ + if (dai->driver->remove) + return dai->driver->remove(dai); + return 0; +} + +int snd_soc_dai_compress_new(struct snd_soc_dai *dai, + struct snd_soc_pcm_runtime *rtd, int num) +{ + if (dai->driver->compress_new) + return dai->driver->compress_new(rtd, num); + return -ENOTSUPP; +} + +/* + * snd_soc_dai_stream_valid() - check if a DAI supports the given stream + * + * Returns true if the DAI supports the indicated stream type. + */ +bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir) +{ + struct snd_soc_pcm_stream *stream; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + stream = &dai->driver->playback; + else + stream = &dai->driver->capture; + + /* If the codec specifies any channels at all, it supports the stream */ + return stream->channels_min; +} diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2790c00735f3..b6378f025836 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -684,8 +684,8 @@ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm, { int ret = 0; - if (dapm->set_bias_level) - ret = dapm->set_bias_level(dapm, level); + if (dapm->component) + ret = snd_soc_component_set_bias_level(dapm->component, level); if (ret == 0) dapm->bias_level = level; @@ -1129,6 +1129,34 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, } /* + * Recursively reset the cached number of inputs or outputs for the specified + * widget and all widgets that can be reached via incoming or outcoming paths + * from the widget. + */ +static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget, + enum snd_soc_dapm_direction dir) +{ + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + struct snd_soc_dapm_path *path; + + widget->endpoints[dir] = -1; + + snd_soc_dapm_widget_for_each_path(widget, rdir, path) { + if (path->weak || path->is_supply) + continue; + + if (path->walking) + return; + + if (path->connect) { + path->walking = 1; + invalidate_paths_ep(path->node[dir], dir); + path->walking = 0; + } + } +} + +/* * Common implementation for is_connected_output_ep() and * is_connected_input_ep(). The function is inlined since the combined size of * the two specialized functions is only marginally larger then the size of the @@ -1257,21 +1285,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - /* - * For is_connected_{output,input}_ep fully discover the graph we need - * to reset the cached number of inputs and outputs. - */ - list_for_each_entry(w, &card->widgets, list) { - w->endpoints[SND_SOC_DAPM_DIR_IN] = -1; - w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1; - } - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - paths = is_connected_output_ep(dai->playback_widget, &widgets, + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + w = dai->playback_widget; + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT); + paths = is_connected_output_ep(w, &widgets, custom_stop_condition); - else - paths = is_connected_input_ep(dai->capture_widget, &widgets, + } else { + w = dai->capture_widget; + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN); + paths = is_connected_input_ep(w, &widgets, custom_stop_condition); + } /* Drop starting point */ list_del(widgets.next); @@ -1611,12 +1635,12 @@ static void dapm_seq_run(struct snd_soc_card *card, if (!list_empty(&pending)) dapm_seq_run_coalesced(card, &pending); - if (cur_dapm && cur_dapm->seq_notifier) { + if (cur_dapm && cur_dapm->component) { for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) if (sort[i] == cur_sort) - cur_dapm->seq_notifier(cur_dapm, - i, - cur_subseq); + snd_soc_component_seq_notifier( + cur_dapm->component, + i, cur_subseq); } if (cur_dapm && w->dapm != cur_dapm) @@ -1674,11 +1698,12 @@ static void dapm_seq_run(struct snd_soc_card *card, if (!list_empty(&pending)) dapm_seq_run_coalesced(card, &pending); - if (cur_dapm && cur_dapm->seq_notifier) { + if (cur_dapm && cur_dapm->component) { for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) if (sort[i] == cur_sort) - cur_dapm->seq_notifier(cur_dapm, - i, cur_subseq); + snd_soc_component_seq_notifier( + cur_dapm->component, + i, cur_subseq); } list_for_each_entry(d, &card->dapm_list, list) { @@ -1912,6 +1937,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) LIST_HEAD(down_list); ASYNC_DOMAIN_EXCLUSIVE(async_domain); enum snd_soc_bias_level bias; + int ret; lockdep_assert_held(&card->dapm_mutex); @@ -2028,8 +2054,12 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* do we need to notify any clients that DAPM event is complete */ list_for_each_entry(d, &card->dapm_list, list) { - if (d->stream_event) - d->stream_event(d, event); + if (!d->component) + continue; + + ret = snd_soc_component_stream_event(d->component, event); + if (ret < 0) + return ret; } pop_dbg(card->dev, card->pop_time, @@ -2154,50 +2184,28 @@ static const struct file_operations dapm_bias_fops = { void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, struct dentry *parent) { - struct dentry *d; - if (!parent || IS_ERR(parent)) return; dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); - if (IS_ERR(dapm->debugfs_dapm)) { - dev_warn(dapm->dev, - "ASoC: Failed to create DAPM debugfs directory %ld\n", - PTR_ERR(dapm->debugfs_dapm)); - return; - } - - d = debugfs_create_file("bias_level", 0444, - dapm->debugfs_dapm, dapm, - &dapm_bias_fops); - if (IS_ERR(d)) - dev_warn(dapm->dev, - "ASoC: Failed to create bias level debugfs file: %ld\n", - PTR_ERR(d)); + debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm, + &dapm_bias_fops); } static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; - struct dentry *d; if (!dapm->debugfs_dapm || !w->name) return; - d = debugfs_create_file(w->name, 0444, - dapm->debugfs_dapm, w, - &dapm_widget_power_fops); - if (IS_ERR(d)) - dev_warn(w->dapm->dev, - "ASoC: Failed to create %s debugfs file: %ld\n", - w->name, PTR_ERR(d)); + debugfs_create_file(w->name, 0444, dapm->debugfs_dapm, w, + &dapm_widget_power_fops); } static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) { - if (!dapm->debugfs_dapm) - return; debugfs_remove_recursive(dapm->debugfs_dapm); dapm->debugfs_dapm = NULL; } @@ -3766,25 +3774,70 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); -static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int +snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, + struct snd_pcm_substream *substream) { struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; - struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config; - struct snd_pcm_substream substream; + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_hw_params *params = NULL; + const struct snd_soc_pcm_stream *config = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; int ret = 0; - config = rtd->dai_link->params + rtd->params_select; + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; - if (WARN_ON(!config) || - WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || - list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) - return -EINVAL; + runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); + if (!runtime) { + ret = -ENOMEM; + goto out; + } + + substream->runtime = runtime; + + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + ret = snd_soc_dai_startup(source, substream); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; + } + source->active++; + } + + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_startup(sink, substream); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", ret); + goto out; + } + sink->active++; + } + + substream->hw_opened = 1; + + /* + * Note: getting the config after .startup() gives a chance to + * either party on the link to alter the configuration if + * necessary + */ + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config)) { + dev_err(w->dapm->dev, "ASoC: link config missing\n"); + ret = -EINVAL; + goto out; + } /* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { @@ -3792,83 +3845,74 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, } else { dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", config->formats); - fmt = 0; - } - /* Currently very limited parameter selection */ - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; + ret = -EINVAL; goto out; } - snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = config->rate_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = config->rate_max; - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = config->channels_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = config->channels_max; - memset(&substream, 0, sizeof(substream)); + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; - /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ - runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); - if (!runtime) { - ret = -ENOMEM; - goto out; + ret = snd_soc_dai_hw_params(source, substream, params); + if (ret < 0) + goto out; + + dapm_update_dai_unlocked(substream, params, source); } - substream.runtime = runtime; - substream.private_data = rtd; - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - snd_soc_dapm_widget_for_each_source_path(w, path) { - source = path->source->priv; + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; - if (source->driver->ops->startup) { - ret = source->driver->ops->startup(&substream, - source); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", - ret); - goto out; - } - } - source->active++; - ret = soc_dai_hw_params(&substream, params, source); - if (ret < 0) - goto out; + ret = snd_soc_dai_hw_params(sink, substream, params); + if (ret < 0) + goto out; - dapm_update_dai_unlocked(&substream, params, source); - } + dapm_update_dai_unlocked(substream, params, sink); + } - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - snd_soc_dapm_widget_for_each_sink_path(w, path) { - sink = path->sink->priv; + runtime->format = params_format(params); + runtime->subformat = params_subformat(params); + runtime->channels = params_channels(params); + runtime->rate = params_rate(params); - if (sink->driver->ops->startup) { - ret = sink->driver->ops->startup(&substream, - sink); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", - ret); - goto out; - } - } - sink->active++; - ret = soc_dai_hw_params(&substream, params, sink); - if (ret < 0) - goto out; +out: + if (ret < 0) + kfree(runtime); + + kfree(params); + return ret; +} + +static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_dapm_path *path; + struct snd_soc_dai *source, *sink; + struct snd_pcm_substream *substream = w->priv; + int ret = 0, saved_stream = substream->stream; + + if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = snd_soc_dai_link_event_pre_pmu(w, substream); + if (ret < 0) + goto out; - dapm_update_dai_unlocked(&substream, params, sink); - } break; case SND_SOC_DAPM_POST_PMU: @@ -3896,41 +3940,45 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = 0; } - substream.stream = SNDRV_PCM_STREAM_CAPTURE; + substream->stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; + snd_soc_dai_hw_free(source, substream); + } - if (source->driver->ops->hw_free) - source->driver->ops->hw_free(&substream, - source); + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + snd_soc_dai_hw_free(sink, substream); + } + substream->stream = SNDRV_PCM_STREAM_CAPTURE; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; source->active--; - if (source->driver->ops->shutdown) - source->driver->ops->shutdown(&substream, - source); + snd_soc_dai_shutdown(source, substream); } - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - - if (sink->driver->ops->hw_free) - sink->driver->ops->hw_free(&substream, sink); - sink->active--; - if (sink->driver->ops->shutdown) - sink->driver->ops->shutdown(&substream, sink); + snd_soc_dai_shutdown(sink, substream); } break; + case SND_SOC_DAPM_POST_PMD: + kfree(substream->runtime); + break; + default: WARN(1, "Unknown event %d\n", event); ret = -EINVAL; } out: - kfree(runtime); - kfree(params); + /* Restore the substream direction */ + substream->stream = saved_stream; return ret; } @@ -4053,10 +4101,11 @@ outfree_w_param: } static struct snd_soc_dapm_widget * -snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) +snd_soc_dapm_new_dai(struct snd_soc_card *card, + struct snd_pcm_substream *substream, + char *id) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; const char **w_param_text; @@ -4065,7 +4114,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int ret; link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", - source->name, sink->name); + rtd->dai_link->name, id); if (!link_name) return ERR_PTR(-ENOMEM); @@ -4075,7 +4124,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, template.name = link_name; template.event = snd_soc_dai_link_event; template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD; + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD; template.kcontrol_news = NULL; /* allocate memory for control, only in case of multiple configs */ @@ -4110,7 +4159,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, goto outfree_kcontrol_news; } - w->priv = rtd; + w->priv = substream; return w; @@ -4232,6 +4281,8 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, struct snd_soc_dai *codec_dai; struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; + struct snd_pcm_substream *substream; + struct snd_pcm_str *streams = rtd->pcm->streams; int i; if (rtd->dai_link->params) { @@ -4245,15 +4296,14 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, } for_each_rtd_codec_dai(rtd, i, codec_dai) { - /* connect BE DAI playback if widgets are valid */ codec = codec_dai->playback_widget; if (playback_cpu && codec) { if (!playback) { - playback = snd_soc_dapm_new_dai(card, rtd, - playback_cpu, - codec); + substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + playback = snd_soc_dapm_new_dai(card, substream, + "playback"); if (IS_ERR(playback)) { dev_err(rtd->dev, "ASoC: Failed to create DAI %s: %ld\n", @@ -4281,9 +4331,9 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, if (codec && capture_cpu) { if (!capture) { - capture = snd_soc_dapm_new_dai(card, rtd, - codec, - capture_cpu); + substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; + capture = snd_soc_dapm_new_dai(card, substream, + "capture"); if (IS_ERR(capture)) { dev_err(rtd->dev, "ASoC: Failed to create DAI %s: %ld\n", @@ -4667,6 +4717,27 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_free); +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, + struct snd_soc_card *card, + struct snd_soc_component *component) +{ + dapm->card = card; + dapm->component = component; + dapm->bias_level = SND_SOC_BIAS_OFF; + + if (component) { + dapm->dev = component->dev; + dapm->idle_bias_off = !component->driver->idle_bias_on, + dapm->suspend_bias_off = component->driver->suspend_bias_off; + } else { + dapm->dev = card->dev; + } + + INIT_LIST_HEAD(&dapm->list); + list_add(&dapm->list, &card->dapm_list); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_init); + static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) { struct snd_soc_card *card = dapm->card; diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index c7b990abdbaa..a71d2340eb05 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -24,24 +24,6 @@ struct jack_gpio_tbl { }; /** - * snd_soc_component_set_jack - configure component jack. - * @component: COMPONENTs - * @jack: structure to use for the jack - * @data: can be used if codec driver need extra data for configuring jack - * - * Configures and enables jack detection function. - */ -int snd_soc_component_set_jack(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *data) -{ - if (component->driver->set_jack) - return component->driver->set_jack(component, jack, data); - - return -ENOTSUPP; -} -EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); - -/** * snd_soc_card_jack_new - Create a new jack * @card: ASoC card * @id: an identifying string for this jack diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4878d22ebd8c..e163dde5eab1 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -15,7 +15,6 @@ #include <linux/delay.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> -#include <linux/module.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/export.h> @@ -29,24 +28,6 @@ #define DPCM_MAX_BE_USERS 8 -/* - * snd_soc_dai_stream_valid() - check if a DAI supports the given stream - * - * Returns true if the DAI supports the indicated stream type. - */ -static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_pcm_stream *codec_stream; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - codec_stream = &dai->driver->playback; - else - codec_stream = &dai->driver->capture; - - /* If the codec specifies any channels at all, it supports the stream */ - return codec_stream->channels_min; -} - /** * snd_soc_runtime_activate() - Increment active count for PCM runtime components * @rtd: ASoC PCM runtime that is activated @@ -55,7 +36,7 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) * Increments the active count for all the DAIs and components attached to a PCM * runtime. Should typically be called when a stream is opened. * - * Must be called with the rtd->pcm_mutex being held + * Must be called with the rtd->card->pcm_mutex being held */ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) { @@ -63,7 +44,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) struct snd_soc_dai *codec_dai; int i; - lockdep_assert_held(&rtd->pcm_mutex); + lockdep_assert_held(&rtd->card->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; @@ -91,7 +72,7 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) * Decrements the active count for all the DAIs and components attached to a PCM * runtime. Should typically be called when a stream is closed. * - * Must be called with the rtd->pcm_mutex being held + * Must be called with the rtd->card->pcm_mutex being held */ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) { @@ -99,7 +80,7 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) struct snd_soc_dai *codec_dai; int i; - lockdep_assert_held(&rtd->pcm_mutex); + lockdep_assert_held(&rtd->card->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; @@ -458,19 +439,15 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream, component = rtdcom->component; *last = component; - if (component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) { + ret = snd_soc_component_module_get_when_open(component); + if (ret < 0) { dev_err(component->dev, "ASoC: can't get module %s\n", component->name); - return -ENODEV; + return ret; } - if (!component->driver->ops || - !component->driver->ops->open) - continue; - - ret = component->driver->ops->open(substream); + ret = snd_soc_component_open(component, substream); if (ret < 0) { dev_err(component->dev, "ASoC: can't open component %s: %d\n", @@ -488,6 +465,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + int ret = 0; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -495,15 +473,11 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, if (component == last) break; - if (component->driver->ops && - component->driver->ops->close) - component->driver->ops->close(substream); - - if (component->driver->module_get_upon_open) - module_put(component->dev->driver->owner); + ret |= snd_soc_component_close(component, substream); + snd_soc_component_module_put_when_close(component); } - return 0; + return ret; } /* @@ -532,16 +506,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) pm_runtime_get_sync(component->dev); } - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* startup the audio subsystem */ - if (cpu_dai->driver->ops->startup) { - ret = cpu_dai->driver->ops->startup(substream, cpu_dai); - if (ret < 0) { - dev_err(cpu_dai->dev, "ASoC: can't open interface" - " %s: %d\n", cpu_dai->name, ret); - goto out; - } + ret = snd_soc_dai_startup(cpu_dai, substream); + if (ret < 0) { + dev_err(cpu_dai->dev, "ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; } ret = soc_pcm_components_open(substream, &component); @@ -549,15 +521,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto component_err; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->startup) { - ret = codec_dai->driver->ops->startup(substream, - codec_dai); - if (ret < 0) { - dev_err(codec_dai->dev, - "ASoC: can't open codec %s: %d\n", - codec_dai->name, ret); - goto codec_dai_err; - } + ret = snd_soc_dai_startup(codec_dai, substream); + if (ret < 0) { + dev_err(codec_dai->dev, + "ASoC: can't open codec %s: %d\n", + codec_dai->name, ret); + goto codec_dai_err; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -635,7 +604,7 @@ dynamic: snd_soc_runtime_activate(rtd, substream->stream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; config_err: @@ -646,18 +615,15 @@ machine_err: i = rtd->num_codecs; codec_dai_err: - for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { - if (codec_dai->driver->ops->shutdown) - codec_dai->driver->ops->shutdown(substream, codec_dai); - } + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) + snd_soc_dai_shutdown(codec_dai, substream); component_err: soc_pcm_components_close(substream, component); - if (cpu_dai->driver->ops->shutdown) - cpu_dai->driver->ops->shutdown(substream, cpu_dai); + snd_soc_dai_shutdown(cpu_dai, substream); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -687,7 +653,7 @@ static void close_delayed_work(struct work_struct *work) container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, @@ -701,7 +667,17 @@ static void close_delayed_work(struct work_struct *work) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); +} + +static void codec2codec_close_delayed_work(struct work_struct *work) +{ + /* + * Currently nothing to do for c2c links + * Since c2c links are internal nodes in the DAPM graph and + * don't interface with the outside world or application layer + * we don't have to do any special handling on close. + */ } /* @@ -718,7 +694,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai; int i; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); snd_soc_runtime_deactivate(rtd, substream->stream); @@ -733,13 +709,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); - if (cpu_dai->driver->ops->shutdown) - cpu_dai->driver->ops->shutdown(substream, cpu_dai); + snd_soc_dai_shutdown(cpu_dai, substream); - for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->shutdown) - codec_dai->driver->ops->shutdown(substream, codec_dai); - } + for_each_rtd_codec_dai(rtd, i, codec_dai) + snd_soc_dai_shutdown(codec_dai, substream); if (rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); @@ -765,7 +738,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -798,7 +771,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai; int i, ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); @@ -812,11 +785,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->prepare) - continue; - - ret = component->driver->ops->prepare(substream); + ret = snd_soc_component_prepare(component, substream); if (ret < 0) { dev_err(component->dev, "ASoC: platform prepare error: %d\n", ret); @@ -825,27 +794,22 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->prepare) { - ret = codec_dai->driver->ops->prepare(substream, - codec_dai); - if (ret < 0) { - dev_err(codec_dai->dev, - "ASoC: codec DAI prepare error: %d\n", - ret); - goto out; - } - } - } - - if (cpu_dai->driver->ops->prepare) { - ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); + ret = snd_soc_dai_prepare(codec_dai, substream); if (ret < 0) { - dev_err(cpu_dai->dev, - "ASoC: cpu DAI prepare error: %d\n", ret); + dev_err(codec_dai->dev, + "ASoC: codec DAI prepare error: %d\n", + ret); goto out; } } + ret = snd_soc_dai_prepare(cpu_dai, substream); + if (ret < 0) { + dev_err(cpu_dai->dev, + "ASoC: cpu DAI prepare error: %d\n", ret); + goto out; + } + /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && rtd->pop_wait) { @@ -862,7 +826,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -877,42 +841,13 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, interval->max = channels; } -int soc_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret; - - /* perform any topology hw_params fixups before DAI */ - if (rtd->dai_link->be_hw_params_fixup) { - ret = rtd->dai_link->be_hw_params_fixup(rtd, params); - if (ret < 0) { - dev_err(rtd->dev, - "ASoC: hw_params topology fixup failed %d\n", - ret); - return ret; - } - } - - if (dai->driver->ops->hw_params) { - ret = dai->driver->ops->hw_params(substream, params, dai); - if (ret < 0) { - dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", - dai->name, ret); - return ret; - } - } - - return 0; -} - static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *last) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + int ret = 0; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -920,14 +855,10 @@ static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, if (component == last) break; - if (!component->driver->ops || - !component->driver->ops->hw_free) - continue; - - component->driver->ops->hw_free(substream); + ret |= snd_soc_component_hw_free(component, substream); } - return 0; + return ret; } /* @@ -945,7 +876,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i, ret = 0; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); if (rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { @@ -989,7 +920,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); - ret = soc_dai_hw_params(substream, &codec_params, codec_dai); + ret = snd_soc_dai_hw_params(codec_dai, substream, + &codec_params); if(ret < 0) goto codec_err; @@ -1001,7 +933,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } - ret = soc_dai_hw_params(substream, params, cpu_dai); + ret = snd_soc_dai_hw_params(cpu_dai, substream, params); if (ret < 0) goto interface_err; @@ -1016,11 +948,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->hw_params) - continue; - - ret = component->driver->ops->hw_params(substream, params); + ret = snd_soc_component_hw_params(component, substream, params); if (ret < 0) { dev_err(component->dev, "ASoC: %s hw params failed: %d\n", @@ -1034,14 +962,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (ret) goto component_err; out: - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; component_err: soc_pcm_components_hw_free(substream, component); - if (cpu_dai->driver->ops->hw_free) - cpu_dai->driver->ops->hw_free(substream, cpu_dai); + snd_soc_dai_hw_free(cpu_dai, substream); cpu_dai->rate = 0; interface_err: @@ -1052,15 +979,14 @@ codec_err: if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); + snd_soc_dai_hw_free(codec_dai, substream); codec_dai->rate = 0; } if (rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return ret; } @@ -1075,7 +1001,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int i; - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); /* clear the corresponding DAIs parameters when going to be inactive */ if (cpu_dai->active == 1) { @@ -1112,14 +1038,12 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - if (codec_dai->driver->ops->hw_free) - codec_dai->driver->ops->hw_free(substream, codec_dai); + snd_soc_dai_hw_free(codec_dai, substream); } - if (cpu_dai->driver->ops->hw_free) - cpu_dai->driver->ops->hw_free(substream, cpu_dai); + snd_soc_dai_hw_free(cpu_dai, substream); - mutex_unlock(&rtd->pcm_mutex); + mutex_unlock(&rtd->card->pcm_mutex); return 0; } @@ -1133,31 +1057,22 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int i, ret; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->trigger) { - ret = codec_dai->driver->ops->trigger(substream, - cmd, codec_dai); - if (ret < 0) - return ret; - } + ret = snd_soc_dai_trigger(codec_dai, substream, cmd); + if (ret < 0) + return ret; } for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; - if (!component->driver->ops || - !component->driver->ops->trigger) - continue; - - ret = component->driver->ops->trigger(substream, cmd); + ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; } - if (cpu_dai->driver->ops->trigger) { - ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); - if (ret < 0) - return ret; - } + snd_soc_dai_trigger(cpu_dai, substream, cmd); + if (ret < 0) + return ret; if (rtd->dai_link->ops->trigger) { ret = rtd->dai_link->ops->trigger(substream, cmd); @@ -1177,19 +1092,15 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int i, ret; for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->bespoke_trigger) { - ret = codec_dai->driver->ops->bespoke_trigger(substream, - cmd, codec_dai); - if (ret < 0) - return ret; - } - } - - if (cpu_dai->driver->ops->bespoke_trigger) { - ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); + ret = snd_soc_dai_bespoke_trigger(codec_dai, substream, cmd); if (ret < 0) return ret; } + + snd_soc_dai_bespoke_trigger(cpu_dai, substream, cmd); + if (ret < 0) + return ret; + return 0; } /* @@ -1200,8 +1111,6 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; struct snd_pcm_runtime *runtime = substream->runtime; @@ -1213,28 +1122,16 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) /* clearing the previous total delay */ runtime->delay = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->pointer) - continue; + offset = snd_soc_pcm_component_pointer(substream); - /* FIXME: use 1st pointer */ - offset = component->driver->ops->pointer(substream); - break; - } /* base delay if assigned in pointer callback */ delay = runtime->delay; - if (cpu_dai->driver->ops->delay) - delay += cpu_dai->driver->ops->delay(substream, cpu_dai); + delay += snd_soc_dai_delay(cpu_dai, substream); for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->ops->delay) - codec_delay = max(codec_delay, - codec_dai->driver->ops->delay(substream, - codec_dai)); + codec_delay = max(codec_delay, + snd_soc_dai_delay(codec_dai, substream)); } delay += codec_delay; @@ -1274,9 +1171,9 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, stream ? "<-" : "->", be->dai_link->name); #ifdef CONFIG_DEBUG_FS - if (fe->debugfs_dpcm_root) - dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, - fe->debugfs_dpcm_root, &dpcm->state); + dpcm->debugfs_state = debugfs_create_dir(be->dai_link->name, + fe->debugfs_dpcm_root); + debugfs_create_u32("state", 0644, dpcm->debugfs_state, &dpcm->state); #endif return 1; } @@ -1331,7 +1228,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) dpcm_be_reparent(fe, dpcm->be, stream); #ifdef CONFIG_DEBUG_FS - debugfs_remove(dpcm->debugfs_state); + debugfs_remove_recursive(dpcm->debugfs_state); #endif spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_del(&dpcm->list_be); @@ -2556,27 +2453,6 @@ out: return ret; } -static int soc_pcm_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->ioctl) - continue; - - /* FIXME: use 1st ioctl */ - return component->driver->ops->ioctl(substream, cmd, arg); - } - - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_pcm_substream *substream = @@ -2749,8 +2625,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) new ? "new" : "old", fe->dai_link->name); /* skip if FE doesn't have playback capability */ - if (!fe->cpu_dai->driver->playback.channels_min || - !fe->codec_dai->driver->playback.channels_min) + if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK) || + !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_PLAYBACK)) goto capture; /* skip if FE isn't currently playing */ @@ -2780,8 +2656,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) capture: /* skip if FE doesn't have capture capability */ - if (!fe->cpu_dai->driver->capture.channels_min || - !fe->codec_dai->driver->capture.channels_min) + if (!snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE) || + !snd_soc_dai_stream_valid(fe->codec_dai, SNDRV_PCM_STREAM_CAPTURE)) return 0; /* skip if FE isn't currently capturing */ @@ -2929,149 +2805,10 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) static void soc_pcm_private_free(struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; /* need to sync the delayed work before releasing resources */ flush_delayed_work(&rtd->delayed_work); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (component->driver->pcm_free) - component->driver->pcm_free(pcm); - } -} - -static int soc_rtdcom_ack(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->ack) - continue; - - /* FIXME. it returns 1st ask now */ - return component->driver->ops->ack(substream); - } - - return -EINVAL; -} - -static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, - unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->copy_user) - continue; - - /* FIXME. it returns 1st copy now */ - return component->driver->ops->copy_user(substream, channel, - pos, buf, bytes); - } - - return -EINVAL; -} - -static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void *buf, unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->copy_kernel) - continue; - - /* FIXME. it returns 1st copy now */ - return component->driver->ops->copy_kernel(substream, channel, - pos, buf, bytes); - } - - return -EINVAL; -} - -static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel, - unsigned long pos, unsigned long bytes) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->fill_silence) - continue; - - /* FIXME. it returns 1st silence now */ - return component->driver->ops->fill_silence(substream, channel, - pos, bytes); - } - - return -EINVAL; -} - -static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - struct page *page; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->page) - continue; - - /* FIXME. it returns 1st page now */ - page = component->driver->ops->page(substream, offset); - if (page) - return page; - } - - return NULL; -} - -static int soc_rtdcom_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->ops || - !component->driver->ops->mmap) - continue; - - /* FIXME. it returns 1st mmap now */ - return component->driver->ops->mmap(substream, vma); - } - - return -EINVAL; + snd_soc_pcm_component_free(pcm); } /* create a new pcm */ @@ -3079,7 +2816,6 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_pcm *pcm; char new_name[64]; @@ -3090,15 +2826,23 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) playback = rtd->dai_link->dpcm_playback; capture = rtd->dai_link->dpcm_capture; } else { + /* Adapt stream for codec2codec links */ + struct snd_soc_pcm_stream *cpu_capture = rtd->dai_link->params ? + &cpu_dai->driver->playback : &cpu_dai->driver->capture; + struct snd_soc_pcm_stream *cpu_playback = rtd->dai_link->params ? + &cpu_dai->driver->capture : &cpu_dai->driver->playback; + for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) playback = 1; - if (codec_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) capture = 1; } - capture = capture && cpu_dai->driver->capture.channels_min; - playback = playback && cpu_dai->driver->playback.channels_min; + capture = capture && cpu_capture->channels_min; + playback = playback && cpu_playback->channels_min; } if (rtd->dai_link->playback_only) { @@ -3112,7 +2856,13 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } /* create the PCM */ - if (rtd->dai_link->no_pcm) { + if (rtd->dai_link->params) { + snprintf(new_name, sizeof(new_name), "codec2codec(%s)", + rtd->dai_link->stream_name); + + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + playback, capture, &pcm); + } else if (rtd->dai_link->no_pcm) { snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); @@ -3139,13 +2889,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); /* DAPM dai link stream work */ - INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); + if (rtd->dai_link->params) + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); + else + INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); pcm->nonatomic = rtd->dai_link->nonatomic; rtd->pcm = pcm; pcm->private_data = rtd; - if (rtd->dai_link->no_pcm) { + if (rtd->dai_link->no_pcm || rtd->dai_link->params) { if (playback) pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; if (capture) @@ -3162,7 +2916,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = dpcm_fe_dai_hw_free; rtd->ops.close = dpcm_fe_dai_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = soc_pcm_ioctl; + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } else { rtd->ops.open = soc_pcm_open; rtd->ops.hw_params = soc_pcm_hw_params; @@ -3171,7 +2925,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.hw_free = soc_pcm_hw_free; rtd->ops.close = soc_pcm_close; rtd->ops.pointer = soc_pcm_pointer; - rtd->ops.ioctl = soc_pcm_ioctl; + rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } for_each_rtdcom(rtd, rtdcom) { @@ -3180,18 +2934,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (!ops) continue; - if (ops->ack) - rtd->ops.ack = soc_rtdcom_ack; if (ops->copy_user) - rtd->ops.copy_user = soc_rtdcom_copy_user; - if (ops->copy_kernel) - rtd->ops.copy_kernel = soc_rtdcom_copy_kernel; - if (ops->fill_silence) - rtd->ops.fill_silence = soc_rtdcom_fill_silence; + rtd->ops.copy_user = snd_soc_pcm_component_copy_user; if (ops->page) - rtd->ops.page = soc_rtdcom_page; + rtd->ops.page = snd_soc_pcm_component_page; if (ops->mmap) - rtd->ops.mmap = soc_rtdcom_mmap; + rtd->ops.mmap = snd_soc_pcm_component_mmap; } if (playback) @@ -3200,19 +2948,10 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->pcm_new) - continue; - - ret = component->driver->pcm_new(rtd); - if (ret < 0) { - dev_err(component->dev, - "ASoC: pcm constructor failed: %d\n", - ret); - return ret; - } + ret = snd_soc_pcm_component_new(pcm); + if (ret < 0) { + dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret); + return ret; } pcm->private_free = soc_pcm_private_free; @@ -3436,11 +3175,11 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; - if (fe->cpu_dai->driver->playback.channels_min) + if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, buf + offset, out_count - offset); - if (fe->cpu_dai->driver->capture.channels_min) + if (snd_soc_dai_stream_valid(fe->cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, buf + offset, out_count - offset); @@ -3461,17 +3200,14 @@ void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) if (!rtd->dai_link) return; + if (!rtd->dai_link->dynamic) + return; + if (!rtd->card->debugfs_card_root) return; rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, rtd->card->debugfs_card_root); - if (!rtd->debugfs_dpcm_root) { - dev_dbg(rtd->dev, - "ASoC: Failed to create dpcm debugfs directory %s\n", - rtd->dai_link->name); - return; - } debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root, rtd, &dpcm_state_fops); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2eca85c04a3e..aa9a1fca46fa 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -524,7 +524,7 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); - list_for_each_entry(dai, &comp->dai_list, list) + for_each_component_dais(comp, dai) if (dai->driver == dai_drv) dai->driver = NULL; diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e3b9dd634c6d..54dcece52b0c 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -52,205 +52,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); -int snd_soc_component_enable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_enable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_enable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); - -int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_enable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); - -int snd_soc_component_disable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_disable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_disable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); - -int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_disable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); - -int snd_soc_component_nc_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_nc_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_nc_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); - -int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_nc_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); - -int snd_soc_component_get_pin_status(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_get_pin_status(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_get_pin_status(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); - -int snd_soc_component_force_enable_pin(struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_force_enable_pin(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_force_enable_pin(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); - -int snd_soc_component_force_enable_pin_unlocked( - struct snd_soc_component *component, - const char *pin) -{ - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char *full_name; - int ret; - - if (!component->name_prefix) - return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); - - full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); - if (!full_name) - return -ENOMEM; - - ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); - kfree(full_name); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); - static const struct snd_pcm_hardware dummy_dma_hardware = { /* Random values to keep userspace happy when checking constraints */ .info = SNDRV_PCM_INFO_INTERLEAVED | diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index fb01f0ca6027..bb8036ae567e 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -36,6 +36,16 @@ config SND_SOC_SOF_ACPI Say Y if you need this option If unsure select "N". +config SND_SOC_SOF_OF + tristate "SOF OF enumeration support" + depends on OF || COMPILE_TEST + select SND_SOC_SOF + select SND_SOC_SOF_OPTIONS + help + This adds support for Device Tree enumeration. This option is + required to enable i.MX8 devices. + Say Y if you need this option. If unsure select "N". + config SND_SOC_SOF_OPTIONS tristate help @@ -163,6 +173,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. +source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 8f14c9d2950b..b0a6f01bdc44 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -5,14 +5,18 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o +snd-sof-of-objs := sof-of-dev.o + snd-sof-nocodec-objs := nocodec.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o -obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o -obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o +obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o +obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o +obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5beda47cdf9f..81f28f7ff1a0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -17,8 +17,8 @@ #include "ops.h" /* SOF defaults if not provided by the platform in ms */ -#define TIMEOUT_DEFAULT_IPC_MS 5 -#define TIMEOUT_DEFAULT_BOOT_MS 100 +#define TIMEOUT_DEFAULT_IPC_MS 500 +#define TIMEOUT_DEFAULT_BOOT_MS 2000 /* * Generic object lookup APIs. diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2388477a965e..54cd431faab7 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -128,6 +128,7 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, unsigned long ipc_duration_ms = 0; bool flood_duration_test = false; unsigned long ipc_count = 0; + struct dentry *dentry; int err; #endif size_t size; @@ -149,11 +150,12 @@ static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, * ipc_duration_ms test floods the DSP for the time specified * in the debugfs entry. */ - if (strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") && - strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + dentry = file->f_path.dentry; + if (strcmp(dentry->d_name.name, "ipc_flood_count") && + strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) return -EINVAL; - if (!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + if (!strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) flood_duration_test = true; /* test completion criterion */ @@ -226,8 +228,11 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, u8 *buf; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) - if ((!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") || - !strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) && + struct dentry *dentry; + + dentry = file->f_path.dentry; + if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || + !strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) && dfse->cache_buf) { if (*ppos) return 0; @@ -290,8 +295,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, if (!pm_runtime_active(sdev->dev) && dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { dev_err(sdev->dev, - "error: debugfs entry %s cannot be read in DSP D3\n", - dfse->dfsentry->d_name.name); + "error: debugfs entry cannot be read in DSP D3\n"); kfree(buf); return -EINVAL; } @@ -356,17 +360,11 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, } #endif - dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, - dfse, &sof_dfs_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", - name); - } else { - /* add to dfsentry list */ - list_add(&dfse->list, &sdev->dfsentry_list); + debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, + &sof_dfs_fops); - } + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); return 0; } @@ -402,16 +400,10 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, return -ENOMEM; #endif - dfse->dfsentry = debugfs_create_file(name, mode, sdev->debugfs_root, - dfse, &sof_dfs_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", - name); - } else { - /* add to dfsentry list */ - list_add(&dfse->list, &sdev->dfsentry_list); - } + debugfs_create_file(name, mode, sdev->debugfs_root, dfse, + &sof_dfs_fops); + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); return 0; } @@ -426,10 +418,6 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) /* use "sof" as top level debugFS dir */ sdev->debugfs_root = debugfs_create_dir("sof", NULL); - if (IS_ERR_OR_NULL(sdev->debugfs_root)) { - dev_err(sdev->dev, "error: failed to create debugfs directory\n"); - return 0; - } /* init dfsentry list */ INIT_LIST_HEAD(&sdev->dfsentry_list); diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig new file mode 100644 index 000000000000..5acae75f5750 --- /dev/null +++ b/sound/soc/sof/imx/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +config SND_SOC_SOF_IMX_TOPLEVEL + bool "SOF support for NXP i.MX audio DSPs" + depends on ARM64|| COMPILE_TEST + depends on SND_SOC_SOF_OF + help + This adds support for Sound Open Firmware for NXP i.MX platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_IMX_TOPLEVEL + +config SND_SOC_SOF_IMX8 + tristate "SOF support for i.MX8" + depends on IMX_SCU + depends on IMX_DSP + help + This adds support for Sound Open Firmware for NXP i.MX8 platforms + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile new file mode 100644 index 000000000000..6ef908e8c807 --- /dev/null +++ b/sound/soc/sof/imx/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +snd-sof-imx8-objs := imx8.o + +obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c new file mode 100644 index 000000000000..2a22b18e5ec0 --- /dev/null +++ b/sound/soc/sof/imx/imx8.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta <daniel.baluta@nxp.com> +// +// Hardware interface for audio DSP on i.MX8 + +#include <linux/firmware.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/pm_domain.h> + +#include <linux/module.h> +#include <sound/sof.h> +#include <sound/sof/xtensa.h> +#include <linux/firmware/imx/ipc.h> +#include <linux/firmware/imx/dsp.h> + +#include <linux/firmware/imx/svc/misc.h> +#include <dt-bindings/firmware/imx/rsrc.h> +#include "../ops.h" + +/* DSP memories */ +#define IRAM_OFFSET 0x10000 +#define IRAM_SIZE (2 * 1024) +#define DRAM0_OFFSET 0x0 +#define DRAM0_SIZE (32 * 1024) +#define DRAM1_OFFSET 0x8000 +#define DRAM1_SIZE (32 * 1024) +#define SYSRAM_OFFSET 0x18000 +#define SYSRAM_SIZE (256 * 1024) +#define SYSROM_OFFSET 0x58000 +#define SYSROM_SIZE (192 * 1024) + +#define RESET_VECTOR_VADDR 0x596f8000 + +#define MBOX_OFFSET 0x800000 +#define MBOX_SIZE 0x1000 + +struct imx8_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct imx_dsp_ipc *dsp_ipc; + struct platform_device *ipc_dev; + + /* System Controller IPC handler */ + struct imx_sc_ipc *sc_ipc; + + /* Power domain handling */ + int num_domains; + struct device **pd_dev; + struct device_link **link; + +}; + +static void imx8_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + int ret = 0; + + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply has correct size? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; +} + +static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + +static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + imx8_get_reply(priv->sdev); + snd_sof_ipc_reply(priv->sdev, 0); + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + + snd_sof_ipc_msgs_rx(priv->sdev); +} + +struct imx_dsp_ops dsp_ops = { + .handle_reply = imx8_dsp_handle_reply, + .handle_request = imx8_dsp_handle_request, +}; + +static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + imx_dsp_ring_doorbell(priv->dsp_ipc, 0); + + return 0; +} + +/* + * DSP control. + */ +static int imx8_run(struct snd_sof_dev *sdev) +{ + struct imx8_priv *dsp_priv = (struct imx8_priv *)sdev->private; + int ret; + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 1); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset source select\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_AUDIO, 0x80); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of AUDIO\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_PERIPH, 0x5A); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of PERIPH %d\n", + ret); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_IRQ, 0x51); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of IRQ\n"); + return ret; + } + + imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, + RESET_VECTOR_VADDR); + + return 0; +} + +static int imx8_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct device_node *np = pdev->dev.of_node; + struct device_node *res_node; + struct resource *mmio; + struct imx8_priv *priv; + struct resource res; + u32 base, size; + int ret = 0; + int i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->private = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + /* power up device associated power domains */ + priv->num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + if (priv->num_domains < 0) { + dev_err(sdev->dev, "no power-domains property in %pOF\n", np); + return priv->num_domains; + } + + priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->pd_dev), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->link), GFP_KERNEL); + if (!priv->link) + return -ENOMEM; + + for (i = 0; i < priv->num_domains; i++) { + priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(priv->pd_dev[i])) { + ret = PTR_ERR(priv->pd_dev[i]); + goto exit_unroll_pm; + } + priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!priv->link[i]) { + ret = -ENOMEM; + dev_pm_domain_detach(priv->pd_dev[i], false); + goto exit_unroll_pm; + } + } + + ret = imx_scu_get_handle(&priv->sc_ipc); + if (ret) { + dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n", + ret); + goto exit_unroll_pm; + } + + priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", + PLATFORM_DEVID_NONE, + pdev, sizeof(*pdev)); + if (IS_ERR(priv->ipc_dev)) { + ret = PTR_ERR(priv->ipc_dev); + goto exit_unroll_pm; + } + + priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); + if (!priv->dsp_ipc) { + /* DSP IPC driver not probed yet, try later */ + ret = -EPROBE_DEFER; + dev_err(sdev->dev, "Failed to get drvdata\n"); + goto exit_pdev_unregister; + } + + imx_dsp_set_data(priv->dsp_ipc, priv); + priv->dsp_ipc->ops = &dsp_ops; + + /* DSP base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); + ret = -EINVAL; + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { + dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto exit_pdev_unregister; + } + sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + + res_node = of_parse_phandle(np, "memory-region", 0); + if (!res_node) { + dev_err(&pdev->dev, "failed to get memory region node\n"); + ret = -ENODEV; + goto exit_pdev_unregister; + } + + ret = of_address_to_resource(res_node, 0, &res); + if (ret) { + dev_err(&pdev->dev, "failed to get reserved region address\n"); + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, + res.end - res.start + + 1); + if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { + dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", + base, size); + ret = -ENOMEM; + goto exit_pdev_unregister; + } + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + return 0; + +exit_pdev_unregister: + platform_device_unregister(priv->ipc_dev); +exit_unroll_pm: + while (--i >= 0) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return ret; +} + +static int imx8_remove(struct snd_sof_dev *sdev) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + int i; + + platform_device_unregister(priv->ipc_dev); + + for (i = 0; i < priv->num_domains; i++) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return 0; +} + +/* on i.MX8 there is 1 to 1 match between type and BAR idx */ +static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +static void imx8_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); +} + +static int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + return 0; +} + +static struct snd_soc_dai_driver imx8_dai[] = { +{ + .name = "esai-port", +}, +}; + +/* i.MX8 ops */ +struct snd_sof_dsp_ops sof_imx8_ops = { + /* probe and remove */ + .probe = imx8_probe, + .remove = imx8_remove, + /* DSP core boot */ + .run = imx8_run, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* ipc */ + .send_msg = imx8_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = imx8_get_mailbox_offset, + .get_window_offset = imx8_get_window_offset, + + .ipc_msg_data = imx8_ipc_msg_data, + .ipc_pcm_params = imx8_ipc_pcm_params, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + .get_bar_index = imx8_get_bar_index, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = imx8_dai, + .num_drv = 1, /* we have only 1 ESAI interface on i.MX8 */ +}; +EXPORT_SYMBOL(sof_imx8_ops); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index dd14ce92fe10..479ba249e219 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -27,6 +27,8 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT + select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT + select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -212,6 +214,36 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_TIGERLAKE_SUPPORT + bool "SOF support for Tigerlake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tigerlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_TIGERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_ELKHARTLAKE_SUPPORT + bool "SOF support for ElkhartLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the ElkhartLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ELKHARTLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON @@ -254,6 +286,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_INTEL_NHLT if ACPI help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index fd2e26d79796..8dc7a5558da4 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -46,7 +46,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 70d524ef9bc0..e282179263e8 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -328,153 +328,6 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) } /* - * IPC Firmware ready. - */ -static void bdw_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - bdw_get_windows(sdev); - - return 0; -} - -/* * IPC Mailbox IO */ @@ -527,6 +380,16 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int bdw_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int bdw_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void bdw_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -613,11 +476,8 @@ static int bdw_probe(struct snd_sof_dev *sdev) /* register our IRQ */ sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) return sdev->ipc_irq; - } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, @@ -680,7 +540,9 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* ipc */ .send_msg = bdw_send_msg, - .fw_ready = bdw_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = bdw_get_mailbox_offset, + .get_window_offset = bdw_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 107d711efc3f..5e7a6aaa627a 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -110,153 +110,6 @@ static void byt_dsp_done(struct snd_sof_dev *sdev); static void byt_get_reply(struct snd_sof_dev *sdev); /* - * IPC Firmware ready. - */ -static void byt_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - byt_get_windows(sdev); - - return 0; -} - -/* * Debug */ @@ -423,6 +276,16 @@ static void byt_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int byt_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int byt_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void byt_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -617,7 +480,9 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -728,11 +593,8 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) irq: /* register our IRQ */ sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) return sdev->ipc_irq; - } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, @@ -779,7 +641,9 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -836,7 +700,9 @@ const struct snd_sof_dsp_ops sof_cht_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ffd8d4394537..4ddd73762d81 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -204,7 +204,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* ipc */ .send_msg = cnl_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, @@ -293,3 +295,35 @@ const struct sof_intel_dsp_desc icl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(icl_chip_info); + +const struct sof_intel_dsp_desc tgl_chip_info = { + /* Tigerlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(tgl_chip_info); + +const struct sof_intel_dsp_desc ehl_chip_info = { + /* Elkhartlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(ehl_chip_info); diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index a7e6d8227df6..1d2babdda9dd 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -12,82 +12,27 @@ #include "../sof-priv.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - -static const struct hdac_bus_ops bus_ops = { - .command = snd_hdac_bus_send_cmd, - .get_response = snd_hdac_bus_get_response, -}; - +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#include "../../codecs/hdac_hda.h" +#define sof_hda_ext_ops snd_soc_hdac_hda_get_ops() +#else +#define sof_hda_ext_ops NULL #endif -static void sof_hda_writel(u32 value, u32 __iomem *addr) -{ - writel(value, addr); -} - -static u32 sof_hda_readl(u32 __iomem *addr) -{ - return readl(addr); -} - -static void sof_hda_writew(u16 value, u16 __iomem *addr) -{ - writew(value, addr); -} - -static u16 sof_hda_readw(u16 __iomem *addr) -{ - return readw(addr); -} - -static void sof_hda_writeb(u8 value, u8 __iomem *addr) -{ - writeb(value, addr); -} - -static u8 sof_hda_readb(u8 __iomem *addr) -{ - return readb(addr); -} - -static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, - size_t size, struct snd_dma_buffer *buf) -{ - return snd_dma_alloc_pages(type, bus->dev, size, buf); -} - -static void sof_hda_dma_free_pages(struct hdac_bus *bus, - struct snd_dma_buffer *buf) -{ - snd_dma_free_pages(buf); -} - -static const struct hdac_io_ops io_ops = { - .reg_writel = sof_hda_writel, - .reg_readl = sof_hda_readl, - .reg_writew = sof_hda_writew, - .reg_readw = sof_hda_readw, - .reg_writeb = sof_hda_writeb, - .reg_readb = sof_hda_readb, - .dma_alloc_pages = sof_hda_dma_alloc_pages, - .dma_free_pages = sof_hda_dma_free_pages, -}; - /* * This can be used for both with/without hda link support. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops) +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_ext_bus_init(bus, dev, NULL, sof_hda_ext_ops); +#else /* CONFIG_SND_SOC_SOF_HDA */ memset(bus, 0, sizeof(*bus)); bus->dev = dev; - bus->io_ops = &io_ops; INIT_LIST_HEAD(&bus->stream_list); bus->irq = -1; - bus->ext_ops = ext_ops; /* * There is only one HDA bus atm. keep the index as 0. @@ -96,16 +41,5 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, bus->idx = 0; spin_lock_init(&bus->reg_lock); - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - INIT_LIST_HEAD(&bus->codec_list); - INIT_LIST_HEAD(&bus->hlink_list); - - mutex_init(&bus->cmd_mutex); - mutex_init(&bus->lock); - bus->ops = &bus_ops; - INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); - bus->cmd_dma_state = true; -#endif - +#endif /* CONFIG_SND_SOC_SOF_HDA */ } diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index b8b37f082309..3ca6795a89ba 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <sound/hdaudio_ext.h> +#include <sound/hda_register.h> #include <sound/hda_codec.h> #include <sound/hda_i915.h> #include <sound/sof.h> @@ -37,16 +38,55 @@ static void hda_codec_load_module(struct hda_codec *codec) static void hda_codec_load_module(struct hda_codec *codec) {} #endif +/* enable controller wake up event for all codecs with jack connectors */ +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; + unsigned int mask = 0; + + list_for_each_codec(codec, hbus) + if (codec->jacktbl.used) + mask |= BIT(codec->core.addr); + + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); +} + +/* check jack status after resuming from suspend mode */ +void hda_codec_jack_check(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; + + /* disable controller Wake Up event*/ + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); + + list_for_each_codec(codec, hbus) + /* + * Wake up all jack-detecting codecs regardless whether an event + * has been recorded in STATESTS + */ + if (codec->jacktbl.used) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); +} +#else +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {} +void hda_codec_jack_check(struct snd_sof_dev *sdev) {} #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +EXPORT_SYMBOL(hda_codec_jack_wake_enable); +EXPORT_SYMBOL(hda_codec_jack_check); /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { - struct hda_bus *hbus = sof_to_hbus(sdev); - struct hdac_device *hdev; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; #endif + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -62,8 +102,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) address, resp); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL); + hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) return -ENOMEM; @@ -82,8 +121,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) return 0; #else - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index ea63f83a509b..bc41028a7a01 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -164,6 +164,9 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_ext_link *hlink; +#endif struct hdac_stream *stream; int sd_offset, ret = 0; @@ -173,11 +176,6 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) hda_dsp_ctrl_misc_clock_gating(sdev, false); if (full_reset) { - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - /* reset HDA controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { @@ -245,13 +243,18 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* program the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { - snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); - snd_hdac_chip_writel(bus, DPUBASE, - upper_32_bits(bus->posbuf.addr)); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, + (u32)bus->posbuf.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, + upper_32_bits(bus->posbuf.addr)); } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); #endif bus->chip_init = true; diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a514f9cf5c9a..8796f385be76 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -210,9 +210,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, int stream_tag; int ret; - link_dev = hda_link_stream_assign(bus, substream); - if (!link_dev) - return -EBUSY; + /* get stored dma data if resuming from system suspend */ + link_dev = snd_soc_dai_get_dma_data(dai, substream); + if (!link_dev) { + link_dev = hda_link_stream_assign(bus, substream); + if (!link_dev) + return -EBUSY; + } stream_tag = hdac_stream(link_dev)->stream_tag; @@ -226,8 +230,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - hda_stream->hw_params_upon_resume = 0; - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; @@ -267,8 +269,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, hda_stream = hstream_to_sof_hda_stream(link_dev); - /* setup hw_params again only if resuming from system suspend */ - if (!hda_stream->hw_params_upon_resume) + if (link_dev->link_prepared) return 0; dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); @@ -317,22 +318,25 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_stream_start(link_dev); break; case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: /* - * clear and release link DMA channel. It will be assigned when + * clear link DMA channel. It will be assigned when * hw_params is set up again after resume. */ ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID, substream->stream); if (ret < 0) return ret; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(link_dev, - HDAC_EXT_STREAM_TYPE_LINK); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + + link_dev->link_prepared = 0; /* fallthrough */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); break; default: @@ -369,8 +373,12 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + + snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 91de4785b6a3..fb55a3c5afd0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -282,7 +282,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_suspend(struct snd_sof_dev *sdev, int state) +static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -295,6 +295,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) hda_dsp_ipc_int_disable(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (runtime_suspend) + hda_codec_jack_wake_enable(sdev); + /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); #endif @@ -329,7 +332,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) return 0; } -static int hda_resume(struct snd_sof_dev *sdev) +static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); @@ -343,7 +346,6 @@ static int hda_resume(struct snd_sof_dev *sdev) */ snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* reset and start hda controller */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { @@ -352,46 +354,11 @@ static int hda_resume(struct snd_sof_dev *sdev) return ret; } - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#else - - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* reset controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to reset controller during resume\n"); - return ret; - } - - /* take controller out of reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to ready controller during resume\n"); - return ret; - } - - /* enable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#endif - - /* enable ppcap interrupt */ - hda_dsp_ctrl_ppcap_enable(sdev, true); - hda_dsp_ctrl_ppcap_int_enable(sdev, true); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check jack status */ + if (runtime_resume) + hda_codec_jack_check(sdev); + /* turn off the links that were off before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { if (!hlink->ref_count) @@ -403,19 +370,23 @@ static int hda_resume(struct snd_sof_dev *sdev) snd_hdac_bus_stop_cmd_io(bus); #endif + /* enable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, true); + hda_dsp_ctrl_ppcap_int_enable(sdev, true); + return 0; } int hda_dsp_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, false); } int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, true); } int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) @@ -431,19 +402,19 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) return 0; } -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) { /* stop hda controller and power dsp off */ - return hda_suspend(sdev, state); + return hda_suspend(sdev, true); } -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_suspend(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); int ret; /* stop hda controller and power dsp off */ - ret = hda_suspend(sdev, state); + ret = hda_suspend(sdev, false); if (ret < 0) { dev_err(bus->dev, "error: suspending dsp\n"); return ret; @@ -454,30 +425,24 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct sof_intel_hda_stream *hda_stream; - struct hdac_ext_stream *stream; - struct hdac_stream *s; - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_stream *stream; struct hdac_ext_link *link; + struct hdac_stream *s; const char *name; int stream_tag; -#endif /* set internal flag for BE */ list_for_each_entry(s, &bus->stream_list, list) { stream = stream_to_hdac_ext_stream(s); - hda_stream = container_of(stream, struct sof_intel_hda_stream, - hda_stream); - hda_stream->hw_params_upon_resume = 1; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* - * clear and release stream. This should already be taken care - * for running streams when the SUSPEND trigger is called. - * But paused streams do not get suspended, so this needs to be - * done explicitly during suspend. + * clear stream. This should already be taken care for running + * streams when the SUSPEND trigger is called. But paused + * streams do not get suspended, so this needs to be done + * explicitly during suspend. */ if (stream->link_substream) { rtd = snd_pcm_substream_chip(stream->link_substream); @@ -485,12 +450,17 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) link = snd_hdac_ext_bus_get_link(bus, name); if (!link) return -EINVAL; + + stream->link_prepared = 0; + + if (hdac_stream(stream)->direction == + SNDRV_PCM_STREAM_CAPTURE) + continue; + stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(stream, - HDAC_EXT_STREAM_TYPE_LINK); } -#endif } +#endif return 0; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 2ecba91f5219..6aae6f18b3dc 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -266,156 +266,14 @@ out: return ret; } -/* IPC Firmware ready */ - -static void ipc_get_windows(struct snd_sof_dev *sdev) +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + - SRAM_WINDOW_OFFSET(elem->id); - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); + return HDA_DSP_MBOX_UPLINK_OFFSET; } -/* check for ABI compatibility and create memory windows on first boot */ -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = HDA_DSP_MBOX_UPLINK_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, - HDA_DSP_MBOX_UPLINK_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - ipc_get_windows(sdev); - - return 0; + return SRAM_WINDOW_OFFSET(id); } void hda_ipc_msg_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ae50839fddfe..c72e9a09eee1 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -19,13 +19,11 @@ #include <sound/hda_register.h> #include <linux/module.h> +#include <sound/intel-nhlt.h> #include <sound/sof.h> #include <sound/sof/xtensa.h> #include "../ops.h" #include "hda.h" -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) -#include "../../codecs/hdac_hda.h" -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #include <sound/soc-acpi-intel-match.h> @@ -46,6 +44,18 @@ struct hda_dsp_msg_code { const char *msg; }; +static bool hda_use_msi = IS_ENABLED(CONFIG_PCI); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +module_param_named(use_msi, hda_use_msi, bool, 0444); +MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int hda_dmic_num = -1; +module_param_named(dmic_num, hda_dmic_num, int, 0444); +MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); +#endif + static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, @@ -236,7 +246,6 @@ static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; struct hdac_bus *bus; - struct hdac_ext_bus_ops *ext_ops = NULL; struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; @@ -244,10 +253,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus = sof_to_bus(sdev); /* HDA bus init */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - ext_ops = snd_soc_hdac_hda_get_ops(); -#endif - sof_hda_bus_init(bus, &pci->dev, ext_ops); + sof_hda_bus_init(bus, &pci->dev); /* Workaround for a communication error on CFL (bko#199007) and CNL */ if (IS_CFL(pci) || IS_CNL(pci)) @@ -284,8 +290,26 @@ static int hda_init(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int check_nhlt_dmic(struct snd_sof_dev *sdev) +{ + struct nhlt_acpi_table *nhlt; + int dmic_num; + + nhlt = intel_nhlt_init(sdev->dev); + if (nhlt) { + dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); + intel_nhlt_free(nhlt); + if (dmic_num == 2 || dmic_num == 4) + return dmic_num; + } + + return 0; +} + static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename) + const char *sof_tplg_filename, + const char *idisp_str, + const char *dmic_str) { const char *tplg_filename = NULL; char *filename; @@ -299,7 +323,8 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, split_ext = strsep(&filename, "."); if (split_ext) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s-idisp.tplg", split_ext); + "%s%s%s.tplg", + split_ext, idisp_str, dmic_str); if (!tplg_filename) return NULL; } @@ -318,6 +343,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; const char *tplg_filename; + const char *idisp_str; + const char *dmic_str; + int dmic_num; int codec_num = 0; int i; #endif @@ -388,17 +416,39 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); - /* fixup topology file for HDMI only platforms */ - if (codec_num == 1) { - /* use local variable for readability */ - tplg_filename = pdata->tplg_filename; - tplg_filename = fixup_tplg_name(sdev, tplg_filename); - if (!tplg_filename) { - hda_codec_i915_exit(sdev); - return ret; - } - pdata->tplg_filename = tplg_filename; + if (codec_num == 1) + idisp_str = "-idisp"; + else + idisp_str = ""; + + /* first check NHLT for DMICs */ + dmic_num = check_nhlt_dmic(sdev); + + /* allow for module parameter override */ + if (hda_dmic_num != -1) + dmic_num = hda_dmic_num; + + switch (dmic_num) { + case 2: + dmic_str = "-2ch"; + break; + case 4: + dmic_str = "-4ch"; + break; + default: + dmic_num = 0; + dmic_str = ""; + break; } + + tplg_filename = pdata->tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename, + idisp_str, dmic_str); + if (!tplg_filename) { + hda_codec_i915_exit(sdev); + return ret; + } + pdata->tplg_filename = tplg_filename; } } @@ -535,11 +585,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * register our IRQ * let's try to enable msi firstly * if it fails, use legacy interrupt mode - * TODO: support interrupt mode selection with kernel parameter - * support msi multiple vectors + * TODO: support msi multiple vectors */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { + if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) { + dev_info(sdev->dev, "use msi interrupt mode\n"); + hdev->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = hdev->irq; + /* initialised to "false" by kzalloc() */ + sdev->msi_enabled = true; + } + + if (!sdev->msi_enabled) { dev_info(sdev->dev, "use legacy interrupt mode\n"); /* * in IO-APIC mode, hda->irq and ipc_irq are using the same @@ -547,13 +604,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) */ hdev->irq = pci->irq; sdev->ipc_irq = pci->irq; - sdev->msi_enabled = 0; - } else { - dev_info(sdev->dev, "use msi interrupt mode\n"); - hdev->irq = pci_irq_vector(pci, 0); - /* ipc irq number is the same of hda irq */ - sdev->ipc_irq = hdev->irq; - sdev->msi_enabled = 1; } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d9c17146200b..5591841a1b6f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -175,7 +175,7 @@ #define HDA_DSP_STACK_DUMP_SIZE 32 /* ROM status/error values */ -#define HDA_DSP_ROM_STS_MASK 0xf +#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0) #define HDA_DSP_ROM_INIT 0x1 #define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 #define HDA_DSP_ROM_FW_FW_LOADED 0x4 @@ -418,7 +418,6 @@ struct sof_intel_hda_stream { struct snd_sof_dev *sdev; struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; - int hw_params_upon_resume; /* set up hw_params upon resume */ int host_reserved; /* reserve host DMA channel */ }; @@ -453,9 +452,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_idle(struct snd_sof_dev *sdev); int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); @@ -520,7 +519,9 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev, int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); @@ -549,14 +550,15 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev); /* * HDA bus operations. */ -void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops); +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* * HDA Codec operations. */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev); +void hda_codec_jack_check(struct snd_sof_dev *sdev); #endif /* CONFIG_SND_SOC_SOF_HDA */ @@ -597,5 +599,7 @@ extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; +extern const struct sof_intel_dsp_desc tgl_chip_info; +extern const struct sof_intel_dsp_desc ehl_chip_info; #endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 20dfca9c93b7..b2f359d2f7e5 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -17,12 +17,6 @@ #include "sof-priv.h" #include "ops.h" -/* - * IPC message default size and timeout (ms). - * TODO: allow platforms to set size and timeout. - */ -#define IPC_TIMEOUT_MS 300 - static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); @@ -211,7 +205,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, /* wait for DSP IPC completion */ ret = wait_event_timeout(msg->waitq, msg->ipc_complete, - msecs_to_jiffies(IPC_TIMEOUT_MS)); + msecs_to_jiffies(sdev->ipc_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 952a19091c58..d7f32745fefe 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -87,12 +87,180 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) } EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); +/* + * IPC Firmware ready. + */ +static void sof_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int window_offset; + int bar; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id); + if (window_offset < 0) { + dev_warn(sdev->dev, "warn: no offset for window %d\n", + elem->id); + continue; + } + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = window_offset + elem->offset; + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = window_offset + elem->offset; + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = window_offset + elem->offset; + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = window_offset + elem->offset; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + int offset; + int bar; + int ret; + + /* mailbox must be on 4k boundary */ + offset = snd_sof_dsp_get_mailbox_offset(sdev); + if (offset < 0) { + dev_err(sdev->dev, "error: have no mailbox offset\n"); + return offset; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return -EINVAL; + } + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, bar, offset + + sizeof(struct sof_ipc_fw_ready)); + + sof_get_windows(sdev); + + return 0; +} +EXPORT_SYMBOL(sof_fw_ready); + /* generic module parser for mmaped DSPs */ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) { struct snd_sof_blk_hdr *block; - int count; + int count, bar; u32 offset; size_t remaining; @@ -123,11 +291,19 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, switch (block->type) { case SOF_FW_BLK_TYPE_RSRVD0: - case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: + case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14: continue; /* not handled atm */ case SOF_FW_BLK_TYPE_IRAM: case SOF_FW_BLK_TYPE_DRAM: + case SOF_FW_BLK_TYPE_SRAM: offset = block->offset; + bar = snd_sof_dsp_get_bar_index(sdev, block->type); + if (bar < 0) { + dev_err(sdev->dev, + "error: no BAR mapping for block type 0x%x\n", + block->type); + return bar; + } break; default: dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", @@ -145,7 +321,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_write(sdev, bar, offset, block + 1, block->size); if (remaining < block->size) { diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b1c27615b805..824d36fe59fd 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -100,6 +100,43 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* misc */ + +/** + * snd_sof_dsp_get_bar_index - Maps a section type with a BAR index + * + * @sdev: sof device + * @type: section type as described by snd_sof_fw_blk_type + * + * Returns the corresponding BAR index (a positive integer) or -EINVAL + * in case there is no mapping + */ +static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + if (sof_ops(sdev)->get_bar_index) + return sof_ops(sdev)->get_bar_index(sdev, type); + + return sdev->mmio_bar; +} + +static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->get_mailbox_offset) + return sof_ops(sdev)->get_mailbox_offset(sdev); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + +static inline int snd_sof_dsp_get_window_offset(struct snd_sof_dev *sdev, + u32 id) +{ + if (sof_ops(sdev)->get_window_offset) + return sof_ops(sdev)->get_window_offset(sdev, id); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { @@ -109,10 +146,10 @@ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) +static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->suspend) - return sof_ops(sdev)->suspend(sdev, state); + return sof_ops(sdev)->suspend(sdev); return 0; } @@ -125,11 +162,10 @@ static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, - int state) +static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->runtime_suspend) - return sof_ops(sdev)->runtime_suspend(sdev, state); + return sof_ops(sdev)->runtime_suspend(sdev); return 0; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 334e9d59b1ba..e3f6a6dc0f36 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -208,11 +208,31 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + spcm->prepared[substream->stream] = true; + /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - /* clear hw_params_upon_resume flag */ - spcm->hw_params_upon_resume[substream->stream] = 0; + return ret; +} + +static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, + struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm) +{ + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (!ret) + spcm->prepared[substream->stream] = false; return ret; } @@ -224,8 +244,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; - struct sof_ipc_stream stream; - struct sof_ipc_reply reply; int ret; /* nothing to do for BE */ @@ -236,16 +254,13 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; + if (!spcm->prepared[substream->stream]) + return 0; + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - - /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); snd_pcm_lib_free_pages(substream); @@ -278,11 +293,7 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; - /* - * check if hw_params needs to be set-up again. - * This is only needed when resuming from system sleep. - */ - if (!spcm->hw_params_upon_resume[substream->stream]) + if (spcm->prepared[substream->stream]) return 0; dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, @@ -311,6 +322,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; + bool reset_hw_params = false; int ret; /* nothing to do for BE */ @@ -351,6 +363,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + reset_hw_params = true; break; default: dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); @@ -363,21 +376,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); - if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND) - return ret; + if (!ret && reset_hw_params) + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - /* - * The hw_free op is usually called when the pcm stream is closed. - * Since the stream is not closed during suspend, the DSP needs to be - * notified explicitly to free pcm to prevent errors upon resume. - */ - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - - /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + return ret; } static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) @@ -481,6 +483,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].posn.host_posn = 0; spcm->stream[substream->stream].posn.dai_posn = 0; spcm->stream[substream->stream].substream = substream; + spcm->prepared[substream->stream] = false; ret = snd_sof_pcm_platform_open(sdev, substream); if (ret < 0) @@ -672,6 +675,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_HDA: /* do nothing for HDA dai_link */ break; + case SOF_DAI_INTEL_ALH: + /* do nothing for ALH dai_link */ + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config->type); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 278abfd10490..e23beaeefe00 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -233,7 +233,7 @@ static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) state = substream->runtime->status->state; if (state == SNDRV_PCM_STATE_SUSPENDED) - spcm->hw_params_upon_resume[dir] = 1; + spcm->prepared[dir] = false; } } @@ -377,9 +377,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* power down all DSP cores */ if (runtime_suspend) - ret = snd_sof_dsp_runtime_suspend(sdev, 0); + ret = snd_sof_dsp_runtime_suspend(sdev); else - ret = snd_sof_dsp_suspend(sdev, 0); + ret = snd_sof_dsp_suspend(sdev); if (ret < 0) dev_err(sdev->dev, "error: failed to power down DSP during suspend %d\n", diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c new file mode 100644 index 000000000000..28a9692974e5 --- /dev/null +++ b/sound/soc/sof/sof-of-dev.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta <daniel.baluta@nxp.com> +// + +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/sof.h> + +#include "ops.h" + +extern struct snd_sof_dsp_ops sof_imx8_ops; + +/* platform specific devices */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) +static struct sof_dev_desc sof_of_imx8qxp_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .nocodec_fw_filename = "sof-imx8.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8_ops, +}; +#endif + +static const struct dev_pm_ops sof_of_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) +}; + +static void sof_of_probe_complete(struct device *dev) +{ + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); +} + +static int sof_of_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + /*TODO: create a generic snd_soc_xxx_mach */ + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + const struct snd_sof_dsp_ops *ops; + int ret; + + dev_info(&pdev->dev, "DT DSP detected"); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + desc = device_get_match_data(dev); + if (!desc) + return -ENODEV; + + /* get ops for platform */ + ops = desc->ops; + if (!ops) { + dev_err(dev, "error: no matching DT descriptor ops\n"); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + /* TODO: implement case where we actually have a codec */ + return -ENODEV; +#endif + + if (mach) + mach->mach_params.platform = dev_name(dev); + + sof_pdata->machine = mach; + sof_pdata->desc = desc; + sof_pdata->dev = &pdev->dev; + sof_pdata->platform = dev_name(dev); + + /* TODO: read alternate fw and tplg filenames from DT */ + sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; + sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_of_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); + if (ret) { + dev_err(dev, "error: failed to probe DSP hardware\n"); + return ret; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_of_probe_complete(dev); +#endif + + return ret; +} + +static int sof_of_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pdev->dev); + + return 0; +} + +static const struct of_device_id sof_of_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) + { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, +#endif + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of", + .pm = &sof_of_pm, + .of_match_table = sof_of_ids, + }, +}; +module_platform_driver(snd_sof_of_driver); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 65d1bac4c6b8..d66412a77873 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -203,6 +203,42 @@ static const struct sof_dev_desc kbl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) +static const struct sof_dev_desc tgl_desc = { + .machines = snd_soc_acpi_intel_tgl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tgl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-tgl.ri", + .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) +static const struct sof_dev_desc ehl_desc = { + .machines = snd_soc_acpi_intel_ehl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &ehl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-ehl.ri", + .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -223,6 +259,9 @@ static void sof_pci_probe_complete(struct device *dev) */ pm_runtime_allow(dev); + /* mark last_busy for pm_runtime to make sure not suspend immediately */ + pm_runtime_mark_last_busy(dev); + /* follow recommendation in pci-driver.c to decrement usage counter */ pm_runtime_put_noidle(dev); } @@ -382,6 +421,14 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x06c8), .driver_data = (unsigned long)&cml_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { PCI_DEVICE(0x8086, 0xa0c8), + .driver_data = (unsigned long)&tgl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + { PCI_DEVICE(0x8086, 0x4b55), + .driver_data = (unsigned long)&ehl_desc}, +#endif { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b8c0b2a22684..730f3259dd02 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -171,10 +171,9 @@ struct snd_sof_dsp_ops { int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ /* DSP PM */ - int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ + int (*suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ - int (*runtime_suspend)(struct snd_sof_dev *sof_dev, - int state); /* optional */ + int (*runtime_suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ @@ -196,6 +195,13 @@ struct snd_sof_dsp_ops { int (*trace_trigger)(struct snd_sof_dev *sdev, int cmd); /* optional */ + /* misc */ + int (*get_bar_index)(struct snd_sof_dev *sdev, + u32 type); /* optional */ + int (*get_mailbox_offset)(struct snd_sof_dev *sdev);/* mandatory for common loader code */ + int (*get_window_offset)(struct snd_sof_dev *sdev, + u32 id);/* mandatory for common loader code */ + /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; @@ -228,7 +234,6 @@ enum sof_debugfs_access_type { /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { - struct dentry *dfsentry; size_t size; enum sof_dfsentry_type type; /* @@ -297,7 +302,7 @@ struct snd_sof_pcm { struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; - int hw_params_upon_resume[2]; /* set up hw_params upon resume */ + bool prepared[2]; /* PCM_PARAMS set successfully */ }; /* ALSA SOF Kcontrol device */ @@ -433,7 +438,7 @@ struct snd_sof_dev { u32 dtrace_error; u32 dtrace_draining; - u32 msi_enabled; + bool msi_enabled; void *private; /* core does not touch this */ }; @@ -637,6 +642,8 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); + void intel_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, void *p, size_t sz); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 432ae343f960..fc85efbad378 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -42,6 +42,13 @@ /* size of tplg abi in byte */ #define SOF_TPLG_ABI_SIZE 3 +struct sof_widget_data { + int ctrl_type; + int ipc_cmd; + struct sof_abi_hdr *pdata; + struct snd_sof_control *control; +}; + /* send pcm params ipc */ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { @@ -339,6 +346,9 @@ static const struct sof_dai_types sof_dais[] = { {"SSP", SOF_DAI_INTEL_SSP}, {"HDA", SOF_DAI_INTEL_HDA}, {"DMIC", SOF_DAI_INTEL_DMIC}, + {"ALH", SOF_DAI_INTEL_ALH}, + {"SAI", SOF_DAI_IMX_SAI}, + {"ESAI", SOF_DAI_IMX_ESAI}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -748,6 +758,9 @@ static const struct sof_topology_token ssp_tokens[] = { get_token_u16, offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag), 0}, + {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, bclk_delay), 0}, }; @@ -1739,51 +1752,34 @@ err: return ret; } -static int sof_process_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r, - int type) +static int sof_get_control_data(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + struct sof_widget_data *wdata, + size_t *size) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &tw->priv; - struct snd_soc_dapm_widget *widget = swidget->widget; const struct snd_kcontrol_new *kc; - struct soc_bytes_ext *sbe; struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; struct soc_enum *se; - struct snd_sof_control *scontrol = NULL; - struct sof_abi_hdr *pdata = NULL; - struct sof_ipc_comp_process *process; - size_t ipc_size, ipc_data_size = 0; - int ret, i, offset = 0; + int i; - if (type == SOF_COMP_NONE) { - dev_err(sdev->dev, "error: invalid process comp type %d\n", - type); - return -EINVAL; - } + *size = 0; - /* - * get possible component controls - get size of all pdata, - * then memcpy with headers - */ for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; switch (widget->dobj.widget.kcontrol_type) { case SND_SOC_TPLG_TYPE_MIXER: sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; + wdata[i].control = sm->dobj.private; break; case SND_SOC_TPLG_TYPE_BYTES: sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; + wdata[i].control = sbe->dobj.private; break; case SND_SOC_TPLG_TYPE_ENUM: se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; + wdata[i].control = se->dobj.private; break; default: dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", @@ -1792,31 +1788,97 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - if (!scontrol) { + if (!wdata[i].control) { dev_err(sdev->dev, "error: no scontrol for widget %s\n", widget->name); return -EINVAL; } - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; + wdata[i].pdata = wdata[i].control->control_data->data; + if (!wdata[i].pdata) + return -EINVAL; /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; + if (wdata[i].pdata->magic != SOF_ABI_MAGIC) + return -EINVAL; + + *size += wdata[i].pdata->size; + + /* get data type */ + switch (wdata[i].control->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE; + wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + break; + case SOF_CTRL_CMD_BINARY: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA; + wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET; + break; + default: + break; + } + } + + return 0; +} + +static int sof_process_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + int type) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dapm_widget *widget = swidget->widget; + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_process *process = NULL; + struct sof_widget_data *wdata = NULL; + size_t ipc_data_size = 0; + size_t ipc_size; + int offset = 0; + int ret = 0; + int i; - ipc_data_size += pdata->size; + if (type == SOF_COMP_NONE) { + dev_err(sdev->dev, "error: invalid process comp type %d\n", + type); + return -EINVAL; + } + + /* allocate struct for widget control data sizes and types */ + if (widget->num_kcontrols) { + wdata = kcalloc(widget->num_kcontrols, + sizeof(*wdata), + GFP_KERNEL); + + if (!wdata) + return -ENOMEM; + + /* get possible component controls and get size of all pdata */ + ret = sof_get_control_data(sdev, widget, wdata, + &ipc_data_size); + + if (ret < 0) + goto out; } ipc_size = sizeof(struct sof_ipc_comp_process) + le32_to_cpu(private->size) + ipc_data_size; + /* we are exceeding max ipc size, config needs to be sent separately */ + if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { + ipc_size -= ipc_data_size; + ipc_data_size = 0; + } + process = kzalloc(ipc_size, GFP_KERNEL); - if (!process) - return -ENOMEM; + if (!process) { + ret = -ENOMEM; + goto out; + } /* configure iir IPC message */ process->comp.hdr.size = ipc_size; @@ -1842,40 +1904,13 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, * get possible component controls - get size of all pdata, * then memcpy with headers */ - for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; - - switch (widget->dobj.widget.kcontrol_type) { - case SND_SOC_TPLG_TYPE_MIXER: - sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; - break; - case SND_SOC_TPLG_TYPE_BYTES: - sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; - break; - case SND_SOC_TPLG_TYPE_ENUM: - se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; - break; - default: - dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", - widget->dobj.widget.kcontrol_type, - widget->name); - return -EINVAL; + if (ipc_data_size) { + for (i = 0; i < widget->num_kcontrols; i++) { + memcpy(&process->data + offset, + wdata[i].pdata->data, + wdata[i].pdata->size); + offset += wdata[i].pdata->size; } - - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; - - /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; - - memcpy(&process->data + offset, pdata->data, pdata->size); - offset += pdata->size; } process->size = ipc_data_size; @@ -1883,10 +1918,35 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, ipc_size, r, sizeof(*r)); - if (ret >= 0) - return ret; + + if (ret < 0) { + dev_err(sdev->dev, "error: create process failed\n"); + goto err; + } + + /* we sent the data in single message so return */ + if (ipc_data_size) + goto out; + + /* send control data with large message supported method */ + for (i = 0; i < widget->num_kcontrols; i++) { + wdata[i].control->readback_offset = 0; + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control, + wdata[i].ipc_cmd, + wdata[i].ctrl_type, + wdata[i].control->cmd, + true); + if (ret != 0) { + dev_err(sdev->dev, "error: send control failed\n"); + break; + } + } + err: - kfree(process); + if (ret < 0) + kfree(process); +out: + kfree(wdata); return ret; } @@ -2457,6 +2517,26 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_sai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + +static int sof_link_esai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -2685,6 +2765,40 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_alh_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* init IPC */ + config->hdr.size = size; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for ALH %d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for ALH %d\n", + config->dai_index); + + return ret; +} + /* DAI link - used for any driver specific init */ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, @@ -2781,6 +2895,18 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, &config); break; + case SOF_DAI_INTEL_ALH: + ret = sof_link_alh_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_IMX_SAI: + ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_IMX_ESAI: + ret = sof_link_esai_load(scomp, index, link, cfg, hw_config, + &config); + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); ret = -EINVAL; @@ -2838,7 +2964,8 @@ found: switch (sof_dai->dai_config->type) { case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_DMIC: - /* no resource needs to be released for SSP and DMIC */ + case SOF_DAI_INTEL_ALH: + /* no resource needs to be released for SSP, DMIC and ALH */ break; case SOF_DAI_INTEL_HDA: ret = sof_link_hda_unload(sdev, link); diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index befed975161c..4c3cff031fd6 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -148,13 +148,8 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) dfse->size = sdev->dmatb.bytes; dfse->sdev = sdev; - dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root, - dfse, &sof_dfs_trace_fops); - if (!dfse->dfsentry) { - /* can't rely on debugfs, only log error and keep going */ - dev_err(sdev->dev, - "error: cannot create debugfs entry for trace\n"); - } + debugfs_create_file("trace", 0444, sdev->debugfs_root, dfse, + &sof_dfs_trace_fops); return 0; } diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index 78a6a360b4a6..4b68d6ee75da 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -202,12 +202,11 @@ static int spdif_in_probe(struct platform_device *pdev) { struct spdif_in_dev *host; struct spear_spdif_platform_data *pdata; - struct resource *res, *res_fifo; + struct resource *res_fifo; void __iomem *io_base; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(&pdev->dev, res); + io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c index 7448015a4935..f439e5503a3c 100644 --- a/sound/soc/sprd/sprd-mcdt.c +++ b/sound/soc/sprd/sprd-mcdt.c @@ -959,10 +959,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mcdt); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get MCDT interrupt\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler, 0, "sprd-mcdt", mcdt); diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 645bcbe91601..ee4a0151e63e 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -426,10 +426,8 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, UNIPERIF_FIFO_DATA_OFFSET(uni); uni->irq = platform_get_irq(priv->pdev, 0); - if (uni->irq < 0) { - dev_err(dev, "Failed to get IRQ resource\n"); + if (uni->irq < 0) return -ENXIO; - } uni->type = dev_data->type; diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index ba6452dab69b..3e7226a53e53 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -855,11 +855,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Get irqs */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT, dev_name(&pdev->dev), i2s); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 63f68e663676..ef4273361d0d 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -152,7 +152,6 @@ static int stm32_sai_probe(struct platform_device *pdev) { struct stm32_sai_data *sai; struct reset_control *rst; - struct resource *res; const struct of_device_id *of_id; u32 val; int ret; @@ -161,8 +160,7 @@ static int stm32_sai_probe(struct platform_device *pdev) if (!sai) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sai->base = devm_ioremap_resource(&pdev->dev, res); + sai->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sai->base)) return PTR_ERR(sai->base); @@ -195,10 +193,8 @@ static int stm32_sai_probe(struct platform_device *pdev) /* init irqs */ sai->irq = platform_get_irq(pdev, 0); - if (sai->irq < 0) { - dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + if (sai->irq < 0) return sai->irq; - } /* reset */ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index ee71b898897b..cd4b235fce57 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -909,10 +909,8 @@ static int stm32_spdifrx_parse_of(struct platform_device *pdev, } spdifrx->irq = platform_get_irq(pdev, 0); - if (spdifrx->irq < 0) { - dev_err(&pdev->dev, "No irq for node %s\n", pdev->name); + if (spdifrx->irq < 0) return spdifrx->irq; - } return 0; } diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 619073e7d972..ee448d5e07a6 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1424,7 +1424,7 @@ static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { }; static struct snd_soc_aux_dev aux_dev = { - .name = "Codec Analog Controls", + .dlc = COMP_EMPTY(), }; static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) @@ -1436,10 +1436,10 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; @@ -1474,10 +1474,10 @@ static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; @@ -1512,10 +1512,10 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) if (!card) return ERR_PTR(-ENOMEM); - aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + aux_dev.dlc.of_node = of_parse_phandle(dev->of_node, "allwinner,codec-analog-controls", 0); - if (!aux_dev.codec_of_node) { + if (!aux_dev.dlc.of_node) { dev_err(dev, "Can't find analog controls for codec.\n"); return ERR_PTR(-EINVAL); }; diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 85c3b2c8cd77..d0a8d5810c0a 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -46,8 +46,6 @@ #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) -#define SUN4I_I2S_FMT0_POLARITY_INVERTED (1) -#define SUN4I_I2S_FMT0_POLARITY_NORMAL (0) #define SUN4I_I2S_FMT1_REG 0x08 #define SUN4I_I2S_FIFO_TX_REG 0x0c @@ -76,10 +74,11 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) -#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 +#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 @@ -92,8 +91,19 @@ #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17) +#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) +#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) +#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) + +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) #define SUN8I_I2S_INT_STA_REG 0x0c #define SUN8I_I2S_FIFO_TX_REG 0x20 @@ -120,52 +130,33 @@ struct sun4i_i2s; * struct sun4i_i2s_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. - * @has_slave_select_bit: SoC has a bit to enable slave mode. - * @has_fmt_set_lrck_period: SoC requires lrclk period to be set. - * @has_chcfg: tx and rx slot number need to be set. - * @has_chsel_tx_chen: SoC requires that the tx channels are enabled. - * @has_chsel_offset: SoC uses offset for selecting dai operational mode. * @reg_offset_txdata: offset of the tx fifo. * @sun4i_i2s_regmap: regmap config to use. - * @mclk_offset: Value by which mclkdiv needs to be adjusted. - * @bclk_offset: Value by which bclkdiv needs to be adjusted. * @field_clkdiv_mclk_en: regmap field to enable mclk output. * @field_fmt_wss: regmap field to set word select size. * @field_fmt_sr: regmap field to set sample resolution. - * @field_fmt_bclk: regmap field to set clk polarity. - * @field_fmt_lrclk: regmap field to set frame polarity. - * @field_fmt_mode: regmap field to set the operational mode. - * @field_txchanmap: location of the tx channel mapping register. - * @field_rxchanmap: location of the rx channel mapping register. - * @field_txchansel: location of the tx channel select bit fields. - * @field_rxchansel: location of the rx channel select bit fields. */ struct sun4i_i2s_quirks { bool has_reset; - bool has_slave_select_bit; - bool has_fmt_set_lrck_period; - bool has_chcfg; - bool has_chsel_tx_chen; - bool has_chsel_offset; unsigned int reg_offset_txdata; /* TX FIFO */ const struct regmap_config *sun4i_i2s_regmap; - unsigned int mclk_offset; - unsigned int bclk_offset; /* Register fields for i2s */ struct reg_field field_clkdiv_mclk_en; struct reg_field field_fmt_wss; struct reg_field field_fmt_sr; - struct reg_field field_fmt_bclk; - struct reg_field field_fmt_lrclk; - struct reg_field field_fmt_mode; - struct reg_field field_txchanmap; - struct reg_field field_rxchanmap; - struct reg_field field_txchansel; - struct reg_field field_rxchansel; + const struct sun4i_i2s_clk_div *bclk_dividers; + unsigned int num_bclk_dividers; + const struct sun4i_i2s_clk_div *mclk_dividers; + unsigned int num_mclk_dividers; + + unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *); s8 (*get_sr)(const struct sun4i_i2s *, int); s8 (*get_wss)(const struct sun4i_i2s *, int); + int (*set_chan_cfg)(const struct sun4i_i2s *, + const struct snd_pcm_hw_params *); + int (*set_fmt)(const struct sun4i_i2s *, unsigned int); }; struct sun4i_i2s { @@ -174,7 +165,10 @@ struct sun4i_i2s { struct regmap *regmap; struct reset_control *rst; + unsigned int format; unsigned int mclk_freq; + unsigned int slots; + unsigned int slot_width; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -183,13 +177,6 @@ struct sun4i_i2s { struct regmap_field *field_clkdiv_mclk_en; struct regmap_field *field_fmt_wss; struct regmap_field *field_fmt_sr; - struct regmap_field *field_fmt_bclk; - struct regmap_field *field_fmt_lrclk; - struct regmap_field *field_fmt_mode; - struct regmap_field *field_txchanmap; - struct regmap_field *field_rxchanmap; - struct regmap_field *field_txchansel; - struct regmap_field *field_rxchansel; const struct sun4i_i2s_quirks *variant; }; @@ -221,15 +208,46 @@ static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { /* TODO - extend divide ratio supported by newer SoCs */ }; +static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { + { .div = 1, .val = 1 }, + { .div = 2, .val = 2 }, + { .div = 4, .val = 3 }, + { .div = 6, .val = 4 }, + { .div = 8, .val = 5 }, + { .div = 12, .val = 6 }, + { .div = 16, .val = 7 }, + { .div = 24, .val = 8 }, + { .div = 32, .val = 9 }, + { .div = 48, .val = 10 }, + { .div = 64, .val = 11 }, + { .div = 96, .val = 12 }, + { .div = 128, .val = 13 }, + { .div = 176, .val = 14 }, + { .div = 192, .val = 15 }, +}; + +static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) +{ + return i2s->mclk_freq; +} + +static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) +{ + return clk_get_rate(i2s->mod_clk); +} + static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, + unsigned long parent_rate, + unsigned int sampling_rate, + unsigned int channels, unsigned int word_size) { - int div = oversample_rate / word_size / 2; + const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; + int div = parent_rate / sampling_rate / word_size / channels; int i; - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { - const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; + for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { + const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; if (bdiv->div == div) return bdiv->val; @@ -239,15 +257,15 @@ static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, } static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, - unsigned int oversample_rate, - unsigned int module_rate, - unsigned int sampling_rate) + unsigned long parent_rate, + unsigned long mclk_rate) { - int div = module_rate / sampling_rate / oversample_rate; + const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; + int div = parent_rate / mclk_rate; int i; - for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { - const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; + for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { + const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; if (mdiv->div == div) return mdiv->val; @@ -270,10 +288,11 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, unsigned int rate, - unsigned int word_size) + unsigned int slots, + unsigned int slot_width) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - unsigned int oversample_rate, clk_rate; + unsigned int oversample_rate, clk_rate, bclk_parent_rate; int bclk_div, mclk_div; int ret; @@ -315,36 +334,26 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, return -EINVAL; } - bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); + bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); + bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, + rate, slots, slot_width); if (bclk_div < 0) { dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); return -EINVAL; } - mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, rate); + mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); if (mclk_div < 0) { dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); return -EINVAL; } - /* Adjust the clock division values if needed */ - bclk_div += i2s->variant->bclk_offset; - mclk_div += i2s->variant->mclk_offset; - regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); regmap_field_write(i2s->field_clkdiv_mclk_en, 1); - /* Set sync period */ - if (i2s->variant->has_fmt_set_lrck_period) - regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, - SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, - SUN8I_I2S_FMT0_LRCK_PERIOD(32)); - return 0; } @@ -381,45 +390,105 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width) return (width - 8) / 4 + 1; } -static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int sr, wss, channels; - u32 width; + unsigned int channels = params_channels(params); - channels = params_channels(params); - if (channels != 2) { - dev_err(dai->dev, "Unsupported number of channels: %d\n", - channels); - return -EINVAL; - } + /* Map the channels for playback and capture */ + regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); - if (i2s->variant->has_chcfg) { - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); - regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, - SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); - } + /* Configure the channels */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + + return 0; +} + +static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, + const struct snd_pcm_hw_params *params) +{ + unsigned int channels = params_channels(params); + unsigned int slots = channels; + unsigned int lrck_period; + + if (i2s->slots) + slots = i2s->slots; /* Map the channels for playback and capture */ - regmap_field_write(i2s->field_txchanmap, 0x76543210); - regmap_field_write(i2s->field_rxchanmap, 0x00003210); + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); /* Configure the channels */ - regmap_field_write(i2s->field_txchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN4I_I2S_CHAN_SEL_MASK, + SUN4I_I2S_CHAN_SEL(channels)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, + SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); + + switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + lrck_period = params_physical_width(params) * slots; + break; + + case SND_SOC_DAIFMT_I2S: + lrck_period = params_physical_width(params); + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, + SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); + + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_EN_MASK, + SUN8I_I2S_TX_CHAN_EN(channels)); + + return 0; +} - regmap_field_write(i2s->field_rxchansel, - SUN4I_I2S_CHAN_SEL(params_channels(params))); +static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int word_size = params_width(params); + unsigned int slot_width = params_physical_width(params); + unsigned int channels = params_channels(params); + unsigned int slots = channels; + int ret, sr, wss; + u32 width; + + if (i2s->slots) + slots = i2s->slots; + + if (i2s->slot_width) + slot_width = i2s->slot_width; - if (i2s->variant->has_chsel_tx_chen) - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_EN_MASK, - SUN8I_I2S_TX_CHAN_EN(channels)); + ret = i2s->variant->set_chan_cfg(i2s, params); + if (ret < 0) { + dev_err(dai->dev, "Invalid channel configuration\n"); + return ret; + } switch (params_physical_width(params)) { case 16: @@ -432,11 +501,11 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, } i2s->playback_dma_data.addr_width = width; - sr = i2s->variant->get_sr(i2s, params_width(params)); + sr = i2s->variant->get_sr(i2s, word_size); if (sr < 0) return -EINVAL; - wss = i2s->variant->get_wss(i2s, params_width(params)); + wss = i2s->variant->get_wss(i2s, slot_width); if (wss < 0) return -EINVAL; @@ -444,126 +513,193 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, regmap_field_write(i2s->field_fmt_sr, sr); return sun4i_i2s_set_clk_rate(dai, params_rate(params), - params_width(params)); + slots, slot_width); } -static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) { - struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 val; - u32 offset = 0; - u32 bclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; - u32 lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_NORMAL; + + /* DAI clock polarity */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_IB_NF: + /* Invert bit clock */ + val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_IF: + /* Invert frame clock */ + val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; + break; + case SND_SOC_DAIFMT_NB_NF: + val = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, + val); /* DAI Mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: val = SUN4I_I2S_FMT0_FMT_I2S; - offset = 1; break; + case SND_SOC_DAIFMT_LEFT_J: val = SUN4I_I2S_FMT0_FMT_LEFT_J; break; + case SND_SOC_DAIFMT_RIGHT_J: val = SUN4I_I2S_FMT0_FMT_RIGHT_J; break; + default: - dev_err(dai->dev, "Unsupported format: %d\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } - if (i2s->variant->has_chsel_offset) { - /* - * offset being set indicates that we're connected to an i2s - * device, however offset is only used on the sun8i block and - * i2s shares the same setting with the LJ format. Increment - * val so that the bit to value to write is correct. - */ - if (offset > 0) - val++; - /* blck offset determines whether i2s or LJ */ - regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - - regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, - SUN8I_I2S_TX_CHAN_OFFSET_MASK, - SUN8I_I2S_TX_CHAN_OFFSET(offset)); - } + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN4I_I2S_FMT0_FMT_MASK, val); - regmap_field_write(i2s->field_fmt_mode, val); + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN4I_I2S_CTRL_MODE_MASTER; + break; - /* DAI clock polarity */ + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = SUN4I_I2S_CTRL_MODE_SLAVE; + break; + + default: + return -EINVAL; + } + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_MODE_MASK, val); + return 0; +} + +static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, + unsigned int fmt) +{ + u32 mode, val; + u8 offset; + + /* + * DAI clock polarity + * + * The setup for LRCK contradicts the datasheet, but under a + * scope it's clear that the LRCK polarity is reversed + * compared to the expected polarity on the bus. + */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_IF: /* Invert both clocks */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_IB_NF: /* Invert bit clock */ - bclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; + val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; case SND_SOC_DAIFMT_NB_IF: /* Invert frame clock */ - lrclk_polarity = SUN4I_I2S_FMT0_POLARITY_INVERTED; + val = 0; break; case SND_SOC_DAIFMT_NB_NF: + val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; break; default: - dev_err(dai->dev, "Unsupported clock polarity: %d\n", - fmt & SND_SOC_DAIFMT_INV_MASK); return -EINVAL; } - regmap_field_write(i2s->field_fmt_bclk, bclk_polarity); - regmap_field_write(i2s->field_fmt_lrclk, lrclk_polarity); - - if (i2s->variant->has_slave_select_bit) { - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN4I_I2S_CTRL_MODE_MASTER; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = SUN4I_I2S_CTRL_MODE_SLAVE; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN4I_I2S_CTRL_MODE_MASK, - val); - } else { - /* - * The newer i2s block does not have a slave select bit, - * instead the clk pins are configured as inputs. - */ - /* DAI clock master masks */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - /* BCLK and LRCLK master */ - val = SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT; - break; - case SND_SOC_DAIFMT_CBM_CFM: - /* BCLK and LRCLK slave */ - val = 0; - break; - default: - dev_err(dai->dev, "Unsupported slave setting: %d\n", - fmt & SND_SOC_DAIFMT_MASTER_MASK); - return -EINVAL; - } - regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, - SUN8I_I2S_CTRL_BCLK_OUT | - SUN8I_I2S_CTRL_LRCK_OUT, - val); + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, + val); + + /* DAI Mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 1; + break; + + case SND_SOC_DAIFMT_DSP_B: + mode = SUN8I_I2S_CTRL_MODE_PCM; + offset = 0; + break; + + case SND_SOC_DAIFMT_I2S: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + mode = SUN8I_I2S_CTRL_MODE_LEFT; + offset = 0; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + mode = SUN8I_I2S_CTRL_MODE_RIGHT; + offset = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_MODE_MASK, mode); + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, + SUN8I_I2S_TX_CHAN_OFFSET_MASK, + SUN8I_I2S_TX_CHAN_OFFSET(offset)); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* BCLK and LRCLK master */ + val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* BCLK and LRCLK slave */ + val = 0; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, + val); + + return 0; +} + +static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = i2s->variant->set_fmt(i2s, fmt); + if (ret) { + dev_err(dai->dev, "Unsupported format configuration\n"); + return ret; } /* Set significant bits in our FIFOs */ @@ -572,6 +708,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); + + i2s->format = fmt; + return 0; } @@ -687,10 +826,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, return 0; } +static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (slots > 8) + return -EINVAL; + + i2s->slots = slots; + i2s->slot_width = slot_width; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, .set_sysclk = sun4i_i2s_set_sysclk, + .set_tdm_slot = sun4i_i2s_set_tdm_slot, .trigger = sun4i_i2s_trigger, }; @@ -711,15 +866,15 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, .capture = { .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .playback = { .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, @@ -913,16 +1068,15 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { @@ -932,18 +1086,22 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; +/* + * This doesn't describe the TDM controller documented in the A83t + * datasheet, but the three undocumented I2S controller that use the + * older design. + */ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, @@ -951,59 +1109,51 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .has_slave_select_bit = true, - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), - .get_sr = sun8i_i2s_get_sr_wss, - .get_wss = sun8i_i2s_get_sr_wss, + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, + .get_sr = sun4i_i2s_get_sr, + .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, - .mclk_offset = 1, - .bclk_offset = 2, - .has_fmt_set_lrck_period = true, - .has_chcfg = true, - .has_chsel_tx_chen = true, - .has_chsel_offset = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 19, 19), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_CTRL_REG, 4, 5), - .field_txchanmap = REG_FIELD(SUN8I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN8I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN8I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN8I_I2S_RX_CHAN_SEL_REG, 0, 2), + .bclk_dividers = sun8i_i2s_clk_div, + .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .mclk_dividers = sun8i_i2s_clk_div, + .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), + .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, .get_sr = sun8i_i2s_get_sr_wss, .get_wss = sun8i_i2s_get_sr_wss, + .set_chan_cfg = sun8i_i2s_set_chan_cfg, + .set_fmt = sun8i_i2s_set_soc_fmt, }; static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { .has_reset = true, .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, - .has_slave_select_bit = true, .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), - .field_fmt_bclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 6, 6), - .field_fmt_lrclk = REG_FIELD(SUN4I_I2S_FMT0_REG, 7, 7), - .field_fmt_mode = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 1), - .field_txchanmap = REG_FIELD(SUN4I_I2S_TX_CHAN_MAP_REG, 0, 31), - .field_rxchanmap = REG_FIELD(SUN4I_I2S_RX_CHAN_MAP_REG, 0, 31), - .field_txchansel = REG_FIELD(SUN4I_I2S_TX_CHAN_SEL_REG, 0, 2), - .field_rxchansel = REG_FIELD(SUN4I_I2S_RX_CHAN_SEL_REG, 0, 2), + .bclk_dividers = sun4i_i2s_bclk_div, + .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), + .mclk_dividers = sun4i_i2s_mclk_div, + .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), + .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, .get_sr = sun4i_i2s_get_sr, .get_wss = sun4i_i2s_get_wss, + .set_chan_cfg = sun4i_i2s_set_chan_cfg, + .set_fmt = sun4i_i2s_set_soc_fmt, }; static int sun4i_i2s_init_regmap_fields(struct device *dev, @@ -1027,46 +1177,7 @@ static int sun4i_i2s_init_regmap_fields(struct device *dev, if (IS_ERR(i2s->field_fmt_sr)) return PTR_ERR(i2s->field_fmt_sr); - i2s->field_fmt_bclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_bclk); - if (IS_ERR(i2s->field_fmt_bclk)) - return PTR_ERR(i2s->field_fmt_bclk); - - i2s->field_fmt_lrclk = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_lrclk); - if (IS_ERR(i2s->field_fmt_lrclk)) - return PTR_ERR(i2s->field_fmt_lrclk); - - i2s->field_fmt_mode = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_fmt_mode); - if (IS_ERR(i2s->field_fmt_mode)) - return PTR_ERR(i2s->field_fmt_mode); - - i2s->field_txchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchanmap); - if (IS_ERR(i2s->field_txchanmap)) - return PTR_ERR(i2s->field_txchanmap); - - i2s->field_rxchanmap = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchanmap); - if (IS_ERR(i2s->field_rxchanmap)) - return PTR_ERR(i2s->field_rxchanmap); - - i2s->field_txchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_txchansel); - if (IS_ERR(i2s->field_txchansel)) - return PTR_ERR(i2s->field_txchansel); - - i2s->field_rxchansel = - devm_regmap_field_alloc(dev, i2s->regmap, - i2s->variant->field_rxchansel); - return PTR_ERR_OR_ZERO(i2s->field_rxchansel); + return 0; } static int sun4i_i2s_probe(struct platform_device *pdev) @@ -1087,10 +1198,8 @@ static int sun4i_i2s_probe(struct platform_device *pdev) return PTR_ERR(regs); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Can't retrieve our interrupt\n"); + if (irq < 0) return irq; - } i2s->variant = of_device_get_match_data(&pdev->dev); if (!i2s->variant) { @@ -1154,7 +1263,7 @@ static int sun4i_i2s_probe(struct platform_device *pdev) goto err_suspend; } - ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); goto err_suspend; @@ -1185,8 +1294,6 @@ static int sun4i_i2s_remove(struct platform_device *pdev) { struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); - snd_dmaengine_pcm_unregister(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev); diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index 6d1de565350e..f5b7069bcca2 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -459,12 +459,10 @@ MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match); static int sun50i_codec_analog_probe(struct platform_device *pdev) { - struct resource *res; struct regmap *regmap; void __iomem *base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index e92aeedd6feb..be872eefa61e 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -819,12 +819,10 @@ MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); static int sun8i_codec_analog_probe(struct platform_device *pdev) { - struct resource *res; struct regmap *regmap; void __iomem *base; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 0e0e8ebaa571..55798bc8eae2 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -533,7 +533,6 @@ static const struct regmap_config sun8i_codec_regmap_config = { static int sun8i_codec_probe(struct platform_device *pdev) { - struct resource *res_base; struct sun8i_codec *scodec; void __iomem *base; int ret; @@ -556,8 +555,7 @@ static int sun8i_codec_probe(struct platform_device *pdev) return PTR_ERR(scodec->clk_bus); } - res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res_base); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { dev_err(&pdev->dev, "Failed to map the registers\n"); return PTR_ERR(base); diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 10f9c3b19c88..1070b2710d5e 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -120,7 +120,6 @@ static const struct regmap_config tegra20_das_regmap_config = { static int tegra20_das_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *regs; int ret = 0; @@ -134,8 +133,7 @@ static int tegra20_das_probe(struct platform_device *pdev) } das->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err; diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 952381260dc3..635eacbd28d4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -511,7 +511,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) const struct tegra30_ahub_soc_data *soc_data; struct reset_control *rst; int i; - struct resource *res0, *res1; + struct resource *res0; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -587,8 +587,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) } regcache_cache_only(ahub->regmap_apbif, true); - res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - regs_ahub = devm_ioremap_resource(&pdev->dev, res1); + regs_ahub = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(regs_ahub)) return PTR_ERR(regs_ahub); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index ac6983c6bd72..e6d548fa980b 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -368,7 +368,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) struct tegra30_i2s *i2s; const struct of_device_id *match; u32 cif_ids[2]; - struct resource *mem; void __iomem *regs; int ret; @@ -406,8 +405,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err_clk_put; diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig index 2197f3e1eaed..87a9b9dd4e98 100644 --- a/sound/soc/ti/Kconfig +++ b/sound/soc/ti/Kconfig @@ -12,7 +12,7 @@ config SND_SOC_TI_SDMA_PCM comment "Texas Instruments DAI support for:" config SND_SOC_DAVINCI_ASP - tristate "daVinci Audio Serial Port (ASP) or McBSP suport" + tristate "daVinci Audio Serial Port (ASP) or McBSP support" depends on ARCH_DAVINCI || COMPILE_TEST select SND_SOC_TI_EDMA_PCM help @@ -33,7 +33,7 @@ config SND_SOC_DAVINCI_MCASP - Keystone devices config SND_SOC_DAVINCI_VCIF - tristate "daVinci Voice Interface (VCIF) suport" + tristate "daVinci Voice Interface (VCIF) support" depends on ARCH_DAVINCI || COMPILE_TEST select SND_SOC_TI_EDMA_PCM help diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index bfd8d1a03ba7..686b23d7a90d 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -68,7 +68,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, /* set the CPU system clock */ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); - if (ret < 0) + if (ret < 0 && ret != -ENOTSUPP) return ret; return 0; diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index 27afdbb9adf3..d89b5c928c4d 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -598,6 +598,8 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, } #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops davinci_i2s_dai_ops = { .shutdown = davinci_i2s_shutdown, @@ -625,12 +627,14 @@ static struct snd_soc_dai_driver davinci_i2s_dai = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = DAVINCI_I2S_FORMATS, + }, .capture = { .channels_min = 2, .channels_max = 2, .rates = DAVINCI_I2S_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .formats = DAVINCI_I2S_FORMATS, + }, .ops = &davinci_i2s_dai_ops, }; diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index bc7bf15ed7a4..7aa3c32e4a49 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -109,6 +109,8 @@ struct davinci_mcasp { /* Used for comstraint setting on the second stream */ u32 channels; + int max_format_width; + u8 active_serializers[2]; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; @@ -466,6 +468,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, /* FS need to be inverted */ inv_fs = true; break; + case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_LEFT_J: /* configure a full-word SYNC pulse (LRCLK) */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); @@ -759,34 +762,30 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, int sample_width) { u32 fmt; - u32 tx_rotate = (sample_width / 4) & 0x7; + u32 tx_rotate, rx_rotate, slot_width; u32 mask = (1ULL << sample_width) - 1; - u32 slot_width = sample_width; - - /* - * For captured data we should not rotate, inversion and masking is - * enoguh to get the data to the right position: - * Format data from bus after reverse (XRBUF) - * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| - * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| - * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| - * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| - */ - u32 rx_rotate = 0; + if (mcasp->slot_width) + slot_width = mcasp->slot_width; + else if (mcasp->max_format_width) + slot_width = mcasp->max_format_width; + else + slot_width = sample_width; /* - * Setting the tdm slot width either with set_clkdiv() or - * set_tdm_slot() allows us to for example send 32 bits per - * channel to the codec, while only 16 of them carry audio - * payload. + * TX rotation: + * right aligned formats: rotate w/ slot_width + * left aligned formats: rotate w/ sample_width + * + * RX rotation: + * right aligned formats: no rotation needed + * left aligned formats: rotate w/ (slot_width - sample_width) */ - if (mcasp->slot_width) { - /* - * When we have more bclk then it is needed for the - * data, we need to use the rotation to move the - * received samples to have correct alignment. - */ - slot_width = mcasp->slot_width; + if ((mcasp->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == + SND_SOC_DAIFMT_RIGHT_J) { + tx_rotate = (slot_width / 4) & 0x7; + rx_rotate = 0; + } else { + tx_rotate = (sample_width / 4) & 0x7; rx_rotate = (slot_width - sample_width) / 4; } @@ -819,6 +818,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, u8 rx_ser = 0; u8 slots = mcasp->tdm_slots; u8 max_active_serializers = (channels + slots - 1) / slots; + u8 max_rx_serializers, max_tx_serializers; int active_serializers, numevt; u32 reg; /* Default configuration */ @@ -828,22 +828,28 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); + max_tx_serializers = max_active_serializers; + max_rx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_CAPTURE]; } else { mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS); + max_tx_serializers = + mcasp->active_serializers[SNDRV_PCM_STREAM_PLAYBACK]; + max_rx_serializers = max_active_serializers; } for (i = 0; i < mcasp->num_serializer; i++) { mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->serial_dir[i]); if (mcasp->serial_dir[i] == TX_MODE && - tx_ser < max_active_serializers) { + tx_ser < max_tx_serializers) { mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), mcasp->dismod, DISMOD_MASK); set_bit(PIN_BIT_AXR(i), &mcasp->pdir); tx_ser++; } else if (mcasp->serial_dir[i] == RX_MODE && - rx_ser < max_active_serializers) { + rx_ser < max_rx_serializers) { clear_bit(PIN_BIT_AXR(i), &mcasp->pdir); rx_ser++; } else { @@ -890,7 +896,8 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, } else { dma_data->maxburst = 0; } - return 0; + + goto out; } if (period_words % active_serializers) { @@ -920,6 +927,9 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, numevt = 0; dma_data->maxburst = numevt; +out: + mcasp->active_serializers[stream] = active_serializers; + return 0; } @@ -1159,6 +1169,37 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, int period_size = params_period_size(params); int ret; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + word_length = 8; + break; + + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + word_length = 16; + break; + + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_LE: + word_length = 32; + break; + + default: + printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); + return -EINVAL; + } + ret = davinci_mcasp_set_dai_fmt(cpu_dai, mcasp->dai_fmt); if (ret) return ret; @@ -1193,41 +1234,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_S8: - word_length = 8; - break; - - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S16_LE: - word_length = 16; - break; - - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_S24_3LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_S24_LE: - word_length = 24; - break; - - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_S32_LE: - word_length = 32; - break; - - default: - printk(KERN_WARNING "davinci-mcasp: unsupported PCM format"); - return -EINVAL; - } - davinci_config_channel_size(mcasp, word_length); - if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) + if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { mcasp->channels = channels; + if (!mcasp->max_format_width) + mcasp->max_format_width = word_length; + } return 0; } @@ -1279,6 +1292,28 @@ static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params, return snd_mask_refine(fmt, &nfmt); } +static int davinci_mcasp_hw_rule_format_width(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct davinci_mcasp_ruledata *rd = rule->private; + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_mask nfmt; + int i, format_width; + + snd_mask_none(&nfmt); + format_width = rd->mcasp->max_format_width; + + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { + if (snd_mask_test(fmt, i)) { + if (snd_pcm_format_width(i) == format_width) { + snd_mask_set(&nfmt, i); + } + } + } + + return snd_mask_refine(fmt, &nfmt); +} + static const unsigned int davinci_mcasp_dai_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, @@ -1433,12 +1468,13 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, max_channels *= tdm_slots; /* * If the already active stream has less channels than the calculated - * limnit based on the seirializers * tdm_slots, we need to use that as - * a constraint for the second stream. - * Otherwise (first stream or less allowed channels) we use the - * calculated constraint. + * limit based on the seirializers * tdm_slots, and only one serializer + * is in use we need to use that as a constraint for the second stream. + * Otherwise (first stream or less allowed channels or more than one + * serializer in use) we use the calculated constraint. */ - if (mcasp->channels && mcasp->channels < max_channels) + if (mcasp->channels && mcasp->channels < max_channels && + ruledata->serializers == 1) max_channels = mcasp->channels; /* * But we can always allow channels upto the amount of @@ -1455,7 +1491,20 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &mcasp->chconstr[substream->stream]); - if (mcasp->slot_width) { + if (mcasp->max_format_width) { + /* + * Only allow formats which require same amount of bits on the + * bus as the currently running stream + */ + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_FORMAT, + davinci_mcasp_hw_rule_format_width, + ruledata, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (ret) + return ret; + } + else if (mcasp->slot_width) { /* Only allow formats require <= slot_width bits on the bus */ ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, @@ -1501,12 +1550,15 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); mcasp->substreams[substream->stream] = NULL; + mcasp->active_serializers[substream->stream] = 0; if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) return; - if (!cpu_dai->active) + if (!cpu_dai->active) { mcasp->channels = 0; + mcasp->max_format_width = 0; + } } static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { @@ -1562,7 +1614,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { }, .ops = &davinci_mcasp_dai_ops, - .symmetric_samplebits = 1, .symmetric_rates = 1, }, { diff --git a/sound/soc/ti/edma-pcm.c b/sound/soc/ti/edma-pcm.c index 3ebea1bd15cb..634b040b65f0 100644 --- a/sound/soc/ti/edma-pcm.c +++ b/sound/soc/ti/edma-pcm.c @@ -39,7 +39,22 @@ static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = { int edma_pcm_platform_register(struct device *dev) { - return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config, 0); + struct snd_dmaengine_pcm_config *config; + + if (dev->of_node) + return devm_snd_dmaengine_pcm_register(dev, + &edma_dmaengine_pcm_config, 0); + + config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + *config = edma_dmaengine_pcm_config; + + config->chan_names[0] = "tx"; + config->chan_names[1] = "rx"; + + return devm_snd_dmaengine_pcm_register(dev, config, 0); } EXPORT_SYMBOL_GPL(edma_pcm_platform_register); diff --git a/sound/soc/ti/n810.c b/sound/soc/ti/n810.c index 2c3f2a4c1700..3ad2b6daf31e 100644 --- a/sound/soc/ti/n810.c +++ b/sound/soc/ti/n810.c @@ -46,6 +46,7 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm) switch (n810_jack_func) { case N810_JACK_HS: line1l = 1; + /* fall through */ case N810_JACK_HP: hp = 1; break; diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index bc6046534fa5..588f680a9c24 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -55,6 +55,7 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm) break; case RX51_JACK_HS: hs = 1; + /* fall through */ case RX51_JACK_HP: hp = 1; break; @@ -318,12 +319,10 @@ static struct snd_soc_dai_link rx51_dai[] = { static struct snd_soc_aux_dev rx51_aux_dev[] = { { - .name = "TLV320AIC34b", - .codec_name = "tlv320aic3x-codec.2-0019", + .dlc = COMP_AUX("tlv320aic3x-codec.2-0019"), }, { - .name = "TPA61320A2", - .codec_name = "tpa6130a2.2-0060", + .dlc = COMP_AUX("tpa6130a2.2-0060"), }, }; @@ -396,8 +395,8 @@ static int rx51_soc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n"); return -EINVAL; } - rx51_aux_dev[0].codec_name = NULL; - rx51_aux_dev[0].codec_of_node = dai_node; + rx51_aux_dev[0].dlc.name = NULL; + rx51_aux_dev[0].dlc.of_node = dai_node; rx51_codec_conf[0].dev_name = NULL; rx51_codec_conf[0].of_node = dai_node; @@ -406,8 +405,8 @@ static int rx51_soc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } - rx51_aux_dev[1].codec_name = NULL; - rx51_aux_dev[1].codec_of_node = dai_node; + rx51_aux_dev[1].dlc.name = NULL; + rx51_aux_dev[1].dlc.of_node = dai_node; rx51_codec_conf[1].dev_name = NULL; rx51_codec_conf[1].of_node = dai_node; } diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index fa001d3c1a88..e8446cc4e8f8 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -276,12 +276,10 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev) { struct uniphier_aio_chip *chip = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - struct resource *res; void __iomem *preg; int irq, ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - preg = devm_ioremap_resource(dev, res); + preg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(preg)) return PTR_ERR(preg); @@ -291,10 +289,8 @@ int uniphier_aiodma_soc_register_platform(struct platform_device *pdev) return PTR_ERR(chip->regmap); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "Could not get irq.\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(dev, irq, aiodma_irq, IRQF_SHARED, dev_name(dev), pdev); diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index f9c10165fbc1..d27e9ca07856 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -451,7 +451,6 @@ static const struct regmap_config evea_regmap_config = { static int evea_probe(struct platform_device *pdev) { struct evea_priv *evea; - struct resource *res; void __iomem *preg; int ret; @@ -475,8 +474,7 @@ static int evea_probe(struct platform_device *pdev) if (IS_ERR(evea->rst_exiv)) return PTR_ERR(evea->rst_exiv); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - preg = devm_ioremap_resource(&pdev->dev, res); + preg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(preg)) return PTR_ERR(preg); diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index dc8721f4f56b..48970efe7838 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -613,7 +613,6 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev, "irq_mm2s"); if (aud_drv_data->mm2s_irq < 0) { - dev_err(dev, "xlnx audio mm2s irq resource failed\n"); ret = aud_drv_data->mm2s_irq; goto clk_err; } @@ -640,7 +639,6 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev) aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev, "irq_s2mm"); if (aud_drv_data->s2mm_irq < 0) { - dev_err(dev, "xlnx audio s2mm irq resource failed\n"); ret = aud_drv_data->s2mm_irq; goto clk_err; } diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c index 8b353166ad44..cc641e582c82 100644 --- a/sound/soc/xilinx/xlnx_i2s.c +++ b/sound/soc/xilinx/xlnx_i2s.c @@ -95,7 +95,6 @@ MODULE_DEVICE_TABLE(of, xlnx_i2s_of_match); static int xlnx_i2s_probe(struct platform_device *pdev) { - struct resource *res; void __iomem *base; struct snd_soc_dai_driver *dai_drv; int ret; @@ -107,8 +106,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev) if (!dai_drv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c index 3b9000fd8c49..e2ca087adee6 100644 --- a/sound/soc/xilinx/xlnx_spdif.c +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -260,8 +260,7 @@ static int xlnx_spdif_probe(struct platform_device *pdev) return ret; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->base = devm_ioremap_resource(dev, res); + ctx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctx->base)) { ret = PTR_ERR(ctx->base); goto clk_err; diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 9ce2c75186b9..efd374f114a0 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -531,7 +531,6 @@ static int xtfpga_i2s_runtime_resume(struct device *dev) static int xtfpga_i2s_probe(struct platform_device *pdev) { struct xtfpga_i2s *i2s; - struct resource *mem; int err, irq; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); @@ -543,8 +542,7 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) i2s->dev = &pdev->dev; dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2s->regs = devm_ioremap_resource(&pdev->dev, mem); + i2s->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2s->regs)) { err = PTR_ERR(i2s->regs); goto err; @@ -572,7 +570,6 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "No IRQ resource\n"); err = irq; goto err; } diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c index 5e877fe9ba7b..0e5a05b25a77 100644 --- a/sound/soc/zte/zx-tdm.c +++ b/sound/soc/zte/zx-tdm.c @@ -211,7 +211,6 @@ static int zx_tdm_hw_params(struct snd_pcm_substream *substream, ts_width = 1; break; default: - ts_width = 0; dev_err(socdai->dev, "Unknown data format\n"); return -EINVAL; } |