ASoC: More updates for v5.20

More updates that came in since the last pull request I sent, a series
 of driver specific changes:
 
  - Support for AMD RPL, some Intel platforms and Mediatek MT8186.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmLnvRYACgkQJNaLcl1U
 h9CAVwf/UU9J1cHE064hgfmkMXPFlP1jPs/e9cY8MJhcAZa2fhm4y0UqEg/uZu2A
 0ipufYtJeUWXRtj6ToQj79lWxB28NVNugQxh6wEfqXcHaY81tRgdiX5kxEjmQmf7
 dpQ92so5Bn/r1TRNqYVvfjkvFefvF1DlzQgBRX61cvB5ZOTdvah7UNxq4T7+j1Rs
 +84347X0fDgcl3dbbpuTPz3G1b7D20BYfoUWzAyc/ciYuehQxdDb9sxhX7KgwupW
 li1WPYymPx5eSKm7niPVOMsORjKKceV3Zu1nlZJISCBQacdbvtQDAaXV3UtGSWne
 29lvYPTFu6a2Zz09r2LYIj7Uy3L5sg==
 =5iYn
 -----END PGP SIGNATURE-----

Merge tag 'asoc-v5.20-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: More updates for v5.20

More updates that came in since the last pull request I sent, a series
of driver specific changes:

 - Support for AMD RPL, some Intel platforms and Mediatek MT8186.
This commit is contained in:
Takashi Iwai 2022-08-01 15:26:40 +02:00
commit a3b5d4715f
98 changed files with 7731 additions and 843 deletions

View File

@ -32,8 +32,6 @@ properties:
reset-gpios:
maxItems: 1
spi-max-frequency: true
AVDD-supply:
description: Analog power support for the device.
@ -52,7 +50,10 @@ required:
- compatible
- AVDD-supply
additionalProperties: false
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/atmel,sama5d2-classd.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel ClassD Amplifier
maintainers:
- Nicolas Ferre <nicolas.ferre@microchip.com>
- Alexandre Belloni <alexandre.belloni@bootlin.com>
- Claudiu Beznea <claudiu.beznea@microchip.com>
description:
The Audio Class D Amplifier (CLASSD) is a digital input, Pulse Width
Modulated (PWM) output stereo Class D amplifier.
properties:
compatible:
const: atmel,sama5d2-classd
reg:
maxItems: 1
interrupts:
maxItems: 1
dmas:
maxItems: 1
dma-names:
const: tx
clocks:
maxItems: 2
clock-names:
items:
- const: pclk
- const: gclk
atmel,model:
$ref: /schemas/types.yaml#/definitions/string
default: CLASSD
description: The user-visible name of this sound complex.
atmel,pwm-type:
$ref: /schemas/types.yaml#/definitions/string
enum:
- single
- diff
default: single
description: PWM modulation type.
atmel,non-overlap-time:
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 5
- 10
- 15
- 20
default: 10
description:
Set non-overlapping time, the unit is nanosecond(ns).
Non-overlapping will be disabled if not specified.
required:
- compatible
- reg
- interrupts
- dmas
- dma-names
- clock-names
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
classd: sound@fc048000 {
compatible = "atmel,sama5d2-classd";
reg = <0xfc048000 0x100>;
interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
| AT91_XDMAC_DT_PERID(47))>;
dma-names = "tx";
clocks = <&classd_clk>, <&classd_gclk>;
clock-names = "pclk", "gclk";
assigned-clocks = <&classd_gclk>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_classd_default>;
atmel,model = "classd @ SAMA5D2-Xplained";
atmel,pwm-type = "diff";
atmel,non-overlap-time = <10>;
};

View File

@ -0,0 +1,85 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/atmel,sama5d2-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel I2S controller
maintainers:
- Nicolas Ferre <nicolas.ferre@microchip.com>
- Alexandre Belloni <alexandre.belloni@bootlin.com>
- Claudiu Beznea <claudiu.beznea@microchip.com>
description:
Atmel I2S (Inter-IC Sound Controller) bus is the standard
interface for connecting audio devices, such as audio codecs.
properties:
compatible:
const: atmel,sama5d2-i2s
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Peripheral clock
- description: Generated clock (Optional)
- description: I2S mux clock (Optional). Set
with gclk when Master Mode is required.
minItems: 1
clock-names:
items:
- const: pclk
- const: gclk
- const: muxclk
minItems: 1
dmas:
items:
- description: TX DMA Channel
- description: RX DMA Channel
dma-names:
items:
- const: tx
- const: rx
required:
- compatible
- reg
- interrupts
- dmas
- dma-names
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2s@f8050000 {
compatible = "atmel,sama5d2-i2s";
reg = <0xf8050000 0x300>;
interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(31))>,
<&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(32))>;
dma-names = "tx", "rx";
clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>;
clock-names = "pclk", "gclk", "muxclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s0_default>;
};

View File

@ -0,0 +1,98 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/atmel,sama5d2-pdmic.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel PDMIC decoder
maintainers:
- Claudiu Beznea <claudiu.beznea@microchip.com>
description:
Atmel Pulse Density Modulation Interface Controller
(PDMIC) peripheral is a mono PDM decoder module
that decodes an incoming PDM sample stream.
properties:
compatible:
const: atmel,sama5d2-pdmic
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: peripheral clock
- description: generated clock
clock-names:
items:
- const: pclk
- const: gclk
dmas:
maxItems: 1
dma-names:
const: rx
atmel,mic-min-freq:
$ref: /schemas/types.yaml#/definitions/uint32
description:
The minimal frequency that the microphone supports.
atmel,mic-max-freq:
$ref: /schemas/types.yaml#/definitions/uint32
description:
The maximal frequency that the microphone supports.
atmel,model:
$ref: /schemas/types.yaml#/definitions/string
default: PDMIC
description: The user-visible name of this sound card.
atmel,mic-offset:
$ref: /schemas/types.yaml#/definitions/int32
default: 0
description: The offset that should be added.
required:
- compatible
- reg
- interrupts
- dmas
- dma-names
- clock-names
- clocks
- atmel,mic-min-freq
- atmel,mic-max-freq
additionalProperties: false
examples:
- |
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
pdmic: sound@f8018000 {
compatible = "atmel,sama5d2-pdmic";
reg = <0xf8018000 0x124>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
| AT91_XDMAC_DT_PERID(50))>;
dma-names = "rx";
clocks = <&pdmic_clk>, <&pdmic_gclk>;
clock-names = "pclk", "gclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pdmic_default>;
atmel,model = "PDMIC@sama5d2_xplained";
atmel,mic-min-freq = <1000000>;
atmel,mic-max-freq = <3246000>;
atmel,mic-offset = <0x0>;
};

View File

@ -1,55 +0,0 @@
* Atmel ClassD driver under ALSA SoC architecture
Required properties:
- compatible
Should be "atmel,sama5d2-classd".
- reg
Should contain ClassD registers location and length.
- interrupts
Should contain the IRQ line for the ClassD.
- dmas
One DMA specifiers as described in atmel-dma.txt and dma.txt files.
- dma-names
Must be "tx".
- clock-names
Tuple listing input clock names.
Required elements: "pclk" and "gclk".
- clocks
Please refer to clock-bindings.txt.
- assigned-clocks
Should be <&classd_gclk>.
Optional properties:
- pinctrl-names, pinctrl-0
Please refer to pinctrl-bindings.txt.
- atmel,model
The user-visible name of this sound complex.
The default value is "CLASSD".
- atmel,pwm-type
PWM modulation type, "single" or "diff".
The default value is "single".
- atmel,non-overlap-time
Set non-overlapping time, the unit is nanosecond(ns).
There are four values,
<5>, <10>, <15>, <20>, the default value is <10>.
Non-overlapping will be disabled if not specified.
Example:
classd: classd@fc048000 {
compatible = "atmel,sama5d2-classd";
reg = <0xfc048000 0x100>;
interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
| AT91_XDMAC_DT_PERID(47))>;
dma-names = "tx";
clocks = <&classd_clk>, <&classd_gclk>;
clock-names = "pclk", "gclk";
assigned-clocks = <&classd_gclk>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_classd_default>;
atmel,model = "classd @ SAMA5D2-Xplained";
atmel,pwm-type = "diff";
atmel,non-overlap-time = <10>;
};

View File

@ -1,46 +0,0 @@
* Atmel I2S controller
Required properties:
- compatible: Should be "atmel,sama5d2-i2s".
- reg: Should be the physical base address of the controller and the
length of memory mapped region.
- interrupts: Should contain the interrupt for the controller.
- dmas: Should be one per channel name listed in the dma-names property,
as described in atmel-dma.txt and dma.txt files.
- dma-names: Two dmas have to be defined, "tx" and "rx".
This IP also supports one shared channel for both rx and tx;
if this mode is used, one "rx-tx" name must be used.
- clocks: Must contain an entry for each entry in clock-names.
Please refer to clock-bindings.txt.
- clock-names: Should be one of each entry matching the clocks phandles list:
- "pclk" (peripheral clock) Required.
- "gclk" (generated clock) Optional (1).
- "muxclk" (I2S mux clock) Optional (1).
Optional properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- princtrl-names: Should contain only one value - "default".
(1) : Only the peripheral clock is required. The generated clock and the I2S
mux clock are optional and should only be set together, when Master Mode
is required.
Example:
i2s@f8050000 {
compatible = "atmel,sama5d2-i2s";
reg = <0xf8050000 0x300>;
interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(31))>,
<&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(32))>;
dma-names = "tx", "rx";
clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>;
clock-names = "pclk", "gclk", "muxclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s0_default>;
};

View File

@ -1,55 +0,0 @@
* Atmel PDMIC driver under ALSA SoC architecture
Required properties:
- compatible
Should be "atmel,sama5d2-pdmic".
- reg
Should contain PDMIC registers location and length.
- interrupts
Should contain the IRQ line for the PDMIC.
- dmas
One DMA specifiers as described in atmel-dma.txt and dma.txt files.
- dma-names
Must be "rx".
- clock-names
Required elements:
- "pclk" peripheral clock
- "gclk" generated clock
- clocks
Must contain an entry for each required entry in clock-names.
Please refer to clock-bindings.txt.
- atmel,mic-min-freq
The minimal frequency that the micphone supports.
- atmel,mic-max-freq
The maximal frequency that the micphone supports.
Optional properties:
- pinctrl-names, pinctrl-0
Please refer to pinctrl-bindings.txt.
- atmel,model
The user-visible name of this sound card.
The default value is "PDMIC".
- atmel,mic-offset
The offset that should be added.
The range is from -32768 to 32767.
The default value is 0.
Example:
pdmic@f8018000 {
compatible = "atmel,sama5d2-pdmic";
reg = <0xf8018000 0x124>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
| AT91_XDMAC_DT_PERID(50))>;
dma-names = "rx";
clocks = <&pdmic_clk>, <&pdmic_gclk>;
clock-names = "pclk", "gclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pdmic_default>;
atmel,model = "PDMIC @ sama5d2_xplained";
atmel,mic-min-freq = <1000000>;
atmel,mic-max-freq = <3246000>;
atmel,mic-offset = <0x0>;
};

View File

@ -7,7 +7,9 @@ Must be a child node of PMIC wrapper.
Required properties:
- compatible : "mediatek,mt6358-sound".
- compatible - "string" - One of:
"mediatek,mt6358-sound"
"mediatek,mt6366-sound"
- Avdd-supply : power source of AVDD
Optional properties:

View File

@ -0,0 +1,175 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mt8186-afe-pcm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek AFE PCM controller for mt8186
maintainers:
- Jiaxin Yu <jiaxin.yu@mediatek.com>
properties:
compatible:
const: mediatek,mt8186-sound
reg:
maxItems: 1
interrupts:
maxItems: 1
resets:
maxItems: 1
reset-names:
const: audiosys
mediatek,apmixedsys:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek apmixedsys controller
mediatek,infracfg:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek infracfg controller
mediatek,topckgen:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of the mediatek topckgen controller
clocks:
items:
- description: audio infra sys clock
- description: audio infra 26M clock
- description: audio top mux
- description: audio intbus mux
- description: mainpll 136.5M clock
- description: faud1 mux
- description: apll1 clock
- description: faud2 mux
- description: apll2 clock
- description: audio engen1 mux
- description: apll1_d8 22.5792M clock
- description: audio engen2 mux
- description: apll2_d8 24.576M clock
- description: i2s0 mclk mux
- description: i2s1 mclk mux
- description: i2s2 mclk mux
- description: i2s4 mclk mux
- description: tdm mclk mux
- description: i2s0_mck divider
- description: i2s1_mck divider
- description: i2s2_mck divider
- description: i2s4_mck divider
- description: tdm_mck divider
- description: audio hires mux
- description: 26M clock
clock-names:
items:
- const: aud_infra_clk
- const: mtkaif_26m_clk
- const: top_mux_audio
- const: top_mux_audio_int
- const: top_mainpll_d2_d4
- const: top_mux_aud_1
- const: top_apll1_ck
- const: top_mux_aud_2
- const: top_apll2_ck
- const: top_mux_aud_eng1
- const: top_apll1_d8
- const: top_mux_aud_eng2
- const: top_apll2_d8
- const: top_i2s0_m_sel
- const: top_i2s1_m_sel
- const: top_i2s2_m_sel
- const: top_i2s4_m_sel
- const: top_tdm_m_sel
- const: top_apll12_div0
- const: top_apll12_div1
- const: top_apll12_div2
- const: top_apll12_div4
- const: top_apll12_div_tdm
- const: top_mux_audio_h
- const: top_clk26m_clk
required:
- compatible
- interrupts
- resets
- reset-names
- mediatek,apmixedsys
- mediatek,infracfg
- mediatek,topckgen
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
afe: mt8186-afe-pcm@11210000 {
compatible = "mediatek,mt8186-sound";
reg = <0x11210000 0x2000>;
interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
resets = <&watchdog 17>; //MT8186_TOPRGU_AUDIO_SW_RST
reset-names = "audiosys";
mediatek,apmixedsys = <&apmixedsys>;
mediatek,infracfg = <&infracfg>;
mediatek,topckgen = <&topckgen>;
clocks = <&infracfg_ao 44>, //CLK_INFRA_AO_AUDIO
<&infracfg_ao 54>, //CLK_INFRA_AO_AUDIO_26M_BCLK
<&topckgen 15>, //CLK_TOP_AUDIO
<&topckgen 16>, //CLK_TOP_AUD_INTBUS
<&topckgen 70>, //CLK_TOP_MAINPLL_D2_D4
<&topckgen 17>, //CLK_TOP_AUD_1
<&apmixedsys 12>, //CLK_APMIXED_APLL1
<&topckgen 18>, //CLK_TOP_AUD_2
<&apmixedsys 13>, //CLK_APMIXED_APLL2
<&topckgen 19>, //CLK_TOP_AUD_ENGEN1
<&topckgen 101>, //CLK_TOP_APLL1_D8
<&topckgen 20>, //CLK_TOP_AUD_ENGEN2
<&topckgen 104>, //CLK_TOP_APLL2_D8
<&topckgen 63>, //CLK_TOP_APLL_I2S0_MCK_SEL
<&topckgen 64>, //CLK_TOP_APLL_I2S1_MCK_SEL
<&topckgen 65>, //CLK_TOP_APLL_I2S2_MCK_SEL
<&topckgen 66>, //CLK_TOP_APLL_I2S4_MCK_SEL
<&topckgen 67>, //CLK_TOP_APLL_TDMOUT_MCK_SEL
<&topckgen 131>, //CLK_TOP_APLL12_CK_DIV0
<&topckgen 132>, //CLK_TOP_APLL12_CK_DIV1
<&topckgen 133>, //CLK_TOP_APLL12_CK_DIV2
<&topckgen 134>, //CLK_TOP_APLL12_CK_DIV4
<&topckgen 135>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_M
<&topckgen 44>, //CLK_TOP_AUDIO_H
<&clk26m>;
clock-names = "aud_infra_clk",
"mtkaif_26m_clk",
"top_mux_audio",
"top_mux_audio_int",
"top_mainpll_d2_d4",
"top_mux_aud_1",
"top_apll1_ck",
"top_mux_aud_2",
"top_apll2_ck",
"top_mux_aud_eng1",
"top_apll1_d8",
"top_mux_aud_eng2",
"top_apll2_d8",
"top_i2s0_m_sel",
"top_i2s1_m_sel",
"top_i2s2_m_sel",
"top_i2s4_m_sel",
"top_tdm_m_sel",
"top_apll12_div0",
"top_apll12_div1",
"top_apll12_div2",
"top_apll12_div4",
"top_apll12_div_tdm",
"top_mux_audio_h",
"top_clk26m_clk";
};
...

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mt8186-mt6366-da7219-max98357.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek MT8186 with MT6366, DA7219 and MAX98357 ASoC sound card driver
maintainers:
- Jiaxin Yu <jiaxin.yu@mediatek.com>
description:
This binding describes the MT8186 sound card.
properties:
compatible:
enum:
- mediatek,mt8186-mt6366-da7219-max98357-sound
mediatek,platform:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8186 ASoC platform.
headset-codec:
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
required:
- sound-dai
playback-codecs:
type: object
additionalProperties: false
properties:
sound-dai:
items:
- description: phandle of dp codec
- description: phandle of l channel speaker codec
- description: phandle of r channel speaker codec
minItems: 2
required:
- sound-dai
additionalProperties: false
required:
- compatible
- mediatek,platform
- headset-codec
- playback-codecs
examples:
- |
sound: mt8186-sound {
compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound";
mediatek,platform = <&afe>;
pinctrl-names = "aud_clk_mosi_off",
"aud_clk_mosi_on";
pinctrl-0 = <&aud_clk_mosi_off>;
pinctrl-1 = <&aud_clk_mosi_on>;
headset-codec {
sound-dai = <&da7219>;
};
playback-codecs {
sound-dai = <&anx_bridge_dp>,
<&max98357a>;
};
};
...

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mt8186-mt6366-rt1019-rt5682s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek MT8186 with MT6366, RT1019 and RT5682S ASoC sound card driver
maintainers:
- Jiaxin Yu <jiaxin.yu@mediatek.com>
description:
This binding describes the MT8186 sound card.
properties:
compatible:
enum:
- mediatek,mt8186-mt6366-rt1019-rt5682s-sound
mediatek,platform:
$ref: "/schemas/types.yaml#/definitions/phandle"
description: The phandle of MT8186 ASoC platform.
headset-codec:
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
required:
- sound-dai
playback-codecs:
type: object
additionalProperties: false
properties:
sound-dai:
items:
- description: phandle of dp codec
- description: phandle of l channel speaker codec
- description: phandle of r channel speaker codec
minItems: 2
required:
- sound-dai
additionalProperties: false
required:
- compatible
- mediatek,platform
- headset-codec
- playback-codecs
examples:
- |
sound: mt8186-sound {
compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound";
mediatek,platform = <&afe>;
pinctrl-names = "aud_clk_mosi_off",
"aud_clk_mosi_on";
pinctrl-0 = <&aud_clk_mosi_off>;
pinctrl-1 = <&aud_clk_mosi_on>;
headset-codec {
sound-dai = <&rt5682s>;
};
playback-codecs {
sound-dai = <&it6505dptx>,
<&rt1019p>;
};
};
...

View File

@ -127,7 +127,7 @@ properties:
gpio@42:
type: object
$ref: ../gpio/qcom,wcd934x-gpio.yaml#
$ref: /schemas/gpio/qcom,wcd934x-gpio.yaml#
patternProperties:
"^.*@[0-9a-f]+$":

View File

@ -47,6 +47,7 @@ properties:
description: The bias voltage to be used in mVolts. The voltage can take
values from 1.25V to 3V by 250mV steps. If this node is not mentioned
or the value is unknown, then the value is set to 1.25V.
$ref: "/schemas/types.yaml#/definitions/uint32"
enum: [ 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000 ]
lrclk-strength:

View File

@ -1,72 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020-2022 Texas Instruments Incorporated
%YAML 1.2
---
$id: "http://devicetree.org/schemas/sound/tas2780.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Texas Instruments TAS2780 Smart PA
maintainers:
- Raphael Xu <raphael-xu@ti.com>
description: |
The TAS2780 is a mono, digital input Class-D audio amplifier optimized for
efficiently driving high peak power into small loudspeakers.
Integrated speaker voltage and current sense provides for
real time monitoring of loudspeaker behavior.
properties:
compatible:
enum:
- ti,tas2780
reg:
maxItems: 1
description: |
I2C address of the device can be between 0x38 to 0x45.
reset-gpios:
maxItems: 1
description: GPIO used to reset the device.
interrupts:
maxItems: 1
ti,imon-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description: TDM TX current sense time slot.
ti,vmon-slot-no:
$ref: /schemas/types.yaml#/definitions/uint32
description: TDM TX voltage sense time slot.
'#sound-dai-cells':
const: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
codec: codec@38 {
compatible = "ti,tas2780";
reg = <0x38>;
#sound-dai-cells = <1>;
interrupt-parent = <&gpio1>;
interrupts = <14>;
reset-gpios = <&gpio1 15 0>;
shutdown-gpios = <&gpio1 15 0>;
ti,imon-slot-no = <0>;
ti,vmon-slot-no = <2>;
};
};
...

View File

@ -52,10 +52,6 @@ properties:
DCVDD-supply:
description: Digital core supply regulator for the DCVDD pin.
spi-max-frequency: true
additionalProperties: false
required:
- reg
- compatible
@ -64,6 +60,11 @@ required:
- DBVDD-supply
- DCVDD-supply
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
spi {

View File

@ -291,6 +291,44 @@ int acpi_get_local_address(acpi_handle handle, u32 *addr)
}
EXPORT_SYMBOL(acpi_get_local_address);
#define ACPI_MAX_SUB_BUF_SIZE 9
const char *acpi_get_subsystem_id(acpi_handle handle)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
const char *sub;
size_t len;
status = acpi_evaluate_object(handle, METHOD_NAME__SUB, NULL, &buffer);
if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "Reading ACPI _SUB failed: %#x\n", status);
return ERR_PTR(-ENODATA);
}
obj = buffer.pointer;
if (obj->type == ACPI_TYPE_STRING) {
len = strlen(obj->string.pointer);
if (len < ACPI_MAX_SUB_BUF_SIZE && len > 0) {
sub = kstrdup(obj->string.pointer, GFP_KERNEL);
if (!sub)
sub = ERR_PTR(-ENOMEM);
} else {
acpi_handle_err(handle, "ACPI _SUB Length %zu is Invalid\n", len);
sub = ERR_PTR(-ENODATA);
}
} else {
acpi_handle_warn(handle, "Warning ACPI _SUB did not return a string\n");
sub = ERR_PTR(-ENODATA);
}
acpi_os_free(buffer.pointer);
return sub;
}
EXPORT_SYMBOL_GPL(acpi_get_subsystem_id);
acpi_status
acpi_evaluate_reference(acpi_handle handle,
acpi_string pathname,

View File

@ -2725,6 +2725,9 @@ void cs_dsp_stop(struct cs_dsp *dsp)
mutex_lock(&dsp->pwr_lock);
if (dsp->client_ops->pre_stop)
dsp->client_ops->pre_stop(dsp);
dsp->running = false;
if (dsp->ops->stop_core)
@ -3177,6 +3180,110 @@ static const struct cs_dsp_ops cs_dsp_halo_ops = {
.stop_core = cs_dsp_halo_stop_core,
};
/**
* cs_dsp_chunk_write() - Format data to a DSP memory chunk
* @ch: Pointer to the chunk structure
* @nbits: Number of bits to write
* @val: Value to write
*
* This function sequentially writes values into the format required for DSP
* memory, it handles both inserting of the padding bytes and converting to
* big endian. Note that data is only committed to the chunk when a whole DSP
* words worth of data is available.
*
* Return: Zero for success, a negative number on error.
*/
int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
{
int nwrite, i;
nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits);
ch->cache <<= nwrite;
ch->cache |= val >> (nbits - nwrite);
ch->cachebits += nwrite;
nbits -= nwrite;
if (ch->cachebits == CS_DSP_DATA_WORD_BITS) {
if (cs_dsp_chunk_end(ch))
return -ENOSPC;
ch->cache &= 0xFFFFFF;
for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
*ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS;
ch->bytes += sizeof(ch->cache);
ch->cachebits = 0;
}
if (nbits)
return cs_dsp_chunk_write(ch, nbits, val);
return 0;
}
EXPORT_SYMBOL_GPL(cs_dsp_chunk_write);
/**
* cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
* @ch: Pointer to the chunk structure
*
* As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
* be written out it is possible that some data will remain in the cache, this
* function will pad that data with zeros upto a whole DSP word and write out.
*
* Return: Zero for success, a negative number on error.
*/
int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
{
if (!ch->cachebits)
return 0;
return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
}
EXPORT_SYMBOL_GPL(cs_dsp_chunk_flush);
/**
* cs_dsp_chunk_read() - Parse data from a DSP memory chunk
* @ch: Pointer to the chunk structure
* @nbits: Number of bits to read
*
* This function sequentially reads values from a DSP memory formatted buffer,
* it handles both removing of the padding bytes and converting from big endian.
*
* Return: A negative number is returned on error, otherwise the read value.
*/
int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
{
int nread, i;
u32 result;
if (!ch->cachebits) {
if (cs_dsp_chunk_end(ch))
return -ENOSPC;
ch->cache = 0;
ch->cachebits = CS_DSP_DATA_WORD_BITS;
for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
ch->cache |= *ch->data++;
ch->bytes += sizeof(ch->cache);
}
nread = min(ch->cachebits, nbits);
nbits -= nread;
result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread);
ch->cache <<= nread;
ch->cachebits -= nread;
if (nbits)
result = (result << nbits) | cs_dsp_chunk_read(ch, nbits);
return result;
}
EXPORT_SYMBOL_GPL(cs_dsp_chunk_read);
MODULE_DESCRIPTION("Cirrus Logic DSP Support");
MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
MODULE_LICENSE("GPL v2");

View File

@ -762,6 +762,7 @@ static inline u64 acpi_arch_get_root_pointer(void)
#endif
int acpi_get_local_address(acpi_handle handle, u32 *addr);
const char *acpi_get_subsystem_id(acpi_handle handle);
#else /* !CONFIG_ACPI */
@ -1023,6 +1024,11 @@ static inline int acpi_get_local_address(acpi_handle handle, u32 *addr)
return -ENODEV;
}
static inline const char *acpi_get_subsystem_id(acpi_handle handle)
{
return ERR_PTR(-ENODEV);
}
static inline int acpi_register_wakeup_handler(int wake_irq,
bool (*wakeup)(void *context), void *context)
{

View File

@ -11,6 +11,7 @@
#ifndef __CS_DSP_H
#define __CS_DSP_H
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/list.h>
@ -34,6 +35,7 @@
#define CS_ADSP2_REGION_ALL (CS_ADSP2_REGION_0 | CS_ADSP2_REGION_1_9)
#define CS_DSP_DATA_WORD_SIZE 3
#define CS_DSP_DATA_WORD_BITS (3 * BITS_PER_BYTE)
#define CS_DSP_ACKED_CTL_TIMEOUT_MS 100
#define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10
@ -189,7 +191,8 @@ struct cs_dsp {
* @control_remove: Called under the pwr_lock when a control is destroyed
* @pre_run: Called under the pwr_lock by cs_dsp_run() before the core is started
* @post_run: Called under the pwr_lock by cs_dsp_run() after the core is started
* @post_stop: Called under the pwr_lock by cs_dsp_stop()
* @pre_stop: Called under the pwr_lock by cs_dsp_stop() before the core is stopped
* @post_stop: Called under the pwr_lock by cs_dsp_stop() after the core is stopped
* @watchdog_expired: Called when a watchdog expiry is detected
*
* These callbacks give the cs_dsp client an opportunity to respond to events
@ -200,6 +203,7 @@ struct cs_dsp_client_ops {
void (*control_remove)(struct cs_dsp_coeff_ctl *ctl);
int (*pre_run)(struct cs_dsp *dsp);
int (*post_run)(struct cs_dsp *dsp);
void (*pre_stop)(struct cs_dsp *dsp);
void (*post_stop)(struct cs_dsp *dsp);
void (*watchdog_expired)(struct cs_dsp *dsp);
};
@ -250,4 +254,75 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
const char *cs_dsp_mem_region_name(unsigned int type);
/**
* struct cs_dsp_chunk - Describes a buffer holding data formatted for the DSP
* @data: Pointer to underlying buffer memory
* @max: Pointer to end of the buffer memory
* @bytes: Number of bytes read/written into the memory chunk
* @cache: Temporary holding data as it is formatted
* @cachebits: Number of bits of data currently in cache
*/
struct cs_dsp_chunk {
u8 *data;
u8 *max;
int bytes;
u32 cache;
int cachebits;
};
/**
* cs_dsp_chunk() - Create a DSP memory chunk
* @data: Pointer to the buffer that will be used to store data
* @size: Size of the buffer in bytes
*
* Return: A cs_dsp_chunk structure
*/
static inline struct cs_dsp_chunk cs_dsp_chunk(void *data, int size)
{
struct cs_dsp_chunk ch = {
.data = data,
.max = data + size,
};
return ch;
}
/**
* cs_dsp_chunk_end() - Check if a DSP memory chunk is full
* @ch: Pointer to the chunk structure
*
* Return: True if the whole buffer has been read/written
*/
static inline bool cs_dsp_chunk_end(struct cs_dsp_chunk *ch)
{
return ch->data == ch->max;
}
/**
* cs_dsp_chunk_bytes() - Number of bytes written/read from a DSP memory chunk
* @ch: Pointer to the chunk structure
*
* Return: Number of bytes read/written to the buffer
*/
static inline int cs_dsp_chunk_bytes(struct cs_dsp_chunk *ch)
{
return ch->bytes;
}
/**
* cs_dsp_chunk_valid_addr() - Check if an address is in a DSP memory chunk
* @ch: Pointer to the chunk structure
*
* Return: True if the given address is within the buffer
*/
static inline bool cs_dsp_chunk_valid_addr(struct cs_dsp_chunk *ch, void *addr)
{
return (u8 *)addr >= ch->data && (u8 *)addr < ch->max;
}
int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val);
int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch);
int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits);
#endif

View File

@ -52,6 +52,8 @@
#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES BIT(6)
/* bclk early start */
#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES BIT(7)
/* mclk always on */
#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_AON BIT(8)
/* DMIC max. four controllers for eight microphone channels */
#define SOF_DAI_INTEL_DMIC_NUM_CTRL 4

View File

@ -28,7 +28,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 22
#define SOF_ABI_MINOR 23
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */

View File

@ -413,6 +413,11 @@ static const struct config_entry config_table[] = {
.device = 0x7a50,
},
/* Alderlake-P */
{
.flags = FLAG_SOF,
.device = 0x51c8,
.codec_hid = &essx_83x6,
},
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = 0x51c8,

View File

@ -9,12 +9,12 @@ endif
ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
# snd-soc-test-objs := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o
endif
ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
# snd-soc-test-objs := soc-utils-test.o
obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) := soc-utils-test.o
obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o
endif
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)

View File

@ -117,3 +117,13 @@ config SND_AMD_ACP_CONFIG
driver modules to use
source "sound/soc/amd/acp/Kconfig"
config SND_SOC_AMD_RPL_ACP6x
tristate "AMD Audio Coprocessor-v6.2 RPL support"
depends on X86 && PCI
help
This option enables Audio Coprocessor i.e ACP v6.2 support on
AMD RPL platform. By enabling this flag build will be
triggered for ACP PCI driver.
Say m if you have such a device.
If unsure select "N".

View File

@ -17,3 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/

View File

@ -29,7 +29,7 @@
static struct platform_device *dmic_dev;
static struct platform_device *pdev;
static const struct resource acp3x_res[] = {
static const struct resource acp_res[] = {
{
.start = 0,
.end = ACP3x_REG_END - ACP3x_REG_START,
@ -70,42 +70,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
ret = pci_request_regions(pci, "AMD ACP3x audio");
if (ret < 0) {
dev_err(&pci->dev, "pci_request_regions failed\n");
return -ENOMEM;
ret = -ENOMEM;
goto disable_pci;
}
pci_set_master(pci);
res_acp = acp_res;
num_res = ARRAY_SIZE(acp_res);
switch (pci->revision) {
case 0x01:
res_acp = acp3x_res;
num_res = ARRAY_SIZE(acp3x_res);
chip->name = "acp_asoc_renoir";
chip->acp_rev = ACP3X_DEV;
break;
case 0x6f:
res_acp = acp3x_res;
num_res = ARRAY_SIZE(acp3x_res);
chip->name = "acp_asoc_rembrandt";
chip->acp_rev = ACP6X_DEV;
break;
default:
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
return -EINVAL;
ret = -EINVAL;
goto release_regions;
}
dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
if (IS_ERR(dmic_dev)) {
dev_err(dev, "failed to create DMIC device\n");
return PTR_ERR(dmic_dev);
ret = PTR_ERR(dmic_dev);
goto release_regions;
}
addr = pci_resource_start(pci, 0);
chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
if (!chip->base) {
ret = -ENOMEM;
goto release_regions;
}
res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL);
if (!res) {
platform_device_unregister(dmic_dev);
return -ENOMEM;
ret = -ENOMEM;
goto release_regions;
}
for (i = 0; i < num_res; i++, res_acp++) {
@ -134,8 +141,16 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
platform_device_unregister(dmic_dev);
ret = PTR_ERR(pdev);
goto release_regions;
}
return ret;
release_regions:
pci_release_regions(pci);
disable_pci:
pci_disable_device(pci);
return ret;
};

View File

@ -94,19 +94,19 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
struct acp_resource *rsrc = adata->rsrc;
struct acp_stream *stream;
u16 i2s_flag = 0;
u32 val, val1, i;
u32 ext_intr_stat, ext_intr_stat1, i;
if (!adata)
return IRQ_NONE;
if (adata->rsrc->no_of_ctrls == 2)
val1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
val = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
for (i = 0; i < ACP_MAX_STREAM; i++) {
stream = adata->stream[i];
if (stream && (val & stream->irq_bit)) {
if (stream && (ext_intr_stat & stream->irq_bit)) {
writel(stream->irq_bit,
ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
snd_pcm_period_elapsed(stream->substream);
@ -114,7 +114,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
break;
}
if (adata->rsrc->no_of_ctrls == 2) {
if (stream && (val1 & stream->irq_bit)) {
if (stream && (ext_intr_stat1 & stream->irq_bit)) {
writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata,
(rsrc->irqp_used - 1)));
snd_pcm_period_elapsed(stream->substream);
@ -258,13 +258,6 @@ static int acp_dma_new(struct snd_soc_component *component,
return 0;
}
static int acp_dma_mmap(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
return snd_pcm_lib_default_mmap(substream, vma);
}
static int acp_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@ -288,7 +281,6 @@ static const struct snd_soc_component_driver acp_pcm_component = {
.close = acp_dma_close,
.hw_params = acp_dma_hw_params,
.pointer = acp_dma_pointer,
.mmap = acp_dma_mmap,
.pcm_construct = acp_dma_new,
.legacy_dai_naming = 1,
};

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0+
# RPL platform Support
snd-rpl-pci-acp6x-objs := rpl-pci-acp6x.o
obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o

View File

@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AMD RPL ACP PCI Driver
*
* Copyright 2022 Advanced Micro Devices, Inc.
*/
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include "rpl_acp6x.h"
struct rpl_dev_data {
void __iomem *acp6x_base;
};
static int rpl_power_on(void __iomem *acp_base)
{
u32 val;
int timeout;
val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
if (!val)
return val;
if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
timeout = 0;
while (++timeout < 500) {
val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
if (!val)
return 0;
udelay(1);
}
return -ETIMEDOUT;
}
static int rpl_reset(void __iomem *acp_base)
{
u32 val;
int timeout;
rpl_acp_writel(1, acp_base + ACP_SOFT_RESET);
timeout = 0;
while (++timeout < 500) {
val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
break;
cpu_relax();
}
rpl_acp_writel(0, acp_base + ACP_SOFT_RESET);
timeout = 0;
while (++timeout < 500) {
val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
if (!val)
return 0;
cpu_relax();
}
return -ETIMEDOUT;
}
static int rpl_init(void __iomem *acp_base)
{
int ret;
/* power on */
ret = rpl_power_on(acp_base);
if (ret) {
pr_err("ACP power on failed\n");
return ret;
}
rpl_acp_writel(0x01, acp_base + ACP_CONTROL);
/* Reset */
ret = rpl_reset(acp_base);
if (ret) {
pr_err("ACP reset failed\n");
return ret;
}
rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL);
return 0;
}
static int rpl_deinit(void __iomem *acp_base)
{
int ret;
/* Reset */
ret = rpl_reset(acp_base);
if (ret) {
pr_err("ACP reset failed\n");
return ret;
}
rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL);
rpl_acp_writel(0x00, acp_base + ACP_CONTROL);
return 0;
}
static int snd_rpl_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
struct rpl_dev_data *adata;
u32 addr;
int ret;
/* RPL device check */
switch (pci->revision) {
case 0x62:
break;
default:
dev_dbg(&pci->dev, "acp6x pci device not found\n");
return -ENODEV;
}
if (pci_enable_device(pci)) {
dev_err(&pci->dev, "pci_enable_device failed\n");
return -ENODEV;
}
ret = pci_request_regions(pci, "AMD ACP6x audio");
if (ret < 0) {
dev_err(&pci->dev, "pci_request_regions failed\n");
goto disable_pci;
}
adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data),
GFP_KERNEL);
if (!adata) {
ret = -ENOMEM;
goto release_regions;
}
addr = pci_resource_start(pci, 0);
adata->acp6x_base = devm_ioremap(&pci->dev, addr,
pci_resource_len(pci, 0));
if (!adata->acp6x_base) {
ret = -ENOMEM;
goto release_regions;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
ret = rpl_init(adata->acp6x_base);
if (ret)
goto release_regions;
pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pci->dev);
pm_runtime_put_noidle(&pci->dev);
pm_runtime_allow(&pci->dev);
return 0;
release_regions:
pci_release_regions(pci);
disable_pci:
pci_disable_device(pci);
return ret;
}
static int __maybe_unused snd_rpl_suspend(struct device *dev)
{
struct rpl_dev_data *adata;
int ret;
adata = dev_get_drvdata(dev);
ret = rpl_deinit(adata->acp6x_base);
if (ret)
dev_err(dev, "ACP de-init failed\n");
return ret;
}
static int __maybe_unused snd_rpl_resume(struct device *dev)
{
struct rpl_dev_data *adata;
int ret;
adata = dev_get_drvdata(dev);
ret = rpl_init(adata->acp6x_base);
if (ret)
dev_err(dev, "ACP init failed\n");
return ret;
}
static const struct dev_pm_ops rpl_pm = {
SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
};
static void snd_rpl_remove(struct pci_dev *pci)
{
struct rpl_dev_data *adata;
int ret;
adata = pci_get_drvdata(pci);
ret = rpl_deinit(adata->acp6x_base);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
pm_runtime_forbid(&pci->dev);
pm_runtime_get_noresume(&pci->dev);
pci_release_regions(pci);
pci_disable_device(pci);
}
static const struct pci_device_id snd_rpl_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
.class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
.class_mask = 0xffffff },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, snd_rpl_ids);
static struct pci_driver rpl_acp6x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_rpl_ids,
.probe = snd_rpl_probe,
.remove = snd_rpl_remove,
.driver = {
.pm = &rpl_pm,
}
};
module_pci_driver(rpl_acp6x_driver);
MODULE_DESCRIPTION("AMD ACP RPL PCI driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ACP Driver
*
* Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
*/
#include "rpl_acp6x_chip_offset_byte.h"
#define ACP_DEVICE_ID 0x15E2
#define ACP6x_PHY_BASE_ADDRESS 0x1240000
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0
#define ACP_PGFSM_STATUS_MASK 3
#define ACP_POWERED_ON 0
#define ACP_POWER_ON_IN_PROGRESS 1
#define ACP_POWERED_OFF 2
#define ACP_POWER_OFF_IN_PROGRESS 3
#define DELAY_US 5
#define ACP_COUNTER 20000
/* time in ms for runtime suspend delay */
#define ACP_SUSPEND_DELAY_MS 2000
static inline u32 rpl_acp_readl(void __iomem *base_addr)
{
return readl(base_addr - ACP6x_PHY_BASE_ADDRESS);
}
static inline void rpl_acp_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr - ACP6x_PHY_BASE_ADDRESS);
}

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ACP 6.2 Register Documentation
*
* Copyright 2022 Advanced Micro Devices, Inc.
*/
#ifndef _rpl_acp6x_OFFSET_HEADER
#define _rpl_acp6x_OFFSET_HEADER
/* Registers from ACP_CLKRST block */
#define ACP_SOFT_RESET 0x1241000
#define ACP_CONTROL 0x1241004
#define ACP_STATUS 0x1241008
#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
#define ACP_PGFSM_CONTROL 0x124101C
#define ACP_PGFSM_STATUS 0x1241020
#define ACP_CLKMUX_SEL 0x1241024
/* Registers from ACP_AON block */
#define ACP_PME_EN 0x1241400
#define ACP_DEVICE_STATE 0x1241404
#define AZ_DEVICE_STATE 0x1241408
#define ACP_PIN_CONFIG 0x1241440
#define ACP_PAD_PULLUP_CTRL 0x1241444
#define ACP_PAD_PULLDOWN_CTRL 0x1241448
#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x124144C
#define ACP_PAD_SCHMEN_CTRL 0x1241450
#endif

View File

@ -178,8 +178,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
ret = 0;
for (i = 0; i < num_codecs; i++) {
codec_dai = asoc_rtd_to_codec(rtd, i);
if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) ||
(strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) {
if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) {
switch (params_rate(params)) {
case 48000:
bclk_val = 1536000;

View File

@ -105,28 +105,14 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21AW"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CM"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21AX"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21BN"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"),
DMI_MATCH(DMI_PRODUCT_NAME, "21CN"),
}
},
{
@ -157,20 +143,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "21CL"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D8"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21D9"),
}
},
{}
};

View File

@ -159,7 +159,7 @@ static int snd_acp6x_probe(struct pci_dev *pci,
case 0x6f:
break;
default:
dev_err(&pci->dev, "acp6x pci device not found\n");
dev_dbg(&pci->dev, "acp6x pci device not found\n");
return -ENODEV;
}
if (pci_enable_device(pci)) {

View File

@ -762,7 +762,6 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
return 0;
}
#ifdef CONFIG_PM
static int atmel_ssc_suspend(struct snd_soc_component *component)
{
struct atmel_ssc_info *ssc_p;
@ -821,10 +820,6 @@ static int atmel_ssc_resume(struct snd_soc_component *component)
return 0;
}
#else /* CONFIG_PM */
# define atmel_ssc_suspend NULL
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@ -859,8 +854,8 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
static const struct snd_soc_component_driver atmel_ssc_component = {
.name = "atmel-ssc",
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.suspend = pm_ptr(atmel_ssc_suspend),
.resume = pm_ptr(atmel_ssc_resume),
.legacy_dai_naming = 1,
};

View File

@ -221,11 +221,11 @@ struct mchp_spdifrx_user_data {
};
struct mchp_spdifrx_mixer_control {
struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS];
struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS];
bool ulock;
bool badf;
bool signal;
struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS];
struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS];
bool ulock;
bool badf;
bool signal;
};
struct mchp_spdifrx_dev {
@ -288,15 +288,17 @@ static void mchp_spdifrx_isr_blockend_en(struct mchp_spdifrx_dev *dev)
spin_unlock_irqrestore(&dev->blockend_lock, flags);
}
/* called from atomic context only */
/* called from atomic/non-atomic context */
static void mchp_spdifrx_isr_blockend_dis(struct mchp_spdifrx_dev *dev)
{
spin_lock(&dev->blockend_lock);
unsigned long flags;
spin_lock_irqsave(&dev->blockend_lock, flags);
dev->blockend_refcount--;
/* don't enable BLOCKEND interrupt if it's already enabled */
if (dev->blockend_refcount == 0)
regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND);
spin_unlock(&dev->blockend_lock);
spin_unlock_irqrestore(&dev->blockend_lock, flags);
}
static irqreturn_t mchp_spdif_interrupt(int irq, void *dev_id)
@ -575,6 +577,7 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev,
if (ret <= 0) {
dev_dbg(dev->dev, "user data for channel %d timeout\n",
channel);
mchp_spdifrx_isr_blockend_dis(dev);
return ret;
}

View File

@ -196,7 +196,6 @@ struct mchp_spdiftx_dev {
struct clk *pclk;
struct clk *gclk;
unsigned int fmt;
const struct mchp_i2s_caps *caps;
int gclk_enabled:1;
};
@ -341,12 +340,10 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd,
ret = regmap_write(dev->regmap, SPDIFTX_MR, mr);
spin_unlock(&ctrl->lock);
if (ret) {
if (ret)
dev_err(dev->dev, "unable to disable TX: %d\n", ret);
return ret;
}
return 0;
return ret;
}
static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
@ -763,12 +760,10 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = {
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids);
static int mchp_spdiftx_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct mchp_spdiftx_dev *dev;
struct resource *mem;
struct regmap *regmap;
@ -782,11 +777,6 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
/* Get hardware capabilities. */
match = of_match_node(mchp_spdiftx_dt_ids, np);
if (match)
dev->caps = match->data;
/* Map I/O registers. */
base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
if (IS_ERR(base))
@ -848,12 +838,10 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
err = devm_snd_soc_register_component(&pdev->dev,
&mchp_spdiftx_component,
&mchp_spdiftx_dai, 1);
if (err) {
if (err)
dev_err(&pdev->dev, "failed to register component: %d\n", err);
return err;
}
return 0;
return err;
}
static struct platform_driver mchp_spdiftx_driver = {

View File

@ -6,6 +6,7 @@
//
// Author: David Rhodes <david.rhodes@cirrus.com>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
@ -1142,6 +1143,30 @@ err_dsp:
return ret;
}
static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
{
acpi_handle handle = ACPI_HANDLE(cs35l41->dev);
const char *sub;
/* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
if (!handle)
return 0;
sub = acpi_get_subsystem_id(handle);
if (IS_ERR(sub)) {
/* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */
if (PTR_ERR(sub) == -ENODATA)
return 0;
else
return PTR_ERR(sub);
}
cs35l41->dsp.system_name = sub;
dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name);
return 0;
}
int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg)
{
u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match;
@ -1270,6 +1295,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
goto err;
}
ret = cs35l41_acpi_get_name(cs35l41);
if (ret < 0)
goto err;
ret = cs35l41_dsp_init(cs35l41);
if (ret < 0)
goto err;
@ -1316,6 +1345,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
pm_runtime_disable(cs35l41->dev);
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
kfree(cs35l41->dsp.system_name);
wm_adsp2_remove(&cs35l41->dsp);
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);

View File

@ -36,6 +36,7 @@
static int nau8821_configure_sysclk(struct nau8821 *nau8821,
int clk_id, unsigned int freq);
static bool nau8821_is_jack_inserted(struct regmap *regmap);
struct nau8821_fll {
int mclk_src;
@ -495,7 +496,33 @@ static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w,
return 0;
}
static int system_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
if (SND_SOC_DAPM_EVENT_OFF(event)) {
dev_dbg(nau8821->dev, "system clock control : POWER OFF\n");
/* Set clock source to disable or internal clock before the
* playback or capture end. Codec needs clock for Jack
* detection and button press if jack inserted; otherwise,
* the clock should be closed.
*/
if (nau8821_is_jack_inserted(nau8821->regmap)) {
nau8821_configure_sysclk(nau8821,
NAU8821_CLK_INTERNAL, 0);
} else {
nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0);
}
}
return 0;
}
static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
system_clock_control, SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8821_R74_MIC_BIAS,
NAU8821_MICBIAS_POWERUP_SFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0,
@ -607,6 +634,9 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = {
{"AIFTX", NULL, "ADCL Digital path"},
{"AIFTX", NULL, "ADCR Digital path"},
{"AIFTX", NULL, "System Clock"},
{"AIFRX", NULL, "System Clock"},
{"DDACL", NULL, "AIFRX"},
{"DDACR", NULL, "AIFRX"},
@ -1699,15 +1729,6 @@ static int nau8821_i2c_probe(struct i2c_client *i2c)
return ret;
}
static int nau8821_i2c_remove(struct i2c_client *i2c_client)
{
struct nau8821 *nau8821 = i2c_get_clientdata(i2c_client);
devm_free_irq(nau8821->dev, nau8821->irq, nau8821);
return 0;
}
static const struct i2c_device_id nau8821_i2c_ids[] = {
{ "nau8821", 0 },
{ }
@ -1737,7 +1758,6 @@ static struct i2c_driver nau8821_driver = {
.acpi_match_table = ACPI_PTR(nau8821_acpi_match),
},
.probe_new = nau8821_i2c_probe,
.remove = nau8821_i2c_remove,
.id_table = nau8821_i2c_ids,
};
module_i2c_driver(nau8821_driver);

View File

@ -537,6 +537,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
struct device *codec_dev = NULL;
const char *codec_dai_name;
const char *codec_dev_name;
u32 asrc_fmt = 0;
u32 width;
int ret;
@ -829,8 +830,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto asrc_fail;
}
ret = of_property_read_u32(asrc_np, "fsl,asrc-format",
&priv->asrc_format);
ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(asrc_np, "fsl,asrc-width",

View File

@ -1066,6 +1066,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
struct resource *res;
void __iomem *regs;
int irq, ret, i;
u32 asrc_fmt = 0;
u32 map_idx;
char tmp[16];
u32 width;
@ -1174,7 +1175,8 @@ static int fsl_asrc_probe(struct platform_device *pdev)
return ret;
}
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format);
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
if (ret) {
ret = of_property_read_u32(np, "fsl,asrc-width", &width);
if (ret) {
@ -1197,7 +1199,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
}
if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) {
if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) {
dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n");
asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
}

View File

@ -476,7 +476,8 @@ static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc,
struct fsl_asrc_pair *ctx;
struct device *dev;
u32 inrate, outrate, offset = 0;
u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt;
u32 in_s_rate, out_s_rate;
snd_pcm_format_t in_s_fmt, out_s_fmt;
int ret, i;
if (!easrc)
@ -1874,6 +1875,7 @@ static int fsl_easrc_probe(struct platform_device *pdev)
struct resource *res;
struct device_node *np;
void __iomem *regs;
u32 asrc_fmt = 0;
int ret, irq;
easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL);
@ -1934,13 +1936,14 @@ static int fsl_easrc_probe(struct platform_device *pdev)
return ret;
}
ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format);
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
if (ret) {
dev_err(dev, "failed to asrc format\n");
return ret;
}
if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) {
if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) {
dev_warn(dev, "unsupported format, switching to S24_LE\n");
easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
}

View File

@ -569,7 +569,7 @@ struct fsl_easrc_io_params {
unsigned int access_len;
unsigned int fifo_wtmk;
unsigned int sample_rate;
unsigned int sample_format;
snd_pcm_format_t sample_format;
unsigned int norm_rate;
};

View File

@ -61,7 +61,7 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk)
{
struct pinctrl_state *state = 0;
struct pinctrl_state *state = NULL;
if (sai->is_pdm_mode) {
/* DSD512@44.1kHz, DSD512@48kHz */

View File

@ -118,7 +118,7 @@ struct imx_card_data {
struct snd_soc_card card;
int num_dapm_routes;
u32 asrc_rate;
u32 asrc_format;
snd_pcm_format_t asrc_format;
};
static struct imx_akcodec_fs_mul ak4458_fs_mul[] = {
@ -474,7 +474,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_none(mask);
snd_mask_set(mask, data->asrc_format);
snd_mask_set(mask, (__force unsigned int)data->asrc_format);
return 0;
}
@ -493,6 +493,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
struct dai_link_data *link_data;
struct of_phandle_args args;
int ret, num_links;
u32 asrc_fmt = 0;
u32 width;
ret = snd_soc_of_parse_card_name(card, "model");
@ -639,7 +640,8 @@ static int imx_card_parse_of(struct imx_card_data *data)
goto err;
}
ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format);
ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt);
data->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(args.np, "fsl,asrc-width", &width);

View File

@ -158,8 +158,10 @@ static int asoc_simple_parse_dai(struct device_node *ep,
* if he unbinded CPU or Codec.
*/
ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
if (ret < 0)
if (ret < 0) {
of_node_put(node);
return ret;
}
dlc->of_node = node;

View File

@ -445,8 +445,10 @@ static int asoc_simple_parse_dai(struct device_node *ep,
* if he unbinded CPU or Codec.
*/
ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
if (ret < 0)
if (ret < 0) {
of_node_put(node);
return ret;
}
dlc->of_node = node;

View File

@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)
return ret;
}
static int avs_probe_create(struct avs_dev *adev, struct avs_path_module *mod)
{
dev_err(adev->dev, "Probe module can't be instantiated by topology");
return -EINVAL;
}
struct avs_module_create {
guid_t *guid;
int (*create)(struct avs_dev *adev, struct avs_path_module *mod);
};
static struct avs_module_create avs_module_create[] = {
{ &AVS_MIXIN_MOD_UUID, avs_modbase_create },
{ &AVS_MIXOUT_MOD_UUID, avs_modbase_create },
{ &AVS_KPBUFF_MOD_UUID, avs_modbase_create },
{ &AVS_COPIER_MOD_UUID, avs_copier_create },
{ &AVS_MICSEL_MOD_UUID, avs_micsel_create },
{ &AVS_MUX_MOD_UUID, avs_mux_create },
{ &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create },
{ &AVS_SRCINTC_MOD_UUID, avs_src_create },
{ &AVS_AEC_MOD_UUID, avs_aec_create },
{ &AVS_ASRC_MOD_UUID, avs_asrc_create },
{ &AVS_INTELWOV_MOD_UUID, avs_wov_create },
{ &AVS_PROBE_MOD_UUID, avs_probe_create },
};
static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)
{
const guid_t *type = &mod->template->cfg_ext->type;
if (guid_equal(type, &AVS_MIXIN_MOD_UUID) ||
guid_equal(type, &AVS_MIXOUT_MOD_UUID) ||
guid_equal(type, &AVS_KPBUFF_MOD_UUID))
return avs_modbase_create(adev, mod);
if (guid_equal(type, &AVS_COPIER_MOD_UUID))
return avs_copier_create(adev, mod);
if (guid_equal(type, &AVS_MICSEL_MOD_UUID))
return avs_micsel_create(adev, mod);
if (guid_equal(type, &AVS_MUX_MOD_UUID))
return avs_mux_create(adev, mod);
if (guid_equal(type, &AVS_UPDWMIX_MOD_UUID))
return avs_updown_mix_create(adev, mod);
if (guid_equal(type, &AVS_SRCINTC_MOD_UUID))
return avs_src_create(adev, mod);
if (guid_equal(type, &AVS_AEC_MOD_UUID))
return avs_aec_create(adev, mod);
if (guid_equal(type, &AVS_ASRC_MOD_UUID))
return avs_asrc_create(adev, mod);
if (guid_equal(type, &AVS_INTELWOV_MOD_UUID))
return avs_wov_create(adev, mod);
if (guid_equal(type, &AVS_PROBE_MOD_UUID)) {
dev_err(adev->dev, "Probe module can't be instantiated by topology");
return -EINVAL;
}
for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++)
if (guid_equal(type, avs_module_create[i].guid))
return avs_module_create[i].create(adev, mod);
return avs_modext_create(adev, mod);
}

View File

@ -249,6 +249,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
.nonatomic = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,

View File

@ -349,6 +349,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
.nonatomic = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBC_CFC,

View File

@ -162,6 +162,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
.nonatomic = 1,
.no_pcm = 1,
.init = codec_link_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,

View File

@ -121,6 +121,7 @@ static struct snd_soc_dai_link card_dai_links[] = {
/* SSP0 - Codec */
.name = "Codec",
.id = 0,
.nonatomic = 1,
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
.ignore_pmdown_time = 1,

View File

@ -28,6 +28,24 @@
#define SOF_ES8336_SSP_CODEC_MASK (GENMASK(3, 0))
#define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK BIT(4)
/* HDMI capture*/
#define SOF_SSP_HDMI_CAPTURE_PRESENT BIT(14)
#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 15
#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK (GENMASK(16, 15))
#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk) \
(((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
#define SOF_HDMI_CAPTURE_1_SSP_SHIFT 7
#define SOF_HDMI_CAPTURE_1_SSP_MASK (GENMASK(9, 7))
#define SOF_HDMI_CAPTURE_1_SSP(quirk) \
(((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
#define SOF_HDMI_CAPTURE_2_SSP_SHIFT 10
#define SOF_HDMI_CAPTURE_2_SSP_MASK (GENMASK(12, 10))
#define SOF_HDMI_CAPTURE_2_SSP(quirk) \
(((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
#define SOF_ES8336_ENABLE_DMIC BIT(5)
#define SOF_ES8336_JD_INVERTED BIT(6)
#define SOF_ES8336_HEADPHONE_GPIO BIT(7)
@ -57,28 +75,26 @@ static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true };
static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true };
static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = {
{ "speakers-enable-gpios", &enable_gpio0, 1 },
{ "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = {
{ "speakers-enable-gpios", &enable_gpio1, 1 },
{ "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
};
static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = {
{ "speakers-enable-gpios", &enable_gpio0, 1 },
{ "headphone-enable-gpios", &enable_gpio1, 1 },
{ "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = {
{ "speakers-enable-gpios", &enable_gpio1, 1 },
{ "headphone-enable-gpios", &enable_gpio0, 1 },
{ "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0;
static void log_quirks(struct device *dev)
{
dev_info(dev, "quirk mask %#lx\n", quirk);
@ -272,15 +288,6 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
{
quirk = (unsigned long)id->driver_data;
if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
gpio_mapping = acpi_enable_both_gpios;
else
gpio_mapping = acpi_enable_both_gpios_rev_order;
} else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
gpio_mapping = acpi_speakers_enable_gpio1;
}
return 1;
}
@ -356,6 +363,13 @@ static struct snd_soc_dai_link_component dmic_component[] = {
}
};
static struct snd_soc_dai_link_component dummy_component[] = {
{
.name = "snd-soc-dummy",
.dai_name = "snd-soc-dummy-dai",
}
};
static int sof_es8336_late_probe(struct snd_soc_card *card)
{
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
@ -507,6 +521,37 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
id++;
}
/* HDMI-In SSP */
if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
for (i = 1; i <= num_of_hdmi_ssp; i++) {
int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
SOF_HDMI_CAPTURE_1_SSP_SHIFT :
(quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
SOF_HDMI_CAPTURE_2_SSP_SHIFT);
links[id].cpus = &cpus[id];
links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
"SSP%d Pin", port);
if (!links[id].cpus->dai_name)
return NULL;
links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
if (!links[id].name)
return NULL;
links[id].id = id + hdmi_id_offset;
links[id].codecs = dummy_component;
links[id].num_codecs = ARRAY_SIZE(dummy_component);
links[id].platforms = platform_component;
links[id].num_platforms = ARRAY_SIZE(platform_component);
links[id].dpcm_capture = 1;
links[id].no_pcm = 1;
links[id].num_cpus = 1;
id++;
}
}
return links;
devm_err:
@ -529,6 +574,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
struct acpi_device *adev;
struct snd_soc_dai_link *dai_links;
struct device *codec_dev;
const struct acpi_gpio_mapping *gpio_mapping;
unsigned int cnt = 0;
int dmic_be_num = 0;
int hdmi_num = 3;
@ -541,29 +587,34 @@ static int sof_es8336_probe(struct platform_device *pdev)
card = &sof_es8336_card;
card->dev = dev;
if (pdev->id_entry && pdev->id_entry->driver_data)
quirk = (unsigned long)pdev->id_entry->driver_data;
/* check GPIO DMI quirks */
dmi_check_system(sof_es8336_quirk_table);
if (!mach->mach_params.i2s_link_mask) {
dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
} else {
/*
* Set configuration based on platform NHLT.
* In this machine driver, we can only support one SSP for the
* ES8336 link, the else-if below are intentional.
* In some cases multiple SSPs can be reported by NHLT, starting MSB-first
* seems to pick the right connection.
*/
unsigned long ssp = 0;
/* Use NHLT configuration only for Non-HDMI capture use case.
* Because more than one SSP will be enabled for HDMI capture hence wrong codec
* SSP will be set.
*/
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) {
if (!mach->mach_params.i2s_link_mask) {
dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
} else {
/*
* Set configuration based on platform NHLT.
* In this machine driver, we can only support one SSP for the
* ES8336 link.
* In some cases multiple SSPs can be reported by NHLT, starting MSB-first
* seems to pick the right connection.
*/
unsigned long ssp;
if (mach->mach_params.i2s_link_mask & BIT(2))
ssp = SOF_ES8336_SSP_CODEC(2);
else if (mach->mach_params.i2s_link_mask & BIT(1))
ssp = SOF_ES8336_SSP_CODEC(1);
else if (mach->mach_params.i2s_link_mask & BIT(0))
ssp = SOF_ES8336_SSP_CODEC(0);
/* fls returns 1-based results, SSPs indices are 0-based */
ssp = fls(mach->mach_params.i2s_link_mask) - 1;
quirk |= ssp;
quirk |= ssp;
}
}
if (mach->mach_params.dmic_num)
@ -579,7 +630,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
if (quirk & SOF_ES8336_ENABLE_DMIC)
dmic_be_num = 2;
sof_es8336_card.num_links += dmic_be_num + hdmi_num;
/* compute number of dai links */
sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num;
if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
dai_links = sof_card_dai_links_create(dev,
SOF_ES8336_SSP_CODEC(quirk),
dmic_be_num, hdmi_num);
@ -635,6 +692,17 @@ static int sof_es8336_probe(struct platform_device *pdev)
}
/* get speaker enable GPIO */
if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
gpio_mapping = acpi_enable_both_gpios;
else
gpio_mapping = acpi_enable_both_gpios_rev_order;
} else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
gpio_mapping = acpi_speakers_enable_gpio1;
} else {
gpio_mapping = acpi_speakers_enable_gpio0;
}
ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping);
if (ret)
dev_warn(codec_dev, "unable to add GPIO mapping table\n");
@ -690,6 +758,21 @@ static int sof_es8336_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id board_ids[] = {
{
.name = "adl_es83x6_c1_h02",
.driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
SOF_HDMI_CAPTURE_1_SSP(0) |
SOF_HDMI_CAPTURE_2_SSP(2) |
SOF_SSP_HDMI_CAPTURE_PRESENT |
SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
SOF_ES8336_JD_INVERTED),
},
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
static struct platform_driver sof_es8336_driver = {
.driver = {
.name = "sof-essx8336",
@ -697,6 +780,7 @@ static struct platform_driver sof_es8336_driver = {
},
.probe = sof_es8336_probe,
.remove = sof_es8336_remove,
.id_table = board_ids,
};
module_platform_driver(sof_es8336_driver);

View File

@ -190,11 +190,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
struct sof_hdmi_pcm *pcm;
int err;
if (list_empty(&ctx->hdmi_pcm_list))
return -EINVAL;
pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
@ -204,6 +199,11 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
if (list_empty(&ctx->hdmi_pcm_list))
return -EINVAL;
pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
}

View File

@ -447,6 +447,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
struct sof_hdmi_pcm *pcm;
int err;
if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
snd_soc_dapm_disable_pin(dapm, "Right Spk");
err = snd_soc_dapm_sync(dapm);
if (err < 0)
return err;
}
/* HDMI is not supported by SOF on Baytrail/CherryTrail */
if (is_legacy_cpu || !ctx->idisp_codec)
return 0;
@ -477,15 +486,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
return err;
}
if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
/* Disable Left and Right Spk pin after boot */
snd_soc_dapm_disable_pin(dapm, "Left Spk");
snd_soc_dapm_disable_pin(dapm, "Right Spk");
err = snd_soc_dapm_sync(dapm);
if (err < 0)
return err;
}
return hdac_hdmi_jack_port_init(component, &card->dapm);
}
@ -1092,6 +1092,14 @@ static const struct platform_device_id board_ids[] = {
SOF_RT5682_SSP_AMP(1) |
SOF_RT5682_NUM_HDMIDEV(4)),
},
{
.name = "mtl_mx98357_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_RT5682_SSP_CODEC(0) |
SOF_SPEAKER_AMP_PRESENT |
SOF_RT5682_SSP_AMP(1) |
SOF_RT5682_NUM_HDMIDEV(4)),
},
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);

View File

@ -246,6 +246,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
{
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD2 |
SOF_SDW_FOUR_SPK),
},
{
.callback = sof_sdw_quirk_cb,
.matches = {
@ -315,6 +325,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
RT711_JD2 |
SOF_SDW_FOUR_SPK),
},
{
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
RT711_JD2),
},
/* MeteorLake devices */
{
.callback = sof_sdw_quirk_cb,

View File

@ -139,6 +139,9 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
{
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
if (!ctx->headset_codec_dev)
return 0;
device_remove_software_node(ctx->headset_codec_dev);
put_device(ctx->headset_codec_dev);

View File

@ -140,6 +140,9 @@ int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *
{
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
if (!ctx->headset_codec_dev)
return 0;
device_remove_software_node(ctx->headset_codec_dev);
put_device(ctx->headset_codec_dev);

View File

@ -8,6 +8,11 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
static const struct snd_soc_acpi_codecs essx_83x6 = {
.num_codecs = 3,
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
};
static const struct snd_soc_acpi_endpoint single_endpoint = {
.num = 0,
.aggregated = 0,
@ -137,6 +142,15 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = {
}
};
static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
{
.adr = 0x000330025D131601ull,
.num_endpoints = 1,
.endpoints = &single_endpoint,
.name_prefix = "rt1316-1"
}
};
static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
{
.adr = 0x000030025D071401ull,
@ -326,6 +340,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = {
{}
};
static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
.adr_d = rt711_sdca_0_adr,
},
{
.mask = BIT(3),
.num_adr = ARRAY_SIZE(rt1316_3_single_adr),
.adr_d = rt1316_3_single_adr,
},
{}
};
static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = {
{
.adr = 0x000223019F837300ull,
@ -412,6 +440,11 @@ static const struct snd_soc_acpi_codecs adl_max98390_amp = {
.codecs = {"MX98390"}
};
static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
.num_codecs = 1,
.codecs = {"INTC10B0"}
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
{
.comp_ids = &adl_rt5682_rt5682s_hp,
@ -492,6 +525,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
.drv_name = "adl_cs35l41",
.sof_tplg_filename = "sof-adl-cs35l41.tplg",
},
{
.comp_ids = &essx_83x6,
.drv_name = "adl_es83x6_c1_h02",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &adl_lt6911_hdmi,
.sof_tplg_filename = "sof-adl-es83x6-ssp1-hdmi-ssp02.tplg",
},
{
.comp_ids = &essx_83x6,
.drv_name = "sof-essx8336",
.sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */
.tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
},
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
@ -546,6 +594,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg",
},
{
.link_mask = 0x9, /* 2 active links required */
.links = adl_sdw_rt711_link0_rt1316_link3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg",
},
{
.link_mask = 0x1, /* link0 required */
.links = adl_rvp,

View File

@ -10,7 +10,24 @@
#include <sound/soc-acpi-intel-match.h>
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs mtl_max98357a_amp = {
.num_codecs = 1,
.codecs = {"MX98357A"}
};
static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
.num_codecs = 2,
.codecs = {"10EC5682", "RTL5682"},
};
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
{
.comp_ids = &mtl_rt5682_rt5682s_hp,
.drv_name = "mtl_mx98357_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &mtl_max98357a_amp,
.sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg",
},
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);

View File

@ -93,7 +93,6 @@ struct i2s_soc_info {
};
struct jz4740_i2s {
struct resource *mem;
void __iomem *base;
struct clk *clk_aic;

View File

@ -152,6 +152,51 @@ config SND_SOC_MT8183_DA7219_MAX98357A
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT8186
tristate "ASoC support for Mediatek MT8186 chip"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_MEDIATEK
select SND_SOC_MT6358
select MFD_SYSCON if SND_SOC_MT6358
help
This adds ASoC driver for Mediatek MT8186 boards
that can be used with other codecs.
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT8186_MT6366_DA7219_MAX98357
tristate "ASoC Audio driver for MT8186 with DA7219 MAX98357A codec"
depends on I2C && GPIOLIB
depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
select SND_SOC_MT6358
select SND_SOC_MAX98357A
select SND_SOC_DA7219
select SND_SOC_BT_SCO
select SND_SOC_DMIC
select SND_SOC_HDMI_CODEC
help
This adds ASoC driver for Mediatek MT8186 boards
with the MT6366(MT6358) DA7219 MAX98357A codecs.
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MT8186_MT6366_RT1019_RT5682S
tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec"
depends on I2C && GPIOLIB
depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
select SND_SOC_MT6358
select SND_SOC_RT1015P
select SND_SOC_RT5682S
select SND_SOC_BT_SCO
select SND_SOC_DMIC
select SND_SOC_HDMI_CODEC
help
This adds ASoC driver for Mediatek MT8186 boards
with the MT6366(MT6358) RT1019 RT5682S codecs.
Select Y if you have such device.
If unsure select "N".
config SND_SOC_MTK_BTCVSD
tristate "ALSA BT SCO CVSD/MSBC Driver"
help

View File

@ -4,5 +4,6 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
obj-$(CONFIG_SND_SOC_MT8195) += mt8195/

View File

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o
obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o

View File

@ -0,0 +1,196 @@
// SPDX-License-Identifier: GPL-2.0
/*
* mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Chunxu Li <chunxu.li@mediatek.com>
*/
#include "mtk-dsp-sof-common.h"
#include "mtk-soc-card.h"
/* fixup the BE DAI link to match any values from topology */
int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_soc_card *card = rtd->card;
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
int i, j, ret = 0;
for (i = 0; i < sof_priv->num_streams; i++) {
struct snd_soc_dai *cpu_dai;
struct snd_soc_pcm_runtime *runtime;
struct snd_soc_dai_link *sof_dai_link = NULL;
const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
if (strcmp(rtd->dai_link->name, conn->normal_link))
continue;
for_each_card_rtds(card, runtime) {
if (strcmp(runtime->dai_link->name, conn->sof_link))
continue;
for_each_rtd_cpu_dais(runtime, j, cpu_dai) {
if (cpu_dai->stream_active[conn->stream_dir] > 0) {
sof_dai_link = runtime->dai_link;
break;
}
}
break;
}
if (sof_dai_link && sof_dai_link->be_hw_params_fixup)
ret = sof_dai_link->be_hw_params_fixup(runtime, params);
break;
}
return ret;
}
EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup);
int mtk_sof_card_probe(struct snd_soc_card *card)
{
int i;
struct snd_soc_dai_link *dai_link;
/* Set stream_name to help sof bind widgets */
for_each_card_prelinks(card, i, dai_link) {
if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name)
dai_link->stream_name = dai_link->name;
}
return 0;
}
EXPORT_SYMBOL_GPL(mtk_sof_card_probe);
int mtk_sof_card_late_probe(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *sof_comp = NULL;
struct mtk_soc_card_data *soc_card_data =
snd_soc_card_get_drvdata(card);
struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
int i;
/* 1. find sof component */
for_each_card_rtds(card, rtd) {
sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component");
if (sof_comp)
break;
}
if (!sof_comp) {
dev_info(card->dev, "probe without sof-audio-component\n");
return 0;
}
/* 2. add route path and fixup callback */
for (i = 0; i < sof_priv->num_streams; i++) {
const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
struct snd_soc_pcm_runtime *sof_rtd = NULL;
struct snd_soc_pcm_runtime *normal_rtd = NULL;
for_each_card_rtds(card, rtd) {
if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
sof_rtd = rtd;
continue;
}
if (!strcmp(rtd->dai_link->name, conn->normal_link)) {
normal_rtd = rtd;
continue;
}
if (normal_rtd && sof_rtd)
break;
}
if (normal_rtd && sof_rtd) {
int j;
struct snd_soc_dai *cpu_dai;
for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {
struct snd_soc_dapm_route route;
struct snd_soc_dapm_path *p = NULL;
struct snd_soc_dapm_widget *play_widget =
cpu_dai->playback_widget;
struct snd_soc_dapm_widget *cap_widget =
cpu_dai->capture_widget;
memset(&route, 0, sizeof(route));
if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE &&
cap_widget) {
snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) {
route.source = conn->sof_dma;
route.sink = p->sink->name;
snd_soc_dapm_add_routes(&card->dapm, &route, 1);
}
} else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK &&
play_widget) {
snd_soc_dapm_widget_for_each_source_path(play_widget, p) {
route.source = p->source->name;
route.sink = conn->sof_dma;
snd_soc_dapm_add_routes(&card->dapm, &route, 1);
}
} else {
dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
}
}
sof_rtd->dai_link->be_hw_params_fixup =
sof_comp->driver->be_hw_params_fixup;
if (sof_priv->sof_dai_link_fixup)
normal_rtd->dai_link->be_hw_params_fixup =
sof_priv->sof_dai_link_fixup;
else
normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe);
int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
const char *propname, struct snd_soc_dai_link *pre_dai_links,
int pre_num_links)
{
struct device *dev = card->dev;
struct snd_soc_dai_link *parsed_dai_link;
const char *dai_name = NULL;
int i, j, ret, num_links, parsed_num_links = 0;
num_links = of_property_count_strings(np, "mediatek,dai-link");
if (num_links < 0 || num_links > card->num_links) {
dev_dbg(dev, "number of dai-link is invalid\n");
return -EINVAL;
}
parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL);
if (!parsed_dai_link)
return -ENOMEM;
for (i = 0; i < num_links; i++) {
ret = of_property_read_string_index(np, propname, i, &dai_name);
if (ret) {
dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",
propname, i, ret);
return ret;
}
dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);
for (j = 0; j < pre_num_links; j++) {
if (!strcmp(dai_name, pre_dai_links[j].name)) {
memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j],
sizeof(struct snd_soc_dai_link));
break;
}
}
}
if (parsed_num_links != num_links)
return -EINVAL;
card->dai_link = parsed_dai_link;
card->num_links = parsed_num_links;
return 0;
}
EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of);

View File

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mtk-dsp-sof-common.h -- MediaTek dsp sof common definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Chunxu Li <chunxu.li@mediatek.com>
*/
#ifndef _MTK_DSP_SOF_COMMON_H_
#define _MTK_DSP_SOF_COMMON_H_
#include <sound/soc.h>
struct sof_conn_stream {
const char *normal_link;
const char *sof_link;
const char *sof_dma;
int stream_dir;
};
struct mtk_sof_priv {
const struct sof_conn_stream *conn_streams;
int num_streams;
int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
};
int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
int mtk_sof_card_probe(struct snd_soc_card *card);
int mtk_sof_card_late_probe(struct snd_soc_card *card);
int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
const char *propname, struct snd_soc_dai_link *pre_dai_links,
int pre_num_links);
#endif

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mtk-soc-card.h -- MediaTek soc card data definition
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Chunxu Li <chunxu.li@mediatek.com>
*/
#ifndef _MTK_SOC_CARD_H_
#define _MTK_SOC_CARD_H_
struct mtk_soc_card_data {
void *mach_priv;
void *sof_priv;
};
#endif

View File

@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0
# platform driver
snd-soc-mt8186-afe-objs := \
mt8186-afe-pcm.o \
mt8186-audsys-clk.o \
mt8186-afe-clk.o \
mt8186-afe-gpio.o \
mt8186-dai-adda.o \
mt8186-afe-control.o \
mt8186-dai-i2s.o \
mt8186-dai-hw-gain.o \
mt8186-dai-pcm.o \
mt8186-dai-src.o \
mt8186-dai-hostless.o \
mt8186-dai-tdm.o \
mt8186-misc-control.o \
mt8186-mt6366-common.o
obj-$(CONFIG_SND_SOC_MT8186) += snd-soc-mt8186-afe.o
obj-$(CONFIG_SND_SOC_MT8186_MT6366_DA7219_MAX98357) += mt8186-mt6366-da7219-max98357.o
obj-$(CONFIG_SND_SOC_MT8186_MT6366_RT1019_RT5682S) += mt8186-mt6366-rt1019-rt5682s.o

View File

@ -645,7 +645,8 @@ int mt8186_init_clock(struct mtk_base_afe *afe)
return 0;
}
void mt8186_deinit_clock(struct mtk_base_afe *afe)
void mt8186_deinit_clock(void *priv)
{
struct mtk_base_afe *afe = priv;
mt8186_audsys_clk_unregister(afe);
}

View File

@ -81,7 +81,7 @@ enum {
struct mtk_base_afe;
int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id);
int mt8186_init_clock(struct mtk_base_afe *afe);
void mt8186_deinit_clock(struct mtk_base_afe *afe);
void mt8186_deinit_clock(void *priv);
int mt8186_afe_enable_cgs(struct mtk_base_afe *afe);
void mt8186_afe_disable_cgs(struct mtk_base_afe *afe);
int mt8186_afe_enable_clock(struct mtk_base_afe *afe);

View File

@ -0,0 +1,195 @@
/* SPDX-License-Identifier: GPL-2.0
*
* mt8186-afe-common.h -- Mediatek 8186 audio driver definitions
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT_8186_AFE_COMMON_H_
#define _MT_8186_AFE_COMMON_H_
#include <sound/soc.h>
#include <linux/list.h>
#include <linux/regmap.h>
#include "mt8186-reg.h"
#include "../common/mtk-base-afe.h"
enum {
MT8186_MEMIF_DL1,
MT8186_MEMIF_DL12,
MT8186_MEMIF_DL2,
MT8186_MEMIF_DL3,
MT8186_MEMIF_DL4,
MT8186_MEMIF_DL5,
MT8186_MEMIF_DL6,
MT8186_MEMIF_DL7,
MT8186_MEMIF_DL8,
MT8186_MEMIF_VUL12,
MT8186_MEMIF_VUL2,
MT8186_MEMIF_VUL3,
MT8186_MEMIF_VUL4,
MT8186_MEMIF_VUL5,
MT8186_MEMIF_VUL6,
MT8186_MEMIF_AWB,
MT8186_MEMIF_AWB2,
MT8186_MEMIF_NUM,
MT8186_DAI_ADDA = MT8186_MEMIF_NUM,
MT8186_DAI_AP_DMIC,
MT8186_DAI_CONNSYS_I2S,
MT8186_DAI_I2S_0,
MT8186_DAI_I2S_1,
MT8186_DAI_I2S_2,
MT8186_DAI_I2S_3,
MT8186_DAI_HW_GAIN_1,
MT8186_DAI_HW_GAIN_2,
MT8186_DAI_SRC_1,
MT8186_DAI_SRC_2,
MT8186_DAI_PCM,
MT8186_DAI_TDM_IN,
MT8186_DAI_HOSTLESS_LPBK,
MT8186_DAI_HOSTLESS_FM,
MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO,
MT8186_DAI_HOSTLESS_SRC_AAUDIO,
MT8186_DAI_HOSTLESS_SRC_1,
MT8186_DAI_HOSTLESS_SRC_BARGEIN,
MT8186_DAI_HOSTLESS_UL1,
MT8186_DAI_HOSTLESS_UL2,
MT8186_DAI_HOSTLESS_UL3,
MT8186_DAI_HOSTLESS_UL5,
MT8186_DAI_HOSTLESS_UL6,
MT8186_DAI_NUM,
};
#define MT8186_RECORD_MEMIF MT8186_MEMIF_VUL12
#define MT8186_ECHO_REF_MEMIF MT8186_MEMIF_AWB
#define MT8186_PRIMARY_MEMIF MT8186_MEMIF_DL1
#define MT8186_FAST_MEMIF MT8186_MEMIF_DL2
#define MT8186_DEEP_MEMIF MT8186_MEMIF_DL3
#define MT8186_VOIP_MEMIF MT8186_MEMIF_DL12
#define MT8186_MMAP_DL_MEMIF MT8186_MEMIF_DL5
#define MT8186_MMAP_UL_MEMIF MT8186_MEMIF_VUL5
#define MT8186_BARGEIN_MEMIF MT8186_MEMIF_AWB
enum {
MT8186_IRQ_0,
MT8186_IRQ_1,
MT8186_IRQ_2,
MT8186_IRQ_3,
MT8186_IRQ_4,
MT8186_IRQ_5,
MT8186_IRQ_6,
MT8186_IRQ_7,
MT8186_IRQ_8,
MT8186_IRQ_9,
MT8186_IRQ_10,
MT8186_IRQ_11,
MT8186_IRQ_12,
MT8186_IRQ_13,
MT8186_IRQ_14,
MT8186_IRQ_15,
MT8186_IRQ_16,
MT8186_IRQ_17,
MT8186_IRQ_18,
MT8186_IRQ_19,
MT8186_IRQ_20,
MT8186_IRQ_21,
MT8186_IRQ_22,
MT8186_IRQ_23,
MT8186_IRQ_24,
MT8186_IRQ_25,
MT8186_IRQ_26,
MT8186_IRQ_NUM,
};
enum {
MT8186_AFE_IRQ_DIR_MCU = 0,
MT8186_AFE_IRQ_DIR_DSP,
MT8186_AFE_IRQ_DIR_BOTH,
};
enum {
MTKAIF_PROTOCOL_1 = 0,
MTKAIF_PROTOCOL_2,
MTKAIF_PROTOCOL_2_CLK_P2,
};
enum {
MTK_AFE_ADDA_DL_GAIN_MUTE = 0,
MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f,
/* SA suggest apply -0.3db to audio/speech path */
};
#define MTK_SPK_I2S_0_STR "MTK_SPK_I2S_0"
#define MTK_SPK_I2S_1_STR "MTK_SPK_I2S_1"
#define MTK_SPK_I2S_2_STR "MTK_SPK_I2S_2"
#define MTK_SPK_I2S_3_STR "MTK_SPK_I2S_3"
/* MCLK */
enum {
MT8186_I2S0_MCK = 0,
MT8186_I2S1_MCK,
MT8186_I2S2_MCK,
MT8186_I2S4_MCK,
MT8186_TDM_MCK,
MT8186_MCK_NUM,
};
struct snd_pcm_substream;
struct mtk_base_irq_data;
struct clk;
struct mt8186_afe_private {
struct clk **clk;
struct clk_lookup **lookup;
struct regmap *topckgen;
struct regmap *apmixedsys;
struct regmap *infracfg;
int irq_cnt[MT8186_MEMIF_NUM];
int stf_positive_gain_db;
int pm_runtime_bypass_reg_ctl;
int sgen_mode;
int sgen_rate;
int sgen_amplitude;
/* xrun assert */
int xrun_assert[MT8186_MEMIF_NUM];
/* dai */
bool dai_on[MT8186_DAI_NUM];
void *dai_priv[MT8186_DAI_NUM];
/* adda */
bool mtkaif_calibration_ok;
int mtkaif_protocol;
int mtkaif_chosen_phase[4];
int mtkaif_phase_cycle[4];
int mtkaif_calibration_num_phase;
int mtkaif_dmic;
int mtkaif_looback0;
int mtkaif_looback1;
/* mck */
int mck_rate[MT8186_MCK_NUM];
};
int mt8186_dai_adda_register(struct mtk_base_afe *afe);
int mt8186_dai_i2s_register(struct mtk_base_afe *afe);
int mt8186_dai_tdm_register(struct mtk_base_afe *afe);
int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe);
int mt8186_dai_src_register(struct mtk_base_afe *afe);
int mt8186_dai_pcm_register(struct mtk_base_afe *afe);
int mt8186_dai_hostless_register(struct mtk_base_afe *afe);
int mt8186_add_misc_control(struct snd_soc_component *component);
unsigned int mt8186_general_rate_transform(struct device *dev,
unsigned int rate);
unsigned int mt8186_rate_transform(struct device *dev,
unsigned int rate, int aud_blk);
unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev,
unsigned int rate);
int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id,
int priv_size, const void *priv_data);
#endif

View File

@ -0,0 +1,255 @@
// SPDX-License-Identifier: GPL-2.0
//
// MediaTek ALSA SoC Audio Control
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
#include "mt8186-afe-common.h"
#include <linux/pm_runtime.h>
enum {
MTK_AFE_RATE_8K = 0,
MTK_AFE_RATE_11K,
MTK_AFE_RATE_12K,
MTK_AFE_RATE_384K,
MTK_AFE_RATE_16K,
MTK_AFE_RATE_22K,
MTK_AFE_RATE_24K,
MTK_AFE_RATE_352K,
MTK_AFE_RATE_32K,
MTK_AFE_RATE_44K,
MTK_AFE_RATE_48K,
MTK_AFE_RATE_88K,
MTK_AFE_RATE_96K,
MTK_AFE_RATE_176K,
MTK_AFE_RATE_192K,
MTK_AFE_RATE_260K,
};
enum {
MTK_AFE_PCM_RATE_8K = 0,
MTK_AFE_PCM_RATE_16K,
MTK_AFE_PCM_RATE_32K,
MTK_AFE_PCM_RATE_48K,
};
enum {
MTK_AFE_TDM_RATE_8K = 0,
MTK_AFE_TDM_RATE_12K,
MTK_AFE_TDM_RATE_16K,
MTK_AFE_TDM_RATE_24K,
MTK_AFE_TDM_RATE_32K,
MTK_AFE_TDM_RATE_48K,
MTK_AFE_TDM_RATE_64K,
MTK_AFE_TDM_RATE_96K,
MTK_AFE_TDM_RATE_128K,
MTK_AFE_TDM_RATE_192K,
MTK_AFE_TDM_RATE_256K,
MTK_AFE_TDM_RATE_384K,
MTK_AFE_TDM_RATE_11K,
MTK_AFE_TDM_RATE_22K,
MTK_AFE_TDM_RATE_44K,
MTK_AFE_TDM_RATE_88K,
MTK_AFE_TDM_RATE_176K,
MTK_AFE_TDM_RATE_352K,
};
enum {
MTK_AFE_TDM_RELATCH_RATE_8K = 0,
MTK_AFE_TDM_RELATCH_RATE_11K,
MTK_AFE_TDM_RELATCH_RATE_12K,
MTK_AFE_TDM_RELATCH_RATE_16K,
MTK_AFE_TDM_RELATCH_RATE_22K,
MTK_AFE_TDM_RELATCH_RATE_24K,
MTK_AFE_TDM_RELATCH_RATE_32K,
MTK_AFE_TDM_RELATCH_RATE_44K,
MTK_AFE_TDM_RELATCH_RATE_48K,
MTK_AFE_TDM_RELATCH_RATE_88K,
MTK_AFE_TDM_RELATCH_RATE_96K,
MTK_AFE_TDM_RELATCH_RATE_176K,
MTK_AFE_TDM_RELATCH_RATE_192K,
MTK_AFE_TDM_RELATCH_RATE_352K,
MTK_AFE_TDM_RELATCH_RATE_384K,
};
unsigned int mt8186_general_rate_transform(struct device *dev, unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_RATE_8K;
case 11025:
return MTK_AFE_RATE_11K;
case 12000:
return MTK_AFE_RATE_12K;
case 16000:
return MTK_AFE_RATE_16K;
case 22050:
return MTK_AFE_RATE_22K;
case 24000:
return MTK_AFE_RATE_24K;
case 32000:
return MTK_AFE_RATE_32K;
case 44100:
return MTK_AFE_RATE_44K;
case 48000:
return MTK_AFE_RATE_48K;
case 88200:
return MTK_AFE_RATE_88K;
case 96000:
return MTK_AFE_RATE_96K;
case 176400:
return MTK_AFE_RATE_176K;
case 192000:
return MTK_AFE_RATE_192K;
case 260000:
return MTK_AFE_RATE_260K;
case 352800:
return MTK_AFE_RATE_352K;
case 384000:
return MTK_AFE_RATE_384K;
default:
dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
__func__, rate, MTK_AFE_RATE_48K);
}
return MTK_AFE_RATE_48K;
}
static unsigned int tdm_rate_transform(struct device *dev, unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_TDM_RATE_8K;
case 11025:
return MTK_AFE_TDM_RATE_11K;
case 12000:
return MTK_AFE_TDM_RATE_12K;
case 16000:
return MTK_AFE_TDM_RATE_16K;
case 22050:
return MTK_AFE_TDM_RATE_22K;
case 24000:
return MTK_AFE_TDM_RATE_24K;
case 32000:
return MTK_AFE_TDM_RATE_32K;
case 44100:
return MTK_AFE_TDM_RATE_44K;
case 48000:
return MTK_AFE_TDM_RATE_48K;
case 64000:
return MTK_AFE_TDM_RATE_64K;
case 88200:
return MTK_AFE_TDM_RATE_88K;
case 96000:
return MTK_AFE_TDM_RATE_96K;
case 128000:
return MTK_AFE_TDM_RATE_128K;
case 176400:
return MTK_AFE_TDM_RATE_176K;
case 192000:
return MTK_AFE_TDM_RATE_192K;
case 256000:
return MTK_AFE_TDM_RATE_256K;
case 352800:
return MTK_AFE_TDM_RATE_352K;
case 384000:
return MTK_AFE_TDM_RATE_384K;
default:
dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
__func__, rate, MTK_AFE_TDM_RATE_48K);
}
return MTK_AFE_TDM_RATE_48K;
}
static unsigned int pcm_rate_transform(struct device *dev, unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_PCM_RATE_8K;
case 16000:
return MTK_AFE_PCM_RATE_16K;
case 32000:
return MTK_AFE_PCM_RATE_32K;
case 48000:
return MTK_AFE_PCM_RATE_48K;
default:
dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
__func__, rate, MTK_AFE_PCM_RATE_48K);
}
return MTK_AFE_PCM_RATE_48K;
}
unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev, unsigned int rate)
{
switch (rate) {
case 8000:
return MTK_AFE_TDM_RELATCH_RATE_8K;
case 11025:
return MTK_AFE_TDM_RELATCH_RATE_11K;
case 12000:
return MTK_AFE_TDM_RELATCH_RATE_12K;
case 16000:
return MTK_AFE_TDM_RELATCH_RATE_16K;
case 22050:
return MTK_AFE_TDM_RELATCH_RATE_22K;
case 24000:
return MTK_AFE_TDM_RELATCH_RATE_24K;
case 32000:
return MTK_AFE_TDM_RELATCH_RATE_32K;
case 44100:
return MTK_AFE_TDM_RELATCH_RATE_44K;
case 48000:
return MTK_AFE_TDM_RELATCH_RATE_48K;
case 88200:
return MTK_AFE_TDM_RELATCH_RATE_88K;
case 96000:
return MTK_AFE_TDM_RELATCH_RATE_96K;
case 176400:
return MTK_AFE_TDM_RELATCH_RATE_176K;
case 192000:
return MTK_AFE_TDM_RELATCH_RATE_192K;
case 352800:
return MTK_AFE_TDM_RELATCH_RATE_352K;
case 384000:
return MTK_AFE_TDM_RELATCH_RATE_384K;
default:
dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
__func__, rate, MTK_AFE_TDM_RELATCH_RATE_48K);
}
return MTK_AFE_TDM_RELATCH_RATE_48K;
}
unsigned int mt8186_rate_transform(struct device *dev, unsigned int rate, int aud_blk)
{
switch (aud_blk) {
case MT8186_DAI_PCM:
return pcm_rate_transform(dev, rate);
case MT8186_DAI_TDM_IN:
return tdm_rate_transform(dev, rate);
default:
return mt8186_general_rate_transform(dev, rate);
}
}
int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id, int priv_size, const void *priv_data)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
void *temp_data;
temp_data = devm_kzalloc(afe->dev,
priv_size,
GFP_KERNEL);
if (!temp_data)
return -ENOMEM;
if (priv_data)
memcpy(temp_data, priv_data, priv_size);
afe_priv->dai_priv[id] = temp_data;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -75,8 +75,7 @@ static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
struct mt8186_afe_private *afe_priv = afe->platform_priv;
int dai_id;
if (strncmp(name, "aud_dac_hires_clk", 7) == 0 ||
strncmp(name, "aud_adc_hires_clk", 7) == 0)
if (strncmp(name, "aud_dac", 7) == 0 || strncmp(name, "aud_adc", 7) == 0)
dai_id = MT8186_DAI_ADDA;
else
return NULL;
@ -655,11 +654,6 @@ static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
__func__, id, substream->stream, rate);
if (!adda_priv) {
dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
return -EINVAL;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
unsigned int dl_src2_con0;
unsigned int dl_src2_con1;

View File

@ -119,12 +119,6 @@ static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol,
struct mtk_afe_i2s_priv *i2s_priv;
i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
return 0;
@ -148,12 +142,6 @@ static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol,
__func__, kcontrol->id.name, hd_en);
i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
if (i2s_priv->low_jitter_en == hd_en)
return 0;
@ -377,11 +365,6 @@ static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w,
i2s_priv = get_i2s_priv_by_name(afe, w->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
__func__, w->name, event);
@ -442,11 +425,6 @@ static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
i2s_priv = get_i2s_priv_by_name(afe, w->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
@ -566,12 +544,6 @@ static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
struct mtk_afe_i2s_priv *i2s_priv;
i2s_priv = get_i2s_priv_by_name(afe, sink->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return 0;
}
if (i2s_priv->share_i2s_id < 0)
return 0;
@ -587,12 +559,6 @@ static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
struct mtk_afe_i2s_priv *i2s_priv;
i2s_priv = get_i2s_priv_by_name(afe, sink->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return 0;
}
if (get_i2s_id_by_name(afe, sink->name) ==
get_i2s_id_by_name(afe, source->name))
return i2s_priv->low_jitter_en;
@ -618,15 +584,8 @@ static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
int i2s_need_apll;
i2s_priv = get_i2s_priv_by_name(afe, w->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return 0;
}
/* which apll */
cur_apll = mt8186_get_apll_by_name(afe, source->name);
/* choose APLL from i2s rate */
i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate);
@ -642,12 +601,6 @@ static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
struct mtk_afe_i2s_priv *i2s_priv;
i2s_priv = get_i2s_priv_by_name(afe, sink->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return 0;
}
if (get_i2s_id_by_name(afe, sink->name) ==
get_i2s_id_by_name(afe, source->name))
return (i2s_priv->mclk_rate > 0) ? 1 : 0;
@ -672,12 +625,6 @@ static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
int cur_apll;
i2s_priv = get_i2s_priv_by_name(afe, w->name);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return 0;
}
/* which apll */
cur_apll = mt8186_get_apll_by_name(afe, source->name);
@ -980,11 +927,6 @@ static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
__func__, i2s_id, rate, format);
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
i2s_priv->rate = rate;
switch (i2s_id) {
@ -1053,11 +995,6 @@ static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
int apll;
int apll_rate;
if (!i2s_priv) {
dev_err(afe->dev, "%s(), i2s_priv == NULL", __func__);
return -EINVAL;
}
if (dir != SND_SOC_CLOCK_OUT) {
dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
return -EINVAL;

View File

@ -287,11 +287,6 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id];
if (!pcm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
/* DAI mode*/
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:

View File

@ -106,11 +106,6 @@ static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w,
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
__func__, w->name, event);
@ -138,11 +133,6 @@ static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
__func__, w->name, event, dai_id);
@ -215,11 +205,6 @@ static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source,
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
return (tdm_priv->mclk_rate > 0) ? 1 : 0;
}
@ -250,11 +235,6 @@ static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source,
int dai_id = get_tdm_id_by_name(w->name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
return tdm_priv->low_jitter_en;
}
@ -270,11 +250,6 @@ static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
int cur_apll;
int tdm_need_apll;
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return 0;
}
/* which apll */
cur_apll = mt8186_get_apll_by_name(afe, source->name);
@ -303,11 +278,6 @@ static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
int dai_id = get_tdm_id_by_name(kcontrol->id.name);
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en;
return 0;
@ -332,11 +302,6 @@ static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol,
dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
__func__, kcontrol->id.name, hd_en);
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
if (tdm_priv->low_jitter_en == hd_en)
return 0;
@ -421,22 +386,14 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
unsigned int tran_rate;
unsigned int tran_relatch_rate;
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
tdm_priv->rate = rate;
tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id);
tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate);
/* calculate mclk_rate, if not set explicitly */
if (!tdm_priv->mclk_rate) {
tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
mtk_dai_tdm_cal_mclk(afe,
tdm_priv,
tdm_priv->mclk_rate);
mtk_dai_tdm_cal_mclk(afe, tdm_priv, tdm_priv->mclk_rate);
}
/* ETDM_IN1_CON0 */
@ -508,11 +465,6 @@ static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
if (dir != SND_SOC_CLOCK_IN) {
dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
return -EINVAL;
@ -529,11 +481,6 @@ static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
if (!tdm_priv) {
dev_err(afe->dev, "%s(), tdm_priv == NULL", __func__);
return -EINVAL;
}
/* DAI mode*/
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
//
// mt8186-mt6366-common.c
// -- MT8186 MT6366 ALSA common driver
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
//
#include <sound/soc.h>
#include "../../codecs/mt6358.h"
#include "../common/mtk-afe-platform-driver.h"
#include "mt8186-afe-common.h"
#include "mt8186-mt6366-common.h"
int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8186_afe_private *afe_priv = afe->platform_priv;
struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
int ret;
/* set mtkaif protocol */
mt6358_set_mtkaif_protocol(cmpnt_codec,
MT6358_MTKAIF_PROTOCOL_1);
afe_priv->mtkaif_protocol = MT6358_MTKAIF_PROTOCOL_1;
ret = snd_soc_dapm_sync(dapm);
if (ret) {
dev_err(rtd->dev, "failed to snd_soc_dapm_sync\n");
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt8186_mt6366_init);
int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card,
struct snd_soc_dai_link *link,
struct device_node *node,
char *link_name)
{
int ret;
if (node && strcmp(link->name, link_name) == 0) {
ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link);
if (ret < 0)
return dev_err_probe(card->dev, ret, "get dai link codecs fail\n");
}
return 0;
}
EXPORT_SYMBOL_GPL(mt8186_mt6366_card_set_be_link);

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mt8186-mt6366-common.h
*
* Copyright (c) 2022 MediaTek Inc.
* Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
*/
#ifndef _MT8186_MT6366_COMMON_H_
#define _MT8186_MT6366_COMMON_H_
int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd);
int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card,
struct snd_soc_dai_link *link,
struct device_node *node,
char *link_name);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,978 @@
// SPDX-License-Identifier: GPL-2.0
//
// mt8186-mt6366-rt1019-rt5682s.c
// -- MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver
//
// Copyright (c) 2022 MediaTek Inc.
// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
//
#include <linux/input.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/rt5682.h>
#include <sound/soc.h>
#include "../../codecs/mt6358.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
#include "mt8186-afe-common.h"
#include "mt8186-afe-clk.h"
#include "mt8186-afe-gpio.h"
#include "mt8186-mt6366-common.h"
#define RT1019_CODEC_DAI "HiFi"
#define RT1019_DEV0_NAME "rt1019p"
#define RT5682S_CODEC_DAI "rt5682s-aif1"
#define RT5682S_DEV0_NAME "rt5682s.5-001a"
struct mt8186_mt6366_rt1019_rt5682s_priv {
struct snd_soc_jack headset_jack, hdmi_jack;
};
static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = {
{
.dlc = COMP_CODEC_CONF("mt6358-sound"),
.name_prefix = "Mt6366",
},
{
.dlc = COMP_CODEC_CONF("bt-sco"),
.name_prefix = "Mt8186 bt",
},
{
.dlc = COMP_CODEC_CONF("hdmi-audio-codec"),
.name_prefix = "Mt8186 hdmi",
},
};
static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
{
struct mt8186_mt6366_rt1019_rt5682s_priv *priv =
snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_jack *jack = &priv->headset_jack;
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
int ret;
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3,
jack);
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
}
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
}
static int mt8186_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
int bitwidth;
int ret;
bitwidth = snd_pcm_format_width(params_format(params));
if (bitwidth < 0) {
dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
return bitwidth;
}
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
if (ret) {
dev_err(card->dev, "failed to set tdm slot\n");
return ret;
}
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1,
RT5682_PLL1_S_BCLK1,
params_rate(params) * 64,
params_rate(params) * 512);
if (ret) {
dev_err(card->dev, "failed to set pll\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai,
RT5682_SCLK_S_PLL1,
params_rate(params) * 512,
SND_SOC_CLOCK_IN);
if (ret) {
dev_err(card->dev, "failed to set sysclk\n");
return ret;
}
return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
}
static const struct snd_soc_ops mt8186_rt5682s_i2s_ops = {
.hw_params = mt8186_rt5682s_i2s_hw_params,
};
static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
struct mt8186_mt6366_rt1019_rt5682s_priv *priv =
snd_soc_card_get_drvdata(rtd->card);
int ret;
ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack);
if (ret) {
dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
return ret;
}
return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
}
static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params,
snd_pcm_format_t fmt)
{
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt);
/* fix BE i2s channel to 2 channel */
channels->min = 2;
channels->max = 2;
/* clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
params_set_format(params, fmt);
return 0;
}
static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
}
static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE);
}
static int mt8186_mt6366_rt1019_rt5682s_playback_startup(struct snd_pcm_substream *substream)
{
static const unsigned int rates[] = {
48000
};
static const unsigned int channels[] = {
2
};
static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
if (ret < 0) {
dev_err(rtd->dev, "hw_constraint_list rate failed\n");
return ret;
}
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
if (ret < 0) {
dev_err(rtd->dev, "hw_constraint_list channel failed\n");
return ret;
}
return 0;
}
static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_playback_ops = {
.startup = mt8186_mt6366_rt1019_rt5682s_playback_startup,
};
static int mt8186_mt6366_rt1019_rt5682s_capture_startup(struct snd_pcm_substream *substream)
{
static const unsigned int rates[] = {
48000
};
static const unsigned int channels[] = {
1, 2
};
static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int ret;
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
if (ret < 0) {
dev_err(rtd->dev, "hw_constraint_list rate failed\n");
return ret;
}
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
if (ret < 0) {
dev_err(rtd->dev, "hw_constraint_list channel failed\n");
return ret;
}
return 0;
}
static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_capture_ops = {
.startup = mt8186_mt6366_rt1019_rt5682s_capture_startup,
};
/* FE */
SND_SOC_DAILINK_DEFS(playback1,
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback12,
DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback2,
DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback3,
DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback4,
DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback5,
DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback6,
DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback7,
DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(playback8,
DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture1,
DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture2,
DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture3,
DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture4,
DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture5,
DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture6,
DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(capture7,
DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
/* hostless */
SND_SOC_DAILINK_DEFS(hostless_lpbk,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_fm,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_src1,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_src_bargein,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
/* BE */
SND_SOC_DAILINK_DEFS(adda,
DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound",
"mt6358-snd-codec-aif1"),
COMP_CODEC("dmic-codec",
"dmic-hifi")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(i2s0,
DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(i2s1,
DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(i2s2,
DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(i2s3,
DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
DAILINK_COMP_ARRAY(COMP_EMPTY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hw_gain1,
DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hw_gain2,
DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hw_src1,
DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hw_src2,
DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(connsys_i2s,
DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(pcm1,
DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(tdm_in,
DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
/* hostless */
SND_SOC_DAILINK_DEFS(hostless_ul1,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_ul2,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_ul3,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_ul5,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_ul6,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
SND_SOC_DAILINK_DEFS(hostless_src_aaudio,
DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
/* Front End DAI links */
{
.name = "Playback_1",
.stream_name = "Playback_1",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
.ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
SND_SOC_DAILINK_REG(playback1),
},
{
.name = "Playback_12",
.stream_name = "Playback_12",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback12),
},
{
.name = "Playback_2",
.stream_name = "Playback_2",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
SND_SOC_DAILINK_REG(playback2),
},
{
.name = "Playback_3",
.stream_name = "Playback_3",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
.ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
SND_SOC_DAILINK_REG(playback3),
},
{
.name = "Playback_4",
.stream_name = "Playback_4",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback4),
},
{
.name = "Playback_5",
.stream_name = "Playback_5",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback5),
},
{
.name = "Playback_6",
.stream_name = "Playback_6",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback6),
},
{
.name = "Playback_7",
.stream_name = "Playback_7",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback7),
},
{
.name = "Playback_8",
.stream_name = "Playback_8",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
SND_SOC_DAILINK_REG(playback8),
},
{
.name = "Capture_1",
.stream_name = "Capture_1",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(capture1),
},
{
.name = "Capture_2",
.stream_name = "Capture_2",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
.ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
SND_SOC_DAILINK_REG(capture2),
},
{
.name = "Capture_3",
.stream_name = "Capture_3",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(capture3),
},
{
.name = "Capture_4",
.stream_name = "Capture_4",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
.ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
SND_SOC_DAILINK_REG(capture4),
},
{
.name = "Capture_5",
.stream_name = "Capture_5",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(capture5),
},
{
.name = "Capture_6",
.stream_name = "Capture_6",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
.dpcm_merged_format = 1,
.dpcm_merged_chan = 1,
.dpcm_merged_rate = 1,
SND_SOC_DAILINK_REG(capture6),
},
{
.name = "Capture_7",
.stream_name = "Capture_7",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(capture7),
},
{
.name = "Hostless_LPBK",
.stream_name = "Hostless_LPBK",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_lpbk),
},
{
.name = "Hostless_FM",
.stream_name = "Hostless_FM",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_fm),
},
{
.name = "Hostless_SRC_1",
.stream_name = "Hostless_SRC_1",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src1),
},
{
.name = "Hostless_SRC_Bargein",
.stream_name = "Hostless_SRC_Bargein",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src_bargein),
},
{
.name = "Hostless_HW_Gain_AAudio",
.stream_name = "Hostless_HW_Gain_AAudio",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio),
},
{
.name = "Hostless_SRC_AAudio",
.stream_name = "Hostless_SRC_AAudio",
.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
SND_SOC_DPCM_TRIGGER_PRE},
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_src_aaudio),
},
/* Back End DAI links */
{
.name = "Primary Codec",
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
.init = mt8186_mt6366_init,
SND_SOC_DAILINK_REG(adda),
},
{
.name = "I2S3",
.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,
.init = mt8186_mt6366_rt1019_rt5682s_hdmi_init,
.be_hw_params_fixup = mt8186_it6505_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s3),
},
{
.name = "I2S0",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
.ops = &mt8186_rt5682s_i2s_ops,
SND_SOC_DAILINK_REG(i2s0),
},
{
.name = "I2S1",
.no_pcm = 1,
.dpcm_playback = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
.init = mt8186_rt5682s_init,
.ops = &mt8186_rt5682s_i2s_ops,
SND_SOC_DAILINK_REG(i2s1),
},
{
.name = "I2S2",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
SND_SOC_DAILINK_REG(i2s2),
},
{
.name = "HW Gain 1",
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_gain1),
},
{
.name = "HW Gain 2",
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_gain2),
},
{
.name = "HW_SRC_1",
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_src1),
},
{
.name = "HW_SRC_2",
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hw_src2),
},
{
.name = "CONNSYS_I2S",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(connsys_i2s),
},
{
.name = "PCM 1",
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_IF,
.no_pcm = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(pcm1),
},
{
.name = "TDM IN",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(tdm_in),
},
/* dummy BE for ul memif to record from dl memif */
{
.name = "Hostless_UL1",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul1),
},
{
.name = "Hostless_UL2",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul2),
},
{
.name = "Hostless_UL3",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul3),
},
{
.name = "Hostless_UL5",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul5),
},
{
.name = "Hostless_UL6",
.no_pcm = 1,
.dpcm_capture = 1,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(hostless_ul6),
},
};
static const struct snd_soc_dapm_widget
mt8186_mt6366_rt1019_rt5682s_widgets[] = {
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_OUTPUT("HDMI1"),
};
static const struct snd_soc_dapm_route
mt8186_mt6366_rt1019_rt5682s_routes[] = {
/* SPK */
{ "Speakers", NULL, "Speaker" },
/* HDMI */
{ "HDMI1", NULL, "TX" },
};
static const struct snd_kcontrol_new
mt8186_mt6366_rt1019_rt5682s_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("HDMI1"),
};
static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
.name = "mt8186_mt6366_rt1019_rt5682s",
.owner = THIS_MODULE,
.dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
.num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
.controls = mt8186_mt6366_rt1019_rt5682s_controls,
.num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
.dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
.num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
.dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
.num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
.codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
.num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
};
static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
struct snd_soc_dai_link *dai_link;
struct mt8186_mt6366_rt1019_rt5682s_priv *priv;
struct device_node *platform_node, *headset_codec, *playback_codec;
int ret, i;
card = (struct snd_soc_card *)device_get_match_data(&pdev->dev);
if (!card)
return -EINVAL;
card->dev = &pdev->dev;
platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
if (!platform_node) {
ret = -EINVAL;
dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
return ret;
}
playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs");
if (!playback_codec) {
ret = -EINVAL;
dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
goto err_playback_codec;
}
headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
if (!headset_codec) {
ret = -EINVAL;
dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
goto err_headset_codec;
}
for_each_card_prelinks(card, i, dai_link) {
ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3");
if (ret) {
dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
dai_link->name);
goto err_probe;
}
ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0");
if (ret) {
dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
dai_link->name);
goto err_probe;
}
ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1");
if (ret) {
dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
dai_link->name);
goto err_probe;
}
if (!dai_link->platforms->name)
dai_link->platforms->of_node = platform_node;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto err_probe;
}
snd_soc_card_set_drvdata(card, priv);
ret = mt8186_afe_gpio_init(&pdev->dev);
if (ret) {
dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
goto err_probe;
}
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
err_probe:
of_node_put(headset_codec);
err_headset_codec:
of_node_put(playback_codec);
err_playback_codec:
of_node_put(platform_node);
return ret;
}
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
{ .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
.data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
},
{}
};
#endif
static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = {
.driver = {
.name = "mt8186_mt6366_rt1019_rt5682s",
#if IS_ENABLED(CONFIG_OF)
.of_match_table = mt8186_mt6366_rt1019_rt5682s_dt_match,
#endif
.pm = &snd_soc_pm_ops,
},
.probe = mt8186_mt6366_rt1019_rt5682s_dev_probe,
};
module_platform_driver(mt8186_mt6366_rt1019_rt5682s_driver);
/* Module information */
MODULE_DESCRIPTION("MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver");
MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("mt8186_mt6366_rt1019_rt5682s soc card");

View File

@ -20,6 +20,8 @@
#include "../../codecs/rt1011.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-dsp-sof-common.h"
#include "../common/mtk-soc-card.h"
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h"
@ -54,13 +56,6 @@ struct mt8195_card_data {
unsigned long quirk;
};
struct sof_conn_stream {
const char *normal_link;
const char *sof_link;
const char *sof_dma;
int stream_dir;
};
struct mt8195_mt6359_priv {
struct snd_soc_jack headset_jack;
struct snd_soc_jack dp_jack;
@ -374,7 +369,8 @@ static const struct snd_soc_ops mt8195_dptx_ops = {
static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
int ret;
@ -389,7 +385,8 @@ static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
static int mt8195_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
int ret;
@ -555,7 +552,8 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_codec =
asoc_rtd_to_codec(rtd, 0)->component;
struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
struct snd_soc_jack *jack = &priv->headset_jack;
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
@ -722,7 +720,8 @@ static int mt8195_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
struct snd_soc_component *component = dapm->component;
struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
int ret;
/*
@ -1321,175 +1320,24 @@ static struct snd_soc_card mt8195_mt6359_soc_card = {
static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dai_link *sof_dai_link = NULL;
struct snd_soc_pcm_runtime *runtime;
struct snd_soc_dai *cpu_dai;
int i, j, ret = 0;
int ret;
for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) {
const struct sof_conn_stream *conn = &g_sof_conn_streams[i];
if (strcmp(rtd->dai_link->name, conn->normal_link))
continue;
for_each_card_rtds(card, runtime) {
if (strcmp(runtime->dai_link->name, conn->sof_link))
continue;
for_each_rtd_cpu_dais(runtime, j, cpu_dai) {
if (cpu_dai->stream_active[conn->stream_dir] > 0) {
sof_dai_link = runtime->dai_link;
break;
}
}
break;
}
if (sof_dai_link && sof_dai_link->be_hw_params_fixup)
ret = sof_dai_link->be_hw_params_fixup(runtime, params);
break;
}
ret = mtk_sof_dai_link_fixup(rtd, params);
if (!strcmp(rtd->dai_link->name, "ETDM2_IN_BE") ||
!strcmp(rtd->dai_link->name, "ETDM1_OUT_BE")) {
mt8195_etdm_hw_params_fixup(runtime, params);
mt8195_etdm_hw_params_fixup(rtd, params);
}
return ret;
}
static int mt8195_mt6359_card_late_probe(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *runtime;
struct snd_soc_component *sof_comp = NULL;
int i;
/* 1. find sof component */
for_each_card_rtds(card, runtime) {
for (i = 0; i < runtime->num_components; i++) {
if (!runtime->components[i]->driver->name)
continue;
if (!strcmp(runtime->components[i]->driver->name, "sof-audio-component")) {
sof_comp = runtime->components[i];
break;
}
}
}
if (!sof_comp) {
dev_info(card->dev, " probe without component\n");
return 0;
}
/* 2. add route path and fixup callback */
for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) {
const struct sof_conn_stream *conn = &g_sof_conn_streams[i];
struct snd_soc_pcm_runtime *sof_rtd = NULL;
struct snd_soc_pcm_runtime *normal_rtd = NULL;
struct snd_soc_pcm_runtime *rtd = NULL;
for_each_card_rtds(card, rtd) {
if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
sof_rtd = rtd;
continue;
}
if (!strcmp(rtd->dai_link->name, conn->normal_link)) {
normal_rtd = rtd;
continue;
}
if (normal_rtd && sof_rtd)
break;
}
if (normal_rtd && sof_rtd) {
int j;
struct snd_soc_dai *cpu_dai;
for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {
struct snd_soc_dapm_route route;
struct snd_soc_dapm_path *p = NULL;
struct snd_soc_dapm_widget *play_widget =
cpu_dai->playback_widget;
struct snd_soc_dapm_widget *cap_widget =
cpu_dai->capture_widget;
memset(&route, 0, sizeof(route));
if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE &&
cap_widget) {
snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) {
route.source = conn->sof_dma;
route.sink = p->sink->name;
snd_soc_dapm_add_routes(&card->dapm, &route, 1);
}
} else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK &&
play_widget){
snd_soc_dapm_widget_for_each_source_path(play_widget, p) {
route.source = p->source->name;
route.sink = conn->sof_dma;
snd_soc_dapm_add_routes(&card->dapm, &route, 1);
}
} else {
dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
}
}
normal_rtd->dai_link->be_hw_params_fixup = mt8195_dai_link_fixup;
}
}
return 0;
}
static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
const char *propname)
{
struct device *dev = card->dev;
struct snd_soc_dai_link *link;
const char *dai_name = NULL;
int i, j, ret, num_links;
num_links = of_property_count_strings(np, "mediatek,dai-link");
if (num_links < 0 || num_links > ARRAY_SIZE(mt8195_mt6359_dai_links)) {
dev_dbg(dev, "number of dai-link is invalid\n");
return -EINVAL;
}
card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
if (!card->dai_link)
return -ENOMEM;
card->num_links = 0;
link = card->dai_link;
for (i = 0; i < num_links; i++) {
ret = of_property_read_string_index(np, propname, i, &dai_name);
if (ret) {
dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",
propname, i, ret);
return -EINVAL;
}
for (j = 0; j < ARRAY_SIZE(mt8195_mt6359_dai_links); j++) {
if (!strcmp(dai_name, mt8195_mt6359_dai_links[j].name)) {
memcpy(link, &mt8195_mt6359_dai_links[j],
sizeof(struct snd_soc_dai_link));
link++;
card->num_links++;
break;
}
}
}
if (card->num_links != num_links)
return -EINVAL;
return 0;
}
static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &mt8195_mt6359_soc_card;
struct snd_soc_dai_link *dai_link;
struct mt8195_mt6359_priv *priv;
struct mtk_soc_card_data *soc_card_data;
struct mt8195_mt6359_priv *mach_priv;
struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node;
struct mt8195_card_data *card_data;
int is5682s = 0;
@ -1512,17 +1360,41 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
if (strstr(card->name, "_5682s"))
is5682s = 1;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
if (!soc_card_data)
return -ENOMEM;
mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL);
if (!mach_priv)
return -ENOMEM;
soc_card_data->mach_priv = mach_priv;
adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
if (adsp_node) {
struct mtk_sof_priv *sof_priv;
sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL);
if (!sof_priv) {
ret = -ENOMEM;
goto err_kzalloc;
}
sof_priv->conn_streams = g_sof_conn_streams;
sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams);
sof_priv->sof_dai_link_fixup = mt8195_dai_link_fixup;
soc_card_data->sof_priv = sof_priv;
card->late_probe = mtk_sof_card_late_probe;
sof_on = 1;
}
if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
ret = mt8195_dailink_parse_of(card, pdev->dev.of_node,
"mediatek,dai-link");
ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
"mediatek,dai-link",
mt8195_mt6359_dai_links,
ARRAY_SIZE(mt8195_mt6359_dai_links));
if (ret) {
dev_dbg(&pdev->dev, "Parse dai-link fail\n");
return -EINVAL;
goto err_parse_of;
}
} else {
if (!sof_on)
@ -1533,13 +1405,10 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
"mediatek,platform", 0);
if (!platform_node) {
dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n");
return -EINVAL;
ret = -EINVAL;
goto err_platform_node;
}
adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
if (adsp_node)
sof_on = 1;
dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0);
hdmi_node = of_parse_phandle(pdev->dev.of_node,
"mediatek,hdmi-codec", 0);
@ -1612,17 +1481,17 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
}
}
if (sof_on)
card->late_probe = mt8195_mt6359_card_late_probe;
snd_soc_card_set_drvdata(card, priv);
snd_soc_card_set_drvdata(card, soc_card_data);
ret = devm_snd_soc_register_card(&pdev->dev, card);
of_node_put(platform_node);
of_node_put(adsp_node);
of_node_put(dp_node);
of_node_put(hdmi_node);
err_kzalloc:
err_parse_of:
err_platform_node:
of_node_put(adsp_node);
return ret;
}

View File

@ -217,7 +217,7 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx)
idx = find_first_zero_bit(&adm->copp_bitmap[port_idx],
MAX_COPPS_PER_PORT);
if (idx > MAX_COPPS_PER_PORT)
if (idx >= MAX_COPPS_PER_PORT)
return ERR_PTR(-EBUSY);
c = kzalloc(sizeof(*c), GFP_ATOMIC);

View File

@ -513,7 +513,7 @@ int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
return 0;
}
buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
if (!buf) {
spin_unlock_irqrestore(&ac->lock, flags);
return -ENOMEM;

View File

@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *ssp_str)
{
const char *tplg_filename = NULL;
char *filename;
char *split_ext;
const char *split_ext;
char *filename, *tmp;
filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
if (!filename)
return NULL;
/* this assumes a .tplg extension */
split_ext = strsep(&filename, ".");
if (split_ext) {
tmp = filename;
split_ext = strsep(&tmp, ".");
if (split_ext)
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s-%s.tplg",
split_ext, ssp_str);
if (!tplg_filename)
return NULL;
}
kfree(filename);
return tplg_filename;
}

View File

@ -25,9 +25,9 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
return cstream->runtime->private_data;
}
static int hda_probes_compr_assign(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id)
static int hda_probes_compr_startup(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct hdac_ext_stream *hext_stream;
@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
return 0;
}
static int hda_probes_compr_free(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai)
static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
/* SOF client implementation */
static const struct sof_probes_host_ops hda_probes_ops = {
.assign = hda_probes_compr_assign,
.free = hda_probes_compr_free,
.startup = hda_probes_compr_startup,
.shutdown = hda_probes_compr_shutdown,
.set_params = hda_probes_compr_set_params,
.trigger = hda_probes_compr_trigger,
.pointer = hda_probes_compr_pointer,

View File

@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
return -ENODEV;
}
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
if (hstream->posbuf)
*hstream->posbuf = 0;
@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV;
}
/* decouple host and link DMA */
mask = 0x1 << hstream->index;
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask);
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
/* decouple host and link DMA */
mask = 0x1 << hstream->index;
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask);
/* clear stream status */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_CL_DMA_SD_INT_MASK |

View File

@ -776,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename;
}
static int dmic_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename,
const char *idisp_str,
int *dmic_found)
static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename,
const char *idisp_str,
int *dmic_found,
bool tplg_fixup)
{
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
const char *dmic_str;
int dmic_num;
@ -808,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
break;
}
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
idisp_str, dmic_str);
if (!fixed_tplg_filename)
return -ENOMEM;
if (tplg_fixup) {
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
idisp_str, dmic_str);
if (!fixed_tplg_filename)
return -ENOMEM;
*tplg_filename = fixed_tplg_filename;
}
dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
*dmic_found = dmic_num;
*tplg_filename = fixed_tplg_filename;
return 0;
}
@ -1221,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
* - one external HDAudio codec
*/
if (!*mach && codec_num <= 2) {
bool tplg_fixup;
hda_mach = snd_soc_acpi_intel_hda_machines;
dev_info(bus->dev, "using HDA machine driver %s now\n",
@ -1232,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
idisp_str = "";
/* topology: use the info from hda_machines */
tplg_filename = hda_mach->sof_tplg_filename;
ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
if (pdata->tplg_filename) {
tplg_fixup = false;
tplg_filename = pdata->tplg_filename;
} else {
tplg_fixup = true;
tplg_filename = hda_mach->sof_tplg_filename;
}
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
tplg_fixup);
if (ret < 0)
return;
@ -1397,30 +1410,37 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
}
if (mach && mach->link_mask) {
int dmic_num = 0;
bool tplg_fixup;
const char *tplg_filename;
mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev);
pdata->fw_filename = pdata->desc->default_fw_filename[pdata->ipc_type];
pdata->tplg_filename = mach->sof_tplg_filename;
if (pdata->tplg_filename) {
tplg_fixup = false;
} else {
tplg_fixup = true;
tplg_filename = mach->sof_tplg_filename;
}
/*
* DMICs use up to 4 pins and are typically pin-muxed with SoundWire
* link 2 and 3, thus we only try to enable dmics if all conditions
* are true:
* a) link 2 and 3 are not used by SoundWire
* link 2 and 3, or link 1 and 2, thus we only try to enable dmics
* if all conditions are true:
* a) 2 or fewer links are used by SoundWire
* b) the NHLT table reports the presence of microphones
*/
if (!(mach->link_mask & GENMASK(3, 2))) {
const char *tplg_filename = mach->sof_tplg_filename;
if (hweight_long(mach->link_mask) <= 2) {
int ret;
ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
&dmic_num, tplg_fixup);
if (ret < 0)
return NULL;
pdata->tplg_filename = tplg_filename;
}
if (tplg_fixup)
pdata->tplg_filename = tplg_filename;
mach->mach_params.dmic_num = dmic_num;
dev_dbg(sdev->dev,
@ -1466,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) {
bool add_extension = false;
bool tplg_fixup = false;
/*
* If tplg file name is overridden, use it instead of
* the one set in mach table
*/
if (!sof_pdata->tplg_filename)
if (!sof_pdata->tplg_filename) {
sof_pdata->tplg_filename = mach->sof_tplg_filename;
tplg_fixup = true;
}
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s",
@ -1500,8 +1524,10 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report SSP link mask to machine driver */
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
mach->mach_params.i2s_link_mask) {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
int ssp_num;
if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
@ -1511,6 +1537,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* fls returns 1-based results, SSPs indices are 0-based */
ssp_num = fls(mach->mach_params.i2s_link_mask) - 1;
if (ssp_num >= chip->ssp_count) {
dev_err(sdev->dev, "Invalid SSP %d, max on this platform is %d\n",
ssp_num, chip->ssp_count);
return NULL;
}
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d",
sof_pdata->tplg_filename,
@ -1523,7 +1555,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
add_extension = true;
}
if (add_extension) {
if (tplg_fixup && add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
sof_pdata->tplg_filename,

View File

@ -372,20 +372,9 @@ static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
(dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0) {
if (ret < 0)
dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
__func__);
return ret;
}
/* did core power up ? */
dspcxctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE);
if ((dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK)
!= MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) {
dev_err(sdev->dev, "power up core failed core %d adspcs %#x\n",
core, dspcxctl);
ret = -EIO;
}
return ret;
}

View File

@ -109,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev,
return 0;
}
static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmware *fw)
{
const struct sof_ext_man_header *head;
@ -131,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
return head->full_size;
/* otherwise given fw don't have an extended manifest */
dev_dbg(sdev->dev, "Unexpected extended manifest magic number: %#x\n",
head->magic);
return 0;
}
@ -147,7 +149,7 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
head = (struct sof_ext_man_header *)fw->data;
remaining = head->full_size - head->header_size;
ext_man_size = ipc3_fw_ext_man_size(fw);
ext_man_size = ipc3_fw_ext_man_size(sdev, fw);
/* Assert firmware starts with extended manifest */
if (ext_man_size <= 0)

View File

@ -115,6 +115,9 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
pcm.params.no_stream_position = 1;
}
if (platform_params->cont_update_posn)
pcm.params.cont_update_posn = 1;
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
/* send hw_params IPC to the DSP */

View File

@ -179,6 +179,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_ipc4_copier *ipc4_copier;
@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_mask_none(fmt);
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency;
rate->max = rate->min;
/*
* Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required
* to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI

View File

@ -111,6 +111,12 @@ static const struct sof_topology_token gain_tokens[] = {
get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
};
/* SRC */
static const struct sof_topology_token src_tokens[] = {
{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_src, sink_rate)},
};
static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
@ -134,6 +140,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
};
static void sof_ipc4_dbg_audio_format(struct device *dev,
@ -307,6 +314,7 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
{
struct sof_ipc4_fw_module *fw_module;
uint32_t type;
int ret;
ret = sof_ipc4_widget_set_module_info(swidget);
@ -323,6 +331,9 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_
msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0;
msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
return 0;
}
@ -740,6 +751,58 @@ err:
return ret;
}
static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_src *src;
int ret;
dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
src = kzalloc(sizeof(*src), GFP_KERNEL);
if (!src)
return -ENOMEM;
swidget->private = src;
/* The out_audio_fmt in topology is ignored as it is not required by SRC */
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
if (ret)
goto err;
ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(src), 1);
if (ret) {
dev_err(scomp->dev, "Parsing SRC tokens failed\n");
goto err;
}
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
if (ret)
goto err;
return 0;
err:
sof_ipc4_free_audio_fmt(&src->available_fmt);
kfree(src);
swidget->private = NULL;
return ret;
}
static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
{
struct sof_ipc4_src *src = swidget->private;
if (!src)
return;
sof_ipc4_free_audio_fmt(&src->available_fmt);
kfree(swidget->private);
swidget->private = NULL;
}
static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
{
struct sof_ipc4_mixer *mixer = swidget->private;
@ -891,7 +954,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
{
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
struct sof_ipc4_copier *ipc4_copier = NULL;
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
@ -925,8 +987,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
ipc4_copier->ipc_config_data = NULL;
ipc4_copier->ipc_config_size = 0;
}
ida_free(&fw_module->m_ida, swidget->instance_id);
}
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
@ -1254,15 +1314,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
/* assign instance ID */
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
}
static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget)
{
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
ida_free(&fw_module->m_ida, swidget->instance_id);
return 0;
}
static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
@ -1287,8 +1339,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
/* assign instance ID */
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
return 0;
}
static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
@ -1314,8 +1365,38 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
/* assign instance ID */
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
return 0;
}
static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *fe_params,
struct snd_sof_platform_stream_params *platform_params,
struct snd_pcm_hw_params *pipeline_params, int dir)
{
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_src *src = swidget->private;
struct snd_interval *rate;
int ret;
src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
/* output format is not required to be sent to the FW for SRC */
ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
NULL, pipeline_params, &src->available_fmt,
sizeof(src->base_config));
if (ret < 0)
return ret;
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
/* update pipeline_params for sink widgets */
rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
rate->min = src->sink_rate;
rate->max = rate->min;
return 0;
}
static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
@ -1373,9 +1454,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
u32 ipc_size = 0;
int ret;
dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
switch (swidget->id) {
case snd_soc_dapm_scheduler:
pipeline = swidget->private;
@ -1430,21 +1508,37 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg = &mixer->msg;
break;
}
case snd_soc_dapm_src:
{
struct sof_ipc4_src *src = swidget->private;
ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
ipc_data = src;
msg = &src->msg;
break;
}
default:
dev_err(sdev->dev, "widget type %d not supported", swidget->id);
return -EINVAL;
}
if (swidget->id != snd_soc_dapm_scheduler) {
ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
if (ret < 0) {
dev_err(sdev->dev, "failed to assign instance id for %s\n",
swidget->widget->name);
return ret;
}
pipeline = pipe_widget->private;
msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
msg->extension |= ipc_size >> 2;
msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK;
msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode);
}
dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
msg->data_size = ipc_size;
msg->data_ptr = ipc_data;
@ -1458,6 +1552,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
int ret = 0;
/* freeing a pipeline frees all the widgets associated with it */
@ -1480,6 +1575,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
} else {
ida_free(&fw_module->m_ida, swidget->instance_id);
}
return ret;
@ -1766,6 +1863,15 @@ static enum sof_tokens mixer_token_list[] = {
SOF_COMP_EXT_TOKENS,
};
static enum sof_tokens src_token_list[] = {
SOF_COMP_TOKENS,
SOF_SRC_TOKENS,
SOF_AUDIO_FMT_NUM_TOKENS,
SOF_IN_AUDIO_FORMAT_TOKENS,
SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
SOF_COMP_EXT_TOKENS,
};
static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
[snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
host_token_list, ARRAY_SIZE(host_token_list), NULL,
@ -1789,11 +1895,15 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
sof_ipc4_prepare_gain_module,
sof_ipc4_unprepare_generic_module},
NULL},
[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
mixer_token_list, ARRAY_SIZE(mixer_token_list),
NULL, sof_ipc4_prepare_mixer_module,
sof_ipc4_unprepare_generic_module},
NULL},
[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
src_token_list, ARRAY_SIZE(src_token_list),
NULL, sof_ipc4_prepare_src_module,
NULL},
};
const struct sof_ipc_tplg_ops ipc4_tplg_ops = {

View File

@ -15,7 +15,18 @@
#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12)
#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
#define SOF_IPC4_MODULE_LL BIT(5)
#define SOF_IPC4_MODULE_LOAD_TYPE GENMASK(3, 0)
#define SOF_IPC4_MODULE_AUTO_START BIT(4)
/*
* Two module schedule domains in fw :
* LL domain - Low latency domain
* DP domain - Data processing domain
* The LL setting should be equal to !DP setting
*/
#define SOF_IPC4_MODULE_LL BIT(5)
#define SOF_IPC4_MODULE_DP BIT(6)
#define SOF_IPC4_MODULE_LIB_CODE BIT(7)
#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
@ -242,4 +253,18 @@ struct sof_ipc4_mixer {
struct sof_ipc4_msg msg;
};
/**
* struct sof_ipc4_src SRC config data
* @base_config: IPC base config data
* @sink_rate: Output rate for sink module
* @available_fmt: Available audio format
* @msg: IPC4 message struct containing header and data info
*/
struct sof_ipc4_src {
struct sof_ipc4_base_module_cfg base_config;
uint32_t sink_rate;
struct sof_ipc4_available_audio_format available_fmt;
struct sof_ipc4_msg msg;
};
#endif

View File

@ -21,7 +21,7 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
/* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
DSP_RESET_SW, DSP_RESET_SW);
STATVECTOR_SEL, STATVECTOR_SEL);
/* toggle DReset & BReset */
/* pull high DReset & BReset */
@ -29,6 +29,9 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
ADSP_BRESET_SW | ADSP_DRESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW);
/* delay 10 DSP cycles at 26M about 1us by IP vendor's suggestion */
udelay(1);
/* pull low DReset & BReset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW,
@ -46,11 +49,13 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev)
{
/* Clear to 0 firstly */
snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0);
/* RUN_STALL pull high again to reset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_RUNSTALL, ADSP_RUNSTALL);
/* pull high DReset & BReset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW);
}

View File

@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
if (ret)
return ret;
ret = ops->assign(cdev, cstream, dai, &priv->extractor_stream_tag);
ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag);
if (ret) {
dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret);
priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
sof_client_core_module_put(cdev);
}
@ -310,7 +310,7 @@ exit:
priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
snd_compr_free_pages(cstream);
ret = ops->free(cdev, cstream, dai);
ret = ops->shutdown(cdev, cstream, dai);
sof_client_core_module_put(cdev);
@ -709,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
ops = dev->platform_data;
if (!ops->assign || !ops->free || !ops->set_params || !ops->trigger ||
if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
!ops->pointer) {
dev_err(dev, "missing platform callback(s)\n");
return -ENODEV;

View File

@ -14,10 +14,10 @@ struct snd_soc_dai;
* DSP and host, like HDA.
*/
struct sof_probes_host_ops {
int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id);
int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai);
int (*startup)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id);
int (*shutdown)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai);
int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_compr_params *params,
struct snd_soc_dai *dai);

View File

@ -126,6 +126,7 @@ struct snd_sof_platform_stream_params {
bool use_phy_address;
u32 phy_addr;
bool no_ipc_position;
bool cont_update_posn;
};
/*