Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v7 1/5] dt-bindings: interconnect: Add Qualcomm IPQ9574 support
From: Varadarajan Narayanan @ 2024-04-09 11:03 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: andersson, konrad.dybcio, mturquette, sboyd, robh, krzk+dt,
	conor+dt, djakov, dmitry.baryshkov, quic_anusha, linux-arm-msm,
	linux-clk, devicetree, linux-kernel, linux-pm
In-Reply-To: <1ec401be-11cb-416a-9eae-d72ea8acf06f@kernel.org>

On Tue, Apr 09, 2024 at 11:45:51AM +0200, Krzysztof Kozlowski wrote:
> On 09/04/2024 09:41, Varadarajan Narayanan wrote:
> > On Thu, Apr 04, 2024 at 02:25:06PM +0530, Varadarajan Narayanan wrote:
> >> On Wed, Apr 03, 2024 at 04:59:40PM +0200, Krzysztof Kozlowski wrote:
> >>> On 03/04/2024 12:42, Varadarajan Narayanan wrote:
> >>>> Add interconnect-cells to clock provider so that it can be
> >>>> used as icc provider.
> >>>>
> >>>> Add master/slave ids for Qualcomm IPQ9574 Network-On-Chip
> >>>> interfaces. This will be used by the gcc-ipq9574 driver
> >>>> that will for providing interconnect services using the
> >>>> icc-clk framework.
> >>>>
> >>>> Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
> >>>> ---
> >>>> v7:
> >>>> Fix macro names to be consistent with other bindings
> >>>> v6:
> >>>> Removed Reviewed-by: Krzysztof Kozlowski
> >>>> Redefine the bindings such that driver and DT can share them
> >>>>
> >>>> v3:
> >>>> Squash Documentation/ and include/ changes into same patch
> >>>>
> >>>> qcom,ipq9574.h
> >>>> 	Move 'first id' to clock driver
> >>>>
> >>>> ---
> >>>>  .../bindings/clock/qcom,ipq9574-gcc.yaml      |  3 +
> >>>>  .../dt-bindings/interconnect/qcom,ipq9574.h   | 87 +++++++++++++++++++
> >>>>  2 files changed, 90 insertions(+)
> >>>>  create mode 100644 include/dt-bindings/interconnect/qcom,ipq9574.h
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
> >>>> index 944a0ea79cd6..824781cbdf34 100644
> >>>> --- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
> >>>> +++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-gcc.yaml
> >>>> @@ -33,6 +33,9 @@ properties:
> >>>>        - description: PCIE30 PHY3 pipe clock source
> >>>>        - description: USB3 PHY pipe clock source
> >>>>
> >>>> +  '#interconnect-cells':
> >>>> +    const: 1
> >>>> +
> >>>>  required:
> >>>>    - compatible
> >>>>    - clocks
> >>>> diff --git a/include/dt-bindings/interconnect/qcom,ipq9574.h b/include/dt-bindings/interconnect/qcom,ipq9574.h
> >>>> new file mode 100644
> >>>> index 000000000000..0b076b0cf880
> >>>> --- /dev/null
> >>>> +++ b/include/dt-bindings/interconnect/qcom,ipq9574.h
> >>>> @@ -0,0 +1,87 @@
> >>>> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> >>>> +#ifndef INTERCONNECT_QCOM_IPQ9574_H
> >>>> +#define INTERCONNECT_QCOM_IPQ9574_H
> >>>> +
> >>>> +#define ICC_ANOC_PCIE0		0
> >>>> +#define ICC_SNOC_PCIE0		1
> >>>> +#define ICC_ANOC_PCIE1		2
> >>>> +#define ICC_SNOC_PCIE1		3
> >>>> +#define ICC_ANOC_PCIE2		4
> >>>> +#define ICC_SNOC_PCIE2		5
> >>>> +#define ICC_ANOC_PCIE3		6
> >>>> +#define ICC_SNOC_PCIE3		7
> >>>> +#define ICC_SNOC_USB		8
> >>>> +#define ICC_ANOC_USB_AXI	9
> >>>> +#define ICC_NSSNOC_NSSCC	10
> >>>> +#define ICC_NSSNOC_SNOC_0	11
> >>>> +#define ICC_NSSNOC_SNOC_1	12
> >>>> +#define ICC_NSSNOC_PCNOC_1	13
> >>>> +#define ICC_NSSNOC_QOSGEN_REF	14
> >>>> +#define ICC_NSSNOC_TIMEOUT_REF	15
> >>>> +#define ICC_NSSNOC_XO_DCD	16
> >>>> +#define ICC_NSSNOC_ATB		17
> >>>> +#define ICC_MEM_NOC_NSSNOC	18
> >>>> +#define ICC_NSSNOC_MEMNOC	19
> >>>> +#define ICC_NSSNOC_MEM_NOC_1	20
> >>>> +
> >>>> +#define ICC_NSSNOC_PPE		0
> >>>> +#define ICC_NSSNOC_PPE_CFG	1
> >>>> +#define ICC_NSSNOC_NSS_CSR	2
> >>>> +#define ICC_NSSNOC_IMEM_QSB	3
> >>>> +#define ICC_NSSNOC_IMEM_AHB	4
> >>>> +
> >>>> +#define MASTER_ANOC_PCIE0		(ICC_ANOC_PCIE0 * 2)
> >>>> +#define SLAVE_ANOC_PCIE0		((ICC_ANOC_PCIE0 * 2) + 1)
> >>>
> >>> Which existing Qualcomm platform has such code?
> >>
> >> Existing Qualcomm platforms don't use icc-clk. They use icc-rpm
> >> or icc-rpmh. clk-cbf-msm8996.c is the only driver that uses icc-clk.
> >>
> >> The icc_clk_register automatically creates master & slave nodes
> >> for each clk entry provided as input with the node-ids 'n' and
> >> 'n+1'. Since clk-cbf-msm8996.c has only one entry, it could just
> >> define MASTER_CBF_M4M and SLAVE_CBF_M4M with 0 and 1 and avoid these
> >> calculations.
> >>
> >> However, ipq9574 gives an array of clock entries as input to
> >> icc_clk_register. To tie the order/sequence of these clock
> >> entries correctly with the node-ids, this calculation is needed.
> >>
> >>> This is the third time I am asking for consistent headers. Open
> >>> existing, recently added headers and look how it is done there. Why?
> >>> Because I am against such calculations and see no reason for them.
> >>
> >> Apologies. Regret that I have to trouble you.
> >>
> >> In this ipq9574 case, have to reconcile between the following
> >> feedbacks.
> >>
> >> 1. https://lore.kernel.org/linux-arm-msm/fe40b307-26d0-4b2a-869b-5d093415b9d1@linaro.org/
> >>    We could probably use indexed identifiers here to avoid confusion:
> >>    [ICC_BINDING_NAME] = CLK_BINDING_NAME
> >>
> >> 2. https://lore.kernel.org/linux-arm-msm/95f4e99a60cc97770fc3cee850b62faf.sboyd@kernel.org/
> >>    Are these supposed to be in a dt-binding header?
> >>
> >> 3. https://lore.kernel.org/linux-arm-msm/031d0a35-b192-4161-beef-97b89d5d1da6@linaro.org/
> >>    Do you use them as well in the DTS?
> >>
> >> Having the defines (with the calculations) seemed to to comply
> >> with the above three feedbacks.
> >>
> >> Please let me know if this can be handled in a different way that
> >> would be consistent with other Qualcomm platforms.
> >
> > Krzysztof,
> >
> > Is this ok? Can I post a new version addressing other review comments?
>
> I don't understand and you did not answered before, why you have to do
> it differently than all other Qualcomm interconnect providers. Maybe the
> code here needs it, maybe not, but I don't see any argument proving this.

Other Qualcomm interconnect providers use the icc-rpm.

	1. The SoC specific interconnect providers have control
	   over the master/slave id-numbers and is hard coded.

	2. These id-numbers are used by the RPM firmware.

IPQ9574 uses icc-clk.

	1. The ipq9574 specific interconnect provider doesn't
	   have control over the master/slave id-numbers. The
	   icc-clk framework auto generates it in the order of
	   the clock entries given as input.

	2. These auto-generated id-numbers have to be correctly
	   tied to the DT nodes. Else, the relevant clocks may
	   not get enabled.

Since ICC-CLK creates two ids per clock entry (one MASTER_xxx and
one SLAVE_xxx), using those MASTER/SLAVE_xxx macros as indices in
the below array would create holes.

	static int icc_ipq9574_hws[] = {
		[MASTER_ANOC_PCIE0] = GCC_ANOC_PCIE0_1LANE_M_CLK,
		[MASTER_SNOC_PCIE0] = GCC_SNOC_PCIE0_1LANE_S_CLK,
		[MASTER_ANOC_PCIE1] = GCC_ANOC_PCIE1_1LANE_M_CLK,
		[MASTER_SNOC_PCIE1] = GCC_SNOC_PCIE1_1LANE_S_CLK,
		. . .
	};

Other Qualcomm drivers don't have this issue and they can
directly use the MASTER/SLAVE_xxx macros.

As the MASTER_xxx macros cannot be used, have to define a new set
of macros that can be used for indices in the above array. This
is the reason for the ICC_BINDING_NAME macros.

Does this answer your concern? Please let me know.

Thanks
Varada

^ permalink raw reply

* Re: [PATCH v2 3/6] firmware: arm_scmi: add initial support for i.MX BBM protocol
From: Sudeep Holla @ 2024-04-09 10:49 UTC (permalink / raw)
  To: Peng Fan
  Cc: Peng Fan (OSS), Cristian Marussi, Sudeep Holla, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	devicetree@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <DU0PR04MB94175384AD9113AC6F60546588072@DU0PR04MB9417.eurprd04.prod.outlook.com>

On Tue, Apr 09, 2024 at 09:13:33AM +0000, Peng Fan wrote:
> Hi Sudeep,
>
> > Subject: Re: [PATCH v2 3/6] firmware: arm_scmi: add initial support for i.MX
> > BBM protocol
> >
> > On Mon, Apr 08, 2024 at 07:04:43PM +0100, Cristian Marussi wrote:
> > > On Fri, Apr 05, 2024 at 08:39:25PM +0800, Peng Fan (OSS) wrote:
> > > > From: Peng Fan <peng.fan@nxp.com>
> > > >
> > > > The i.MX BBM protocol is for managing i.MX BBM module which provides
> > > > RTC and BUTTON feature.
> > > >
> > >
> > > I appreciate that you added versioning but I think a bit of
> > > documentation about what the protocol and its comamnds purpose is
> > > still lacking, as asked by Sudeep previously
> > >
> > >
> > > https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore
> > > .kernel.org%2Flinux-arm-
> > kernel%2FZeGtoJ7ztSe8Kg8R%40bogus%2F%23t&data=
> > >
> > 05%7C02%7Cpeng.fan%40nxp.com%7Ce92ff78b9126447afe9708dc587358d
> > 4%7C686e
> > >
> > a1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C638482499632395762%7C
> > Unknown%7C
> > >
> > TWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiL
> > CJXVC
> > >
> > I6Mn0%3D%7C0%7C%7C%7C&sdata=7QP%2BkkjHA3Sa0CdcbbObGG4kgYYK
> > XAGA2r%2F%2F
> > > x0MogqU%3D&reserved=0
> > >
> >
> > I have decided to ignore all these vendor protocol patches until they have
> > some documentation to understand what these protocol are for, what are the
> > commands, their input/output parameter details, any conditions are the
> > caller and callee,..etc very similar to SCMI spec.
>
> Where do you expect the documentation to be put?
>

To begin with, we need all these vendor protocols in a directory say
vendors/nxp under drivers/firmware/arm_scmi. It can be a simple text file
under that. We can see later if we need any more formal version elsewhere
but that shouldn't be a blocker for these changes.

> similar as scmi_protocol.h, put in scmi_imx_protcol.h?
> >
> > To start with can you please expand what is BBM or MISC protocol is ?
>
> ok. Sorry for missing your previous comment in v1. Let me write here briefly
> first.
>

Thanks

> The Battery Backup (BB) Domain contains the Battery Backed Security
> Module (BBSM) and the Battery Backed Non-Secure Module (BBNSM).
> BBM protocol is to manage i.MX BBSM and BBNSM. This protocol supports
> #define COMMAND_PROTOCOL_VERSION             0x0U
> #define COMMAND_PROTOCOL_ATTRIBUTES          0x1U
> #define COMMAND_PROTOCOL_MESSAGE_ATTRIBUTES  0x2U
> #define COMMAND_BBM_GPR_SET                  0x3U
> #define COMMAND_BBM_GPR_GET                  0x4U
> #define COMMAND_BBM_RTC_ATTRIBUTES           0x5U
> #define COMMAND_BBM_RTC_TIME_SET             0x6U
> #define COMMAND_BBM_RTC_TIME_GET             0x7U
> #define COMMAND_BBM_RTC_ALARM_SET            0x8U
> #define COMMAND_BBM_BUTTON_GET               0x9U
> #define COMMAND_BBM_RTC_NOTIFY               0xAU
> #define COMMAND_BBM_BUTTON_NOTIFY            0xBU
> #define COMMAND_NEGOTIATE_PROTOCOL_VERSION   0x10U
>

Hopefully description of each of these commands cover what GPR above means
really.

> For now in this patchset for linux, we only use RTC, and BUTTON
> for system wakeup
>
> For MISC protocol, it is for various misc things, such as discover
> build info, get rom passed data, get reset reason, get i.mx
> cfg name, control set(for gpio expander under m33 control and
> etc). The command as below:
> #define COMMAND_PROTOCOL_VERSION             0x0U
> #define COMMAND_PROTOCOL_ATTRIBUTES          0x1U
> #define COMMAND_PROTOCOL_MESSAGE_ATTRIBUTES  0x2U
> #define COMMAND_MISC_CONTROL_SET             0x3U
> #define COMMAND_MISC_CONTROL_GET             0x4U
> #define COMMAND_MISC_CONTROL_ACTION          0x5U
> #define COMMAND_MISC_DISCOVER_BUILD_INFO     0x6U
> #define COMMAND_MISC_ROM_PASSOVER_GET        0x7U
> #define COMMAND_MISC_CONTROL_NOTIFY          0x8U
> #define COMMAND_MISC_REASON_ATTRIBUTES       0x9U
> #define COMMAND_MISC_RESET_REASON            0xAU
> #define COMMAND_MISC_SI_INFO                 0xBU
> #define COMMAND_MISC_CFG_INFO                0xCU
> #define COMMAND_MISC_SYSLOG                  0xDU
> #define COMMAND_NEGOTIATE_PROTOCOL_VERSION   0x10U
>

And same here. Just as an example what BUILD_INFO ? There will be 10s if not
100s of different image in the system. What does this BUILD_INFO provide ?
And why is this important over version or release info ?

These are simple pointers, expect more questions like this if the document
is not self sufficient in explaining such details.

--
Regards,
Sudeep

^ permalink raw reply

* Re: [PATCH] arm64: dts: rockchip: remove startup-delay-us from vcc3v3_pcie2x1l0 on rock-5b
From: Jianfeng Liu @ 2024-04-09 10:32 UTC (permalink / raw)
  To: liujianfeng1994
  Cc: conor+dt, devicetree, heiko, krzysztof.kozlowski+dt,
	linux-arm-kernel, linux-kernel, linux-rockchip, robh, sfr
In-Reply-To: <20240401081302.942742-1-liujianfeng1994@gmail.com>

After removing this property I still meet the wifi card missing issue
today. So this fix doesn't hit the root cause. But this property from
rockchip's sdk kernel will definitely make the situation worse.

Jianfeng

^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: clock: rockchip: add USB480M_PHY mux
From: Krzysztof Kozlowski @ 2024-04-09 10:29 UTC (permalink / raw)
  To: Sascha Hauer, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-rockchip
In-Reply-To: <20240405-clk-rk3568-usb480m-phy-mux-v1-1-6c89de20a6ff@pengutronix.de>

On 05/04/2024 09:38, Sascha Hauer wrote:
> The USB480M clock can source from a MUX that selects the clock to come
> from either of the USB-phy internal 480MHz PLLs. These clocks are
> provided by the USB phy driver. This adds the define for it.
> 
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  include/dt-bindings/clock/rk3568-cru.h | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v3 1/2] ASoC: dt-bindings: imx-audio-spdif: convert to YAML
From: Krzysztof Kozlowski @ 2024-04-09 10:29 UTC (permalink / raw)
  To: Shengjiu Wang, lgirdwood, broonie, robh+dt,
	krzysztof.kozlowski+dt, conor+dt, shengjiu.wang, linux-sound,
	devicetree, linux-kernel, shawnguo, s.hauer, kernel, festevam,
	imx, linux-arm-kernel
In-Reply-To: <1712652644-28887-2-git-send-email-shengjiu.wang@nxp.com>

On 09/04/2024 10:50, Shengjiu Wang wrote:
> Convert the imx-audio-spdif binding to YAML.
> 
> When testing dtbs_check, found below compatible strings
> are not listed in document:
> 
> fsl,imx-sabreauto-spdif
> fsl,imx6sx-sdb-spdif
> 
> So add them in yaml file to pass the test.
> 
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> ---
>  .../bindings/sound/fsl,imx-audio-spdif.yaml   | 67 +++++++++++++++++++
>  .../bindings/sound/imx-audio-spdif.txt        | 36 ----------
>  2 files changed, 67 insertions(+), 36 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml
>  delete mode 100644 Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml
> new file mode 100644
> index 000000000000..fec008ffae43
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/fsl,imx-audio-spdif.yaml
> @@ -0,0 +1,67 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/fsl,imx-audio-spdif.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Freescale i.MX audio complex with S/PDIF transceiver
> +
> +maintainers:
> +  - Shengjiu Wang <shengjiu.wang@nxp.com>
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - items:
> +          - enum:
> +              - fsl,imx-sabreauto-spdif
> +              - fsl,imx6sx-sdb-spdif
> +          - enum:
> +              - fsl,imx-audio-spdif

If there is going to be any new version/resend:
This one should be const, not enum.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>


---

This is an automated instruction, just in case, because many review tags
are being ignored. If you know the process, you can skip it (please do
not feel offended by me posting it here - no bad intentions intended).
If you do not know the process, here is a short explanation:

Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions, under or above your Signed-off-by tag. Tag is "received", when
provided in a message replied to you on the mailing list. Tools like b4
can help here. However, there's no need to repost patches *only* to add
the tags. The upstream maintainer will do that for tags received on the
version they apply.

https://elixir.bootlin.com/linux/v6.5-rc3/source/Documentation/process/submitting-patches.rst#L577

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH 0/9] rtc: convert multiple bindings into dtschema
From: Alexandre Belloni @ 2024-04-09 10:26 UTC (permalink / raw)
  To: Javier Carrasco
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jiaxun Yang,
	Vladimir Zapolskiy, Joel Stanley, Andrew Jeffery, Maxime Coquelin,
	Alexandre Torgue, linux-rtc, devicetree, linux-kernel,
	linux-arm-kernel, linux-aspeed, linux-stm32
In-Reply-To: <20240408-rtc_dtschema-v1-0-c447542fc362@gmail.com>

On 08/04/2024 17:53:00+0200, Javier Carrasco wrote:
> This series converts the following bindings into dtschema, moving them
> to trivial-rtc whenever possible:
> 
> - orion-rtc: trival-rtc, referenced in arm arch.
> - google,goldfish-rtc: trivial-rtc, referenced in mips arch.
> - lpc32xx-rtc: trival-rtc, referenced in arm arch.
> - maxim,ds1742: trivial-rtc, not referenced in arch, cheap conversion.
> - rtc-aspeed: 3 devices to trivial-rtc, all referenced in arm arch.
> - pxa-rtc: add missing properties and convert. Referenced in arm arch.
> - st,spear600-rtc: trivial-rtc, referenced in arm arch.
> - stmp3xxx-rtc: convert, referenced in arm arch.
> - via,vt8500-rtc: trivial-rtc, referenced in arm arch.

Probably all the moves to trivial-rtc can be squashed.

> 
> Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
> ---
> Javier Carrasco (9):
>       dt-bindings: rtc: orion-rtc: move to trivial-rtc
>       dt-bindings: rtc: google,goldfish-rtc: move to trivial-rtc
>       dt-bindings: rtc: lpc32xx-rtc: move to trivial-rtc
>       dt-bindings: rtc: maxim,ds1742: move to trivial-rtc
>       dt-bindings: rtc: rtc-aspeed: move to trivial-rtc
>       dt-bindings: rtc: pxa-rtc: convert to dtschema
>       dt-bindings: rtc: spear-rtc: move to trivial-rtc
>       dt-bindings: rtc: stmp3xxx-rtc: convert to dtschema
>       dt-bindings: rtc: via,vt8500-rtc: move to trivial-rtc
> 
>  .../devicetree/bindings/rtc/fsl,stmp3xxx-rtc.yaml  | 45 ++++++++++++++++++++++
>  .../bindings/rtc/google,goldfish-rtc.txt           | 17 --------
>  .../devicetree/bindings/rtc/lpc32xx-rtc.txt        | 15 --------
>  .../devicetree/bindings/rtc/marvell,pxa-rtc.yaml   | 40 +++++++++++++++++++
>  .../devicetree/bindings/rtc/maxim,ds1742.txt       | 12 ------
>  .../devicetree/bindings/rtc/orion-rtc.txt          | 18 ---------
>  Documentation/devicetree/bindings/rtc/pxa-rtc.txt  | 14 -------
>  .../devicetree/bindings/rtc/rtc-aspeed.txt         | 22 -----------
>  .../devicetree/bindings/rtc/spear-rtc.txt          | 15 --------
>  .../devicetree/bindings/rtc/stmp3xxx-rtc.txt       | 21 ----------
>  .../devicetree/bindings/rtc/trivial-rtc.yaml       | 18 +++++++++
>  .../devicetree/bindings/rtc/via,vt8500-rtc.txt     | 15 --------
>  12 files changed, 103 insertions(+), 149 deletions(-)
> ---
> base-commit: fec50db7033ea478773b159e0e2efb135270e3b7
> change-id: 20240406-rtc_dtschema-302824d1ec20
> 
> Best regards,
> -- 
> Javier Carrasco <javier.carrasco.cruz@gmail.com>
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply

* Re: [PATCH v7 2/7] iommu/arm-smmu-qcom-tbu: Add Qualcomm TBU driver
From: Will Deacon @ 2024-04-09 10:20 UTC (permalink / raw)
  To: Georgi Djakov
  Cc: robin.murphy, joro, iommu, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, devicetree, andersson, konrad.dybcio, robdclark,
	linux-arm-kernel, linux-kernel, linux-arm-msm, quic_cgoldswo,
	quic_sukadev, quic_pdaly, quic_sudaraja, djakov
In-Reply-To: <20240329210638.3647523-3-quic_c_gdjako@quicinc.com>

On Fri, Mar 29, 2024 at 02:06:33PM -0700, Georgi Djakov wrote:
> Operating the TBUs (Translation Buffer Units) from Linux on Qualcomm
> platforms can help with debugging context faults. To help with that,
> the TBUs can run ATOS (Address Translation Operations) to manually
> trigger address translation of IOVA to physical address in hardware
> and provide more details when a context fault happens.
> 
> The driver will control the resources needed by the TBU to allow
> running the debug operations such as ATOS, check for outstanding
> transactions, do snapshot capture etc.
> 
> Signed-off-by: Georgi Djakov <quic_c_gdjako@quicinc.com>
> ---
>  drivers/iommu/Kconfig                         |   9 +
>  drivers/iommu/arm/arm-smmu/Makefile           |   1 +
>  .../iommu/arm/arm-smmu/arm-smmu-qcom-tbu.c    | 372 ++++++++++++++++++
>  drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h    |   2 +
>  drivers/iommu/arm/arm-smmu/arm-smmu.h         |   2 +
>  5 files changed, 386 insertions(+)
>  create mode 100644 drivers/iommu/arm/arm-smmu/arm-smmu-qcom-tbu.c
> 
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 0af39bbbe3a3..b699e88f42c5 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -374,6 +374,15 @@ config ARM_SMMU_QCOM
>  	  When running on a Qualcomm platform that has the custom variant
>  	  of the ARM SMMU, this needs to be built into the SMMU driver.
>  
> +config ARM_SMMU_QCOM_TBU
> +	bool "Qualcomm TBU driver"
> +	depends on ARM_SMMU_QCOM
> +	help
> +	  The SMMUs on Qualcomm platforms may include Translation Buffer
> +	  Units (TBUs) for each master. Enabling support for these units
> +	  allows to operate the TBUs and obtain additional information
> +	  when debugging memory management issues like context faults.
> +
>  config ARM_SMMU_QCOM_DEBUG

Can we just use ARM_SMMU_QCOM_DEBUG for all of this? Having both
ARM_SMMU_QCOM_DEBUG and ARM_SMMU_QCOM_TBU for the same hardware is
pretty confusing, I think.

Will

^ permalink raw reply

* [PATCH v10 6/6] PCI: qcom: Add OPP support to scale performance state of power domain
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

QCOM Resource Power Manager-hardened (RPMh) is a hardware block which
maintains hardware state of a regulator by performing max aggregation of
the requests made by all of the clients.

PCIe controller can operate on different RPMh performance state of power
domain based on the speed of the link. And this performance state varies
from target to target, like some controllers support GEN3 in NOM (Nominal)
voltage corner, while some other supports GEN3 in low SVS (static voltage
scaling).

The SoC can be more power efficient if we scale the performance state
based on the aggregate PCIe link bandwidth.

Add Operating Performance Points (OPP) support to vote for RPMh state based
on the aggregate link bandwidth.

OPP can handle ICC bw voting also, so move ICC bw voting through OPP
framework if OPP entries are present.

As we are moving ICC voting as part of OPP, don't initialize ICC if OPP
is supported.

Before PCIe link is initialized vote for highest OPP in the OPP table,
so that we are voting for maximum voltage corner for the link to come up
in maximum supported speed.

Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 drivers/pci/controller/dwc/pcie-qcom.c | 81 ++++++++++++++++++++++++++++------
 1 file changed, 67 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index e53422171c01..ad4f456619cb 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -22,6 +22,7 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/pci.h>
+#include <linux/pm_opp.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/phy/pcie.h>
@@ -1443,15 +1444,13 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
 	return 0;
 }
 
-static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
+static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
 {
 	struct dw_pcie *pci = pcie->pci;
-	u32 offset, status;
+	u32 offset, status, freq;
+	struct dev_pm_opp *opp;
 	int speed, width;
-	int ret;
-
-	if (!pcie->icc_mem)
-		return;
+	int ret, mbps;
 
 	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
 	status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
@@ -1463,10 +1462,26 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
 	speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
 	width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
 
-	ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
-	if (ret) {
-		dev_err(pci->dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n",
-			ret);
+	if (pcie->icc_mem) {
+		ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
+		if (ret) {
+			dev_err(pci->dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n",
+				ret);
+		}
+	} else {
+		mbps = pcie_link_speed_to_mbps(pcie_link_speed[speed]);
+		if (mbps < 0)
+			return;
+
+		freq = mbps * 1000;
+		opp = dev_pm_opp_find_freq_exact(pci->dev, freq * width, true);
+		if (!IS_ERR(opp)) {
+			ret = dev_pm_opp_set_opp(pci->dev, opp);
+			if (ret)
+				dev_err(pci->dev, "Failed to set opp for freq (%ld): %d\n",
+					dev_pm_opp_get_freq(opp), ret);
+		}
+		dev_pm_opp_put(opp);
 	}
 }
 
@@ -1510,7 +1525,9 @@ static void qcom_pcie_init_debugfs(struct qcom_pcie *pcie)
 static int qcom_pcie_probe(struct platform_device *pdev)
 {
 	const struct qcom_pcie_cfg *pcie_cfg;
+	unsigned long max_freq = INT_MAX;
 	struct device *dev = &pdev->dev;
+	struct dev_pm_opp *opp;
 	struct qcom_pcie *pcie;
 	struct dw_pcie_rp *pp;
 	struct resource *res;
@@ -1578,9 +1595,42 @@ static int qcom_pcie_probe(struct platform_device *pdev)
 		goto err_pm_runtime_put;
 	}
 
-	ret = qcom_pcie_icc_init(pcie);
-	if (ret)
+	/* OPP table is optional */
+	ret = devm_pm_opp_of_add_table(dev);
+	if (ret && ret != -ENODEV) {
+		dev_err_probe(dev, ret, "Failed to add OPP table\n");
 		goto err_pm_runtime_put;
+	}
+
+	/*
+	 * Before PCIe link is initialized vote for highest OPP in the OPP table,
+	 * so that we are voting for maximum voltage corner for the link to come up
+	 * in maximum supported speed. At the end of the probe(), OPP will be
+	 * updated using qcom_pcie_icc_opp_update().
+	 */
+	if (!ret) {
+		opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
+		if (IS_ERR(opp)) {
+			dev_err_probe(pci->dev, PTR_ERR(opp),
+				      "Unable to find max freq OPP\n");
+			goto err_pm_runtime_put;
+		} else {
+			ret = dev_pm_opp_set_opp(dev, opp);
+		}
+
+		dev_pm_opp_put(opp);
+		if (ret) {
+			dev_err_probe(pci->dev, ret,
+				      "Failed to set OPP for freq (%ld): %d\n",
+				      max_freq, ret);
+			goto err_pm_runtime_put;
+		}
+	} else {
+		/* Skip ICC init if OPP is supported as it is handled by OPP */
+		ret = qcom_pcie_icc_init(pcie);
+		if (ret)
+			goto err_pm_runtime_put;
+	}
 
 	ret = pcie->cfg->ops->get_resources(pcie);
 	if (ret)
@@ -1600,7 +1650,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
 		goto err_phy_exit;
 	}
 
-	qcom_pcie_icc_update(pcie);
+	qcom_pcie_icc_opp_update(pcie);
 
 	if (pcie->mhi)
 		qcom_pcie_init_debugfs(pcie);
@@ -1660,6 +1710,9 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
 		ret = icc_disable(pcie->icc_cpu);
 		if (ret)
 			dev_err(dev, "Failed to disable Interconnect path of CPU-PCIe: %d\n", ret);
+
+		if (!pcie->icc_mem)
+			dev_pm_opp_set_opp(pcie->pci->dev, NULL);
 	}
 	return ret;
 }
@@ -1685,7 +1738,7 @@ static int qcom_pcie_resume_noirq(struct device *dev)
 		pcie->suspended = false;
 	}
 
-	qcom_pcie_icc_update(pcie);
+	qcom_pcie_icc_opp_update(pcie);
 
 	return 0;
 }

-- 
2.42.0


^ permalink raw reply related

* [PATCH v10 5/6] PCI: Bring the PCIe speed to MBps logic to new pcie_link_speed_to_mbps()
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

Bring the switch case in pcie_link_speed_mbps() to new function to
the header file so that it can be used in other places like
in controller driver.

Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 drivers/pci/pci.c | 19 +------------------
 drivers/pci/pci.h | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e5f243dd4288..40487b86a75e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5922,24 +5922,7 @@ int pcie_link_speed_mbps(struct pci_dev *pdev)
 	if (err)
 		return err;
 
-	switch (to_pcie_link_speed(lnksta)) {
-	case PCIE_SPEED_2_5GT:
-		return 2500;
-	case PCIE_SPEED_5_0GT:
-		return 5000;
-	case PCIE_SPEED_8_0GT:
-		return 8000;
-	case PCIE_SPEED_16_0GT:
-		return 16000;
-	case PCIE_SPEED_32_0GT:
-		return 32000;
-	case PCIE_SPEED_64_0GT:
-		return 64000;
-	default:
-		break;
-	}
-
-	return -EINVAL;
+	return pcie_link_speed_to_mbps(to_pcie_link_speed(lnksta));
 }
 EXPORT_SYMBOL(pcie_link_speed_mbps);
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 17fed1846847..4de10087523e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -290,6 +290,28 @@ void pci_bus_put(struct pci_bus *bus);
 	 (speed) == PCIE_SPEED_2_5GT  ?  2500*8/10 : \
 	 0)
 
+static inline int pcie_link_speed_to_mbps(enum pci_bus_speed speed)
+{
+	switch (speed) {
+	case PCIE_SPEED_2_5GT:
+		return 2500;
+	case PCIE_SPEED_5_0GT:
+		return 5000;
+	case PCIE_SPEED_8_0GT:
+		return 8000;
+	case PCIE_SPEED_16_0GT:
+		return 16000;
+	case PCIE_SPEED_32_0GT:
+		return 32000;
+	case PCIE_SPEED_64_0GT:
+		return 64000;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
 const char *pci_speed_string(enum pci_bus_speed speed);
 enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev);
 enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev);

-- 
2.42.0


^ permalink raw reply related

* [PATCH v10 4/6] arm64: dts: qcom: sm8450: Add OPP table support to PCIe
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

PCIe needs to choose the appropriate performance state of RPMh power
domain and interconnect bandwidth based up on the PCIe data rate.

Add the OPP table support to specify RPMh performance states and
interconnect peak bandwidth.

Different link configurations may share the same aggregate bandwidth,
e.g., a 2.5 GT/s x2 link and a 5.0 GT/s x1 link have the same bandwidth
and share the same OPP entry.

Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 arch/arm64/boot/dts/qcom/sm8450.dtsi | 77 ++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index 615296e13c43..9dfe16012726 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -1855,7 +1855,35 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
 			pinctrl-names = "default";
 			pinctrl-0 = <&pcie0_default_state>;
 
+			operating-points-v2 = <&pcie0_opp_table>;
+
 			status = "disabled";
+
+			pcie0_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				/* GEN 1 x1 */
+				opp-2500000 {
+					opp-hz = /bits/ 64 <2500000>;
+					required-opps = <&rpmhpd_opp_low_svs>;
+					opp-peak-kBps = <250000 1>;
+				};
+
+				/* GEN 2 x1 */
+				opp-5000000 {
+					opp-hz = /bits/ 64 <5000000>;
+					required-opps = <&rpmhpd_opp_low_svs>;
+					opp-peak-kBps = <500000 1>;
+				};
+
+				/* GEN 3 x1 */
+				opp-8000000 {
+					opp-hz = /bits/ 64 <8000000>;
+					required-opps = <&rpmhpd_opp_nom>;
+					opp-peak-kBps = <984500 1>;
+				};
+			};
+
 		};
 
 		pcie0_phy: phy@1c06000 {
@@ -1982,7 +2010,56 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
 			pinctrl-names = "default";
 			pinctrl-0 = <&pcie1_default_state>;
 
+			operating-points-v2 = <&pcie1_opp_table>;
+
 			status = "disabled";
+
+			pcie1_opp_table: opp-table {
+				compatible = "operating-points-v2";
+
+				/* GEN 1 x1 */
+				opp-2500000 {
+					opp-hz = /bits/ 64 <2500000>;
+					required-opps = <&rpmhpd_opp_low_svs>;
+					opp-peak-kBps = <250000 1>;
+				};
+
+				/* GEN 1 x2 GEN 2 x1 */
+				opp-5000000 {
+					opp-hz = /bits/ 64 <5000000>;
+					required-opps = <&rpmhpd_opp_low_svs>;
+					opp-peak-kBps = <500000 1>;
+				};
+
+				/* GEN 2 x2 */
+				opp-10000000 {
+					opp-hz = /bits/ 64 <10000000>;
+					required-opps = <&rpmhpd_opp_low_svs>;
+					opp-peak-kBps = <1000000 1>;
+				};
+
+				/* GEN 3 x1 */
+				opp-8000000 {
+					opp-hz = /bits/ 64 <8000000>;
+					required-opps = <&rpmhpd_opp_nom>;
+					opp-peak-kBps = <984500 1>;
+				};
+
+				/* GEN 3 x2 GEN 4 x1 */
+				opp-16000000 {
+					opp-hz = /bits/ 64 <16000000>;
+					required-opps = <&rpmhpd_opp_nom>;
+					opp-peak-kBps = <1969000 1>;
+				};
+
+				/* GEN 4 x2 */
+				opp-32000000 {
+					opp-hz = /bits/ 64 <32000000>;
+					required-opps = <&rpmhpd_opp_nom>;
+					opp-peak-kBps = <3938000 1>;
+				};
+			};
+
 		};
 
 		pcie1_phy: phy@1c0e000 {

-- 
2.42.0


^ permalink raw reply related

* [PATCH v10 3/6] dt-bindings: pci: qcom: Add OPP table
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski, Krzysztof Kozlowski
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

PCIe needs to choose the appropriate performance state of RPMh power
domain based on the PCIe gen speed.

Adding the Operating Performance Points table allows to adjust power
domain performance state and ICC peak bw, depending on the PCIe data
rate and link width.

Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
index 1496d6993ab4..d8c0afaa4b19 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
@@ -69,6 +69,10 @@ properties:
       - const: msi6
       - const: msi7
 
+  operating-points-v2: true
+  opp-table:
+    type: object
+
   resets:
     maxItems: 1
 

-- 
2.42.0


^ permalink raw reply related

* [PATCH v2 18/18] arm64: dts: mediatek: add audio support for mt8365-evk
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add the sound node which is linked to the MT8365 SoC AFE and
the MT6357 audio codec.

Update the file header.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt8365-evk.dts | 98 +++++++++++++++++++++++++++--
 1 file changed, 94 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8365-evk.dts b/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
index 50cbaefa1a99..bf15d3c7a965 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8365-evk.dts
@@ -1,9 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2021-2022 BayLibre, SAS.
- * Authors:
- * Fabien Parent <fparent@baylibre.com>
- * Bernhard Rosenkränzer <bero@baylibre.com>
+ * Copyright (c) 2024 BayLibre, SAS.
+ * Authors: Fabien Parent <fparent@baylibre.com>
+ *	    Bernhard Rosenkränzer <bero@baylibre.com>
+ *	    Alexandre Mergnat <amergnat@baylibre.com>
  */
 
 /dts-v1/;
@@ -86,6 +86,29 @@ optee_reserved: optee@43200000 {
 			reg = <0 0x43200000 0 0x00c00000>;
 		};
 	};
+
+	sound: sound {
+		compatible = "mediatek,mt8365-mt6357";
+		pinctrl-names = "default",
+				"dmic",
+				"miso_off",
+				"miso_on",
+				"mosi_off",
+				"mosi_on";
+		pinctrl-0 = <&aud_default_pins>;
+		pinctrl-1 = <&aud_dmic_pins>;
+		pinctrl-2 = <&aud_miso_off_pins>;
+		pinctrl-3 = <&aud_miso_on_pins>;
+		pinctrl-4 = <&aud_mosi_off_pins>;
+		pinctrl-5 = <&aud_mosi_on_pins>;
+		mediatek,platform = <&afe>;
+		status = "okay";
+	};
+};
+
+&afe {
+	mediatek,dmic-mode = <1>;
+	status = "okay";
 };
 
 &cpu0 {
@@ -174,6 +197,12 @@ &mmc1 {
 	status = "okay";
 };
 
+&mt6357_codec {
+	vaud28-supply = <&mt6357_vaud28_reg>;
+	mediatek,micbias0-microvolt = <1900000>;
+	mediatek,micbias1-microvolt = <1700000>;
+};
+
 &mt6357_pmic {
 	interrupts-extended = <&pio 145 IRQ_TYPE_LEVEL_HIGH>;
 	interrupt-controller;
@@ -181,6 +210,67 @@ &mt6357_pmic {
 };
 
 &pio {
+	aud_default_pins: audiodefault-pins {
+		pins {
+		pinmux = <MT8365_PIN_72_CMDAT4__FUNC_I2S3_BCK>,
+			 <MT8365_PIN_73_CMDAT5__FUNC_I2S3_LRCK>,
+			 <MT8365_PIN_74_CMDAT6__FUNC_I2S3_MCK>,
+			 <MT8365_PIN_75_CMDAT7__FUNC_I2S3_DO>;
+		};
+	};
+
+	aud_dmic_pins: audiodmic-pins {
+		pins {
+		pinmux = <MT8365_PIN_117_DMIC0_CLK__FUNC_DMIC0_CLK>,
+			 <MT8365_PIN_118_DMIC0_DAT0__FUNC_DMIC0_DAT0>,
+			 <MT8365_PIN_119_DMIC0_DAT1__FUNC_DMIC0_DAT1>;
+		};
+	};
+
+	aud_miso_off_pins: misooff-pins {
+		pins {
+		pinmux = <MT8365_PIN_53_AUD_CLK_MISO__FUNC_GPIO53>,
+			 <MT8365_PIN_54_AUD_SYNC_MISO__FUNC_GPIO54>,
+			 <MT8365_PIN_55_AUD_DAT_MISO0__FUNC_GPIO55>,
+			 <MT8365_PIN_56_AUD_DAT_MISO1__FUNC_GPIO56>;
+		input-enable;
+		bias-pull-down;
+		drive-strength = <MTK_DRIVE_2mA>;
+		};
+	};
+
+	aud_miso_on_pins: misoon-pins {
+		pins {
+		pinmux = <MT8365_PIN_53_AUD_CLK_MISO__FUNC_AUD_CLK_MISO>,
+			 <MT8365_PIN_54_AUD_SYNC_MISO__FUNC_AUD_SYNC_MISO>,
+			 <MT8365_PIN_55_AUD_DAT_MISO0__FUNC_AUD_DAT_MISO0>,
+			 <MT8365_PIN_56_AUD_DAT_MISO1__FUNC_AUD_DAT_MISO1>;
+		drive-strength = <MTK_DRIVE_6mA>;
+		};
+	};
+
+	aud_mosi_off_pins: mosioff-pins {
+		pins {
+		pinmux = <MT8365_PIN_49_AUD_CLK_MOSI__FUNC_GPIO49>,
+			 <MT8365_PIN_50_AUD_SYNC_MOSI__FUNC_GPIO50>,
+			 <MT8365_PIN_51_AUD_DAT_MOSI0__FUNC_GPIO51>,
+			 <MT8365_PIN_52_AUD_DAT_MOSI1__FUNC_GPIO52>;
+		input-enable;
+		bias-pull-down;
+		drive-strength = <MTK_DRIVE_2mA>;
+		};
+	};
+
+	aud_mosi_on_pins: mosion-pins {
+		pins {
+		pinmux = <MT8365_PIN_49_AUD_CLK_MOSI__FUNC_AUD_CLK_MOSI>,
+			 <MT8365_PIN_50_AUD_SYNC_MOSI__FUNC_AUD_SYNC_MOSI>,
+			 <MT8365_PIN_51_AUD_DAT_MOSI0__FUNC_AUD_DAT_MOSI0>,
+			 <MT8365_PIN_52_AUD_DAT_MOSI1__FUNC_AUD_DAT_MOSI1>;
+		drive-strength = <MTK_DRIVE_6mA>;
+		};
+	};
+
 	ethernet_pins: ethernet-pins {
 		phy_reset_pins {
 			pinmux = <MT8365_PIN_133_TDM_TX_DATA1__FUNC_GPIO133>;

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 17/18] arm64: dts: mediatek: add afe support for mt8365 SoC
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add audio front end support of MT8365 SoC.
Update the file header.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt8365.dtsi | 46 +++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
index 24581f7410aa..0bb6f6388bb8 100644
--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi
@@ -1,10 +1,12 @@
 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * (C) 2018 MediaTek Inc.
- * Copyright (C) 2022 BayLibre SAS
- * Fabien Parent <fparent@baylibre.com>
- * Bernhard Rosenkränzer <bero@baylibre.com>
+ * Copyright (C) 2024 BayLibre SAS
+ * Authors: Fabien Parent <fparent@baylibre.com>
+ *	    Bernhard Rosenkränzer <bero@baylibre.com>
+ *	    Alexandre Mergnat <amergnat@baylibre.com>
  */
+
 #include <dt-bindings/clock/mediatek,mt8365-clk.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
@@ -813,6 +815,44 @@ apu: syscon@19020000 {
 			reg = <0 0x19020000 0 0x1000>;
 			#clock-cells = <1>;
 		};
+
+		afe: audio-controller@11220000 {
+			compatible = "mediatek,mt8365-afe-pcm";
+			reg = <0 0x11220000 0 0x1000>;
+			#sound-dai-cells = <0>;
+			clocks = <&clk26m>,
+				 <&topckgen CLK_TOP_AUDIO_SEL>,
+				 <&topckgen CLK_TOP_AUD_I2S0_M>,
+				 <&topckgen CLK_TOP_AUD_I2S1_M>,
+				 <&topckgen CLK_TOP_AUD_I2S2_M>,
+				 <&topckgen CLK_TOP_AUD_I2S3_M>,
+				 <&topckgen CLK_TOP_AUD_ENGEN1_SEL>,
+				 <&topckgen CLK_TOP_AUD_ENGEN2_SEL>,
+				 <&topckgen CLK_TOP_AUD_1_SEL>,
+				 <&topckgen CLK_TOP_AUD_2_SEL>,
+				 <&topckgen CLK_TOP_APLL_I2S0_SEL>,
+				 <&topckgen CLK_TOP_APLL_I2S1_SEL>,
+				 <&topckgen CLK_TOP_APLL_I2S2_SEL>,
+				 <&topckgen CLK_TOP_APLL_I2S3_SEL>;
+			clock-names = "top_clk26m_clk",
+				      "top_audio_sel",
+				      "audio_i2s0_m",
+				      "audio_i2s1_m",
+				      "audio_i2s2_m",
+				      "audio_i2s3_m",
+				      "engen1",
+				      "engen2",
+				      "aud1",
+				      "aud2",
+				      "i2s0_m_sel",
+				      "i2s1_m_sel",
+				      "i2s2_m_sel",
+				      "i2s3_m_sel";
+			interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
+			power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>;
+			mediatek,topckgen = <&topckgen>;
+			status = "disabled";
+		};
 	};
 
 	timer {

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 16/18] arm64: dts: mediatek: add mt6357 audio codec support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add audio codec support of MT6357 PMIC.
Update the file header.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt6357.dtsi | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt6357.dtsi b/arch/arm64/boot/dts/mediatek/mt6357.dtsi
index 3330a03c2f74..ade410851524 100644
--- a/arch/arm64/boot/dts/mediatek/mt6357.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6357.dtsi
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
 /*
  * Copyright (c) 2020 MediaTek Inc.
- * Copyright (c) 2023 BayLibre Inc.
+ * Copyright (c) 2024 BayLibre Inc.
  */
 
 #include <dt-bindings/input/input.h>
@@ -10,6 +10,9 @@ &pwrap {
 	mt6357_pmic: pmic {
 		compatible = "mediatek,mt6357";
 
+		mt6357_codec: codec {
+		};
+
 		regulators {
 			mt6357_vproc_reg: buck-vproc {
 				regulator-name = "vproc";

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 15/18] arm64: defconfig: enable mt8365 sound
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Enable the MediaTek MT8365-EVK sound support.

The audio feature is handled by the MT8365 SoC and
the MT6357 PMIC codec audio.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 arch/arm64/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 2c30d617e180..40e88cdafa3a 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -939,6 +939,8 @@ CONFIG_SND_SOC_MT8192=m
 CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682=m
 CONFIG_SND_SOC_MT8195=m
 CONFIG_SND_SOC_MT8195_MT6359=m
+CONFIG_SND_SOC_MT8365=m
+CONFIG_SND_SOC_MT8365_MT6357=m
 CONFIG_SND_MESON_AXG_SOUND_CARD=m
 CONFIG_SND_MESON_GX_SOUND_CARD=m
 CONFIG_SND_SOC_QCOM=m

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 14/18] ASoC: mediatek: Add MT8365 support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

- Add specific config to enable:
  - MT8365 sound support
  - MT6357 audio codec support
- Add the mt8365 directory and all drivers under it.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/Kconfig         | 20 ++++++++++++++++++++
 sound/soc/mediatek/Makefile        |  1 +
 sound/soc/mediatek/mt8365/Makefile | 15 +++++++++++++++
 3 files changed, 36 insertions(+)

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 5a8476e1ecca..c1c86ecc0601 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -298,3 +298,23 @@ config SND_SOC_MT8195_MT6359
 	  boards with the MT6359 and other I2S audio codecs.
 	  Select Y if you have such device.
 	  If unsure select "N".
+
+config SND_SOC_MT8365
+	tristate "ASoC support for Mediatek MT8365 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC platform driver support for Mediatek MT8365 chip
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT8365_MT6357
+	tristate "ASoC Audio driver for MT8365 with MT6357 codec"
+	depends on SND_SOC_MT8365 && MTK_PMIC_WRAP
+	select SND_SOC_MT6357
+	help
+	  This adds support for ASoC machine driver for Mediatek MT8365
+	  boards with the MT6357 codec.
+	  Select Y if you have such device.
+	  If unsure select "N".
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 3938e7f75c2e..4b55434f2168 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
 obj-$(CONFIG_SND_SOC_MT8188) += mt8188/
 obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
 obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
+obj-$(CONFIG_SND_SOC_MT8365) += mt8365/
diff --git a/sound/soc/mediatek/mt8365/Makefile b/sound/soc/mediatek/mt8365/Makefile
new file mode 100644
index 000000000000..52ba45a8498a
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# MTK Platform driver
+snd-soc-mt8365-pcm-objs := \
+	mt8365-afe-clk.o \
+	mt8365-afe-pcm.o \
+	mt8365-dai-adda.o \
+	mt8365-dai-dmic.o \
+	mt8365-dai-i2s.o \
+	mt8365-dai-pcm.o
+
+obj-$(CONFIG_SND_SOC_MT8365) += snd-soc-mt8365-pcm.o
+
+# Machine driver
+obj-$(CONFIG_SND_SOC_MT8365_MT6357) += mt8365-mt6357.o

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 13/18] ASoC: codecs: add MT6357 support
From: amergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat, Nicolas Belin
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

From: Nicolas Belin <nbelin@baylibre.com>

Add the support of MT6357 PMIC audio codec.

Signed-off-by: Nicolas Belin <nbelin@baylibre.com>
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/codecs/Kconfig  |    7 +
 sound/soc/codecs/Makefile |    2 +
 sound/soc/codecs/mt6357.c | 1898 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/mt6357.h |  662 ++++++++++++++++
 4 files changed, 2569 insertions(+)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 1752814fffdd..7742445f7b7b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -154,6 +154,7 @@ config SND_SOC_ALL_CODECS
 	imply SND_SOC_MC13783
 	imply SND_SOC_ML26124
 	imply SND_SOC_MT6351
+	imply SND_SOC_MT6357
 	imply SND_SOC_MT6358
 	imply SND_SOC_MT6359
 	imply SND_SOC_MT6660
@@ -2421,6 +2422,12 @@ config SND_SOC_ML26124
 config SND_SOC_MT6351
 	tristate "MediaTek MT6351 Codec"
 
+config SND_SOC_MT6357
+	tristate "MediaTek MT6357 Codec"
+	help
+	  Enable support for the platform which uses MT6357 as
+	  external codec device.
+
 config SND_SOC_MT6358
 	tristate "MediaTek MT6358 Codec"
 	help
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 9ba24fb870b1..d43a6065706c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -172,6 +172,7 @@ snd-soc-ml26124-objs := ml26124.o
 snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
 snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
 snd-soc-mt6351-objs := mt6351.o
+snd-soc-mt6357-objs := mt6357.o
 snd-soc-mt6358-objs := mt6358.o
 snd-soc-mt6359-objs := mt6359.o
 snd-soc-mt6359-accdet-objs := mt6359-accdet.o
@@ -563,6 +564,7 @@ obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
 obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
 obj-$(CONFIG_SND_SOC_MT6351)	+= snd-soc-mt6351.o
+obj-$(CONFIG_SND_SOC_MT6357)	+= snd-soc-mt6357.o
 obj-$(CONFIG_SND_SOC_MT6358)	+= snd-soc-mt6358.o
 obj-$(CONFIG_SND_SOC_MT6359)	+= snd-soc-mt6359.o
 obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o
diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
new file mode 100644
index 000000000000..b3c3d9d73aa3
--- /dev/null
+++ b/sound/soc/codecs/mt6357.c
@@ -0,0 +1,1898 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MT6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <nbelin@baylibre.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/regulator/consumer.h>
+
+#include "mt6357.h"
+
+static void set_playback_gpio(struct mt6357_priv *priv, bool enable)
+{
+	regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, MT6357_GPIO_MODE2_CLEAR_ALL);
+	if (enable) {
+		/* set gpio mosi mode */
+		regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET,
+			     MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI |
+			     MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 |
+			     MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 |
+			     MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI);
+	} else {
+		/* pad_aud_*_mosi are GPIO mode after clear and set them to dir input
+		 * reason:
+		 * pad_aud_dat_mosi*, because the pin is used as boot strap
+		 */
+		regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0,
+				   MT6357_GPIO8_DIR_MASK |
+				   MT6357_GPIO9_DIR_MASK |
+				   MT6357_GPIO10_DIR_MASK |
+				   MT6357_GPIO11_DIR_MASK,
+				   MT6357_GPIO8_DIR_INPUT |
+				   MT6357_GPIO9_DIR_INPUT |
+				   MT6357_GPIO10_DIR_INPUT |
+				   MT6357_GPIO11_DIR_INPUT);
+	}
+}
+
+static void set_capture_gpio(struct mt6357_priv *priv, bool enable)
+{
+	regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, MT6357_GPIO_MODE3_CLEAR_ALL);
+	if (enable) {
+		/* set gpio miso mode */
+		regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET,
+			     MT6357_GPIO12_MODE_SET_AUD_CLK_MISO |
+			     MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 |
+			     MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 |
+			     MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO);
+	} else {
+		/* pad_aud_*_mosi are GPIO mode after clear and set them to dir input
+		 * reason:
+		 * pad_aud_clk_miso, because when playback only the miso_clk
+		 * will also have 26m, so will have power leak
+		 * pad_aud_dat_miso*, because the pin is used as boot strap
+		 */
+		regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0,
+				   MT6357_GPIO12_DIR_MASK |
+				   MT6357_GPIO13_DIR_MASK |
+				   MT6357_GPIO14_DIR_MASK |
+				   MT6357_GPIO15_DIR_MASK,
+				   MT6357_GPIO12_DIR_INPUT |
+				   MT6357_GPIO13_DIR_INPUT |
+				   MT6357_GPIO14_DIR_INPUT |
+				   MT6357_GPIO15_DIR_INPUT);
+	}
+}
+
+static void hp_main_output_ramp(struct mt6357_priv *priv, bool up)
+{
+	int i, stage;
+
+	/* Enable/Reduce HPL/R main output stage step by step */
+	for (i = 0; i <= MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX; i++) {
+		stage = up ? i : MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX - i;
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK,
+				   stage << MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT);
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_STG_CTRL_VAUDP15_MASK,
+				   stage << MT6357_HPROUT_STG_CTRL_VAUDP15_SFT);
+		usleep_range(600, 700);
+	}
+}
+
+static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up)
+{
+	int i, stage;
+
+	/* Reduce HP aux feedback loop gain step by step */
+	for (i = 0; i <= MT6357_HP_AUX_LOOP_GAIN_MAX; i++) {
+		stage = up ? i : MT6357_HP_AUX_LOOP_GAIN_MAX - i;
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HP_AUX_LOOP_GAIN_MASK,
+				   stage << MT6357_HP_AUX_LOOP_GAIN_SFT);
+		usleep_range(600, 700);
+	}
+}
+
+static void hp_pull_down(struct mt6357_priv *priv, bool enable)
+{
+	if (enable)
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+				   MT6357_HPP_SHORT_2VCM_VAUDP15_MASK,
+				   MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE);
+	else
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+				   MT6357_HPP_SHORT_2VCM_VAUDP15_MASK,
+				   MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE);
+}
+
+static bool is_valid_hp_pga_idx(int reg_idx)
+{
+	return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB;
+}
+
+static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto,
+			int rfrom, int rto, unsigned int reg_addr)
+{
+	int lcount, rcount, sleep = 0;
+
+	if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto))
+		pr_debug("%s(), invalid left volume index, from %d, to %d\n",
+			 __func__, lfrom, lto);
+
+	if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto))
+		pr_debug("%s(), invalid right volume index, from %d, to %d\n",
+			 __func__, rfrom, rto);
+
+	if (lto > lfrom)
+		lcount = 1;
+	else
+		lcount = -1;
+
+	if (rto > rfrom)
+		rcount = 1;
+	else
+		rcount = -1;
+
+	while ((lto != lfrom) || (rto != rfrom)) {
+		if (lto != lfrom) {
+			lfrom += lcount;
+			if (is_valid_hp_pga_idx(lfrom)) {
+				regmap_update_bits(priv->regmap, reg_addr,
+						   MT6357_DL_GAIN_REG_LEFT_MASK,
+						   lfrom << MT6357_DL_GAIN_REG_LEFT_SHIFT);
+				sleep = 1;
+			}
+		}
+		if (rto != rfrom) {
+			rfrom += rcount;
+			if (is_valid_hp_pga_idx(rfrom)) {
+				regmap_update_bits(priv->regmap, reg_addr,
+						   MT6357_DL_GAIN_REG_RIGHT_MASK,
+						   rfrom << MT6357_DL_GAIN_REG_RIGHT_SHIFT);
+				sleep = 1;
+			}
+		}
+		if (sleep)
+			usleep_range(200, 300);
+	}
+}
+
+static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+	volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1);
+}
+
+static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto)
+{
+	volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2);
+}
+
+static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to)
+{
+	volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3);
+}
+
+/* Volume and channel swap controls */
+static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_degain_tlv, -1200, 1200, 0);
+
+static const struct snd_kcontrol_new mt6357_controls[] = {
+	/* dl pga gain */
+	SOC_DOUBLE_TLV("Headphone Volume",
+		       MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_SFT,
+		       MT6357_AUD_HPR_GAIN_SFT, MT6357_AUD_HP_GAIN_MAX,
+		       1, playback_tlv),
+	SOC_SINGLE_TLV("Headphone Vin Volume",
+		       MT6357_AUDDEC_ANA_CON7, MT6357_HP_IVBUF_DEGAIN_SFT,
+		       MT6357_HP_IVBUF_DEGAIN_MAX, 1, hp_degain_tlv),
+	SOC_DOUBLE_TLV("Lineout Volume",
+		       MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_SFT,
+		       MT6357_AUD_LOR_GAIN_SFT, MT6357_AUD_LO_GAIN_MAX,
+		       1, playback_tlv),
+	SOC_SINGLE_TLV("Handset Volume",
+		       MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_SFT,
+		       MT6357_AUD_HS_GAIN_MAX, 1, playback_tlv),
+	/* ul pga gain */
+	SOC_DOUBLE_R_TLV("Mic Volume",
+			 MT6357_AUDENC_ANA_CON0, MT6357_AUDENC_ANA_CON1,
+			 MT6357_AUDPREAMPLGAIN_SFT, MT6357_AUDPREAMPLGAIN_MAX,
+			 0, capture_tlv),
+};
+
+/* Uplink controls */
+
+enum {
+	MIC_TYPE_MUX_IDLE,
+	MIC_TYPE_MUX_ACC,
+	MIC_TYPE_MUX_DMIC,
+	MIC_TYPE_MUX_DCC,
+	MIC_TYPE_MUX_DCC_ECM_DIFF,
+	MIC_TYPE_MUX_DCC_ECM_SINGLE,
+	MIC_TYPE_MUX_LPBK,
+	MIC_TYPE_MUX_SGEN,
+};
+
+#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \
+			(type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \
+			(type) == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+
+static const char * const mic_type_mux_map[] = {
+	"Idle",
+	"ACC",
+	"DMIC",
+	"DCC",
+	"DCC_ECM_DIFF",
+	"DCC_ECM_SINGLE",
+	"Loopback",
+	"Sine Generator",
+};
+
+static SOC_ENUM_SINGLE_DECL(mic_type_mux_map_enum, SND_SOC_NOPM,
+			    0, mic_type_mux_map);
+
+static const struct snd_kcontrol_new mic_type_mux_control =
+	SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum);
+
+static const char * const pga_mux_map[] = {
+	"None", "AIN0", "AIN1", "AIN2"
+};
+
+static SOC_ENUM_SINGLE_DECL(pga_left_mux_map_enum,
+			    MT6357_AUDENC_ANA_CON0,
+			    MT6357_AUDPREAMPLINPUTSEL_SFT,
+			    pga_mux_map);
+
+static const struct snd_kcontrol_new pga_left_mux_control =
+	SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(pga_right_mux_map_enum,
+			    MT6357_AUDENC_ANA_CON1,
+			    MT6357_AUDPREAMPRINPUTSEL_SFT,
+			    pga_mux_map);
+
+static const struct snd_kcontrol_new pga_right_mux_control =
+	SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum);
+
+/* Downlink controls */
+static const char * const hslo_mux_map[] = {
+	"Open", "DACR", "Playback", "Test mode"
+};
+
+static SOC_ENUM_SINGLE_DECL(lo_mux_map_enum,
+			    MT6357_AUDDEC_ANA_CON4,
+			    MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT,
+			    hslo_mux_map);
+
+static const struct snd_kcontrol_new lo_mux_control =
+	SOC_DAPM_ENUM("Line out source", lo_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(hs_mux_map_enum,
+			    MT6357_AUDDEC_ANA_CON3,
+			    MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT,
+			    hslo_mux_map);
+
+static const struct snd_kcontrol_new hs_mux_control =
+	SOC_DAPM_ENUM("Handset source", hs_mux_map_enum);
+
+static const char * const hplr_mux_map[] = {
+	"Open", "Line Out", "DAC", "Handset"
+};
+
+static SOC_ENUM_SINGLE_DECL(hpr_mux_map_enum,
+			    MT6357_AUDDEC_ANA_CON0,
+			    MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT,
+			    hplr_mux_map);
+
+static const struct snd_kcontrol_new hpr_mux_control =
+	SOC_DAPM_ENUM("Headphone Right source", hpr_mux_map_enum);
+
+static SOC_ENUM_SINGLE_DECL(hpl_mux_map_enum,
+			    MT6357_AUDDEC_ANA_CON0,
+			    MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT,
+			    hplr_mux_map);
+
+static const struct snd_kcontrol_new hpl_mux_control =
+	SOC_DAPM_ENUM("Headphone Left source", hpl_mux_map_enum);
+
+static const char * const dac_mux_map[] = {
+	"Normal Path", "Sine Generator"
+};
+
+static SOC_ENUM_SINGLE_DECL(dac_mux_map_enum,
+			    MT6357_AFE_TOP_CON0,
+			    MT6357_DL_SINE_ON_SFT,
+			    dac_mux_map);
+
+static const struct snd_kcontrol_new dac_mux_control =
+	SOC_DAPM_ENUM("DAC Select", dac_mux_map_enum);
+
+static int mt6357_set_dmic(struct mt6357_priv *priv, bool enable)
+{
+	if (enable) {
+		/* DMIC enable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+				   MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK,
+				   MT6357_AUDDIGMICBIAS_DEFAULT_VALUE | MT6357_AUDDIGMICEN_ENABLE);
+		/* enable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+		/* UL dmic setting: dual mode */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+				   MT6357_C_TWO_DIGITAL_MIC_CTL_MASK,
+				   MT6357_C_TWO_DIGITAL_MIC_ENABLE);
+		/* UL turn on SDM 3 level mode */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SDM_3_LEVEL_CTL_MASK,
+				   MT6357_UL_SDM_3_LEVEL_SELECT);
+		/* UL turn on */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_ENABLE);
+		/* Wait to avoid any pop noises */
+		msleep(100);
+	} else {
+		/* UL turn off */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_DISABLE);
+		/* UL turn on SDM 3 level mode */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SDM_3_LEVEL_CTL_MASK,
+				   MT6357_UL_SDM_3_LEVEL_DESELECT);
+		/* disable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+		/* UL dmic setting: dual mode */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H,
+				   MT6357_C_TWO_DIGITAL_MIC_CTL_MASK,
+				   MT6357_C_TWO_DIGITAL_MIC_DISABLE);
+		/* DMIC disable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7,
+				   MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK,
+				   MT6357_AUDDIGMICBIAS_OFF | MT6357_AUDDIGMICEN_DISABLE);
+	}
+	return 0;
+}
+
+static int mt6357_set_amic(struct mt6357_priv *priv, bool enable, unsigned int mic_type)
+{
+	if (enable) {
+		if (IS_DCC_BASE(mic_type)) {
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_RUN_VALUE);
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_OUTPUT);
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_ON);
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG1,
+					   MT6357_DCCLK_RESYNC_BYPASS_MASK,
+					   MT6357_DCCLK_RESYNC_BYPASS);
+
+			/* mic bias 0: set the correct DC couple*/
+			switch (mic_type) {
+			case MIC_TYPE_MUX_DCC_ECM_DIFF:
+				regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+						   MT6357_AUD_MICBIAS0_DC_MASK,
+						   MT6357_AUD_MICBIAS0_DC_ENABLE_ALL);
+				break;
+			case MIC_TYPE_MUX_DCC_ECM_SINGLE:
+				regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+						   MT6357_AUD_MICBIAS0_DC_MASK,
+						   MT6357_AUD_MICBIAS0_DC_ENABLE_P1);
+				break;
+			default:
+				regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+						   MT6357_AUD_MICBIAS0_DC_MASK,
+						   MT6357_AUD_MICBIAS0_DC_DISABLE_ALL);
+				break;
+			}
+
+			/* mic bias 1: set the correct DC couple */
+			if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE)
+				regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+						   MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK,
+						   MT6357_AUD_MICBIAS1_DCSW1P_ENABLE);
+
+			/* Audio L/R preamplifier DCC precharge */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+					   MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+					   MT6357_AUDPREAMPLDCPRECHARGE_ENABLE);
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+					   MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+					   MT6357_AUDPREAMPRDCPRECHARGE_ENABLE);
+			/* L preamplifier DCCEN */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+					   MT6357_AUDPREAMPLDCCEN_MASK,
+					   MT6357_AUDPREAMPLDCCEN_DC);
+			/* R preamplifier DCCEN */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+					   MT6357_AUDPREAMPRDCCEN_MASK,
+					   MT6357_AUDPREAMPRDCCEN_DC);
+		} else {
+			/* Audio L preamplifier DCC precharge disable */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+					   MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+					   MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+			/* L preamplifier ACC */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+					   MT6357_AUDPREAMPLDCCEN_MASK,
+					   MT6357_AUDPREAMPLDCCEN_AC);
+			/* Audio R preamplifier DCC precharge disable */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+					   MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+					   MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+			/* R preamplifier ACC */
+			regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+					   MT6357_AUDPREAMPRDCCEN_MASK,
+					   MT6357_AUDPREAMPRDCCEN_AC);
+		}
+	} else {
+		/* disable any Mic Bias 0 DC couple */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+				   MT6357_AUD_MICBIAS0_DC_MASK,
+				   MT6357_AUD_MICBIAS0_DC_DISABLE_ALL);
+		/* disable any Mic Bias 1 DC couple */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+				   MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK,
+				   MT6357_AUD_MICBIAS1_DCSW1P_DISABLE);
+		if (IS_DCC_BASE(mic_type)) {
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_OFF);
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_PDN);
+			regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0,
+					   MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_STOP_VALUE);
+		}
+	}
+
+	return 0;
+}
+
+static int mt6357_set_loopback(struct mt6357_priv *priv, bool enable)
+{
+	if (enable) {
+		/* enable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+		/* enable aud_pad lpk TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_LPBK_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE);
+		/* Set UL Part: enable new lpbk 2 */
+		regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+				   MT6357_ADDA_MTKAIF_LPBK_CTL_MASK,
+				   MT6357_ADDA_MTKAIF_LPBK_ENABLE);
+		/* UL turn on */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_ENABLE);
+	} else {
+		/* UL turn off */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_DISABLE);
+		/* disable new lpbk 2 */
+		regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0,
+				   MT6357_ADDA_MTKAIF_LPBK_CTL_MASK,
+				   MT6357_ADDA_MTKAIF_LPBK_DISABLE);
+		/* disable aud_pad lpbk TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_LPBK_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE);
+		/* disable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+	}
+
+	return 0;
+}
+
+static int mt6357_set_ul_sine_gen(struct mt6357_priv *priv, bool enable)
+{
+	if (enable) {
+		/* enable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+		/* UL turn on */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_ENABLE);
+	} else {
+		/* UL turn off */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK,
+				   MT6357_UL_SRC_DISABLE);
+		/* disable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+	}
+
+	return 0;
+}
+
+static int mt_aif_out_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol,
+			    int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		set_capture_gpio(priv, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		set_capture_gpio(priv, false);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_adc_supply_event(struct snd_soc_dapm_widget *w,
+			       struct snd_kcontrol *kcontrol,
+			       int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable audio ADC CLKGEN  */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+				   MT6357_RSTB_ENCODER_VA28_MASK, MT6357_RSTB_ENCODER_VA28_ENABLE);
+		/* Enable  LCLDO_ENC 2P8V */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_LCLDO_ENC_EN_VA28_MASK, MT6357_LCLDO_ENC_EN_VA28_ENABLE);
+		/* LCLDO_ENC remote sense */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_VA28REFGEN_EN_VA28_MASK |
+				   MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+				   MT6357_VA28REFGEN_EN_VA28_ENABLE |
+				   MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* LCLDO_ENC remote sense off */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_VA28REFGEN_EN_VA28_MASK |
+				   MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK,
+				   MT6357_VA28REFGEN_EN_VA28_DISABLE |
+				   MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE);
+		/* disable LCLDO_ENC 2P8V */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_LCLDO_ENC_EN_VA28_MASK,
+				   MT6357_LCLDO_ENC_EN_VA28_DISABLE);
+		/* disable audio ADC CLKGEN  */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+				   MT6357_RSTB_ENCODER_VA28_MASK,
+				   MT6357_RSTB_ENCODER_VA28_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_mic_type_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	unsigned int mic_type = dapm_kcontrol_get_value(w->kcontrols[0]);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		switch (mic_type) {
+		case MIC_TYPE_MUX_DMIC:
+			mt6357_set_dmic(priv, true);
+			break;
+		case MIC_TYPE_MUX_LPBK:
+			mt6357_set_loopback(priv, true);
+			break;
+		case MIC_TYPE_MUX_SGEN:
+			mt6357_set_ul_sine_gen(priv, true);
+			break;
+		default:
+			mt6357_set_amic(priv, true, mic_type);
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		switch (mic_type) {
+		case MIC_TYPE_MUX_DMIC:
+			mt6357_set_dmic(priv, false);
+			break;
+		case MIC_TYPE_MUX_LPBK:
+			mt6357_set_loopback(priv, false);
+			break;
+		case MIC_TYPE_MUX_SGEN:
+			mt6357_set_ul_sine_gen(priv, false);
+			break;
+		default:
+			mt6357_set_amic(priv, false, mic_type);
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_pga_left_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* L preamplifier enable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLON_MASK,
+				   MT6357_AUDPREAMPLON_ENABLE);
+		/* L ADC input sel : L PGA. Enable audio L ADC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDADCLINPUTSEL_MASK,
+				   MT6357_AUDADCLINPUTSEL_PREAMPLIFIER);
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDADCLPWRUP_MASK,
+				   MT6357_AUDADCLPWRUP);
+		/* Audio L preamplifier DCC precharge off */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+				   MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Audio L ADC input sel : off, disable audio L ADC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDADCLPWRUP_MASK,
+				   MT6357_AUDADCLPWRDOWN);
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDADCLINPUTSEL_MASK,
+				   MT6357_AUDADCLINPUTSEL_IDLE);
+		/* L preamplifier ACC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLDCCEN_MASK,
+				   MT6357_AUDPREAMPLDCCEN_AC);
+		/* L preamplifier disable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLON_MASK,
+				   MT6357_AUDPREAMPLON_DISABLE);
+		/* disable Audio L preamplifier DCC precharge */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLDCPRECHARGE_MASK,
+				   MT6357_AUDPREAMPLDCPRECHARGE_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_pga_right_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol,
+			      int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* R preamplifier enable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_ENABLE);
+		/* R ADC input sel : R PGA. Enable audio R ADC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDADCRINPUTSEL_MASK,
+				   MT6357_AUDADCRINPUTSEL_PREAMPLIFIER);
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRUP);
+		/* Audio R preamplifier DCC precharge off */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+				   MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Audio R ADC input sel : off, disable audio R ADC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRDOWN);
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDADCRINPUTSEL_MASK, MT6357_AUDADCRINPUTSEL_IDLE);
+		/* R preamplifier ACC */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_AC);
+		/* R preamplifier disable */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_DISABLE);
+		/* disable Audio R preamplifier DCC precharge */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRDCPRECHARGE_MASK,
+				   MT6357_AUDPREAMPRDCPRECHARGE_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int adc_enable_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol,
+			    int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int lgain, rgain;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &lgain);
+		regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &rgain);
+		/* L PGA 0 dB gain */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLGAIN_MASK,
+				   UL_GAIN_0DB << MT6357_AUDPREAMPLGAIN_SFT);
+		/* R PGA 0 dB gain */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRGAIN_MASK,
+				   UL_GAIN_0DB << MT6357_AUDPREAMPRGAIN_SFT);
+		/* enable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE);
+		/* UL turn on */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE);
+		/* Wait to avoid any pop noises */
+		msleep(100);
+		/* set the mic gains to the stored values */
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0,
+				   MT6357_AUDPREAMPLGAIN_MASK, lgain);
+		regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1,
+				   MT6357_AUDPREAMPRGAIN_MASK, rgain);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* UL turn off */
+		regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L,
+				   MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE);
+		/* disable aud_pad TX fifos */
+		regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK,
+				   MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void configure_downlinks(struct mt6357_priv *priv, bool enable)
+{
+	if (enable) {
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ELR_0,
+				   MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK,
+				   MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE);
+		/* Disable headphone short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK,
+				   MT6357_AUD_HPR_SC_VAUDP15_DISABLE |
+				   MT6357_AUD_HPL_SC_VAUDP15_DISABLE);
+		/* Disable handset short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_SC_VAUDP15_MASK,
+				   MT6357_AUD_HS_SC_VAUDP15_DISABLE);
+		/* Disable lineout short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_SC_VAUDP15_MASK,
+				   MT6357_AUD_LOL_SC_VAUDP15_DISABLE);
+		/* Reduce ESD resistance of AU_REFN */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+				   MT6357_AUD_REFN_DERES_VAUDP15_MASK,
+				   MT6357_AUD_REFN_DERES_VAUDP15_ENABLE);
+		/* Turn on DA_600K_NCP_VA18 */
+		regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON1, MT6357_DIVCKS_ON);
+		/* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */
+		regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON2, 0x002c);
+		/* Toggle DIVCKS_CHG */
+		regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON0, MT6357_DIVCKS_CHG);
+		/* Set NCP soft start mode as default mode: 150us */
+		regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON4,
+			     MT6357_DIVCKS_PWD_NCP_ST_150US);
+		/* Enable NCP */
+		regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3,
+			     MT6357_DIVCKS_PWD_NCP_ENABLE);
+		usleep_range(250, 270);
+		/* Enable cap-less LDOs (1.5V) */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_VA33REFGEN_EN_VA18_MASK |
+				   MT6357_LCLDO_REMOTE_SENSE_VA18_MASK |
+				   MT6357_LCLDO_EN_VA18_MASK |
+				   MT6357_HCLDO_REMOTE_SENSE_VA18_MASK |
+				   MT6357_HCLDO_EN_VA18_MASK,
+				   MT6357_VA33REFGEN_EN_VA18_ENABLE |
+				   MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE |
+				   MT6357_LCLDO_EN_VA18_ENABLE |
+				   MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE |
+				   MT6357_HCLDO_EN_VA18_ENABLE);
+		/* Enable NV regulator (-1.2V) */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+				   MT6357_NVREG_EN_VAUDP15_MASK, MT6357_NVREG_EN_VAUDP15_ENABLE);
+		usleep_range(100, 120);
+		/* Enable IBIST */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+				   MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK,
+				   MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE);
+		/* Enable AUD_CLK */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+				   MT6357_RSTB_DECODER_VA28_MASK,
+				   MT6357_RSTB_DECODER_VA28_ENABLE);
+		/* Enable low-noise mode of DAC */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_DAC_LOW_NOISE_MODE_MASK,
+				   MT6357_DAC_LOW_NOISE_MODE_ENABLE);
+		usleep_range(100, 120);
+	} else {
+		/* Disable low-noise mode of DAC */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_DAC_LOW_NOISE_MODE_MASK,
+				   MT6357_DAC_LOW_NOISE_MODE_DISABLE);
+		/* Disable AUD_CLK */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11,
+				   MT6357_RSTB_DECODER_VA28_MASK,
+				   MT6357_RSTB_DECODER_VA28_DISABLE);
+		/* Enable linout short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_SC_VAUDP15_MASK,
+				   MT6357_AUD_LOL_SC_VAUDP15_ENABLE);
+		/* Enable handset short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_SC_VAUDP15_MASK,
+				   MT6357_AUD_HS_SC_VAUDP15_ENABLE);
+		/* Enable headphone short-circuit protection */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_SC_VAUDP15_MASK |
+				   MT6357_AUD_HPL_SC_VAUDP15_MASK,
+				   MT6357_AUD_HPR_SC_VAUDP15_ENABLE |
+				   MT6357_AUD_HPL_SC_VAUDP15_ENABLE);
+		/* Disable IBIST */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10,
+				   MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK,
+				   MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE);
+		/* Disable NV regulator (-1.2V) */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13,
+				   MT6357_NVREG_EN_VAUDP15_MASK,
+				   MT6357_NVREG_EN_VAUDP15_DISABLE);
+		/* Disable cap-less LDOs (1.5V) */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12,
+				   MT6357_VA33REFGEN_EN_VA18_MASK |
+				   MT6357_LCLDO_REMOTE_SENSE_VA18_MASK |
+				   MT6357_LCLDO_EN_VA18_MASK |
+				   MT6357_HCLDO_REMOTE_SENSE_VA18_MASK |
+				   MT6357_HCLDO_EN_VA18_MASK,
+				   MT6357_VA33REFGEN_EN_VA18_DISABLE |
+				   MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE |
+				   MT6357_LCLDO_EN_VA18_DISABLE |
+				   MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE |
+				   MT6357_HCLDO_EN_VA18_DISABLE);
+		/* Disable NCP */
+		regmap_update_bits(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3,
+				   MT6357_DIVCKS_PWD_NCP_MASK, MT6357_DIVCKS_PWD_NCP_DISABLE);
+	}
+}
+
+static int mt_audio_in_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		set_playback_gpio(priv, true);
+
+		/* Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, true);
+
+		/* Disable HP main CMFB Switch */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE);
+		/* Audio system digital clock power down release */
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+			     MT6357_CCI_AUDIO_FIFO_DISABLE |
+			     MT6357_CCI_ACD_MODE_NORMAL_PATH |
+			     MT6357_CCI_AFIFO_CLK_PWDB_ON |
+			     MT6357_CCI_ACD_FUNC_RSTB_RESET);
+		/* sdm audio fifo clock power on */
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0,
+			     MT6357_CCI_AUD_ANACK_INVERT |
+			     (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) |
+			     MT6357_CCI_SCRAMBLER_CG_ENABLE |
+			     MT6357_CCI_RAND_ENABLE |
+			     MT6357_CCI_SPLT_SCRMB_CLK_ON |
+			     MT6357_CCI_SPLT_SCRMB_ON |
+			     MT6357_CCI_ZERO_PADDING_DISABLE |
+			     MT6357_CCI_SCRAMBLER_ENABLE);
+		/* scrambler clock on enable */
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+			     MT6357_CCI_AUDIO_FIFO_DISABLE |
+			     MT6357_CCI_ACD_MODE_TEST_PATH |
+			     MT6357_CCI_AFIFO_CLK_PWDB_ON |
+			     MT6357_CCI_ACD_FUNC_RSTB_RELEASE);
+		/* sdm power on */
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+			     MT6357_CCI_AUDIO_FIFO_ENABLE |
+			     MT6357_CCI_ACD_MODE_TEST_PATH |
+			     MT6357_CCI_AFIFO_CLK_PWDB_ON |
+			     MT6357_CCI_ACD_FUNC_RSTB_RELEASE);
+
+		configure_downlinks(priv, true);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		configure_downlinks(priv, false);
+		/* DL scrambler disabling sequence */
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2,
+			     MT6357_CCI_AUDIO_FIFO_DISABLE |
+			     MT6357_CCI_ACD_MODE_TEST_PATH |
+			     MT6357_CCI_AFIFO_CLK_PWDB_DOWN |
+			     MT6357_CCI_ACD_FUNC_RSTB_RESET);
+		regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0,
+			     MT6357_CCI_AUD_ANACK_INVERT |
+			     (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) |
+			     MT6357_CCI_SCRAMBLER_CG_ENABLE |
+			     MT6357_CCI_RAND_ENABLE |
+			     MT6357_CCI_SPLT_SCRMB_CLK_ON |
+			     MT6357_CCI_SPLT_SCRMB_ON |
+			     MT6357_CCI_ZERO_PADDING_DISABLE |
+			     MT6357_CCI_SCRAMBLER_DISABLE);
+
+		set_playback_gpio(priv, false);
+
+		/* disable Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, false);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt_delay_250_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol,
+			      int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(250, 270);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		usleep_range(250, 270);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int lo_mux_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol,
+			int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int lgain, rgain;
+
+	/* Get current gain value */
+	regmap_read(priv->regmap, MT6357_ZCD_CON1, &lgain);
+	rgain = (lgain & MT6357_AUD_LOR_GAIN_MASK) >> MT6357_AUD_LOR_GAIN_SFT;
+	lgain = lgain & MT6357_AUD_LOL_GAIN_MASK;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Set -40dB before enable HS to avoid POP noise */
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON1,
+				   MT6357_AUD_LOL_GAIN_MASK |
+				   MT6357_AUD_LOR_GAIN_MASK,
+				   MT6357_DL_GAIN_N_40DB_REG);
+		/* Set LO STB enhance circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+				   MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE);
+		/* Enable LO driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE);
+		/* Enable LO driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE);
+		/* Set LOL gain to normal gain step by step */
+		lo_volume_ramp(priv, DL_GAIN_N_40DB, lgain,
+			       DL_GAIN_N_40DB, rgain);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* decrease LOL gain to minimum gain step by step */
+
+		lo_volume_ramp(priv, lgain, DL_GAIN_N_40DB,
+			       rgain, DL_GAIN_N_40DB);
+		/* Disable LO driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE);
+		/* Disable LO driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE);
+		/* Clear LO STB enhance circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+				   MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK,
+				   MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE);
+		/* Save the gain value into the register*/
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON1,
+				   MT6357_AUD_LOL_GAIN_MASK |
+				   MT6357_AUD_LOR_GAIN_MASK,
+				   lgain << MT6357_AUD_LOL_GAIN_SFT |
+				   rgain << MT6357_AUD_LOR_GAIN_SFT);
+
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hs_mux_event(struct snd_soc_dapm_widget *w,
+			struct snd_kcontrol *kcontrol,
+			int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int gain; /* HS register has only one gain slot */
+
+	/* Get current gain value */
+	regmap_read(priv->regmap, MT6357_ZCD_CON3, &gain);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* Set -40dB before enable HS to avoid POP noise */
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON3,
+				   MT6357_AUD_HS_GAIN_MASK,
+				   DL_GAIN_N_40DB);
+
+		/* Set HS STB enhance circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+				   MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE);
+		/* Enable HS driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+		/* Enable HS driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE);
+		/* Set HS gain to normal gain step by step */
+		hs_volume_ramp(priv, DL_GAIN_N_40DB, gain);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* decrease HS gain to minimum gain step by step */
+		hs_volume_ramp(priv,  gain, DL_GAIN_N_40DB);
+		/* Disable HS driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE);
+		/* Disable HS driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE);
+		/* Clear HS STB enhance circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+				   MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK,
+				   MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE);
+		/* Save the gain value into the register*/
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON3,
+				   MT6357_AUD_HS_GAIN_MASK, gain);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hp_main_mux_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol,
+			     int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+	int lgain, rgain;
+
+	/* Get current gain value */
+	regmap_read(priv->regmap, MT6357_ZCD_CON2, &lgain);
+	rgain = (lgain & MT6357_AUD_HPR_GAIN_MASK) >> MT6357_AUD_HPR_GAIN_SFT;
+	lgain = lgain & MT6357_AUD_HPL_GAIN_MASK;
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		priv->hp_channel_number++;
+		if (priv->hp_channel_number > 1)
+			break;
+		/* Set -40dB before enable HS to avoid POP noise */
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON2,
+				   MT6357_AUD_HPL_GAIN_MASK |
+				   MT6357_AUD_HPR_GAIN_MASK,
+				   MT6357_DL_GAIN_N_40DB_REG);
+		/* Set HPP/N STB enhance circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2,
+				   MT6357_HPROUT_STB_ENH_VAUDP15_MASK |
+				   MT6357_HPLOUT_STB_ENH_VAUDP15_MASK,
+				   MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 |
+				   MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250);
+		/* Enable HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+		/* Enable HP aux feedback loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE);
+		/* Enable HP aux CMFB loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HP_CMFB_RST_MASK |
+				   MT6357_HPL_AUX_CMFB_LOOP_MASK |
+				   MT6357_HPR_AUX_CMFB_LOOP_MASK,
+				   MT6357_HP_CMFB_RST_NORMAL |
+				   MT6357_HPL_AUX_CMFB_LOOP_ENABLE |
+				   MT6357_HPR_AUX_CMFB_LOOP_ENABLE);
+		/* Enable HP driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_BIAS_VAUDP15_MASK |
+				   MT6357_AUD_HPL_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE |
+				   MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE);
+		/* Enable HP driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_PWRUP_VAUDP15_MASK |
+				   MT6357_AUD_HPL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE |
+				   MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE);
+		/* Short HP main output to HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+		/* Enable HP main CMFB loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE);
+		/* Disable HP aux CMFB loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HPR_AUX_CMFB_LOOP_MASK |
+				   MT6357_HPL_AUX_CMFB_LOOP_MASK,
+				   MT6357_HPR_AUX_CMFB_LOOP_DISABLE |
+				   MT6357_HPL_AUX_CMFB_LOOP_DISABLE);
+		/* Enable HP main output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_PWRUP_VAUDP15_ENABLE |
+				   MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE);
+		/* Enable HPR/L main output stage step by step */
+		hp_main_output_ramp(priv, true);
+		usleep_range(1000, 1200);
+		/* Reduce HP aux feedback loop gain */
+		hp_aux_feedback_loop_gain_ramp(priv, true);
+		/* Disable HP aux feedback loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE);
+		/* apply volume setting */
+		hp_volume_ramp(priv, DL_GAIN_N_40DB, lgain,
+			       DL_GAIN_N_40DB, rgain);
+		/* Disable HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+		/* Unshort HP main output to HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+		usleep_range(100, 120);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		priv->hp_channel_number--;
+		if (priv->hp_channel_number > 0)
+			break;
+		/* Short HP main output to HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE);
+		/* Enable HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE);
+		/* decrease HPL/R gain to normal gain step by step */
+		hp_volume_ramp(priv, lgain, DL_GAIN_N_40DB,
+			       rgain, DL_GAIN_N_40DB);
+		/* Enable HP aux feedback loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE);
+		/* Reduce HP aux feedback loop gain */
+		hp_aux_feedback_loop_gain_ramp(priv, false);
+		/* decrease HPR/L main output stage step by step */
+		hp_main_output_ramp(priv, false);
+		/* Disable HP main output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_PWRUP_VAUDP15_DISABLE |
+				   MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE);
+		/* Enable HP aux CMFB loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HP_CMFB_RST_MASK |
+				   MT6357_HPL_AUX_CMFB_LOOP_MASK |
+				   MT6357_HPR_AUX_CMFB_LOOP_MASK,
+				   MT6357_HP_CMFB_RST_RESET |
+				   MT6357_HPL_AUX_CMFB_LOOP_ENABLE |
+				   MT6357_HPR_AUX_CMFB_LOOP_ENABLE);
+		/* Disable HP main CMFB loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_MASK,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE);
+		/* Unshort HP main output to HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK,
+				   MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE |
+				   MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE);
+		/* Disable HP driver core circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_PWRUP_VAUDP15_MASK |
+				   MT6357_AUD_HPL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE |
+				   MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE);
+		/* Disable HP driver bias circuits */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_HPR_BIAS_VAUDP15_MASK |
+				   MT6357_AUD_HPL_BIAS_VAUDP15_MASK,
+				   MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE |
+				   MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE);
+		/* Disable HP aux CMFB loop,
+		 * Enable HP main CMFB for HP off state
+		 */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_MASK |
+				   MT6357_HPR_AUX_CMFB_LOOP_MASK |
+				   MT6357_HPL_AUX_CMFB_LOOP_MASK,
+				   MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE |
+				   MT6357_HPR_AUX_CMFB_LOOP_DISABLE |
+				   MT6357_HPL_AUX_CMFB_LOOP_DISABLE);
+		/* Disable HP aux feedback loop */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_MASK |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_MASK,
+				   MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE |
+				   MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE);
+		/* Disable HP aux output stage */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK,
+				   MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE |
+				   MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE);
+		/* Save the gain value into the register*/
+		regmap_update_bits(priv->regmap, MT6357_ZCD_CON2,
+				   MT6357_AUD_HPL_GAIN_MASK |
+				   MT6357_AUD_HPR_GAIN_MASK,
+				   lgain << MT6357_AUD_HPL_GAIN_SFT |
+				   rgain << MT6357_AUD_HPR_GAIN_SFT);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int right_dac_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol,
+			   int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable Audio DAC and control audio bias gen */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_DACR_PWRUP_VA28_MASK |
+				   MT6357_AUD_DACR_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_DACR_PWRUP_VA28_ENABLE |
+				   MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* disable Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, false);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, true);
+		/* Disable Audio DAC and control audio bias gen  */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_DACR_PWRUP_VA28_MASK |
+				   MT6357_AUD_DACR_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_DACR_PWRUP_VA28_DISABLE |
+				   MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int left_dac_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable Audio DAC and control audio bias gen  */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_DACL_PWRUP_VA28_MASK |
+				   MT6357_AUD_DACL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_DACL_PWRUP_VA28_ENABLE |
+				   MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* disable Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, false);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		/* Pull-down HPL/R to AVSS28_AUD */
+		if (priv->pull_down_needed)
+			hp_pull_down(priv, true);
+		/* Disable Audio DAC and control audio bias gen  */
+		regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+				   MT6357_AUD_DACL_PWRUP_VA28_MASK |
+				   MT6357_AUD_DACL_PWRUP_VAUDP15_MASK,
+				   MT6357_AUD_DACL_PWRUP_VA28_DISABLE |
+				   MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* Supply widgets subsequence */
+enum {
+	/* common */
+	SUPPLY_SEQ_CLK_BUF,
+	SUPPLY_SEQ_AUD_GLB,
+	SUPPLY_SEQ_CLKSQ,
+	SUPPLY_SEQ_VOW_AUD_LPW,
+	SUPPLY_SEQ_AUD_VOW,
+	SUPPLY_SEQ_VOW_CLK,
+	SUPPLY_SEQ_VOW_LDO,
+	SUPPLY_SEQ_TOP_CK,
+	SUPPLY_SEQ_TOP_CK_LAST,
+	SUPPLY_SEQ_AUD_TOP,
+	SUPPLY_SEQ_AUD_TOP_LAST,
+	SUPPLY_SEQ_AFE,
+	/* capture */
+	SUPPLY_SEQ_ADC_SUPPLY,
+};
+
+/* DAPM Widgets */
+static const struct snd_soc_dapm_widget mt6357_dapm_widgets[] = {
+	/* Analog Clocks */
+	SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF,
+			      MT6357_DCXO_CW14,
+			      MT6357_XO_AUDIO_EN_M_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB,
+			      MT6357_AUDDEC_ANA_CON11,
+			      MT6357_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ,
+			      MT6357_AUDENC_ANA_CON6,
+			      MT6357_CLKSQ_EN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK,
+			      MT6357_AUD_TOP_CKPDN_CON0,
+			      MT6357_AUDNCP_CK_PDN_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK,
+			      MT6357_AUD_TOP_CKPDN_CON0,
+			      MT6357_ZCD13M_CK_PDN_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST,
+			      MT6357_AUD_TOP_CKPDN_CON0,
+			      MT6357_AUD_CK_PDN_SFT, 1,
+			      mt_delay_250_event,
+			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK,
+			      MT6357_AUD_TOP_CKPDN_CON0,
+			      MT6357_AUDIF_CK_PDN_SFT, 1, NULL, 0),
+
+	/* Digital Clocks */
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_AFE_CTL_SFT, 1,
+			      mt_delay_250_event,
+			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_DAC_CTL_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_ADC_CTL_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_I2S_DL_CTL_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PWR_CLK_DIS_CTL_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_RESERVED_SFT, 1, NULL, 0),
+	SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_LPBK", SUPPLY_SEQ_AUD_TOP,
+			      MT6357_AUDIO_TOP_CON0,
+			      MT6357_PDN_LPBK_CTL_SFT, 1, NULL, 0),
+
+	/* General */
+	SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE,
+			      MT6357_AFE_UL_DL_CON0,
+			      MT6357_AFE_ON_SFT, 0, NULL, 0),
+
+	/* Uplinks */
+	SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "MT6357 Capture", 0,
+			       SND_SOC_NOPM, 0, 0,
+			       mt_aif_out_event,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY,
+			      SND_SOC_NOPM, 0, 0,
+			      mt_adc_supply_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, adc_enable_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0,
+			   &pga_left_mux_control,
+			   mt_pga_left_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0,
+			   &pga_right_mux_control,
+			   mt_pga_right_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0,
+			   &mic_type_mux_control,
+			   mt_mic_type_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MICBIAS0", MT6357_AUDENC_ANA_CON8,
+			    MT6357_AUD_MICBIAS0_PWD_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("MICBIAS1", MT6357_AUDENC_ANA_CON9,
+			    MT6357_AUD_MICBIAS1_PWD_SFT, 0, NULL, 0),
+
+	/* UL inputs */
+	SND_SOC_DAPM_INPUT("AIN0"),
+	SND_SOC_DAPM_INPUT("AIN1"),
+	SND_SOC_DAPM_INPUT("AIN2"),
+	SND_SOC_DAPM_INPUT("LPBK"),
+	SND_SOC_DAPM_INPUT("SGEN UL"),
+
+	/* Downlinks */
+	SND_SOC_DAPM_AIF_IN_E("AIF_RX", "MT6357 Playback", 0,
+			      SND_SOC_NOPM, 0, 0,
+			      mt_audio_in_event,
+			      SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_INPUT("SGEN DL"),
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux_control),
+
+	SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, 0, 0, right_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, 0, 0, left_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_SUPPLY("DL Digital Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DL Analog Supply", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("DL SRC", MT6357_AFE_DL_SRC2_CON0_L,
+			    MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX_E("Line Out Source", SND_SOC_NOPM, 0, 0, &lo_mux_control,
+			   lo_mux_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX_E("Handset Source", SND_SOC_NOPM, 0, 0, &hs_mux_control,
+			   hs_mux_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX_E("Headphone Right Source", SND_SOC_NOPM, 0, 0, &hpr_mux_control,
+			   hp_main_mux_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX_E("Headphone Left Source", SND_SOC_NOPM, 0, 0, &hpl_mux_control,
+			   hp_main_mux_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	/* DL outputs */
+	SND_SOC_DAPM_OUTPUT("Headphones"),
+	SND_SOC_DAPM_OUTPUT("Hansdet"),
+	SND_SOC_DAPM_OUTPUT("Line out"),
+
+	/* Sine generator */
+	SND_SOC_DAPM_SUPPLY("SGEN UL Enable",
+			    MT6357_AFE_TOP_CON0, MT6357_UL_SINE_ON_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("SGEN Enable",
+			    MT6357_AFE_SGEN_CFG0,
+			    MT6357_SGEN_DAC_EN_CTL_SFT, 0, mt_audio_in_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("SGEN MUTE",
+			    MT6357_AFE_SGEN_CFG0,
+			    MT6357_SGEN_MUTE_SW_CTL_SFT, 1, NULL, 0)
+};
+
+static const struct snd_soc_dapm_route mt6357_dapm_routes[] = {
+	/* Capture */
+	{"AIF1TX", NULL, "Mic Type Mux"},
+	{"AIF1TX", NULL, "CLK_BUF"},
+	{"AIF1TX", NULL, "AUDGLB"},
+	{"AIF1TX", NULL, "CLKSQ Audio"},
+	{"AIF1TX", NULL, "AUD_CK"},
+	{"AIF1TX", NULL, "AUDIF_CK"},
+
+	{"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"},
+	{"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"},
+	{"AIF1TX", NULL, "AFE_ON"},
+
+	{"Mic Type Mux", "ACC", "ADC"},
+	{"Mic Type Mux", "DCC", "ADC"},
+	{"Mic Type Mux", "DCC_ECM_DIFF", "ADC"},
+	{"Mic Type Mux", "DCC_ECM_SINGLE", "ADC"},
+	{"Mic Type Mux", "DMIC", "AIN0"},
+	{"Mic Type Mux", "DMIC", "AIN2"},
+	{"Mic Type Mux", "Loopback", "LPBK"},
+	{"Mic Type Mux", "Sine Generator", "SGEN UL"},
+
+	{"SGEN UL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+	{"SGEN UL", NULL, "SGEN UL Enable"},
+	{"SGEN UL", NULL, "SGEN MUTE"},
+	{"SGEN UL", NULL, "SGEN Enable"},
+
+	{"ADC", NULL, "PGA L Mux"},
+	{"ADC", NULL, "PGA R Mux"},
+	{"ADC", NULL, "ADC Supply"},
+
+	{"PGA L Mux", "AIN0", "AIN0"},
+	{"PGA L Mux", "AIN1", "AIN1"},
+	{"PGA L Mux", "AIN2", "AIN2"},
+
+	{"PGA R Mux", "AIN0", "AIN0"},
+	{"PGA R Mux", "AIN1", "AIN1"},
+	{"PGA R Mux", "AIN2", "AIN2"},
+
+	{"AIN0", NULL, "MICBIAS0"},
+	{"AIN1", NULL, "MICBIAS1"},
+	{"AIN2", NULL, "MICBIAS0"},
+	{"LPBK", NULL, "AUDIO_TOP_LPBK"},
+
+	/* Playback */
+	{"DAC Mux", "Normal Path", "AIF_RX"},
+	{"DAC Mux", "Sine Generator", "SGEN DL"},
+
+	{"AIF_RX", NULL, "DL SRC"},
+
+	{"SGEN DL", NULL, "DL SRC"},
+	{"SGEN DL", NULL, "SGEN MUTE"},
+	{"SGEN DL", NULL, "SGEN Enable"},
+	{"SGEN DL", NULL, "DL Digital Supply"},
+	{"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"},
+
+	{"DACL", NULL, "DAC Mux"},
+	{"DACR", NULL, "DAC Mux"},
+
+	{"DL Analog Supply", NULL, "CLK_BUF"},
+	{"DL Analog Supply", NULL, "AUDGLB"},
+	{"DL Analog Supply", NULL, "CLKSQ Audio"},
+	{"DL Analog Supply", NULL, "AUDNCP_CK"},
+	{"DL Analog Supply", NULL, "ZCD13M_CK"},
+	{"DL Analog Supply", NULL, "AUD_CK"},
+	{"DL Analog Supply", NULL, "AUDIF_CK"},
+
+	{"DL Digital Supply", NULL, "AUDIO_TOP_AFE_CTL"},
+	{"DL Digital Supply", NULL, "AUDIO_TOP_DAC_CTL"},
+	{"DL Digital Supply", NULL, "AUDIO_TOP_PWR_CLK"},
+	{"DL Digital Supply", NULL, "AFE_ON"},
+
+	{"DACR", NULL, "DL Digital Supply"},
+	{"DACR", NULL, "DL Analog Supply"},
+	{"DACL", NULL, "DL Digital Supply"},
+	{"DACL", NULL, "DL Analog Supply"},
+
+	{"Line Out Source", "DACR", "DACR"},
+	{"Line Out Source", "Playback", "DACL"},
+	{"Line Out Source", "Test mode", "DACL"},
+
+	{"Handset Source", "DACR", "DACR"},
+	{"Handset Source", "Playback", "DACL"},
+	{"Handset Source", "Test mode", "DACL"},
+
+	{"Headphone Right Source", "DAC", "DACR"},
+	{"Headphone Right Source", "Line Out", "Line Out Source"},
+	{"Headphone Right Source", "Handset", "Handset Source"},
+
+	{"Headphone Left Source", "DAC", "DACL"},
+	{"Headphone Left Source", "Line Out", "Line Out Source"},
+	{"Headphone Left Source", "Handset", "Handset Source"},
+
+	{"Line out", NULL, "Line Out Source"},
+	{"Hansdet", NULL, "Handset Source"},
+
+	{"Headphones", NULL, "Headphone Right Source"},
+	{"Headphones", NULL, "Headphone Left Source"},
+};
+
+static struct snd_soc_dai_driver mtk_6357_dai_codecs[] = {
+	{
+		.name = "mt6357-snd-codec-aif1",
+		.playback = {
+			.stream_name = "MT6357 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = MT6357_SND_SOC_ADV_MT_FMTS,
+			},
+		.capture = {
+			.stream_name = "MT6357 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MT6357_SOC_HIGH_USE_RATE,
+			.formats = MT6357_SND_SOC_ADV_MT_FMTS,
+			},
+	},
+};
+
+static void mt6357_codec_init(struct mt6357_priv *priv)
+{
+	/* Enable audio part */
+	regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+			   MT6357_XO_AUDIO_EN_M_MASK, MT6357_XO_AUDIO_EN_M_ENABLE);
+	/* Disable HeadphoneL/HeadphoneR short circuit protection */
+	regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0,
+			   MT6357_AUD_HPR_SC_VAUDP15_MASK |
+			   MT6357_AUD_HPL_SC_VAUDP15_MASK,
+			   MT6357_AUD_HPR_SC_VAUDP15_DISABLE |
+			   MT6357_AUD_HPL_SC_VAUDP15_DISABLE);
+	/* Disable voice short circuit protection */
+	regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3,
+			   MT6357_AUD_HS_SC_VAUDP15_MASK,
+			   MT6357_AUD_HS_SC_VAUDP15_DISABLE);
+	/* disable LO buffer left short circuit protection */
+	regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4,
+			   MT6357_AUD_LOL_SC_VAUDP15_MASK,
+			   MT6357_AUD_LOL_SC_VAUDP15_DISABLE);
+	/* set gpio */
+	set_playback_gpio(priv, false);
+	set_capture_gpio(priv, false);
+	/* Disable audio part */
+	regmap_update_bits(priv->regmap, MT6357_DCXO_CW14,
+			   MT6357_XO_AUDIO_EN_M_MASK,
+			   MT6357_XO_AUDIO_EN_M_DISABLE);
+
+	/* gain default values*/
+	regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLGAIN_MASK,
+			   UL_GAIN_0DB << MT6357_AUDPREAMPLGAIN_SFT);
+	regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRGAIN_MASK,
+			   UL_GAIN_0DB << MT6357_AUDPREAMPRGAIN_SFT);
+
+	regmap_update_bits(priv->regmap, MT6357_ZCD_CON1,
+			   MT6357_AUD_LOL_GAIN_MASK |
+			   MT6357_AUD_LOR_GAIN_MASK,
+			   DL_GAIN_0DB << MT6357_AUD_LOL_GAIN_SFT |
+			   DL_GAIN_0DB << MT6357_AUD_LOR_GAIN_SFT);
+
+	regmap_update_bits(priv->regmap, MT6357_ZCD_CON2,
+			   MT6357_AUD_HPL_GAIN_MASK |
+			   MT6357_AUD_HPR_GAIN_MASK,
+			   DL_GAIN_0DB << MT6357_AUD_HPL_GAIN_SFT |
+			   DL_GAIN_0DB << MT6357_AUD_HPR_GAIN_SFT);
+
+	regmap_update_bits(priv->regmap, MT6357_ZCD_CON3,
+			   MT6357_AUD_HS_GAIN_MASK, DL_GAIN_0DB);
+}
+
+static int mt6357_codec_probe(struct snd_soc_component *codec)
+{
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+
+	mt6357_codec_init(priv);
+	return 0;
+}
+
+static unsigned int mt6357_read(struct snd_soc_component *codec, unsigned int reg)
+{
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+	unsigned int val;
+
+	regmap_read(priv->regmap, reg, &val);
+	return val;
+}
+
+static int mt6357_write(struct snd_soc_component *codec, unsigned int reg, unsigned int value)
+{
+	struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec);
+
+	return regmap_update_bits(priv->regmap, reg, 0xffff, value);
+}
+
+static const struct snd_soc_component_driver mt6357_soc_component_driver = {
+	.probe = mt6357_codec_probe,
+	.read = mt6357_read,
+	.write = mt6357_write,
+	.controls = mt6357_controls,
+	.num_controls = ARRAY_SIZE(mt6357_controls),
+	.dapm_widgets = mt6357_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets),
+	.dapm_routes = mt6357_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes),
+};
+
+static const u32 micbias_values[MT6357_MICBIAS_ARRAY_SIZE] = {
+	1700000, 1800000, 1900000, 2000000,
+	2100000, 2500000, 2600000, 2700000
+};
+
+static u32 mt6357_get_micbias_idx(struct device_node *np, const char *micbias)
+{
+	int err;
+	u32 idx, val;
+
+	err = of_property_read_u32(np, micbias,  &val);
+	if (err)
+		return 0;
+
+	for (idx = 0; idx < MT6357_MICBIAS_ARRAY_SIZE; idx++) {
+		if (val == micbias_values[idx])
+			return idx;
+	}
+	return 0;
+}
+
+static int mt6357_parse_dt(struct mt6357_priv *priv)
+{
+	u32 micbias_voltage_index = 0;
+	struct device_node *np;
+
+	np = of_get_child_by_name(priv->dev->parent->of_node, "codec");
+	if (!np)
+		return -EINVAL;
+
+	priv->pull_down_needed = false;
+	if (of_property_read_bool(np, "mediatek,hp-pull-down"))
+		priv->pull_down_needed = true;
+
+	micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias0-microvolt");
+	regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8,
+			   MT6357_AUD_MICBIAS0_VREF_MASK,
+			   micbias_voltage_index << MT6357_AUD_MICBIAS0_VREF_SFT);
+
+	micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias1-microvolt");
+	regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9,
+			   MT6357_AUD_MICBIAS1_VREF_MASK,
+			   micbias_voltage_index << MT6357_AUD_MICBIAS1_VREF_SFT);
+
+	return 0;
+}
+
+static int mt6357_platform_driver_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+	struct mt6357_priv *priv;
+	int ret;
+
+	ret = devm_regulator_get_enable(&pdev->dev, "vaud28");
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "Failed to enable vaud28 regulator\n");
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, priv);
+	priv->dev = &pdev->dev;
+
+	priv->regmap = mt6397->regmap;
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	ret = mt6357_parse_dt(priv);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "Failed to parse dts\n", __func__);
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+	return devm_snd_soc_register_component(&pdev->dev,
+					       &mt6357_soc_component_driver,
+					       mtk_6357_dai_codecs,
+					       ARRAY_SIZE(mtk_6357_dai_codecs));
+}
+
+static const struct platform_device_id mt6357_platform_ids[] = {
+	{"mt6357-sound", 0},
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6357_platform_ids);
+
+static struct platform_driver mt6357_platform_driver = {
+	.driver = {
+		.name = "mt6357-sound",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = mt6357_platform_driver_probe,
+	.id_table = mt6357_platform_ids,
+};
+
+module_platform_driver(mt6357_platform_driver)
+
+MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver");
+MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mt6357.h b/sound/soc/codecs/mt6357.h
new file mode 100644
index 000000000000..68fd2ed90353
--- /dev/null
+++ b/sound/soc/codecs/mt6357.h
@@ -0,0 +1,662 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt6357.h  --  mt6357 ALSA SoC audio codec driver
+ *
+ * Copyright (c) 2024 Baylibre
+ * Author: Nicolas Belin <nbelin@baylibre.com>
+ */
+
+#ifndef __MT6357_H__
+#define __MT6357_H__
+
+#include <linux/types.h>
+
+/* Reg bit defines */
+/* MT6357_GPIO_DIR0 */
+#define MT6357_GPIO8_DIR_MASK			BIT(8)
+#define MT6357_GPIO8_DIR_INPUT			0
+#define MT6357_GPIO8_DIR_OUTPUT			BIT(8)
+#define MT6357_GPIO9_DIR_MASK			BIT(9)
+#define MT6357_GPIO9_DIR_INPUT			0
+#define MT6357_GPIO9_DIR_OUTPUT			BIT(9)
+#define MT6357_GPIO10_DIR_MASK			BIT(10)
+#define MT6357_GPIO10_DIR_INPUT			0
+#define MT6357_GPIO10_DIR_OUTPUT		BIT(10)
+#define MT6357_GPIO11_DIR_MASK			BIT(11)
+#define MT6357_GPIO11_DIR_INPUT			0
+#define MT6357_GPIO11_DIR_OUTPUT		BIT(11)
+#define MT6357_GPIO12_DIR_MASK			BIT(12)
+#define MT6357_GPIO12_DIR_INPUT			0
+#define MT6357_GPIO12_DIR_OUTPUT		BIT(12)
+#define MT6357_GPIO13_DIR_MASK			BIT(13)
+#define MT6357_GPIO13_DIR_INPUT			0
+#define MT6357_GPIO13_DIR_OUTPUT		BIT(13)
+#define MT6357_GPIO14_DIR_MASK			BIT(14)
+#define MT6357_GPIO14_DIR_INPUT			0
+#define MT6357_GPIO14_DIR_OUTPUT		BIT(14)
+#define MT6357_GPIO15_DIR_MASK			BIT(15)
+#define MT6357_GPIO15_DIR_INPUT			0
+#define MT6357_GPIO15_DIR_OUTPUT		BIT(15)
+
+/* MT6357_GPIO_MODE2 */
+#define MT6357_GPIO8_MODE_MASK			GENMASK(2, 0)
+#define MT6357_GPIO8_MODE_AUD_CLK_MOSI		BIT(0)
+#define MT6357_GPIO8_MODE_GPIO			0
+#define MT6357_GPIO9_MODE_MASK			GENMASK(5, 3)
+#define MT6357_GPIO9_MODE_AUD_DAT_MOSI0		BIT(3)
+#define MT6357_GPIO9_MODE_GPIO			0
+#define MT6357_GPIO10_MODE_MASK			GENMASK(8, 6)
+#define MT6357_GPIO10_MODE_AUD_DAT_MOSI1	BIT(6)
+#define MT6357_GPIO10_MODE_GPIO			0
+#define MT6357_GPIO11_MODE_MASK			GENMASK(11, 9)
+#define MT6357_GPIO11_MODE_AUD_SYNC_MOSI	BIT(9)
+#define MT6357_GPIO11_MODE_GPIO			0
+
+/* MT6357_GPIO_MODE2_SET */
+#define MT6357_GPIO8_MODE_SET_MASK		GENMASK(2, 0)
+#define MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI	BIT(0)
+#define MT6357_GPIO9_MODE_SET_MASK		GENMASK(5, 3)
+#define MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0	BIT(3)
+#define MT6357_GPIO10_MODE_SET_MASK		GENMASK(8, 6)
+#define MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1	BIT(6)
+#define MT6357_GPIO11_MODE_SET_MASK		GENMASK(11, 9)
+#define MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI	BIT(9)
+
+/* MT6357_GPIO_MODE2_CLR */
+#define MT6357_GPIO_MODE2_CLEAR_ALL		GENMASK(15, 0)
+
+/* MT6357_GPIO_MODE3 */
+#define MT6357_GPIO12_MODE_MASK			GENMASK(2, 0)
+#define MT6357_GPIO12_MODE_AUD_CLK_MISO		BIT(0)
+#define MT6357_GPIO12_MODE_GPIO			0
+#define MT6357_GPIO13_MODE_MASK			GENMASK(5, 3)
+#define MT6357_GPIO13_MODE_AUD_DAT_MISO0	BIT(3)
+#define MT6357_GPIO13_MODE_GPIO			0
+#define MT6357_GPIO14_MODE_MASK			GENMASK(8, 6)
+#define MT6357_GPIO14_MODE_AUD_DAT_MISO1	BIT(6)
+#define MT6357_GPIO14_MODE_GPIO			0
+#define MT6357_GPIO15_MODE_MASK			GENMASK(11, 9)
+#define MT6357_GPIO15_MODE_AUD_SYNC_MISO	BIT(9)
+#define MT6357_GPIO15_MODE_GPIO			0
+
+/* MT6357_GPIO_MODE3_SET */
+#define MT6357_GPIO12_MODE_SET_MASK		GENMASK(2, 0)
+#define MT6357_GPIO12_MODE_SET_AUD_CLK_MISO	BIT(0)
+#define MT6357_GPIO13_MODE_SET_MASK		GENMASK(5, 3)
+#define MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0	BIT(3)
+#define MT6357_GPIO14_MODE_SET_MASK		GENMASK(8, 6)
+#define MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1	BIT(6)
+#define MT6357_GPIO15_MODE_SET_MASK		GENMASK(11, 9)
+#define MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO	BIT(9)
+
+/* MT6357_GPIO_MODE3_CLR */
+#define MT6357_GPIO_MODE3_CLEAR_ALL		GENMASK(15, 0)
+
+/* MT6357_DCXO_CW14 */
+#define MT6357_XO_AUDIO_EN_M_SFT		13
+#define MT6357_XO_AUDIO_EN_M_MASK		BIT(13)
+#define MT6357_XO_AUDIO_EN_M_ENABLE		BIT(13)
+#define MT6357_XO_AUDIO_EN_M_DISABLE		0
+
+/* MT6357_AUD_TOP_CKPDN_CON0 */
+#define MT6357_AUDNCP_CK_PDN_SFT		6
+#define MT6357_ZCD13M_CK_PDN_SFT		5
+#define MT6357_AUDIF_CK_PDN_SFT			2
+#define MT6357_AUD_CK_PDN_SFT			1
+
+/* MT6357_AUDNCP_CLKDIV_CON0 */
+#define MT6357_DIVCKS_CHG			BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON1 */
+#define MT6357_DIVCKS_ON			BIT(0)
+
+/* MT6357_AUDNCP_CLKDIV_CON3 */
+#define MT6357_DIVCKS_PWD_NCP_MASK		BIT(0)
+#define MT6357_DIVCKS_PWD_NCP_DISABLE		BIT(0)
+#define MT6357_DIVCKS_PWD_NCP_ENABLE		0
+
+/* MT6357_AUDNCP_CLKDIV_CON4 */
+#define MT6357_DIVCKS_PWD_NCP_ST_SEL_MASK	GENMASK(1, 0)
+#define MT6357_DIVCKS_PWD_NCP_ST_50US		0
+#define MT6357_DIVCKS_PWD_NCP_ST_100US		1
+#define MT6357_DIVCKS_PWD_NCP_ST_150US		2
+#define MT6357_DIVCKS_PWD_NCP_ST_200US		3
+
+/* MT6357_AFE_UL_DL_CON0 */
+#define MT6357_AFE_UL_LR_SWAP_SFT		15
+#define MT6357_AFE_ON_SFT			0
+
+/* MT6357_AFE_DL_SRC2_CON0_L */
+#define MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT	0
+
+/* MT6357_AFE_UL_SRC_CON0_H */
+#define MT6357_C_TWO_DIGITAL_MIC_CTL_MASK	BIT(7)
+#define MT6357_C_TWO_DIGITAL_MIC_ENABLE		BIT(7)
+#define MT6357_C_TWO_DIGITAL_MIC_DISABLE	0
+
+/* MT6357_AFE_UL_SRC_CON0_L */
+#define MT6357_UL_SDM_3_LEVEL_CTL_MASK		BIT(1)
+#define MT6357_UL_SDM_3_LEVEL_SELECT		BIT(1)
+#define MT6357_UL_SDM_3_LEVEL_DESELECT		0
+#define MT6357_UL_SRC_ON_TMP_CTL_MASK		BIT(0)
+#define MT6357_UL_SRC_ENABLE			BIT(0)
+#define MT6357_UL_SRC_DISABLE			0
+
+/* MT6357_AFE_TOP_CON0 */
+#define MT6357_UL_SINE_ON_SFT			1
+#define MT6357_UL_SINE_ON_MASK			BIT(1)
+#define MT6357_DL_SINE_ON_SFT			0
+#define MT6357_DL_SINE_ON_MASK			BIT(0)
+
+/* MT6357_AUDIO_TOP_CON0 */
+#define MT6357_PDN_LPBK_CTL_SFT			15
+#define MT6357_PDN_AFE_CTL_SFT			7
+#define MT6357_PDN_DAC_CTL_SFT			6
+#define MT6357_PDN_ADC_CTL_SFT			5
+#define MT6357_PDN_I2S_DL_CTL_SFT		3
+#define MT6357_PWR_CLK_DIS_CTL_SFT		2
+#define MT6357_PDN_AFE_TESTMODEL_CTL_SFT	1
+#define MT6357_PDN_RESERVED_SFT			0
+
+/* MT6357_AFUNC_AUD_CON0 */
+#define MT6357_CCI_AUD_ANACK_INVERT			BIT(15)
+#define MT6357_CCI_AUD_ANACK_NORMAL			0
+#define MT6357_CCI_AUDIO_FIFO_WPTR_SFT			12
+#define MT6357_CCI_SCRAMBLER_CG_ENABLE			BIT(11)
+#define MT6357_CCI_SCRAMBLER_CG_DISABLE			0
+#define MT6357_CCI_LCK_INV_OUT_OF_PHASE			BIT(10)
+#define MT6357_CCI_LCK_INV_IN_PHASE			0
+#define MT6357_CCI_RAND_ENABLE				BIT(9)
+#define MT6357_CCI_RAND_DISABLE				0
+#define MT6357_CCI_SPLT_SCRMB_CLK_ON			BIT(8)
+#define MT6357_CCI_SPLT_SCRMB_CLK_OFF			0
+#define MT6357_CCI_SPLT_SCRMB_ON			BIT(7)
+#define MT6357_CCI_SPLT_SCRMB_OFF			0
+#define MT6357_CCI_AUD_IDAC_TEST_EN_FROM_TEST_IN	BIT(6)
+#define MT6357_CCI_AUD_IDAC_TEST_EN_NORMAL_PATH		0
+#define MT6357_CCI_ZERO_PADDING_DISABLE			BIT(5)
+#define MT6357_CCI_ZERO_PADDING_ENABLE			0
+#define MT6357_CCI_AUD_SPLIT_TEST_EN_FROM_TEST_IN	BIT(4)
+#define MT6357_CCI_AUD_SPLIT_TEST_EN_NORMAL_PATH	0
+#define MT6357_CCI_AUD_SDM_MUTE_L_REG_CTL		BIT(3)
+#define MT6357_CCI_AUD_SDM_MUTE_L_NO_CTL		0
+#define MT6357_CCI_AUD_SDM_MUTE_R_REG_CTL		BIT(2)
+#define MT6357_CCI_AUD_SDM_MUTE_R_NO_CTL		0
+#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER3		BIT(1)
+#define MT6357_CCI_AUD_SDM_7BIT_FROM_SPLITTER1		0
+#define MT6357_CCI_SCRAMBLER_ENABLE			BIT(0)
+#define MT6357_CCI_SCRAMBLER_DISABLE			0
+
+/* MT6357_AFUNC_AUD_CON2 */
+#define MT6357_CCI_AUDIO_FIFO_ENABLE		BIT(3)
+#define MT6357_CCI_AUDIO_FIFO_DISABLE		0
+#define MT6357_CCI_ACD_MODE_NORMAL_PATH		BIT(2)
+#define MT6357_CCI_ACD_MODE_TEST_PATH		0
+#define MT6357_CCI_AFIFO_CLK_PWDB_ON		BIT(1)
+#define MT6357_CCI_AFIFO_CLK_PWDB_DOWN		0
+#define MT6357_CCI_ACD_FUNC_RSTB_RELEASE	BIT(0)
+#define MT6357_CCI_ACD_FUNC_RSTB_RESET		0
+
+/* MT6357_AFE_ADDA_MTKAIF_CFG0 */
+#define MT6357_ADDA_MTKAIF_LPBK_CTL_MASK	BIT(1)
+#define MT6357_ADDA_MTKAIF_LPBK_ENABLE		BIT(1)
+#define MT6357_ADDA_MTKAIF_LPBK_DISABLE		0
+
+/* MT6357_AFE_SGEN_CFG0 */
+#define MT6357_SGEN_DAC_EN_CTL_SFT		7
+#define MT6357_SGEN_DAC_ENABLE			BIT(7)
+#define MT6357_SGEN_MUTE_SW_CTL_SFT		6
+#define MT6357_SGEN_MUTE_SW_DISABLE		0
+
+/* MT6357_AFE_DCCLK_CFG0 */
+#define MT6357_DCCLK_DIV_MASK			GENMASK(15, 5)
+#define MT6357_DCCLK_DIV_SFT			5
+#define MT6357_DCCLK_DIV_RUN_VALUE		(32 << MT6357_DCCLK_DIV_SFT)
+#define MT6357_DCCLK_DIV_STOP_VALUE		(259 << MT6357_DCCLK_DIV_SFT)
+#define MT6357_DCCLK_PDN_MASK			BIT(1)
+#define MT6357_DCCLK_PDN			BIT(1)
+#define MT6357_DCCLK_OUTPUT			0
+#define MT6357_DCCLK_GEN_ON_MASK		BIT(0)
+#define MT6357_DCCLK_GEN_ON			BIT(0)
+#define MT6357_DCCLK_GEN_OFF			0
+
+/* MT6357_AFE_DCCLK_CFG1 */
+#define MT6357_DCCLK_RESYNC_BYPASS_MASK		BIT(8)
+#define MT6357_DCCLK_RESYNC_BYPASS		BIT(8)
+
+/* MT6357_AFE_AUD_PAD_TOP */
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK		GENMASK(15, 8)
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE	(BIT(13) | BIT(12) | BIT(8))
+#define MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE	(BIT(13) | BIT(12))
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_MASK		GENMASK(7, 0)
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE		(BIT(5) | BIT(4) | BIT(0))
+#define MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE		0
+
+/* MT6357_AUDENC_ANA_CON0 */
+#define MT6357_AUDADCLINPUTSEL_MASK		GENMASK(14, 13)
+#define MT6357_AUDADCLINPUTSEL_PREAMPLIFIER	BIT(14)
+#define MT6357_AUDADCLINPUTSEL_IDLE		0
+#define MT6357_AUDADCLPWRUP_SFT			12
+#define MT6357_AUDADCLPWRUP_MASK		BIT(12)
+#define MT6357_AUDADCLPWRUP			BIT(12)
+#define MT6357_AUDADCLPWRDOWN			0
+#define MT6357_AUDPREAMPLGAIN_SFT		8
+#define MT6357_AUDPREAMPLGAIN_MASK		GENMASK(10, 8)
+#define MT6357_AUDPREAMPLGAIN_MAX		4
+#define MT6357_AUDPREAMPLINPUTSEL_SFT		6
+#define MT6357_AUDPREAMPLINPUTSEL_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUDPREAMPLDCPRECHARGE_MASK	BIT(2)
+#define MT6357_AUDPREAMPLDCPRECHARGE_ENABLE	BIT(2)
+#define MT6357_AUDPREAMPLDCPRECHARGE_DISABLE	0
+#define MT6357_AUDPREAMPLDCCEN_MASK		BIT(1)
+#define MT6357_AUDPREAMPLDCCEN_DC		BIT(1)
+#define MT6357_AUDPREAMPLDCCEN_AC		0
+#define MT6357_AUDPREAMPLON_MASK		BIT(0)
+#define MT6357_AUDPREAMPLON_ENABLE		BIT(0)
+#define MT6357_AUDPREAMPLON_DISABLE		0
+
+/* MT6357_AUDENC_ANA_CON1 */
+#define MT6357_AUDADCRINPUTSEL_MASK		GENMASK(14, 13)
+#define MT6357_AUDADCRINPUTSEL_PREAMPLIFIER	BIT(14)
+#define MT6357_AUDADCRINPUTSEL_IDLE		0
+#define MT6357_AUDADCRPWRUP_SFT			12
+#define MT6357_AUDADCRPWRUP_MASK		BIT(12)
+#define MT6357_AUDADCRPWRUP			BIT(12)
+#define MT6357_AUDADCRPWRDOWN			0
+#define MT6357_AUDPREAMPRGAIN_SFT		8
+#define MT6357_AUDPREAMPRGAIN_MASK		GENMASK(10, 8)
+#define MT6357_AUDPREAMPRGAIN_MAX		4
+#define MT6357_AUDPREAMPRINPUTSEL_SFT		6
+#define MT6357_AUDPREAMPRINPUTSEL_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUDPREAMPRDCPRECHARGE_MASK	BIT(2)
+#define MT6357_AUDPREAMPRDCPRECHARGE_ENABLE	BIT(2)
+#define MT6357_AUDPREAMPRDCPRECHARGE_DISABLE	0
+#define MT6357_AUDPREAMPRDCCEN_MASK		BIT(1)
+#define MT6357_AUDPREAMPRDCCEN_DC		BIT(1)
+#define MT6357_AUDPREAMPRDCCEN_AC		0
+#define MT6357_AUDPREAMPRON_MASK		BIT(0)
+#define MT6357_AUDPREAMPRON_ENABLE		BIT(0)
+#define MT6357_AUDPREAMPRON_DISABLE		0
+
+/* MT6357_AUDENC_ANA_CON6 */
+#define MT6357_CLKSQ_EN_SFT			0
+
+/* MT6357_AUDENC_ANA_CON7 */
+#define MT6357_AUDDIGMICBIAS_MASK		GENMASK(2, 1)
+#define MT6357_AUDDIGMICBIAS_DEFAULT_VALUE	BIT(2)
+#define MT6357_AUDDIGMICBIAS_OFF		0
+#define MT6357_AUDDIGMICEN_MASK			BIT(0)
+#define MT6357_AUDDIGMICEN_ENABLE		BIT(0)
+#define MT6357_AUDDIGMICEN_DISABLE		0
+
+/* MT6357_AUDENC_ANA_CON8 */
+#define MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK	BIT(14)
+#define MT6357_AUD_MICBIAS0_DCSW2N_ENABLE	BIT(14)
+#define MT6357_AUD_MICBIAS0_DCSW2N_DISABLE	0
+#define MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK	BIT(13)
+#define MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE	BIT(13)
+#define MT6357_AUD_MICBIAS0_DCSW2P2_DISABLE	0
+#define MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK	BIT(12)
+#define MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE	BIT(12)
+#define MT6357_AUD_MICBIAS0_DCSW2P1_DISABLE	0
+#define MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK	BIT(10)
+#define MT6357_AUD_MICBIAS0_DCSW0N_ENABLE	BIT(10)
+#define MT6357_AUD_MICBIAS0_DCSWN_DISABLE	0
+#define MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK	BIT(9)
+#define MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE	BIT(9)
+#define MT6357_AUD_MICBIAS0_DCSW0P2_DISABLE	0
+#define MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK	BIT(8)
+#define MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE	BIT(8)
+#define MT6357_AUD_MICBIAS0_DCSW0P1_DISABLE	0
+#define MT6357_AUD_MICBIAS0_VREF_MASK		GENMASK(6, 4)
+#define MT6357_AUD_MICBIAS0_VREF_SFT		4
+#define MT6357_AUD_MICBIAS0_PWD_SFT		0
+
+#define MT6357_AUD_MICBIAS0_DC_MASK		(MT6357_AUD_MICBIAS0_DCSW2N_EN_MASK | \
+						 MT6357_AUD_MICBIAS0_DCSW2P2_EN_MASK | \
+						 MT6357_AUD_MICBIAS0_DCSW2P1_EN_MASK | \
+						 MT6357_AUD_MICBIAS0_DCSW0N_EN_MASK | \
+						 MT6357_AUD_MICBIAS0_DCSW0P2_EN_MASK | \
+						 MT6357_AUD_MICBIAS0_DCSW0P1_EN_MASK)
+
+#define MT6357_AUD_MICBIAS0_DC_ENABLE_ALL	(MT6357_AUD_MICBIAS0_DCSW2N_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW2P2_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW0N_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW0P2_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define MT6357_AUD_MICBIAS0_DC_ENABLE_P1	(MT6357_AUD_MICBIAS0_DCSW2P1_ENABLE | \
+						 MT6357_AUD_MICBIAS0_DCSW0P1_ENABLE)
+
+#define MT6357_AUD_MICBIAS0_DC_DISABLE_ALL	0
+
+/* MT6357_AUDENC_ANA_CON9 */
+#define MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK	BIT(8)
+#define MT6357_AUD_MICBIAS1_DCSW1P_ENABLE	BIT(8)
+#define MT6357_AUD_MICBIAS1_DCSW1P_DISABLE	0
+#define MT6357_AUD_MICBIAS1_VREF_MASK		GENMASK(6, 4)
+#define MT6357_AUD_MICBIAS1_VREF_SFT		4
+#define MT6357_AUD_MICBIAS1_PWD_SFT		0
+
+/* MT6357_AUDDEC_ANA_CON0 */
+#define MT6357_AUD_HPR_SC_VAUDP15_MASK			BIT(13)
+#define MT6357_AUD_HPR_SC_VAUDP15_DISABLE		BIT(13)
+#define MT6357_AUD_HPR_SC_VAUDP15_ENABLE		0
+#define MT6357_AUD_HPL_SC_VAUDP15_MASK			BIT(12)
+#define MT6357_AUD_HPL_SC_VAUDP15_DISABLE		BIT(12)
+#define MT6357_AUD_HPL_SC_VAUDP15_ENABLE		0
+#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT		10
+#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT		8
+#define MT6357_AUD_HPR_BIAS_VAUDP15_MASK		BIT(7)
+#define MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE		BIT(7)
+#define MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE		0
+#define MT6357_AUD_HPL_BIAS_VAUDP15_MASK		BIT(6)
+#define MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE		BIT(6)
+#define MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE		0
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_MASK		BIT(5)
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE		BIT(5)
+#define MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE		0
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_MASK		BIT(4)
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE		BIT(4)
+#define MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE		0
+#define MT6357_AUD_DACL_PWRUP_VA28_MASK			BIT(3)
+#define MT6357_AUD_DACL_PWRUP_VA28_ENABLE		BIT(3)
+#define MT6357_AUD_DACL_PWRUP_VA28_DISABLE		0
+#define MT6357_AUD_DACR_PWRUP_VA28_MASK			BIT(2)
+#define MT6357_AUD_DACR_PWRUP_VA28_ENABLE		BIT(2)
+#define MT6357_AUD_DACR_PWRUP_VA28_DISABLE		0
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_MASK		BIT(1)
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE		BIT(1)
+#define MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE		0
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_MASK		BIT(0)
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE		BIT(0)
+#define MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE		0
+
+/* MT6357_AUDDEC_ANA_CON1 */
+#define MT6357_HPROUT_STG_CTRL_VAUDP15_MASK		GENMASK(14, 12)
+#define MT6357_HPROUT_STG_CTRL_VAUDP15_SFT		12
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK		GENMASK(10, 8)
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT		8
+#define MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX		7
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK		BIT(7)
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE		BIT(7)
+#define MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE	0
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK		BIT(6)
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE		BIT(6)
+#define MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE	0
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_MASK		BIT(5)
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE		BIT(5)
+#define MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE		0
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_MASK		BIT(4)
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE		BIT(4)
+#define MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE		0
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK		BIT(3)
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE		BIT(3)
+#define MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE	0
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK		BIT(2)
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE		BIT(2)
+#define MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE	0
+#define MT6357_HPROUT_PWRUP_VAUDP15_MASK		BIT(1)
+#define MT6357_HPROUT_PWRUP_VAUDP15_ENABLE		BIT(1)
+#define MT6357_HPROUT_PWRUP_VAUDP15_DISABLE		0
+#define MT6357_HPLOUT_PWRUP_VAUDP15_MASK		BIT(0)
+#define MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE		BIT(0)
+#define MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE		0
+
+/* MT6357_AUDDEC_ANA_CON2 */
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_MASK		BIT(10)
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE		BIT(10)
+#define MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE		0
+#define MT6357_AUD_REFN_DERES_VAUDP15_MASK		BIT(9)
+#define MT6357_AUD_REFN_DERES_VAUDP15_ENABLE		BIT(9)
+#define MT6357_AUD_REFN_DERES_VAUDP15_DISABLE		0
+#define MT6357_HPROUT_STB_ENH_VAUDP15_MASK		GENMASK(6, 4)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_OPEN		0
+#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P250	BIT(4)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_POPEN	BIT(5)
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250		(BIT(4) | BIT(5))
+#define MT6357_HPROUT_STB_ENH_VAUDP15_NOPEN_P470	(BIT(4) | BIT(6))
+#define MT6357_HPROUT_STB_ENH_VAUDP15_N470_P470		(BIT(4) | BIT(5) | BIT(6))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_MASK		GENMASK(2, 0)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_OPEN		0
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P250	BIT(0)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_POPEN	BIT(1)
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250		(BIT(0) | BIT(1))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_NOPEN_P470	(BIT(0) | BIT(2))
+#define MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P470		(BIT(0) | BIT(1) | BIT(2))
+
+/* MT6357_AUDDEC_ANA_CON3 */
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK		BIT(7)
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE		BIT(7)
+#define MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE	0
+#define MT6357_AUD_HS_SC_VAUDP15_MASK			BIT(4)
+#define MT6357_AUD_HS_SC_VAUDP15_DISABLE		BIT(4)
+#define MT6357_AUD_HS_SC_VAUDP15_ENABLE			0
+#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT		2
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK		BIT(1)
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE		BIT(1)
+#define MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_DISABLE	0
+#define MT6357_AUD_HS_PWRUP_VAUDP15_MASK		BIT(0)
+#define MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE		BIT(0)
+#define MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE		0
+
+/* MT6357_AUDDEC_ANA_CON4 */
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK		BIT(8)
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE	BIT(8)
+#define MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE	0
+#define MT6357_AUD_LOL_SC_VAUDP15_MASK			BIT(4)
+#define MT6357_AUD_LOL_SC_VAUDP15_DISABLE		BIT(4)
+#define MT6357_AUD_LOL_SC_VAUDP15_ENABLE		0
+#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_MASK_NOSFT	GENMASK(1, 0)
+#define MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT		2
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK		BIT(1)
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE	BIT(1)
+#define MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE	0
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_MASK		BIT(0)
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE		BIT(0)
+#define MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE		0
+
+/* MT6357_AUDDEC_ANA_CON6 */
+#define MT6357_HP_AUX_LOOP_GAIN_MASK		GENMASK(15, 12)
+#define MT6357_HP_AUX_LOOP_GAIN_SFT		12
+#define MT6357_HP_AUX_LOOP_GAIN_MAX		0x0f
+#define MT6357_HPR_AUX_CMFB_LOOP_MASK		BIT(11)
+#define MT6357_HPR_AUX_CMFB_LOOP_ENABLE		BIT(11)
+#define MT6357_HPR_AUX_CMFB_LOOP_DISABLE	0
+#define MT6357_HPL_AUX_CMFB_LOOP_MASK		BIT(10)
+#define MT6357_HPL_AUX_CMFB_LOOP_ENABLE		BIT(10)
+#define MT6357_HPL_AUX_CMFB_LOOP_DISABLE	0
+#define MT6357_HPRL_MAIN_CMFB_LOOP_MASK		BIT(9)
+#define MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE	BIT(9)
+#define MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE	0
+#define MT6357_HP_CMFB_RST_MASK			BIT(7)
+#define MT6357_HP_CMFB_RST_NORMAL		BIT(7)
+#define MT6357_HP_CMFB_RST_RESET		0
+#define MT6357_DAC_LOW_NOISE_MODE_MASK		BIT(0)
+#define MT6357_DAC_LOW_NOISE_MODE_ENABLE	BIT(0)
+#define MT6357_DAC_LOW_NOISE_MODE_DISABLE	0
+
+/* MT6357_AUDDEC_ANA_CON7 */
+#define MT6357_HP_IVBUF_DEGAIN_SFT		2
+#define MT6357_HP_IVBUF_DEGAIN_MAX		1
+
+/* MT6357_AUDDEC_ANA_CON10 */
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK	BIT(8)
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE	BIT(8)
+#define MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE	0
+
+/* MT6357_AUDDEC_ANA_CON11 */
+#define MT6357_RSTB_ENCODER_VA28_MASK		BIT(5)
+#define MT6357_RSTB_ENCODER_VA28_ENABLE		BIT(5)
+#define MT6357_RSTB_ENCODER_VA28_DISABLE	0
+#define MT6357_AUDGLB_PWRDN_VA28_SFT		4
+#define MT6357_RSTB_DECODER_VA28_MASK		BIT(0)
+#define MT6357_RSTB_DECODER_VA28_ENABLE		BIT(0)
+#define MT6357_RSTB_DECODER_VA28_DISABLE	0
+
+/* MT6357_AUDDEC_ANA_CON12 */
+#define MT6357_VA28REFGEN_EN_VA28_MASK			BIT(13)
+#define MT6357_VA28REFGEN_EN_VA28_ENABLE		BIT(13)
+#define MT6357_VA28REFGEN_EN_VA28_DISABLE		0
+#define MT6357_VA33REFGEN_EN_VA18_MASK			BIT(12)
+#define MT6357_VA33REFGEN_EN_VA18_ENABLE		BIT(12)
+#define MT6357_VA33REFGEN_EN_VA18_DISABLE		0
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK		BIT(10)
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE	BIT(10)
+#define MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE	0
+#define MT6357_LCLDO_ENC_EN_VA28_MASK			BIT(8)
+#define MT6357_LCLDO_ENC_EN_VA28_ENABLE			BIT(8)
+#define MT6357_LCLDO_ENC_EN_VA28_DISABLE		0
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_MASK		BIT(6)
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE		BIT(6)
+#define MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE		0
+#define MT6357_LCLDO_EN_VA18_MASK			BIT(4)
+#define MT6357_LCLDO_EN_VA18_ENABLE			BIT(4)
+#define MT6357_LCLDO_EN_VA18_DISABLE			0
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_MASK		BIT(2)
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE		BIT(2)
+#define MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE		0
+#define MT6357_HCLDO_EN_VA18_MASK			BIT(0)
+#define MT6357_HCLDO_EN_VA18_ENABLE			BIT(0)
+#define MT6357_HCLDO_EN_VA18_DISABLE			0
+
+/* MT6357_AUDDEC_ANA_CON13 */
+#define MT6357_NVREG_EN_VAUDP15_MASK		BIT(0)
+#define MT6357_NVREG_EN_VAUDP15_ENABLE		BIT(0)
+#define MT6357_NVREG_EN_VAUDP15_DISABLE		0
+
+/* MT6357_AUDDEC_ELR_0 */
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK	BIT(12)
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE	BIT(12)
+#define MT6357_AUD_HP_TRIM_EN_VAUDP15_DISABLE	0
+
+/* MT6357_ZCD_CON1 */
+#define MT6357_AUD_LOL_GAIN_MASK		GENMASK(4, 0)
+#define MT6357_AUD_LOL_GAIN_SFT			0
+#define MT6357_AUD_LOR_GAIN_MASK		GENMASK(11, 7)
+#define MT6357_AUD_LOR_GAIN_SFT			7
+#define MT6357_AUD_LO_GAIN_MAX			0x12
+
+/* MT6357_ZCD_CON2 */
+#define MT6357_AUD_HPL_GAIN_MASK		GENMASK(4, 0)
+#define MT6357_AUD_HPL_GAIN_SFT			0
+#define MT6357_AUD_HPR_GAIN_MASK		GENMASK(11, 7)
+#define MT6357_AUD_HPR_GAIN_SFT			7
+#define MT6357_AUD_HP_GAIN_MAX			0x12
+
+/* MT6357_ZCD_CON3 */
+#define MT6357_AUD_HS_GAIN_MASK			GENMASK(4, 0)
+#define MT6357_AUD_HS_GAIN_SFT			0
+#define MT6357_AUD_HS_GAIN_MAX			0x12
+
+/* Registers list */
+/* gpio direction */
+#define MT6357_GPIO_DIR0			0x0088
+/* mosi */
+#define MT6357_GPIO_MODE2			0x00B6
+#define MT6357_GPIO_MODE2_SET			0x00B8
+#define MT6357_GPIO_MODE2_CLR			0x00BA
+/* miso */
+#define MT6357_GPIO_MODE3			0x00BC
+#define MT6357_GPIO_MODE3_SET			0x00BE
+#define MT6357_GPIO_MODE3_CLR			0x00C0
+
+#define MT6357_DCXO_CW14			0x07AC
+
+#define MT6357_AUD_TOP_CKPDN_CON0		0x208C
+#define MT6357_AUDNCP_CLKDIV_CON0		0x20B4
+#define MT6357_AUDNCP_CLKDIV_CON1		0x20B6
+#define MT6357_AUDNCP_CLKDIV_CON2		0x20B8
+#define MT6357_AUDNCP_CLKDIV_CON3		0x20BA
+#define MT6357_AUDNCP_CLKDIV_CON4		0x20BC
+#define MT6357_AFE_UL_DL_CON0			0x2108
+#define MT6357_AFE_DL_SRC2_CON0_L		0x210A
+#define MT6357_AFE_UL_SRC_CON0_H		0x210C
+#define MT6357_AFE_UL_SRC_CON0_L		0x210E
+#define MT6357_AFE_TOP_CON0			0x2110
+#define MT6357_AUDIO_TOP_CON0			0x2112
+#define MT6357_AFUNC_AUD_CON0			0x2116
+#define MT6357_AFUNC_AUD_CON2			0x211A
+#define MT6357_AFE_ADDA_MTKAIF_CFG0		0x2134
+#define MT6357_AFE_SGEN_CFG0			0x2140
+#define MT6357_AFE_DCCLK_CFG0			0x2146
+#define MT6357_AFE_DCCLK_CFG1			0x2148
+#define MT6357_AFE_AUD_PAD_TOP			0x214C
+#define MT6357_AUDENC_ANA_CON0			0x2188
+#define MT6357_AUDENC_ANA_CON1			0x218A
+#define MT6357_AUDENC_ANA_CON6			0x2194
+#define MT6357_AUDENC_ANA_CON7			0x2196
+#define MT6357_AUDENC_ANA_CON8			0x2198
+#define MT6357_AUDENC_ANA_CON9			0x219A
+#define MT6357_AUDDEC_ANA_CON0			0x2208
+#define MT6357_AUDDEC_ANA_CON1			0x220A
+#define MT6357_AUDDEC_ANA_CON2			0x220C
+#define MT6357_AUDDEC_ANA_CON3			0x220E
+#define MT6357_AUDDEC_ANA_CON4			0x2210
+#define MT6357_AUDDEC_ANA_CON6			0x2214
+#define MT6357_AUDDEC_ANA_CON7			0x2216
+#define MT6357_AUDDEC_ANA_CON10			0x221C
+#define MT6357_AUDDEC_ANA_CON11			0x221E
+#define MT6357_AUDDEC_ANA_CON12			0x2220
+#define MT6357_AUDDEC_ANA_CON13			0x2222
+#define MT6357_AUDDEC_ELR_0			0x2226
+#define MT6357_ZCD_CON1				0x228A
+#define MT6357_ZCD_CON2				0x228C
+#define MT6357_ZCD_CON3				0x228E
+
+enum {
+	DL_GAIN_8DB = 0,
+	DL_GAIN_0DB = 8,
+	DL_GAIN_N_1DB = 9,
+	DL_GAIN_N_10DB = 18,
+	DL_GAIN_N_12DB = 20,
+	DL_GAIN_N_40DB = 0x1f,
+};
+
+enum {
+	UL_GAIN_0DB = 0,
+	UL_GAIN_6DB,
+	UL_GAIN_12DB,
+	UL_GAIN_18DB,
+	UL_GAIN_24DB,
+};
+
+#define MT6357_DL_GAIN_N_40DB_REG		(DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
+#define MT6357_DL_GAIN_REG_LEFT_MASK		0x001f
+#define MT6357_DL_GAIN_REG_LEFT_SHIFT		0
+#define MT6357_DL_GAIN_REG_RIGHT_MASK		0x0f80
+#define MT6357_DL_GAIN_REG_RIGHT_SHIFT		7
+#define MT6357_DL_GAIN_REG_MASK			0x0f9f
+
+#define MT6357_SND_SOC_ADV_MT_FMTS (\
+				SNDRV_PCM_FMTBIT_S16_LE |\
+				SNDRV_PCM_FMTBIT_S16_BE |\
+				SNDRV_PCM_FMTBIT_U16_LE |\
+				SNDRV_PCM_FMTBIT_U16_BE |\
+				SNDRV_PCM_FMTBIT_S24_LE |\
+				SNDRV_PCM_FMTBIT_S24_BE |\
+				SNDRV_PCM_FMTBIT_U24_LE |\
+				SNDRV_PCM_FMTBIT_U24_BE |\
+				SNDRV_PCM_FMTBIT_S32_LE |\
+				SNDRV_PCM_FMTBIT_S32_BE |\
+				SNDRV_PCM_FMTBIT_U32_LE |\
+				SNDRV_PCM_FMTBIT_U32_BE)
+
+#define MT6357_SOC_HIGH_USE_RATE (\
+				SNDRV_PCM_RATE_CONTINUOUS |\
+				SNDRV_PCM_RATE_8000_192000)
+
+#define MT6357_MICBIAS_ARRAY_SIZE	8
+
+/* codec private structure */
+struct mt6357_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	bool pull_down_needed;
+	int hp_channel_number;
+};
+#endif

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 12/18] ASoC: mediatek: mt8365: Add platform driver
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add mt8365 platform driver.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-afe-pcm.c | 2275 ++++++++++++++++++++++++++++
 1 file changed, 2275 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
new file mode 100644
index 000000000000..ae99f8bdd251
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
@@ -0,0 +1,2275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC AFE platform driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ *          Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-common.h"
+#include "mt8365-afe-clk.h"
+#include "mt8365-reg.h"
+#include "../common/mtk-base-afe.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#define AFE_BASE_END_OFFSET 8
+
+static unsigned int mCM2Input;
+
+static const unsigned int mt8365_afe_backup_list[] = {
+	AUDIO_TOP_CON0,
+	AFE_CONN0,
+	AFE_CONN1,
+	AFE_CONN3,
+	AFE_CONN4,
+	AFE_CONN5,
+	AFE_CONN6,
+	AFE_CONN7,
+	AFE_CONN8,
+	AFE_CONN9,
+	AFE_CONN10,
+	AFE_CONN11,
+	AFE_CONN12,
+	AFE_CONN13,
+	AFE_CONN14,
+	AFE_CONN15,
+	AFE_CONN16,
+	AFE_CONN17,
+	AFE_CONN18,
+	AFE_CONN19,
+	AFE_CONN20,
+	AFE_CONN21,
+	AFE_CONN26,
+	AFE_CONN27,
+	AFE_CONN28,
+	AFE_CONN29,
+	AFE_CONN30,
+	AFE_CONN31,
+	AFE_CONN32,
+	AFE_CONN33,
+	AFE_CONN34,
+	AFE_CONN35,
+	AFE_CONN36,
+	AFE_CONN_24BIT,
+	AFE_CONN_24BIT_1,
+	AFE_DAC_CON0,
+	AFE_DAC_CON1,
+	AFE_DL1_BASE,
+	AFE_DL1_END,
+	AFE_DL2_BASE,
+	AFE_DL2_END,
+	AFE_VUL_BASE,
+	AFE_VUL_END,
+	AFE_AWB_BASE,
+	AFE_AWB_END,
+	AFE_VUL3_BASE,
+	AFE_VUL3_END,
+	AFE_HDMI_OUT_BASE,
+	AFE_HDMI_OUT_END,
+	AFE_HDMI_IN_2CH_BASE,
+	AFE_HDMI_IN_2CH_END,
+	AFE_ADDA_UL_DL_CON0,
+	AFE_ADDA_DL_SRC2_CON0,
+	AFE_ADDA_DL_SRC2_CON1,
+	AFE_I2S_CON,
+	AFE_I2S_CON1,
+	AFE_I2S_CON2,
+	AFE_I2S_CON3,
+	AFE_ADDA_UL_SRC_CON0,
+	AFE_AUD_PAD_TOP,
+	AFE_HD_ENGEN_ENABLE,
+};
+
+static const struct snd_pcm_hardware mt8365_afe_hardware = {
+	.info = (SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP_VALID),
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 512,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.fifo_size = 0,
+};
+
+struct mt8365_afe_rate {
+	unsigned int rate;
+	unsigned int reg_val;
+};
+
+static const struct mt8365_afe_rate mt8365_afe_fs_rates[] = {
+	{ .rate = 8000, .reg_val = MT8365_FS_8K },
+	{ .rate = 11025, .reg_val = MT8365_FS_11D025K },
+	{ .rate = 12000, .reg_val = MT8365_FS_12K },
+	{ .rate = 16000, .reg_val = MT8365_FS_16K },
+	{ .rate = 22050, .reg_val = MT8365_FS_22D05K },
+	{ .rate = 24000, .reg_val = MT8365_FS_24K },
+	{ .rate = 32000, .reg_val = MT8365_FS_32K },
+	{ .rate = 44100, .reg_val = MT8365_FS_44D1K },
+	{ .rate = 48000, .reg_val = MT8365_FS_48K },
+	{ .rate = 88200, .reg_val = MT8365_FS_88D2K },
+	{ .rate = 96000, .reg_val = MT8365_FS_96K },
+	{ .rate = 176400, .reg_val = MT8365_FS_176D4K },
+	{ .rate = 192000, .reg_val = MT8365_FS_192K },
+};
+
+int mt8365_afe_fs_timing(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mt8365_afe_fs_rates); i++)
+		if (mt8365_afe_fs_rates[i].rate == rate)
+			return mt8365_afe_fs_rates[i].reg_val;
+
+	return -EINVAL;
+}
+
+bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id)
+{
+	switch (id) {
+	case MT8365_AFE_IO_TDM_IN:
+		if (rate >= 8000 && rate <= 192000)
+			return true;
+		break;
+	case MT8365_AFE_IO_DMIC:
+		if (rate >= 8000 && rate <= 48000)
+			return true;
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
+bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id)
+{
+	switch (id) {
+	case MT8365_AFE_IO_TDM_IN:
+		if (channel >= 1 && channel <= 8)
+			return true;
+		break;
+	case MT8365_AFE_IO_DMIC:
+		if (channel >= 1 && channel <= 8)
+			return true;
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
+bool mt8365_afe_clk_group_44k(int sample_rate)
+{
+	if (sample_rate == 11025 ||
+	    sample_rate == 22050 ||
+	    sample_rate == 44100 ||
+	    sample_rate == 88200 ||
+	    sample_rate == 176400)
+		return true;
+	else
+		return false;
+}
+
+bool mt8365_afe_clk_group_48k(int sample_rate)
+{
+	return (!mt8365_afe_clk_group_44k(sample_rate));
+}
+
+int mt8365_dai_set_priv(struct mtk_base_afe *afe, int id,
+			int priv_size, const void *priv_data)
+{
+	struct mt8365_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;
+}
+
+static int mt8365_afe_irq_direction_enable(struct mtk_base_afe *afe,
+					   int irq_id, int direction)
+{
+	struct mtk_base_afe_irq *irq;
+
+	if (irq_id >= MT8365_AFE_IRQ_NUM)
+		return -1;
+
+	irq = &afe->irqs[irq_id];
+
+	if (direction == MT8365_AFE_IRQ_DIR_MCU) {
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   0);
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   (1 << irq->irq_data->irq_clr_shift));
+	} else if (direction == MT8365_AFE_IRQ_DIR_DSP) {
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   (1 << irq->irq_data->irq_clr_shift));
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   0);
+	} else {
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   (1 << irq->irq_data->irq_clr_shift));
+		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN,
+				   (1 << irq->irq_data->irq_clr_shift),
+				   (1 << irq->irq_data->irq_clr_shift));
+	}
+	return 0;
+}
+
+static int mt8365_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	return mt8365_afe_fs_timing(rate);
+}
+
+static int mt8365_irq_fs(struct snd_pcm_substream *substream,
+			 unsigned int rate)
+{
+	return mt8365_memif_fs(substream, rate);
+}
+
+static const struct mt8365_cm_ctrl_reg cm_ctrl_reg[MT8365_CM_NUM] = {
+	[MT8365_CM1] = {
+		.con0 = AFE_CM1_CON0,
+		.con1 = AFE_CM1_CON1,
+		.con2 = AFE_CM1_CON2,
+		.con3 = AFE_CM1_CON3,
+		.con4 = AFE_CM1_CON4,
+	},
+	[MT8365_CM2] = {
+		.con0 = AFE_CM2_CON0,
+		.con1 = AFE_CM2_CON1,
+		.con2 = AFE_CM2_CON2,
+		.con3 = AFE_CM2_CON3,
+		.con4 = AFE_CM2_CON4,
+	}
+};
+
+static int mt8365_afe_cm2_mux_conn(struct mtk_base_afe *afe)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	unsigned int input = afe_priv->cm2_mux_input;
+
+	/* TDM_IN interconnect to CM2 */
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG1_MASK,
+			   CM2_AFE_CM2_CONN_CFG1(TDM_IN_CH0));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG2_MASK,
+			   CM2_AFE_CM2_CONN_CFG2(TDM_IN_CH1));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG3_MASK,
+			   CM2_AFE_CM2_CONN_CFG3(TDM_IN_CH2));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG4_MASK,
+			   CM2_AFE_CM2_CONN_CFG4(TDM_IN_CH3));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG5_MASK,
+			   CM2_AFE_CM2_CONN_CFG5(TDM_IN_CH4));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN0,
+			   CM2_AFE_CM2_CONN_CFG6_MASK,
+			   CM2_AFE_CM2_CONN_CFG6(TDM_IN_CH5));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+			   CM2_AFE_CM2_CONN_CFG7_MASK,
+			   CM2_AFE_CM2_CONN_CFG7(TDM_IN_CH6));
+	regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+			   CM2_AFE_CM2_CONN_CFG8_MASK,
+			   CM2_AFE_CM2_CONN_CFG8(TDM_IN_CH7));
+
+	/* ref data interconnect to CM2 */
+	if (input == MT8365_FROM_GASRC1) {
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG9_MASK,
+				   CM2_AFE_CM2_CONN_CFG9(GENERAL1_ASRC_OUT_LCH));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG10_MASK,
+				   CM2_AFE_CM2_CONN_CFG10(GENERAL1_ASRC_OUT_RCH));
+	} else if (input == MT8365_FROM_GASRC2) {
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG9_MASK,
+				   CM2_AFE_CM2_CONN_CFG9(GENERAL2_ASRC_OUT_LCH));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG10_MASK,
+				   CM2_AFE_CM2_CONN_CFG10(GENERAL2_ASRC_OUT_RCH));
+	} else if (input == MT8365_FROM_TDM_ASRC) {
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG9_MASK,
+				   CM2_AFE_CM2_CONN_CFG9(TDM_OUT_ASRC_CH0));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG10_MASK,
+				   CM2_AFE_CM2_CONN_CFG10(TDM_OUT_ASRC_CH1));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG11_MASK,
+				   CM2_AFE_CM2_CONN_CFG11(TDM_OUT_ASRC_CH2));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN1,
+				   CM2_AFE_CM2_CONN_CFG12_MASK,
+				   CM2_AFE_CM2_CONN_CFG12(TDM_OUT_ASRC_CH3));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+				   CM2_AFE_CM2_CONN_CFG13_MASK,
+				   CM2_AFE_CM2_CONN_CFG13(TDM_OUT_ASRC_CH4));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+				   CM2_AFE_CM2_CONN_CFG14_MASK,
+				   CM2_AFE_CM2_CONN_CFG14(TDM_OUT_ASRC_CH5));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+				   CM2_AFE_CM2_CONN_CFG15_MASK,
+				   CM2_AFE_CM2_CONN_CFG15(TDM_OUT_ASRC_CH6));
+		regmap_update_bits(afe->regmap, AFE_CM2_CONN2,
+				   CM2_AFE_CM2_CONN_CFG16_MASK,
+				   CM2_AFE_CM2_CONN_CFG16(TDM_OUT_ASRC_CH7));
+	} else {
+		dev_err(afe->dev, "%s wrong CM2 input %d\n", __func__, input);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int mt8365_afe_get_cm_update_cnt(struct mtk_base_afe *afe,
+					enum mt8365_cm_num cmNum,
+					unsigned int rate, unsigned int channel)
+{
+	unsigned int total_cnt, div_cnt, ch_pair, best_cnt;
+	unsigned int ch_update_cnt[MT8365_CM_UPDATA_CNT_SET];
+	int i;
+
+	/* calculate cm update cnt
+	 * total_cnt = clk / fs, clk is 26m or 24m or 22m
+	 * div_cnt = total_cnt / ch_pair, max ch 16ch ,2ch is a set
+	 * best_cnt < div_cnt ,we set best_cnt = div_cnt -10
+	 * ch01 = best_cnt, ch23 = 2* ch01_up_cnt
+	 * ch45 = 3* ch01_up_cnt ...ch1415 = 8* ch01_up_cnt
+	 */
+
+	if (cmNum == MT8365_CM1) {
+		total_cnt = MT8365_CLK_26M / rate;
+	} else if (cmNum == MT8365_CM2) {
+		if (mt8365_afe_clk_group_48k(rate))
+			total_cnt = MT8365_CLK_24M / rate;
+		else
+			total_cnt = MT8365_CLK_22M / rate;
+	} else {
+		return -1;
+	}
+
+	if (channel % 2)
+		ch_pair = (channel / 2) + 1;
+	else
+		ch_pair = channel / 2;
+
+	div_cnt =  total_cnt / ch_pair;
+	best_cnt = div_cnt - 10;
+
+	if (best_cnt <= 0)
+		return -1;
+
+	for (i = 0; i < ch_pair; i++)
+		ch_update_cnt[i] = (i + 1) * best_cnt;
+
+	switch (channel) {
+	case 16:
+		fallthrough;
+	case 15:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+				   CM_AFE_CM_UPDATE_CNT2_MASK,
+				   CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[7]));
+		fallthrough;
+	case 14:
+		fallthrough;
+	case 13:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4,
+				   CM_AFE_CM_UPDATE_CNT1_MASK,
+				   CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[6]));
+		fallthrough;
+	case 12:
+		fallthrough;
+	case 11:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+				   CM_AFE_CM_UPDATE_CNT2_MASK,
+				   CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[5]));
+		fallthrough;
+	case 10:
+		fallthrough;
+	case 9:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3,
+				   CM_AFE_CM_UPDATE_CNT1_MASK,
+				   CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[4]));
+		fallthrough;
+	case 8:
+		fallthrough;
+	case 7:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+				   CM_AFE_CM_UPDATE_CNT2_MASK,
+				   CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[3]));
+		fallthrough;
+	case 6:
+		fallthrough;
+	case 5:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2,
+				   CM_AFE_CM_UPDATE_CNT1_MASK,
+				   CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[2]));
+		fallthrough;
+	case 4:
+		fallthrough;
+	case 3:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+				   CM_AFE_CM_UPDATE_CNT2_MASK,
+				   CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[1]));
+		fallthrough;
+	case 2:
+		fallthrough;
+	case 1:
+		regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1,
+				   CM_AFE_CM_UPDATE_CNT1_MASK,
+				   CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[0]));
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int mt8365_afe_configure_cm(struct mtk_base_afe *afe,
+				   enum mt8365_cm_num cmNum,
+				   unsigned int channels,
+				   unsigned int rate)
+{
+	unsigned int val, mask;
+	unsigned int fs = mt8365_afe_fs_timing(rate);
+
+	val = FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, (channels - 1)) |
+	      FIELD_PREP(CM_AFE_CM_START_DATA_MASK, 0);
+
+	mask = CM_AFE_CM_CH_NUM_MASK |
+	       CM_AFE_CM_START_DATA_MASK;
+
+	if (cmNum == MT8365_CM1) {
+		val |= FIELD_PREP(CM_AFE_CM1_IN_MODE_MASK, fs);
+
+		mask |= CM_AFE_CM1_VUL_SEL |
+			CM_AFE_CM1_IN_MODE_MASK;
+	} else if (cmNum == MT8365_CM2) {
+		if (mt8365_afe_clk_group_48k(rate))
+			val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 0);
+		else
+			val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 1);
+
+		val |= FIELD_PREP(CM_AFE_CM2_TDM_SEL, 1);
+
+		mask |= CM_AFE_CM2_TDM_SEL |
+			CM_AFE_CM1_IN_MODE_MASK |
+			CM_AFE_CM2_CLK_SEL;
+
+		mt8365_afe_cm2_mux_conn(afe);
+	} else {
+		return -1;
+	}
+
+	regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con0, mask, val);
+
+	mt8365_afe_get_cm_update_cnt(afe, cmNum, rate, channels);
+
+	return 0;
+}
+
+int mt8365_afe_fe_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+	int ret;
+
+	memif->substream = substream;
+
+	snd_pcm_hw_constraint_step(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+	snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+	mt8365_afe_enable_main_clk(afe);
+	return ret;
+}
+
+static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+
+	memif->substream = NULL;
+
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params,
+				   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+	int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+	struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+	size_t request_size = params_buffer_bytes(params);
+	unsigned int channels = params_channels(params);
+	unsigned int rate = params_rate(params);
+	unsigned int base_end_offset = 8;
+	int ret, fs;
+
+	dev_info(afe->dev, "%s %s period = %d rate = %d channels = %d\n",
+		 __func__, memif->data->name, params_period_size(params),
+		 rate, channels);
+
+	if (dai_id == MT8365_AFE_MEMIF_VUL2) {
+		if (!ctrl_data->bypass_cm1)
+			/* configure cm1 */
+			mt8365_afe_configure_cm(afe, MT8365_CM1,
+						channels, rate);
+		else
+			regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+					   CM_AFE_CM1_VUL_SEL,
+					   CM_AFE_CM1_VUL_SEL);
+	} else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+		if (!ctrl_data->bypass_cm2)
+			/* configure cm2 */
+			mt8365_afe_configure_cm(afe, MT8365_CM2,
+						channels, rate);
+		else
+			regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+					   CM_AFE_CM2_TDM_SEL,
+					   ~CM_AFE_CM2_TDM_SEL);
+
+		base_end_offset = 4;
+	}
+
+	if (request_size > fe_data->sram_size) {
+		ret = snd_pcm_lib_malloc_pages(substream, request_size);
+		if (ret < 0) {
+			dev_err(afe->dev,
+				"%s %s malloc pages %zu bytes failed %d\n",
+				__func__, memif->data->name, request_size, ret);
+			return ret;
+		}
+
+		fe_data->use_sram = false;
+
+		mt8365_afe_emi_clk_on(afe);
+	} else {
+		struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+
+		dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+		dma_buf->dev.dev = substream->pcm->card->dev;
+		dma_buf->area = (unsigned char *)fe_data->sram_vir_addr;
+		dma_buf->addr = fe_data->sram_phy_addr;
+		dma_buf->bytes = request_size;
+		snd_pcm_set_runtime_buffer(substream, dma_buf);
+
+		fe_data->use_sram = true;
+	}
+
+	memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
+	memif->buffer_size = substream->runtime->dma_bytes;
+
+	/* start */
+	regmap_write(afe->regmap, memif->data->reg_ofs_base,
+		     memif->phys_buf_addr);
+	/* end */
+	regmap_write(afe->regmap,
+		     memif->data->reg_ofs_base + base_end_offset,
+		     memif->phys_buf_addr + memif->buffer_size - 1);
+
+	/* set channel */
+	if (memif->data->mono_shift >= 0) {
+		unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
+
+		if (memif->data->mono_reg < 0)
+			dev_info(afe->dev, "%s mono_reg is NULL\n", __func__);
+		else
+			regmap_update_bits(afe->regmap, memif->data->mono_reg,
+					   1 << memif->data->mono_shift,
+					   mono << memif->data->mono_shift);
+	}
+
+	/* set rate */
+	if (memif->data->fs_shift < 0)
+		return 0;
+
+	fs = afe->memif_fs(substream, params_rate(params));
+
+	if (fs < 0)
+		return -EINVAL;
+
+	if (memif->data->fs_reg < 0)
+		dev_info(afe->dev, "%s fs_reg is NULL\n", __func__);
+	else
+		regmap_update_bits(afe->regmap, memif->data->fs_reg,
+				   memif->data->fs_maskbit << memif->data->fs_shift,
+				   fs << memif->data->fs_shift);
+
+	return 0;
+}
+
+static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+	struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id];
+	int ret = 0;
+
+	if (fe_data->use_sram) {
+		snd_pcm_set_runtime_buffer(substream, NULL);
+	} else {
+		ret = snd_pcm_lib_free_pages(substream);
+
+		mt8365_afe_emi_clk_off(afe);
+	}
+
+	return ret;
+}
+
+static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[dai_id];
+
+	/* set format */
+	if (memif->data->hd_reg >= 0) {
+		switch (substream->runtime->format) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+			regmap_update_bits(afe->regmap, memif->data->hd_reg,
+					   3 << memif->data->hd_shift,
+					   0 << memif->data->hd_shift);
+			break;
+		case SNDRV_PCM_FORMAT_S32_LE:
+			regmap_update_bits(afe->regmap, memif->data->hd_reg,
+					   3 << memif->data->hd_shift,
+					   3 << memif->data->hd_shift);
+
+			if (dai_id == MT8365_AFE_MEMIF_TDM_IN) {
+				regmap_update_bits(afe->regmap,
+						   memif->data->hd_reg,
+						   3 << memif->data->hd_shift,
+						   1 << memif->data->hd_shift);
+				regmap_update_bits(afe->regmap,
+						   memif->data->hd_reg,
+						   1 << memif->data->hd_align_mshift,
+						   1 << memif->data->hd_align_mshift);
+			}
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+			regmap_update_bits(afe->regmap, memif->data->hd_reg,
+					   3 << memif->data->hd_shift,
+					   1 << memif->data->hd_shift);
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	mt8365_afe_irq_direction_enable(afe, memif->irq_usage,
+					MT8365_AFE_IRQ_DIR_MCU);
+
+	return 0;
+}
+
+int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id;
+	struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		/* enable channel merge */
+		if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+		    !ctrl_data->bypass_cm1) {
+			regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+					   CM_AFE_CM_ON, CM_AFE_CM_ON);
+		} else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+			   !ctrl_data->bypass_cm2) {
+			regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+					   CM_AFE_CM_ON, CM_AFE_CM_ON);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		/* disable channel merge */
+		if (dai_id == MT8365_AFE_MEMIF_VUL2 &&
+		    !ctrl_data->bypass_cm1) {
+			regmap_update_bits(afe->regmap, AFE_CM1_CON0,
+					   CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+		} else if (dai_id == MT8365_AFE_MEMIF_TDM_IN &&
+			   !ctrl_data->bypass_cm2) {
+			regmap_update_bits(afe->regmap, AFE_CM2_CON0,
+					   CM_AFE_CM_ON, ~CM_AFE_CM_ON);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return mtk_afe_fe_trigger(substream, cmd, dai);
+}
+
+static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mt8365_afe_enable_main_clk(afe);
+	return 0;
+}
+
+static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream,
+					 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be =
+		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+	if (be->prepared[substream->stream]) {
+		regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+				   AFE_GAIN1_CON0_EN_MASK, 0);
+		be->prepared[substream->stream] = false;
+	}
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be =
+		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+	int fs;
+	unsigned int val1 = 0, val2 = 0;
+
+	if (be->prepared[substream->stream]) {
+		dev_info(afe->dev, "%s prepared already\n", __func__);
+		return 0;
+	}
+
+	fs = mt8365_afe_fs_timing(substream->runtime->rate);
+	regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+			   AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs << 4);
+
+	regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1);
+	regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2);
+	if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK))
+		regmap_update_bits(afe->regmap, AFE_GAIN1_CUR,
+				   AFE_GAIN1_CUR_MASK, val1);
+
+	regmap_update_bits(afe->regmap, AFE_GAIN1_CON0,
+			   AFE_GAIN1_CON0_EN_MASK, 1);
+	be->prepared[substream->stream] = true;
+
+	return 0;
+}
+
+static const struct snd_pcm_hardware mt8365_hostless_hardware = {
+	.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP_VALID),
+	.period_bytes_min = 256,
+	.period_bytes_max = 4 * 48 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 8 * 48 * 1024,
+	.fifo_size = 0,
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &mt8365_hostless_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+	return ret;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = {
+	.startup	= mt8365_afe_fe_startup,
+	.shutdown	= mt8365_afe_fe_shutdown,
+	.hw_params	= mt8365_afe_fe_hw_params,
+	.hw_free	= mt8365_afe_fe_hw_free,
+	.prepare	= mt8365_afe_fe_prepare,
+	.trigger	= mt8365_afe_fe_trigger,
+};
+
+static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = {
+	.startup = mtk_dai_hostless_startup,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_hw_gain1_ops = {
+	.startup	= mt8365_afe_hw_gain1_startup,
+	.shutdown	= mt8365_afe_hw_gain1_shutdown,
+	.prepare	= mt8365_afe_hw_gain1_prepare,
+};
+
+static struct snd_soc_dai_driver mt8365_memif_dai_driver[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "DL1",
+		.id = MT8365_AFE_MEMIF_DL1,
+		.playback = {
+			.stream_name = "DL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "DL2",
+		.id = MT8365_AFE_MEMIF_DL2,
+		.playback = {
+			.stream_name = "DL2",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "TDM_OUT",
+		.id = MT8365_AFE_MEMIF_TDM_OUT,
+		.playback = {
+			.stream_name = "TDM_OUT",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "AWB",
+		.id = MT8365_AFE_MEMIF_AWB,
+		.capture = {
+			.stream_name = "AWB",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "VUL",
+		.id = MT8365_AFE_MEMIF_VUL,
+		.capture = {
+			.stream_name = "VUL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "VUL2",
+		.id = MT8365_AFE_MEMIF_VUL2,
+		.capture = {
+			.stream_name = "VUL2",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "VUL3",
+		.id = MT8365_AFE_MEMIF_VUL3,
+		.capture = {
+			.stream_name = "VUL3",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "TDM_IN",
+		.id = MT8365_AFE_MEMIF_TDM_IN,
+		.capture = {
+			.stream_name = "TDM_IN",
+			.channels_min = 1,
+			.channels_max = 16,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_fe_dai_ops,
+	}, {
+		.name = "Hostless FM DAI",
+		.id = MT8365_AFE_IO_VIRTUAL_FM,
+		.playback = {
+			.stream_name = "Hostless FM DL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+					  SNDRV_PCM_FMTBIT_S24_LE |
+					   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "Hostless FM UL",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+					  SNDRV_PCM_FMTBIT_S24_LE |
+					   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_dai_hostless_ops,
+	}, {
+		.name = "HW_GAIN1",
+		.id = MT8365_AFE_IO_HW_GAIN1,
+		.playback = {
+			.stream_name = "HW Gain 1 In",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "HW Gain 1 Out",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_hw_gain1_ops,
+		.symmetric_rate = 1,
+		.symmetric_channels = 1,
+		.symmetric_sample_bits = 1,
+	},
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o00_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN0, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN0, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o01_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN1, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN1, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o03_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN3, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN3, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN3, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I10 Switch", AFE_CONN3, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o04_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN4, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN4, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN4, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I11 Switch", AFE_CONN4, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o05_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN5, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN5, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN5, 7, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN5, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN5, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN5, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN5, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN5, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN5, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I10L Switch", AFE_CONN5, 10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o06_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN6, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN6, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN6, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN6, 8, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN6, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN6, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN6, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN6, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN6, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN6, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I11L Switch", AFE_CONN6, 11, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o07_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN7, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN7, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o08_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN8, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN8, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o09_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN9, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN9, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN9, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN9, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN9, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN9, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN9, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o10_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN10, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN10, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN10, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN10, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN10, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN10, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN10, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o11_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN11, 0, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN11, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN11, 9, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN11, 14, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN11, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN11, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN11, 20, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o12_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN12, 1, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN12, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN12, 22, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN12, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN12, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN12, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN12, 21, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o13_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN13, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o14_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN14, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o15_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o16_mix[] = {
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o17_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN17, 3, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o18_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN18, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN18, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN18, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o19_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN19, 4, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN19, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN19, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN19, 25, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN19, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o20_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN20, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN20, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o21_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN21, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN21, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o22_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN22, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN22, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o23_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN23, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN23, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o24_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN24, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN24, 26, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN24, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN24, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o25_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I27 Switch", AFE_CONN25, 27, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN25, 23, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN25, 25, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o26_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I28 Switch", AFE_CONN26, 28, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN26, 24, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN26, 26, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o27_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN27, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN27, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o28_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN28, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN28, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o29_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN29, 5, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN29, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o30_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN30, 6, 1, 0),
+	SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN30, 8, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o31_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I29 Switch", AFE_CONN31, 29, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o32_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I30 Switch", AFE_CONN32, 30, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o33_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I31 Switch", AFE_CONN33, 31, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o34_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I32 Switch", AFE_CONN34_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o35_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I33 Switch", AFE_CONN35_1, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mt8365_afe_o36_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I34 Switch", AFE_CONN36_1, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13,
+				    0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14,
+				    1, 1, 0),
+};
+
+static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = mCM2Input;
+
+	return 0;
+}
+
+static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	mCM2Input = ucontrol->value.enumerated.item[0];
+
+	afe_priv->cm2_mux_input = mCM2Input;
+	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+	return ret;
+}
+
+static const char * const fmhwgain_text[] = {
+	"OPEN", "FM_HW_GAIN_IO"
+};
+
+static const char * const ain_text[] = {
+	"INT ADC", "EXT ADC",
+};
+
+static const char * const vul2_in_input_text[] = {
+	"VUL2_IN_FROM_O17O18", "VUL2_IN_FROM_CM1",
+};
+
+static const char * const mt8365_afe_cm2_mux_text[] = {
+	"OPEN", "FROM_GASRC1_OUT", "FROM_GASRC2_OUT", "FROM_TDM_ASRC_OUT",
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmhwgain_enum, fmhwgain_text);
+static SOC_ENUM_SINGLE_DECL(ain_enum, AFE_ADDA_TOP_CON0, 0, ain_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(vul2_in_input_enum, vul2_in_input_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(mt8365_afe_cm2_mux_input_enum,
+	mt8365_afe_cm2_mux_text);
+
+static const struct snd_kcontrol_new fmhwgain_mux =
+	SOC_DAPM_ENUM("FM HW Gain Source", fmhwgain_enum);
+
+static const struct snd_kcontrol_new ain_mux =
+	SOC_DAPM_ENUM("AIN Source", ain_enum);
+
+static const struct snd_kcontrol_new vul2_in_input_mux =
+	SOC_DAPM_ENUM("VUL2 Input", vul2_in_input_enum);
+
+static const struct snd_kcontrol_new mt8365_afe_cm2_mux_input_mux =
+	SOC_DAPM_ENUM_EXT("CM2_MUX Source", mt8365_afe_cm2_mux_input_enum,
+			  mt8365_afe_cm2_io_input_mux_get,
+			  mt8365_afe_cm2_io_input_mux_put);
+
+static const struct snd_soc_dapm_widget mt8365_memif_widgets[] = {
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I07", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I08", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I05L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I06L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I07L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I08L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I09", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I10", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I11", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I10L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I11L", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I20", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I21", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I22", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I23", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I24", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I25", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I27", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I28", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I29", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I30", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I31", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I32", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I33", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I34", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o00_mix, ARRAY_SIZE(mt8365_afe_o00_mix)),
+	SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o01_mix, ARRAY_SIZE(mt8365_afe_o01_mix)),
+	SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o03_mix, ARRAY_SIZE(mt8365_afe_o03_mix)),
+	SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o04_mix, ARRAY_SIZE(mt8365_afe_o04_mix)),
+	SND_SOC_DAPM_MIXER("O05", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o05_mix, ARRAY_SIZE(mt8365_afe_o05_mix)),
+	SND_SOC_DAPM_MIXER("O06", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o06_mix, ARRAY_SIZE(mt8365_afe_o06_mix)),
+	SND_SOC_DAPM_MIXER("O07", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o07_mix, ARRAY_SIZE(mt8365_afe_o07_mix)),
+	SND_SOC_DAPM_MIXER("O08", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o08_mix, ARRAY_SIZE(mt8365_afe_o08_mix)),
+	SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o09_mix, ARRAY_SIZE(mt8365_afe_o09_mix)),
+	SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o10_mix, ARRAY_SIZE(mt8365_afe_o10_mix)),
+	SND_SOC_DAPM_MIXER("O11", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o11_mix, ARRAY_SIZE(mt8365_afe_o11_mix)),
+	SND_SOC_DAPM_MIXER("O12", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o12_mix, ARRAY_SIZE(mt8365_afe_o12_mix)),
+	SND_SOC_DAPM_MIXER("O13", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o13_mix, ARRAY_SIZE(mt8365_afe_o13_mix)),
+	SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o14_mix, ARRAY_SIZE(mt8365_afe_o14_mix)),
+	SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o15_mix, ARRAY_SIZE(mt8365_afe_o15_mix)),
+	SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o16_mix, ARRAY_SIZE(mt8365_afe_o16_mix)),
+	SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o17_mix, ARRAY_SIZE(mt8365_afe_o17_mix)),
+	SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o18_mix, ARRAY_SIZE(mt8365_afe_o18_mix)),
+	SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o19_mix, ARRAY_SIZE(mt8365_afe_o19_mix)),
+	SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o20_mix, ARRAY_SIZE(mt8365_afe_o20_mix)),
+	SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o21_mix, ARRAY_SIZE(mt8365_afe_o21_mix)),
+	SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o22_mix, ARRAY_SIZE(mt8365_afe_o22_mix)),
+	SND_SOC_DAPM_MIXER("O23", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o23_mix, ARRAY_SIZE(mt8365_afe_o23_mix)),
+	SND_SOC_DAPM_MIXER("O24", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o24_mix, ARRAY_SIZE(mt8365_afe_o24_mix)),
+	SND_SOC_DAPM_MIXER("O25", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o25_mix, ARRAY_SIZE(mt8365_afe_o25_mix)),
+	SND_SOC_DAPM_MIXER("O26", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o26_mix, ARRAY_SIZE(mt8365_afe_o26_mix)),
+	SND_SOC_DAPM_MIXER("O27", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o27_mix, ARRAY_SIZE(mt8365_afe_o27_mix)),
+	SND_SOC_DAPM_MIXER("O28", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o28_mix, ARRAY_SIZE(mt8365_afe_o28_mix)),
+	SND_SOC_DAPM_MIXER("O29", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o29_mix, ARRAY_SIZE(mt8365_afe_o29_mix)),
+	SND_SOC_DAPM_MIXER("O30", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o30_mix, ARRAY_SIZE(mt8365_afe_o30_mix)),
+	SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o31_mix, ARRAY_SIZE(mt8365_afe_o31_mix)),
+	SND_SOC_DAPM_MIXER("O32", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o32_mix, ARRAY_SIZE(mt8365_afe_o32_mix)),
+	SND_SOC_DAPM_MIXER("O33", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o33_mix, ARRAY_SIZE(mt8365_afe_o33_mix)),
+	SND_SOC_DAPM_MIXER("O34", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o34_mix, ARRAY_SIZE(mt8365_afe_o34_mix)),
+	SND_SOC_DAPM_MIXER("O35", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o35_mix, ARRAY_SIZE(mt8365_afe_o35_mix)),
+	SND_SOC_DAPM_MIXER("O36", SND_SOC_NOPM, 0, 0,
+			   mt8365_afe_o36_mix, ARRAY_SIZE(mt8365_afe_o36_mix)),
+	SND_SOC_DAPM_MIXER("CM2_Mux IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("CM1_IO", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("O17O18", SND_SOC_NOPM, 0, 0, NULL, 0),
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_hw_gain1_in_ch1_mix,
+			   ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
+	SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_hw_gain1_in_ch2_mix,
+			   ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
+
+	SND_SOC_DAPM_INPUT("DL Source"),
+
+	SND_SOC_DAPM_MUX("CM2_Mux_IO Input Mux", SND_SOC_NOPM, 0, 0,
+			 &mt8365_afe_cm2_mux_input_mux),
+
+	SND_SOC_DAPM_MUX("AIN Mux", SND_SOC_NOPM, 0, 0, &ain_mux),
+	SND_SOC_DAPM_MUX("VUL2 Input Mux", SND_SOC_NOPM, 0, 0,
+			 &vul2_in_input_mux),
+
+	SND_SOC_DAPM_MUX("FM HW Gain Mux", SND_SOC_NOPM, 0, 0, &fmhwgain_mux),
+
+	SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
+	SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
+};
+
+static const struct snd_soc_dapm_route mt8365_memif_routes[] = {
+	/* downlink */
+	{"I00", NULL, "2ND I2S Capture"},
+	{"I01", NULL, "2ND I2S Capture"},
+	{"I05", NULL, "DL1"},
+	{"I06", NULL, "DL1"},
+	{"I07", NULL, "DL2"},
+	{"I08", NULL, "DL2"},
+
+	{"O03", "I05 Switch", "I05"},
+	{"O04", "I06 Switch", "I06"},
+	{"O00", "I05 Switch", "I05"},
+	{"O01", "I06 Switch", "I06"},
+	{"O07", "I05 Switch", "I05"},
+	{"O08", "I06 Switch", "I06"},
+	{"O27", "I05 Switch", "I05"},
+	{"O28", "I06 Switch", "I06"},
+	{"O29", "I05 Switch", "I05"},
+	{"O30", "I06 Switch", "I06"},
+
+	{"O03", "I07 Switch", "I07"},
+	{"O04", "I08 Switch", "I08"},
+	{"O00", "I07 Switch", "I07"},
+	{"O01", "I08 Switch", "I08"},
+	{"O07", "I07 Switch", "I07"},
+	{"O08", "I08 Switch", "I08"},
+
+	/* uplink */
+	{"AWB", NULL, "O05"},
+	{"AWB", NULL, "O06"},
+	{"VUL", NULL, "O09"},
+	{"VUL", NULL, "O10"},
+	{"VUL3", NULL, "O11"},
+	{"VUL3", NULL, "O12"},
+
+	{"AIN Mux", "EXT ADC", "I2S Capture"},
+	{"I03", NULL, "AIN Mux"},
+	{"I04", NULL, "AIN Mux"},
+
+	{"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1", "Hostless FM DL"},
+	{"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2", "Hostless FM DL"},
+
+	{"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
+	{"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
+	{"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
+	{"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
+
+	{"FM HW Gain Mux", "FM_HW_GAIN_IO", "HW Gain 1 Out"},
+	{"Hostless FM UL", NULL, "FM HW Gain Mux"},
+	{"Hostless FM UL", NULL, "FM 2ND I2S Mux"},
+
+	{"O05", "I05 Switch", "I05L"},
+	{"O06", "I06 Switch", "I06L"},
+	{"O05", "I07 Switch", "I07L"},
+	{"O06", "I08 Switch", "I08L"},
+
+	{"O05", "I03 Switch", "I03"},
+	{"O06", "I04 Switch", "I04"},
+	{"O05", "I00 Switch", "I00"},
+	{"O06", "I01 Switch", "I01"},
+	{"O05", "I09 Switch", "I09"},
+	{"O06", "I22 Switch", "I22"},
+	{"O05", "I14 Switch", "I14"},
+	{"O06", "I15 Switch", "I15"},
+	{"O05", "I16 Switch", "I16"},
+	{"O06", "I17 Switch", "I17"},
+	{"O05", "I18 Switch", "I18"},
+	{"O06", "I19 Switch", "I19"},
+	{"O05", "I20 Switch", "I20"},
+	{"O06", "I21 Switch", "I21"},
+	{"O05", "I23 Switch", "I23"},
+	{"O06", "I24 Switch", "I24"},
+
+	{"O09", "I03 Switch", "I03"},
+	{"O10", "I04 Switch", "I04"},
+	{"O09", "I00 Switch", "I00"},
+	{"O10", "I01 Switch", "I01"},
+	{"O09", "I09 Switch", "I09"},
+	{"O10", "I22 Switch", "I22"},
+	{"O09", "I14 Switch", "I14"},
+	{"O10", "I15 Switch", "I15"},
+	{"O09", "I16 Switch", "I16"},
+	{"O10", "I17 Switch", "I17"},
+	{"O09", "I18 Switch", "I18"},
+	{"O10", "I19 Switch", "I19"},
+	{"O09", "I20 Switch", "I20"},
+	{"O10", "I21 Switch", "I21"},
+
+	{"O11", "I03 Switch", "I03"},
+	{"O12", "I04 Switch", "I04"},
+	{"O11", "I00 Switch", "I00"},
+	{"O12", "I01 Switch", "I01"},
+	{"O11", "I09 Switch", "I09"},
+	{"O12", "I22 Switch", "I22"},
+	{"O11", "I14 Switch", "I14"},
+	{"O12", "I15 Switch", "I15"},
+	{"O11", "I16 Switch", "I16"},
+	{"O12", "I17 Switch", "I17"},
+	{"O11", "I18 Switch", "I18"},
+	{"O12", "I19 Switch", "I19"},
+	{"O11", "I20 Switch", "I20"},
+	{"O12", "I21 Switch", "I21"},
+
+	/* CM2_Mux*/
+	{"CM2_Mux IO", NULL, "CM2_Mux_IO Input Mux"},
+
+	/* VUL2 */
+	{"VUL2", NULL, "VUL2 Input Mux"},
+	{"VUL2 Input Mux", "VUL2_IN_FROM_O17O18", "O17O18"},
+	{"VUL2 Input Mux", "VUL2_IN_FROM_CM1", "CM1_IO"},
+
+	{"O17O18", NULL, "O17"},
+	{"O17O18", NULL, "O18"},
+	{"CM1_IO", NULL, "O17"},
+	{"CM1_IO", NULL, "O18"},
+	{"CM1_IO", NULL, "O19"},
+	{"CM1_IO", NULL, "O20"},
+	{"CM1_IO", NULL, "O21"},
+	{"CM1_IO", NULL, "O22"},
+	{"CM1_IO", NULL, "O23"},
+	{"CM1_IO", NULL, "O24"},
+	{"CM1_IO", NULL, "O25"},
+	{"CM1_IO", NULL, "O26"},
+	{"CM1_IO", NULL, "O31"},
+	{"CM1_IO", NULL, "O32"},
+	{"CM1_IO", NULL, "O33"},
+	{"CM1_IO", NULL, "O34"},
+	{"CM1_IO", NULL, "O35"},
+	{"CM1_IO", NULL, "O36"},
+
+	{"O17", "I14 Switch", "I14"},
+	{"O18", "I15 Switch", "I15"},
+	{"O19", "I16 Switch", "I16"},
+	{"O20", "I17 Switch", "I17"},
+	{"O21", "I18 Switch", "I18"},
+	{"O22", "I19 Switch", "I19"},
+	{"O23", "I20 Switch", "I20"},
+	{"O24", "I21 Switch", "I21"},
+	{"O25", "I23 Switch", "I23"},
+	{"O26", "I24 Switch", "I24"},
+	{"O25", "I25 Switch", "I25"},
+	{"O26", "I26 Switch", "I26"},
+
+	{"O17", "I03 Switch", "I03"},
+	{"O18", "I04 Switch", "I04"},
+	{"O18", "I23 Switch", "I23"},
+	{"O18", "I25 Switch", "I25"},
+	{"O19", "I04 Switch", "I04"},
+	{"O19", "I23 Switch", "I23"},
+	{"O19", "I24 Switch", "I24"},
+	{"O19", "I25 Switch", "I25"},
+	{"O19", "I26 Switch", "I26"},
+	{"O20", "I24 Switch", "I24"},
+	{"O20", "I26 Switch", "I26"},
+	{"O21", "I23 Switch", "I23"},
+	{"O21", "I25 Switch", "I25"},
+	{"O22", "I24 Switch", "I24"},
+	{"O22", "I26 Switch", "I26"},
+
+	{"O23", "I23 Switch", "I23"},
+	{"O23", "I25 Switch", "I25"},
+	{"O24", "I24 Switch", "I24"},
+	{"O24", "I26 Switch", "I26"},
+	{"O24", "I23 Switch", "I23"},
+	{"O24", "I25 Switch", "I25"},
+	{"O13", "I00 Switch", "I00"},
+	{"O14", "I01 Switch", "I01"},
+	{"O03", "I10 Switch", "I10"},
+	{"O04", "I11 Switch", "I11"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8365_AFE_MEMIF_NUM] = {
+	{
+		.name = "DL1",
+		.id = MT8365_AFE_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL1_BASE,
+		.reg_ofs_cur = AFE_DL1_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 0,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = 21,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 16,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 1,
+		.msb_reg = -1,
+		.msb_shift = -1,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "DL2",
+		.id = MT8365_AFE_MEMIF_DL2,
+		.reg_ofs_base = AFE_DL2_BASE,
+		.reg_ofs_cur = AFE_DL2_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 4,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = 22,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 18,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 2,
+		.msb_reg = -1,
+		.msb_shift = -1,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "TDM OUT",
+		.id = MT8365_AFE_MEMIF_TDM_OUT,
+		.reg_ofs_base = AFE_HDMI_OUT_BASE,
+		.reg_ofs_cur = AFE_HDMI_OUT_CUR,
+		.fs_reg = -1,
+		.fs_shift = -1,
+		.fs_maskbit = -1,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 28,
+		.enable_reg = AFE_HDMI_OUT_CON0,
+		.enable_shift = 0,
+		.msb_reg = -1,
+		.msb_shift = -1,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "AWB",
+		.id = MT8365_AFE_MEMIF_AWB,
+		.reg_ofs_base = AFE_AWB_BASE,
+		.reg_ofs_cur = AFE_AWB_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 12,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = 24,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 20,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 6,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 17,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "VUL",
+		.id = MT8365_AFE_MEMIF_VUL,
+		.reg_ofs_base = AFE_VUL_BASE,
+		.reg_ofs_cur = AFE_VUL_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 16,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
+		.mono_shift = 27,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 22,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 3,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 20,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "VUL2",
+		.id = MT8365_AFE_MEMIF_VUL2,
+		.reg_ofs_base = AFE_VUL_D2_BASE,
+		.reg_ofs_cur = AFE_VUL_D2_CUR,
+		.fs_reg = AFE_DAC_CON0,
+		.fs_shift = 20,
+		.fs_maskbit = 0xf,
+		.mono_reg = -1,
+		.mono_shift = -1,
+		.hd_reg = AFE_MEMIF_PBUF_SIZE,
+		.hd_shift = 14,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 9,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 21,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "VUL3",
+		.id = MT8365_AFE_MEMIF_VUL3,
+		.reg_ofs_base = AFE_VUL3_BASE,
+		.reg_ofs_cur = AFE_VUL3_CUR,
+		.fs_reg = AFE_DAC_CON1,
+		.fs_shift = 8,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON0,
+		.mono_shift = 13,
+		.hd_reg = AFE_MEMIF_PBUF2_SIZE,
+		.hd_shift = 10,
+		.enable_reg = AFE_DAC_CON0,
+		.enable_shift = 12,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 27,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	}, {
+		.name = "TDM IN",
+		.id = MT8365_AFE_MEMIF_TDM_IN,
+		.reg_ofs_base = AFE_HDMI_IN_2CH_BASE,
+		.reg_ofs_cur = AFE_HDMI_IN_2CH_CUR,
+		.fs_reg = -1,
+		.fs_shift = -1,
+		.fs_maskbit = -1,
+		.mono_reg = AFE_HDMI_IN_2CH_CON0,
+		.mono_shift = 1,
+		.hd_reg = AFE_MEMIF_PBUF2_SIZE,
+		.hd_shift = 8,
+		.hd_align_mshift = 5,
+		.enable_reg = AFE_HDMI_IN_2CH_CON0,
+		.enable_shift = 0,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 28,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT8365_AFE_IRQ_NUM] = {
+	{
+		.id = MT8365_AFE_IRQ1,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 0,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 4,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 0,
+	}, {
+		.id = MT8365_AFE_IRQ2,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 1,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 8,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 1,
+	}, {
+		.id = MT8365_AFE_IRQ3,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 2,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 16,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 2,
+	}, {
+		.id = MT8365_AFE_IRQ4,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 3,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 20,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 3,
+	}, {
+		.id = MT8365_AFE_IRQ5,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON2,
+		.irq_en_shift = 3,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0x0,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 4,
+	}, {
+		.id = MT8365_AFE_IRQ6,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x0,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 13,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0x0,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 5,
+	}, {
+		.id = MT8365_AFE_IRQ7,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 14,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 6,
+	}, {
+		.id = MT8365_AFE_IRQ8,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 15,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 28,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 7,
+	}, {
+		.id = MT8365_AFE_IRQ9,
+		.irq_cnt_reg = -1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x0,
+		.irq_en_reg = AFE_IRQ_MCU_CON2,
+		.irq_en_shift = 2,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0x0,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 8,
+	}, {
+		.id = MT8365_AFE_IRQ10,
+		.irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON2,
+		.irq_en_shift = 4,
+		.irq_fs_reg = -1,
+		.irq_fs_shift = 0,
+		.irq_fs_maskbit = 0x0,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = 9,
+	},
+};
+
+static int memif_specified_irqs[MT8365_AFE_MEMIF_NUM] = {
+	[MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1,
+	[MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2,
+	[MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5,
+	[MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3,
+	[MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4,
+	[MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7,
+	[MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8,
+	[MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10,
+};
+
+static const struct regmap_config mt8365_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = MAX_REGISTER,
+	.cache_type = REGCACHE_NONE,
+};
+
+static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id)
+{
+	struct mtk_base_afe *afe = dev_id;
+	unsigned int reg_value;
+	unsigned int mcu_irq_mask;
+	int i, ret;
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &reg_value);
+	if (ret) {
+		dev_err_ratelimited(afe->dev, "%s irq status err\n", __func__);
+		reg_value = AFE_IRQ_STATUS_BITS;
+		goto err_irq;
+	}
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask);
+	if (ret) {
+		dev_err_ratelimited(afe->dev, "%s irq mcu_en err\n", __func__);
+		reg_value = AFE_IRQ_STATUS_BITS;
+		goto err_irq;
+	}
+
+	/* only clr cpu irq */
+	reg_value &= mcu_irq_mask;
+
+	for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) {
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+		struct mtk_base_afe_irq *mcu_irq;
+
+		if (memif->irq_usage < 0)
+			continue;
+
+		mcu_irq = &afe->irqs[memif->irq_usage];
+
+		if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift)))
+			continue;
+
+		snd_pcm_period_elapsed(memif->substream);
+	}
+
+err_irq:
+	/* clear irq */
+	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR,
+		     reg_value & AFE_IRQ_STATUS_BITS);
+
+	return IRQ_HANDLED;
+}
+
+static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int mt8365_afe_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static int __maybe_unused mt8365_afe_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct regmap *regmap = afe->regmap;
+	int i;
+
+	mt8365_afe_enable_main_clk(afe);
+
+	if (!afe->reg_back_up)
+		afe->reg_back_up =
+			devm_kcalloc(dev, afe->reg_back_up_list_num,
+				     sizeof(unsigned int), GFP_KERNEL);
+
+	for (i = 0; i < afe->reg_back_up_list_num; i++)
+		regmap_read(regmap, afe->reg_back_up_list[i],
+			    &afe->reg_back_up[i]);
+
+	mt8365_afe_disable_main_clk(afe);
+
+	return 0;
+}
+
+static int __maybe_unused mt8365_afe_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct regmap *regmap = afe->regmap;
+	int i = 0;
+
+	if (!afe->reg_back_up)
+		return 0;
+
+	mt8365_afe_enable_main_clk(afe);
+
+	for (i = 0; i < afe->reg_back_up_list_num; i++)
+		regmap_write(regmap, afe->reg_back_up_list[i],
+			     afe->reg_back_up[i]);
+
+	mt8365_afe_disable_main_clk(afe);
+
+	return 0;
+}
+
+static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	if (pm_runtime_status_suspended(dev) || afe->suspended)
+		return 0;
+
+	mt8365_afe_suspend(dev);
+	afe->suspended = true;
+	return 0;
+}
+
+static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+
+	if (pm_runtime_status_suspended(dev) || !afe->suspended)
+		return 0;
+
+	mt8365_afe_resume(dev);
+	afe->suspended = false;
+	return 0;
+}
+
+static int mt8365_afe_init_registers(struct mtk_base_afe *afe)
+{
+	size_t i;
+
+	static struct {
+		unsigned int reg;
+		unsigned int mask;
+		unsigned int val;
+	} init_regs[] = {
+		{ AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) },
+		{ AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) },
+	};
+
+	mt8365_afe_enable_main_clk(afe);
+
+	for (i = 0; i < ARRAY_SIZE(init_regs); i++)
+		regmap_update_bits(afe->regmap, init_regs[i].reg,
+				   init_regs[i].mask, init_regs[i].val);
+
+	mt8365_afe_disable_main_clk(afe);
+
+	return 0;
+}
+
+static int mt8365_dai_memif_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mt8365_memif_dai_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver);
+
+	dai->dapm_widgets = mt8365_memif_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets);
+	dai->dapm_routes = mt8365_memif_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes);
+	return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+	mt8365_dai_pcm_register,
+	mt8365_dai_i2s_register,
+	mt8365_dai_adda_register,
+	mt8365_dai_dmic_register,
+	mt8365_dai_memif_register,
+};
+
+static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe;
+	struct mt8365_afe_private *afe_priv;
+	struct device *dev;
+	int ret, i, sel_irq;
+	unsigned int irq_id;
+	struct resource *res;
+
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, afe);
+
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+
+	afe_priv = afe->platform_priv;
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	spin_lock_init(&afe_priv->afe_ctrl_lock);
+	mutex_init(&afe_priv->afe_clk_mutex);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(afe->base_addr))
+		return PTR_ERR(afe->base_addr);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		afe_priv->afe_sram_vir_addr =
+			devm_ioremap_resource(&pdev->dev, res);
+		if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
+			afe_priv->afe_sram_phy_addr = res->start;
+			afe_priv->afe_sram_size = resource_size(res);
+		}
+	}
+
+	/* initial audio related clock */
+	ret = mt8365_afe_init_audio_clk(afe);
+	if (ret)
+		return dev_err_probe(afe->dev, ret, "mt8365_afe_init_audio_clk fail\n");
+
+	afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel",
+						afe->base_addr,
+						&mt8365_afe_regmap_config);
+	if (IS_ERR(afe->regmap))
+		return PTR_ERR(afe->regmap);
+
+	/* memif % irq initialize*/
+	afe->memif_size = MT8365_AFE_MEMIF_NUM;
+	afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+				  sizeof(*afe->memif), GFP_KERNEL);
+	if (!afe->memif)
+		return -ENOMEM;
+
+	afe->irqs_size = MT8365_AFE_IRQ_NUM;
+	afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+				 sizeof(*afe->irqs), GFP_KERNEL);
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	irq_id = platform_get_irq(pdev, 0);
+	if (!irq_id) {
+		dev_err_probe(afe->dev, irq_id, "np %s no irq\n", afe->dev->of_node->name);
+		return -ENXIO;
+	}
+	ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler,
+			       0, "Afe_ISR_Handle", (void *)afe);
+	if (ret)
+		return dev_err_probe(afe->dev, ret, "could not request_irq\n");
+
+	/* init sub_dais */
+	INIT_LIST_HEAD(&afe->sub_dais);
+
+	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+		ret = dai_register_cbs[i](afe);
+		if (ret) {
+			dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+				 i, ret);
+			return ret;
+		}
+	}
+
+	/* init dai_driver and component_driver */
+	ret = mtk_afe_combine_sub_dai(afe);
+	if (ret) {
+		dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+			 ret);
+		return ret;
+	}
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		sel_irq = memif_specified_irqs[i];
+		if (sel_irq >= 0) {
+			afe->memif[i].irq_usage = sel_irq;
+			afe->memif[i].const_irq = 1;
+			afe->irqs[sel_irq].irq_occupyed = true;
+		} else {
+			afe->memif[i].irq_usage = -1;
+		}
+	}
+
+	afe->mtk_afe_hardware = &mt8365_afe_hardware;
+	afe->memif_fs = mt8365_memif_fs;
+	afe->irq_fs = mt8365_irq_fs;
+
+	ret = devm_pm_runtime_enable(&pdev->dev);
+	if (ret)
+		return ret;
+
+	pm_runtime_get_sync(&pdev->dev);
+	afe->reg_back_up_list = mt8365_afe_backup_list;
+	afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list);
+	afe->runtime_resume = mt8365_afe_runtime_resume;
+	afe->runtime_suspend = mt8365_afe_runtime_suspend;
+
+	/* open afe pdn for dapm read/write audio register */
+	mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+	/* Set 26m parent clk */
+	mt8365_afe_set_clk_parent(afe,
+				  afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL],
+				  afe_priv->clocks[MT8365_CLK_CLK26M]);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &mtk_afe_pcm_platform,
+					      afe->dai_drivers,
+					      afe->num_dai_drivers);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		return ret;
+	}
+
+	mt8365_afe_init_registers(afe);
+
+	return 0;
+}
+
+static void mt8365_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe = platform_get_drvdata(pdev);
+
+	mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
+
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt8365_afe_runtime_suspend(&pdev->dev);
+}
+
+static const struct of_device_id mt8365_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt8365-afe-pcm", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8365_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend,
+			   mt8365_afe_dev_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend,
+				mt8365_afe_resume)
+};
+
+static struct platform_driver mt8365_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt8365-afe-pcm",
+		   .of_match_table = mt8365_afe_pcm_dt_match,
+		   .pm = &mt8365_afe_pm_ops,
+	},
+	.probe = mt8365_afe_pcm_dev_probe,
+	.remove_new = mt8365_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt8365_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver");
+MODULE_AUTHOR("Jia Zeng <jia.zeng@mediatek.com>");
+MODULE_AUTHOR("Alexandre Mergnat <amergnat@baylibre.com>");
+MODULE_LICENSE("GPL");

-- 
2.25.1


^ permalink raw reply related

* [PATCH v10 2/6] PCI: qcom: Add ICC bandwidth vote for CPU to PCIe path
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski, Bryan O'Donoghue
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

To access PCIe registers of the host controller and endpoint PCIe
BAR space, config space the CPU-PCIe ICC (interconnect) path should
be voted otherwise it may lead to NoC (Network on chip) timeout.
We are surviving because of other driver voting for this path.

As there is less access on this path compared to PCIe to mem path
add minimum vote i.e 1KBps bandwidth always which is sufficient enough
to keep the path active and is recommended by HW team.

In suspend to ram case there can be some DBI access. Except in suspend
to ram case disable CPU-PCIe ICC path after register space access
is done.

Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 drivers/pci/controller/dwc/pcie-qcom.c | 43 ++++++++++++++++++++++++++++++----
 1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 14772edcf0d3..e53422171c01 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -245,6 +245,7 @@ struct qcom_pcie {
 	struct phy *phy;
 	struct gpio_desc *reset;
 	struct icc_path *icc_mem;
+	struct icc_path *icc_cpu;
 	const struct qcom_pcie_cfg *cfg;
 	struct dentry *debugfs;
 	bool suspended;
@@ -1409,6 +1410,9 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
 	if (IS_ERR(pcie->icc_mem))
 		return PTR_ERR(pcie->icc_mem);
 
+	pcie->icc_cpu = devm_of_icc_get(pci->dev, "cpu-pcie");
+	if (IS_ERR(pcie->icc_cpu))
+		return PTR_ERR(pcie->icc_cpu);
 	/*
 	 * Some Qualcomm platforms require interconnect bandwidth constraints
 	 * to be set before enabling interconnect clocks.
@@ -1418,7 +1422,20 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
 	 */
 	ret = icc_set_bw(pcie->icc_mem, 0, QCOM_PCIE_LINK_SPEED_TO_BW(1));
 	if (ret) {
-		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
+		dev_err(pci->dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * Since the CPU-PCIe path is only used for activities like register
+	 * access of the host controller and endpoint Config/BAR space access,
+	 * HW team has recommended to use a  minimal bandwidth of 1KBps just to
+	 * keep the path active.
+	 */
+	ret = icc_set_bw(pcie->icc_cpu, 0, kBps_to_icc(1));
+	if (ret) {
+		dev_err(pci->dev, "Failed to set interconnect bandwidth for CPU-PCIe: %d\n",
 			ret);
 		return ret;
 	}
@@ -1448,7 +1465,7 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
 
 	ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
 	if (ret) {
-		dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
+		dev_err(pci->dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n",
 			ret);
 	}
 }
@@ -1610,7 +1627,7 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
 	 */
 	ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1));
 	if (ret) {
-		dev_err(dev, "Failed to set interconnect bandwidth: %d\n", ret);
+		dev_err(dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n", ret);
 		return ret;
 	}
 
@@ -1634,7 +1651,17 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
 		pcie->suspended = true;
 	}
 
-	return 0;
+	/*
+	 * In suspend to ram case there are DBI access, except in suspend to ram case
+	 * remove the vote for CPU-PCIe path now, since at this point onwards,
+	 * no register access will be done.
+	 */
+	if (pm_suspend_target_state != PM_SUSPEND_MEM) {
+		ret = icc_disable(pcie->icc_cpu);
+		if (ret)
+			dev_err(dev, "Failed to disable Interconnect path of CPU-PCIe: %d\n", ret);
+	}
+	return ret;
 }
 
 static int qcom_pcie_resume_noirq(struct device *dev)
@@ -1642,6 +1669,14 @@ static int qcom_pcie_resume_noirq(struct device *dev)
 	struct qcom_pcie *pcie = dev_get_drvdata(dev);
 	int ret;
 
+	if (pm_suspend_target_state != PM_SUSPEND_MEM) {
+		ret = icc_enable(pcie->icc_cpu);
+		if (ret) {
+			dev_err(dev, "Failed to enable Interconnect path of CPU-PCIe: %d\n", ret);
+			return ret;
+		}
+	}
+
 	if (pcie->suspended) {
 		ret = qcom_pcie_host_init(&pcie->pci->pp);
 		if (ret)

-- 
2.42.0


^ permalink raw reply related

* [PATCH v2 11/18] ASoc: mediatek: mt8365: Add a specific soundcard for EVK
From: amergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat, Nicolas Belin
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

From: Nicolas Belin <nbelin@baylibre.com>

Add a specific soundcard for mt8365-evk. It supports audio jack
in/out, dmics, the amic and lineout.

Signed-off-by: Nicolas Belin <nbelin@baylibre.com>
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-mt6357.c | 348 ++++++++++++++++++++++++++++++
 1 file changed, 348 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
new file mode 100644
index 000000000000..9f1be194fe34
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek MT8365 Sound Card driver
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Nicolas Belin <nbelin@baylibre.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-common.h"
+#include <linux/pinctrl/consumer.h>
+#include "../common/mtk-soc-card.h"
+#include "../common/mtk-soundcard-driver.h"
+
+enum pinctrl_pin_state {
+	PIN_STATE_DEFAULT,
+	PIN_STATE_DMIC,
+	PIN_STATE_MISO_OFF,
+	PIN_STATE_MISO_ON,
+	PIN_STATE_MOSI_OFF,
+	PIN_STATE_MOSI_ON,
+	PIN_STATE_MAX
+};
+
+static const char * const mt8365_mt6357_pin_str[PIN_STATE_MAX] = {
+	"default",
+	"dmic",
+	"miso_off",
+	"miso_on",
+	"mosi_off",
+	"mosi_on",
+};
+
+struct mt8365_mt6357_priv {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pin_states[PIN_STATE_MAX];
+};
+
+enum {
+	/* FE */
+	DAI_LINK_DL1_PLAYBACK = 0,
+	DAI_LINK_DL2_PLAYBACK,
+	DAI_LINK_AWB_CAPTURE,
+	DAI_LINK_VUL_CAPTURE,
+	/* BE */
+	DAI_LINK_2ND_I2S_INTF,
+	DAI_LINK_DMIC,
+	DAI_LINK_INT_ADDA,
+	DAI_LINK_NUM
+};
+
+static const struct snd_soc_dapm_widget mt8365_mt6357_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("HDMI Out"),
+};
+
+static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
+	{"HDMI Out", NULL, "2ND I2S Playback"},
+	{"DMIC In", NULL, "MICBIAS0"},
+};
+
+static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_ON]))
+			return ret;
+
+		ret = pinctrl_select_state(priv->pinctrl,
+					   priv->pin_states[PIN_STATE_MOSI_ON]);
+		if (ret)
+			dev_err(rtd->card->dev, "%s failed to select state %d\n",
+				__func__, ret);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (IS_ERR(priv->pin_states[PIN_STATE_MISO_ON]))
+			return ret;
+
+		ret = pinctrl_select_state(priv->pinctrl,
+					   priv->pin_states[PIN_STATE_MISO_ON]);
+		if (ret)
+			dev_err(rtd->card->dev, "%s failed to select state %d\n",
+				__func__, ret);
+	}
+
+	return 0;
+}
+
+static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (IS_ERR(priv->pin_states[PIN_STATE_MOSI_OFF]))
+			return;
+
+		ret = pinctrl_select_state(priv->pinctrl,
+					   priv->pin_states[PIN_STATE_MOSI_OFF]);
+		if (ret)
+			dev_err(rtd->card->dev, "%s failed to select state %d\n",
+				__func__, ret);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (IS_ERR(priv->pin_states[PIN_STATE_MISO_OFF]))
+			return;
+
+		ret = pinctrl_select_state(priv->pinctrl,
+					   priv->pin_states[PIN_STATE_MISO_OFF]);
+		if (ret)
+			dev_err(rtd->card->dev, "%s failed to select state %d\n",
+				__func__, ret);
+	}
+}
+
+static const struct snd_soc_ops mt8365_mt6357_int_adda_ops = {
+	.startup = mt8365_mt6357_int_adda_startup,
+	.shutdown = mt8365_mt6357_int_adda_shutdown,
+};
+
+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(playback2,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(awb_capture,
+		     DAILINK_COMP_ARRAY(COMP_CPU("AWB")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(vul,
+		     DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(i2s3,
+		     DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(dmic,
+		     DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),
+		     DAILINK_COMP_ARRAY(COMP_DUMMY()),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(primary_codec,
+		     DAILINK_COMP_ARRAY(COMP_CPU("INT ADDA")),
+		     DAILINK_COMP_ARRAY(COMP_CODEC("mt6357-sound", "mt6357-snd-codec-aif1")),
+		     DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
+	/* Front End DAI links */
+	[DAI_LINK_DL1_PLAYBACK] = {
+		.name = "DL1_FE",
+		.stream_name = "MultiMedia1_PLayback",
+		.id = DAI_LINK_DL1_PLAYBACK,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_merged_rate = 1,
+		SND_SOC_DAILINK_REG(playback1),
+	},
+	[DAI_LINK_DL2_PLAYBACK] = {
+		.name = "DL2_FE",
+		.stream_name = "MultiMedia2_PLayback",
+		.id = DAI_LINK_DL2_PLAYBACK,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST
+		},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		.dpcm_merged_rate = 1,
+		SND_SOC_DAILINK_REG(playback2),
+	},
+	[DAI_LINK_AWB_CAPTURE] = {
+		.name = "AWB_FE",
+		.stream_name = "DL1_AWB_Record",
+		.id = DAI_LINK_AWB_CAPTURE,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.dpcm_merged_rate = 1,
+		SND_SOC_DAILINK_REG(awb_capture),
+	},
+	[DAI_LINK_VUL_CAPTURE] = {
+		.name = "VUL_FE",
+		.stream_name = "MultiMedia1_Capture",
+		.id = DAI_LINK_VUL_CAPTURE,
+		.trigger = {
+			SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST
+		},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		.dpcm_merged_rate = 1,
+		SND_SOC_DAILINK_REG(vul),
+	},
+	/* Back End DAI links */
+	[DAI_LINK_2ND_I2S_INTF] = {
+		.name = "2ND_I2S_BE",
+		.no_pcm = 1,
+		.id = DAI_LINK_2ND_I2S_INTF,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBS_CFS,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(i2s3),
+	},
+	[DAI_LINK_DMIC] = {
+		.name = "DMIC_BE",
+		.no_pcm = 1,
+		.id = DAI_LINK_DMIC,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(dmic),
+	},
+	[DAI_LINK_INT_ADDA] = {
+		.name = "MTK_Codec",
+		.no_pcm = 1,
+		.id = DAI_LINK_INT_ADDA,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		.ops = &mt8365_mt6357_int_adda_ops,
+		SND_SOC_DAILINK_REG(primary_codec),
+	},
+};
+
+static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
+{
+	struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
+	int ret, i;
+
+	priv->pinctrl = devm_pinctrl_get(card->dev);
+	if (IS_ERR(priv->pinctrl)) {
+		ret = PTR_ERR(priv->pinctrl);
+		return dev_err_probe(card->dev, ret,
+				     "Failed to get pinctrl\n");
+	}
+
+	for (i = PIN_STATE_DEFAULT ; i < PIN_STATE_MAX ; i++) {
+		priv->pin_states[i] = pinctrl_lookup_state(priv->pinctrl,
+							   mt8365_mt6357_pin_str[i]);
+		if (IS_ERR(priv->pin_states[i])) {
+			ret = PTR_ERR(priv->pin_states[i]);
+			dev_warn(card->dev, "No pin state for %s\n",
+				 mt8365_mt6357_pin_str[i]);
+		} else {
+			ret = pinctrl_select_state(priv->pinctrl,
+						   priv->pin_states[i]);
+			if (ret) {
+				dev_err_probe(card->dev, ret,
+					      "Failed to select pin state %s\n",
+					      mt8365_mt6357_pin_str[i]);
+				return ret;
+			}
+		}
+	}
+	return 0;
+}
+
+static struct snd_soc_card mt8365_mt6357_soc_card = {
+	.name = "mt8365-evk",
+	.owner = THIS_MODULE,
+	.dai_link = mt8365_mt6357_dais,
+	.num_links = ARRAY_SIZE(mt8365_mt6357_dais),
+	.dapm_widgets = mt8365_mt6357_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8365_mt6357_widgets),
+	.dapm_routes = mt8365_mt6357_routes,
+	.num_dapm_routes = ARRAY_SIZE(mt8365_mt6357_routes),
+};
+
+static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool legacy)
+{
+	struct mtk_platform_card_data *card_data = soc_card_data->card_data;
+	struct snd_soc_card *card = card_data->card;
+	struct device *dev = card->dev;
+	struct device_node *platform_node;
+	struct mt8365_mt6357_priv *mach_priv;
+	int i, ret;
+
+	card->dev = dev;
+	ret = parse_dai_link_info(card);
+	if (ret)
+		goto err;
+
+	mach_priv = devm_kzalloc(dev, sizeof(*mach_priv),
+				 GFP_KERNEL);
+	if (!mach_priv)
+		return -ENOMEM;
+	soc_card_data->mach_priv = mach_priv;
+	snd_soc_card_set_drvdata(card, soc_card_data);
+	mt8365_mt6357_gpio_probe(card);
+	return 0;
+
+err:
+	clean_card_reference(card);
+	return ret;
+}
+
+static const struct mtk_soundcard_pdata mt8365_mt6357_card = {
+	.card_name = "mt8365-mt6357",
+	.card_data = &(struct mtk_platform_card_data) {
+		.card = &mt8365_mt6357_soc_card,
+	},
+	.soc_probe = mt8365_mt6357_dev_probe
+};
+
+static const struct of_device_id mt8365_mt6357_dt_match[] = {
+	{
+		.compatible = "mediatek,mt8365-mt6357",
+		.data = &mt8365_mt6357_card,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt8365_mt6357_dt_match);
+
+static struct platform_driver mt8365_mt6357_driver = {
+	.driver = {
+		   .name = "mt8365_mt6357",
+		   .of_match_table = mt8365_mt6357_dt_match,
+		   .pm = &snd_soc_pm_ops,
+	},
+	.probe = mtk_soundcard_common_probe,
+};
+
+module_platform_driver(mt8365_mt6357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8365 EVK SoC machine driver");
+MODULE_AUTHOR("Nicolas Belin <nbelin@baylibre.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: mt8365_mt6357");

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 10/18] ASoC: mediatek: mt8365: Add PCM DAI support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add Pulse Code Modulation Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-dai-pcm.c | 293 +++++++++++++++++++++++++++++
 1 file changed, 293 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
new file mode 100644
index 000000000000..a5de47c69620
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI PCM Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ *          Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_pcm_intf_data {
+	bool slave_mode;
+	bool lrck_inv;
+	bool bck_inv;
+	unsigned int format;
+};
+
+/* DAI Drivers */
+
+static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
+{
+	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+			   PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
+}
+
+static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
+{
+	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+			   PCM_INTF_CON1_EN, 0x0);
+}
+
+static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+	bool slave_mode = pcm_priv->slave_mode;
+	bool lrck_inv = pcm_priv->lrck_inv;
+	bool bck_inv = pcm_priv->bck_inv;
+	unsigned int fmt = pcm_priv->format;
+	unsigned int bit_width = dai->sample_bits;
+	unsigned int val = 0;
+
+	if (!slave_mode) {
+		val |= PCM_INTF_CON1_MASTER_MODE |
+		       PCM_INTF_CON1_BYPASS_ASRC;
+
+		if (lrck_inv)
+			val |= PCM_INTF_CON1_SYNC_OUT_INV;
+		if (bck_inv)
+			val |= PCM_INTF_CON1_BCLK_OUT_INV;
+	} else {
+		val |= PCM_INTF_CON1_SLAVE_MODE;
+
+		if (lrck_inv)
+			val |= PCM_INTF_CON1_SYNC_IN_INV;
+		if (bck_inv)
+			val |= PCM_INTF_CON1_BCLK_IN_INV;
+
+		// TODO: add asrc setting
+	}
+
+	val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
+
+	if (fmt == MT8365_PCM_FORMAT_PCMA ||
+	    fmt == MT8365_PCM_FORMAT_PCMB)
+		val |= PCM_INTF_CON1_SYNC_LEN(1);
+	else
+		val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
+
+	switch (substream->runtime->rate) {
+	case 48000:
+		val |= PCM_INTF_CON1_FS_48K;
+		break;
+	case 32000:
+		val |= PCM_INTF_CON1_FS_32K;
+		break;
+	case 16000:
+		val |= PCM_INTF_CON1_FS_16K;
+		break;
+	case 8000:
+		val |= PCM_INTF_CON1_FS_8K;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (bit_width > 16)
+		val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
+	else
+		val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
+
+	val |= PCM_INTF_CON1_EXT_MODEM;
+
+	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
+			   PCM_INTF_CON1_CONFIG_MASK, val);
+
+	return 0;
+}
+
+static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	if (snd_soc_dai_active(dai))
+		return 0;
+
+	mt8365_afe_enable_main_clk(afe);
+
+	return 0;
+}
+
+static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	if (snd_soc_dai_active(dai))
+		return;
+
+	mt8365_dai_disable_pcm1(afe);
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	int ret;
+
+	if ((snd_soc_dai_stream_active_playback(dai) +
+	    snd_soc_dai_stream_active_capture(dai)) > 1) {
+		dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
+			 __func__, snd_pcm_stream_str(substream),
+			 snd_soc_dai_stream_active_playback(dai),
+			 snd_soc_dai_stream_active_capture(dai));
+		return 0;
+	}
+
+	ret = mt8365_dai_configure_pcm1(substream, dai);
+	if (ret)
+		return ret;
+
+	mt8365_dai_enable_pcm1(afe);
+
+	return 0;
+}
+
+static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		pcm_priv->format = MT8365_PCM_FORMAT_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		pcm_priv->bck_inv = false;
+		pcm_priv->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		pcm_priv->bck_inv = false;
+		pcm_priv->lrck_inv = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		pcm_priv->bck_inv = true;
+		pcm_priv->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		pcm_priv->bck_inv = true;
+		pcm_priv->lrck_inv = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		pcm_priv->slave_mode = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		pcm_priv->slave_mode = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
+	.startup	= mt8365_dai_pcm1_startup,
+	.shutdown	= mt8365_dai_pcm1_shutdown,
+	.prepare	= mt8365_dai_pcm1_prepare,
+	.set_fmt	= mt8365_dai_pcm1_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+	{
+		.name = "PCM1",
+		.id = MT8365_AFE_IO_PCM1,
+		.playback = {
+			.stream_name = "PCM1 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_32000 |
+				 SNDRV_PCM_RATE_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "PCM1 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000 |
+				 SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_32000 |
+				 SNDRV_PCM_RATE_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_dai_pcm1_ops,
+		.symmetric_rate = 1,
+		.symmetric_sample_bits = 1,
+	}
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("PCM1 Out"),
+	SND_SOC_DAPM_INPUT("PCM1 In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+	{"PCM1 Playback", NULL, "O07"},
+	{"PCM1 Playback", NULL, "O08"},
+	{"PCM1 Out", NULL, "PCM1 Playback"},
+
+	{"I09", NULL, "PCM1 Capture"},
+	{"I22", NULL, "PCM1 Capture"},
+	{"PCM1 Capture", NULL, "PCM1 In"},
+};
+
+static int init_pcmif_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_pcm_intf_data *pcmif_priv;
+
+	pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
+				  GFP_KERNEL);
+	if (!pcmif_priv)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
+	return 0;
+}
+
+int mt8365_dai_pcm_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+	dai->dai_drivers = mtk_dai_pcm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+	dai->dapm_widgets = mtk_dai_pcm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+	dai->dapm_routes = mtk_dai_pcm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+	return init_pcmif_priv_data(afe);
+}

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 09/18] ASoC: mediatek: mt8365: Add DMIC DAI support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add Digital Micro Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-dai-dmic.c | 347 ++++++++++++++++++++++++++++
 1 file changed, 347 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
new file mode 100644
index 000000000000..0dd606274d8e
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI DMIC Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ *          Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mt8365_dmic_data {
+	bool two_wire_mode;
+	unsigned int clk_phase_sel_ch1;
+	unsigned int clk_phase_sel_ch2;
+	bool iir_on;
+	unsigned int irr_mode;
+	unsigned int dmic_mode;
+	unsigned int dmic_channel;
+};
+
+static int get_chan_reg(unsigned int channel)
+{
+	switch (channel) {
+	case 8:
+		fallthrough;
+	case 7:
+		return AFE_DMIC3_UL_SRC_CON0;
+	case 6:
+		fallthrough;
+	case 5:
+		return AFE_DMIC2_UL_SRC_CON0;
+	case 4:
+		fallthrough;
+	case 3:
+		return AFE_DMIC1_UL_SRC_CON0;
+	case 2:
+		fallthrough;
+	case 1:
+		return AFE_DMIC0_UL_SRC_CON0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/* DAI Drivers */
+
+static void audio_dmic_adda_enable(struct mtk_base_afe *afe)
+{
+	mt8365_dai_enable_adda_on(afe);
+	regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+			   AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,
+			   AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+}
+
+static void audio_dmic_adda_disable(struct mtk_base_afe *afe)
+{
+	regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+			   AFE_ADDA_UL_DL_DMIC_CLKDIV_ON,
+			   ~AFE_ADDA_UL_DL_DMIC_CLKDIV_ON);
+	mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_enable_dmic(struct mtk_base_afe *afe,
+				   struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+	unsigned int val_mask;
+	int reg = get_chan_reg(dmic_data->dmic_channel);
+
+	if (reg < 0)
+		return;
+
+	/* val and mask will be always same to enable */
+	val_mask = DMIC_TOP_CON_CH1_ON |
+		   DMIC_TOP_CON_CH2_ON |
+		   DMIC_TOP_CON_SRC_ON;
+
+	regmap_update_bits(afe->regmap, reg, val_mask, val_mask);
+}
+
+static void mt8365_dai_disable_dmic(struct mtk_base_afe *afe,
+				    struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+	unsigned int mask;
+	int reg = get_chan_reg(dmic_data->dmic_channel);
+
+	if (reg < 0)
+		return;
+
+	dev_info(afe->dev, "%s dmic_channel %d\n",
+		 __func__, dmic_data->dmic_channel);
+
+	mask = DMIC_TOP_CON_CH1_ON |
+	       DMIC_TOP_CON_CH2_ON |
+	       DMIC_TOP_CON_SRC_ON |
+	       DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+	/* Set all masked values to 0 */
+	regmap_update_bits(afe->regmap, reg, mask, 0);
+}
+
+static const struct reg_sequence mt8365_dmic_iir_coeff[] = {
+	{ AFE_DMIC0_IIR_COEF_02_01, 0x00000000 },
+	{ AFE_DMIC0_IIR_COEF_04_03, 0x00003FB8 },
+	{ AFE_DMIC0_IIR_COEF_06_05, 0x3FB80000 },
+	{ AFE_DMIC0_IIR_COEF_08_07, 0x3FB80000 },
+	{ AFE_DMIC0_IIR_COEF_10_09, 0x0000C048 },
+	{ AFE_DMIC1_IIR_COEF_02_01, 0x00000000 },
+	{ AFE_DMIC1_IIR_COEF_04_03, 0x00003FB8 },
+	{ AFE_DMIC1_IIR_COEF_06_05, 0x3FB80000 },
+	{ AFE_DMIC1_IIR_COEF_08_07, 0x3FB80000 },
+	{ AFE_DMIC1_IIR_COEF_10_09, 0x0000C048 },
+	{ AFE_DMIC2_IIR_COEF_02_01, 0x00000000 },
+	{ AFE_DMIC2_IIR_COEF_04_03, 0x00003FB8 },
+	{ AFE_DMIC2_IIR_COEF_06_05, 0x3FB80000 },
+	{ AFE_DMIC2_IIR_COEF_08_07, 0x3FB80000 },
+	{ AFE_DMIC2_IIR_COEF_10_09, 0x0000C048 },
+	{ AFE_DMIC3_IIR_COEF_02_01, 0x00000000 },
+	{ AFE_DMIC3_IIR_COEF_04_03, 0x00003FB8 },
+	{ AFE_DMIC3_IIR_COEF_06_05, 0x3FB80000 },
+	{ AFE_DMIC3_IIR_COEF_08_07, 0x3FB80000 },
+	{ AFE_DMIC3_IIR_COEF_10_09, 0x0000C048 },
+};
+
+static int mt8365_dai_load_dmic_iir_coeff_table(struct mtk_base_afe *afe)
+{
+	return regmap_multi_reg_write(afe->regmap,
+				      mt8365_dmic_iir_coeff,
+				      ARRAY_SIZE(mt8365_dmic_iir_coeff));
+}
+
+static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe,
+				     struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_dmic_data *dmic_data = afe_priv->dai_priv[MT8365_AFE_IO_DMIC];
+	bool two_wire_mode = dmic_data->two_wire_mode;
+	unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1;
+	unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	unsigned int rate = dai->rate;
+	int reg = get_chan_reg(dai->channels);
+
+	if (reg < 0)
+		return -EINVAL;
+
+	dmic_data->dmic_channel = dai->channels;
+
+	val |= DMIC_TOP_CON_SDM3_LEVEL_MODE;
+	mask |= DMIC_TOP_CON_SDM3_LEVEL_MODE;
+
+	if (two_wire_mode) {
+		val |= DMIC_TOP_CON_TWO_WIRE_MODE;
+		mask |= DMIC_TOP_CON_TWO_WIRE_MODE;
+	} else {
+		val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH1,
+				  clk_phase_sel_ch1);
+		val |= FIELD_PREP(DMIC_TOP_CON_CK_PHASE_SEL_CH2,
+				  clk_phase_sel_ch2);
+		mask |= DMIC_TOP_CON_CK_PHASE_SEL_CH1;
+		mask |= DMIC_TOP_CON_CK_PHASE_SEL_CH2;
+	}
+
+	switch (rate) {
+	case 48000:
+		val |= DMIC_TOP_CON_VOICE_MODE_48K;
+		break;
+	case 32000:
+		val |= DMIC_TOP_CON_VOICE_MODE_32K;
+		break;
+	case 16000:
+		val |= DMIC_TOP_CON_VOICE_MODE_16K;
+		break;
+	case 8000:
+		val |= DMIC_TOP_CON_VOICE_MODE_8K;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mask |= DMIC_TOP_CON_VOICE_MODE_MASK;
+
+	regmap_update_bits(afe->regmap, reg, DMIC_TOP_CON_CONFIG_MASK, val);
+
+	return 0;
+}
+
+static int mt8365_dai_dmic_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mt8365_afe_enable_main_clk(afe);
+
+	mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+	mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+	mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+	mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+
+	audio_dmic_adda_enable(afe);
+
+	return 0;
+}
+
+static void mt8365_dai_dmic_shutdown(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mt8365_dai_disable_dmic(afe, substream, dai);
+	audio_dmic_adda_disable(afe);
+	/* HW Request delay 125us before CG off */
+	usleep_range(125, 300);
+	mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC3_ADC);
+	mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC2_ADC);
+	mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC1_ADC);
+	mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DMIC0_ADC);
+
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_dmic_prepare(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mt8365_dai_configure_dmic(afe, substream, dai);
+	mt8365_dai_enable_dmic(afe, substream, dai);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_dmic_ops = {
+	.startup	= mt8365_dai_dmic_startup,
+	.shutdown	= mt8365_dai_dmic_shutdown,
+	.prepare	= mt8365_dai_dmic_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {
+	{
+		.name = "DMIC",
+		.id = MT8365_AFE_IO_DMIC,
+		.capture = {
+			.stream_name = "DMIC Capture",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_32000 |
+				 SNDRV_PCM_RATE_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_dmic_ops,
+	}
+};
+
+/* DAI Controls */
+
+/* Values for 48kHz mode */
+static const char * const iir_mode_src[] = {
+	"SW custom", "5Hz", "10Hz", "25Hz", "50Hz", "65Hz"
+};
+
+static SOC_ENUM_SINGLE_DECL(iir_mode, AFE_DMIC0_UL_SRC_CON0, 7, iir_mode_src);
+
+static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {
+	SOC_SINGLE("DMIC IIR Switch", AFE_DMIC0_UL_SRC_CON0, DMIC_TOP_CON_IIR_ON, 1, 0),
+	SOC_ENUM("DMIC IIR Mode", iir_mode),
+};
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC In"),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {
+	{"I14", NULL, "DMIC Capture"},
+	{"I15", NULL, "DMIC Capture"},
+	{"I16", NULL, "DMIC Capture"},
+	{"I17", NULL, "DMIC Capture"},
+	{"I18", NULL, "DMIC Capture"},
+	{"I19", NULL, "DMIC Capture"},
+	{"I20", NULL, "DMIC Capture"},
+	{"I21", NULL, "DMIC Capture"},
+	{"DMIC Capture", NULL, "DMIC In"},
+};
+
+static int init_dmic_priv_data(struct mtk_base_afe *afe)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_dmic_data *dmic_priv;
+	struct device_node *np = afe->dev->of_node;
+	unsigned int temps[4];
+	int ret;
+
+	dmic_priv = devm_kzalloc(afe->dev, sizeof(*dmic_priv), GFP_KERNEL);
+	if (!dmic_priv)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "mediatek,dmic-mode",
+					 &temps[0],
+					 1);
+	if (ret == 0)
+		dmic_priv->two_wire_mode = !!temps[0];
+
+	if (!dmic_priv->two_wire_mode) {
+		dmic_priv->clk_phase_sel_ch1 = 0;
+		dmic_priv->clk_phase_sel_ch2 = 4;
+	}
+
+	afe_priv->dai_priv[MT8365_AFE_IO_DMIC] = dmic_priv;
+	return 0;
+}
+
+int mt8365_dai_dmic_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+	dai->dai_drivers = mtk_dai_dmic_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);
+	dai->controls = mtk_dai_dmic_controls;
+	dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);
+	dai->dapm_widgets = mtk_dai_dmic_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);
+	dai->dapm_routes = mtk_dai_dmic_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);
+	return init_dmic_priv_data(afe);
+}

-- 
2.25.1


^ permalink raw reply related

* [PATCH v10 1/6] arm64: dts: qcom: sm8450: Add interconnect path to PCIe node
From: Krishna chaitanya chundru @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Manivannan Sadhasivam, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Bjorn Helgaas, johan+linaro, bmasney,
	djakov
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, vireshk,
	quic_vbadigan, quic_skananth, quic_nitegupt, quic_parass,
	quic_krichai, krzysztof.kozlowski
In-Reply-To: <20240409-opp_support-v10-0-1956e6be343f@quicinc.com>

Add PCIe-MEM & CPU-PCIe interconnect path to the PCIe nodes.

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
---
 arch/arm64/boot/dts/qcom/sm8450.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
index b86be34a912b..615296e13c43 100644
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
@@ -1807,6 +1807,12 @@ pcie0: pcie@1c00000 {
 					<0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
 					<0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
+			interconnects = <&pcie_noc MASTER_PCIE_0 QCOM_ICC_TAG_ALWAYS
+					 &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+					<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+					 &config_noc SLAVE_PCIE_0 QCOM_ICC_TAG_ALWAYS>;
+			interconnect-names = "pcie-mem", "cpu-pcie";
+
 			clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
 				 <&gcc GCC_PCIE_0_PIPE_CLK_SRC>,
 				 <&pcie0_phy>,
@@ -1930,6 +1936,12 @@ pcie1: pcie@1c08000 {
 					<0 0 0 3 &intc 0 0 0 438 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
 					<0 0 0 4 &intc 0 0 0 439 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
 
+			interconnects = <&pcie_noc MASTER_PCIE_1 QCOM_ICC_TAG_ALWAYS
+					 &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
+					<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS
+					 &config_noc SLAVE_PCIE_1 QCOM_ICC_TAG_ALWAYS>;
+			interconnect-names = "pcie-mem", "cpu-pcie";
+
 			clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
 				 <&gcc GCC_PCIE_1_PIPE_CLK_SRC>,
 				 <&pcie1_phy>,

-- 
2.42.0


^ permalink raw reply related

* [PATCH v2 08/18] ASoC: mediatek: mt8365: Add ADDA DAI support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add ADDA Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-dai-adda.c | 315 ++++++++++++++++++++++++++++
 1 file changed, 315 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-adda.c b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
new file mode 100644
index 000000000000..65d45010ac90
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-adda.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI ADDA Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ *          Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+#include "../common/mtk-dai-adda-common.h"
+
+static int adda_afe_on_ref_cnt;
+
+/* DAI Drivers */
+
+static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)
+{
+	unsigned int val;
+
+	switch (rate) {
+	case 8000:
+		val = AFE_ADDA_DL_VOICE_DATA;
+		break;
+	case 16000:
+		val = AFE_ADDA_DL_VOICE_DATA;
+		break;
+	default:
+		val = 0;
+	}
+
+	val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,
+		mtk_adda_dl_rate_transform(afe, rate));
+	val |= AFE_ADDA_DL_8X_UPSAMPLE |
+	       AFE_ADDA_DL_MUTE_OFF_CH1 |
+	       AFE_ADDA_DL_MUTE_OFF_CH2 |
+	       AFE_ADDA_DL_DEGRADE_GAIN;
+
+	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);
+	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);
+	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);
+	/* SA suggest apply -0.3db to audio/speech path */
+	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,
+			   0xffffffff, 0xf74f0000);
+	/* SA suggest use default value for sdm */
+	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
+			   0xffffffff, 0x0700701e);
+
+	return 0;
+}
+
+static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)
+{
+	unsigned int val;
+
+	val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,
+			 mtk_adda_ul_rate_transform(afe, rate));
+	regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
+			   AFE_ADDA_UL_SAMPLING_RATE, val);
+	/* Using Internal ADC */
+	regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);
+
+	return 0;
+}
+
+int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)
+{
+	unsigned long flags;
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+	adda_afe_on_ref_cnt++;
+	if (adda_afe_on_ref_cnt == 1)
+		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+				   AFE_ADDA_UL_DL_ADDA_AFE_ON,
+				   AFE_ADDA_UL_DL_ADDA_AFE_ON);
+
+	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+	return 0;
+}
+
+int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)
+{
+	unsigned long flags;
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+	adda_afe_on_ref_cnt--;
+	if (adda_afe_on_ref_cnt == 0)
+		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
+				   AFE_ADDA_UL_DL_ADDA_AFE_ON,
+				   ~AFE_ADDA_UL_DL_ADDA_AFE_ON);
+	else if (adda_afe_on_ref_cnt < 0)
+		adda_afe_on_ref_cnt = 0;
+
+	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+
+	return 0;
+}
+
+static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,
+					   bool enable)
+{
+	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);
+
+	if (enable)
+		mt8365_dai_enable_adda_on(afe);
+	else
+		mt8365_dai_disable_adda_on(afe);
+}
+
+static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable)
+{
+	if (enable) {
+		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);
+		mt8365_dai_enable_adda_on(afe);
+		/* enable aud_pad_top fifo */
+		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+				   0xffffffff, 0x31);
+	} else {
+		/* disable aud_pad_top fifo */
+		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
+				   0xffffffff, 0x30);
+		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);
+		/* de suggest disable ADDA_UL_SRC at least wait 125us */
+		usleep_range(150, 300);
+		mt8365_dai_disable_adda_on(afe);
+	}
+}
+
+static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	unsigned int stream = substream->stream;
+
+	mt8365_afe_enable_main_clk(afe);
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);
+		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);
+	}
+
+	return 0;
+}
+
+static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,
+					 struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be =
+		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+	unsigned int stream = substream->stream;
+
+	if (be->prepared[stream]) {
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			mt8365_dai_set_adda_out_enable(afe, false);
+			mt8365_afe_set_i2s_out_enable(afe, false);
+		} else {
+			mt8365_dai_set_adda_in_enable(afe, false);
+		}
+		be->prepared[stream] = false;
+	}
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
+		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);
+	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);
+	}
+
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,
+				       struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be =
+		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+	unsigned int rate = substream->runtime->rate;
+	int bit_width = snd_pcm_format_width(substream->runtime->format);
+	int ret;
+
+	dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,
+		 snd_pcm_stream_str(substream), rate);
+
+	if (be->prepared[substream->stream]) {
+		dev_info(afe->dev, "%s '%s' prepared already\n",
+			 __func__, snd_pcm_stream_str(substream));
+		return 0;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret = mt8365_dai_set_adda_out(afe, rate);
+		if (ret)
+			return ret;
+
+		ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);
+		if (ret)
+			return ret;
+
+		mt8365_dai_set_adda_out_enable(afe, true);
+		mt8365_afe_set_i2s_out_enable(afe, true);
+	} else {
+		ret = mt8365_dai_set_adda_in(afe, rate);
+		if (ret)
+			return ret;
+
+		mt8365_dai_set_adda_in_enable(afe, true);
+	}
+	be->prepared[substream->stream] = true;
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {
+	.startup	= mt8365_dai_int_adda_startup,
+	.shutdown	= mt8365_dai_int_adda_shutdown,
+	.prepare	= mt8365_dai_int_adda_prepare,
+};
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+	{
+		.name = "INT ADDA",
+		.id = MT8365_AFE_IO_INT_ADDA,
+		.playback = {
+			.stream_name = "INT ADDA Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			.stream_name = "INT ADDA Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_16000 |
+				 SNDRV_PCM_RATE_32000 |
+				 SNDRV_PCM_RATE_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_int_adda_ops,
+	}
+};
+
+/* DAI Controls */
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
+				    10, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
+				    11, 1, 0),
+};
+
+static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+/* DAI widget */
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+	SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,
+			    &int_adda_o03_o04_enable_ctl),
+	/* inter-connections */
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch1_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+			   mtk_adda_dl_ch2_mix,
+			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+};
+
+/* DAI route */
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+	{"INT ADDA O03_O04", "Switch", "O03"},
+	{"INT ADDA O03_O04", "Switch", "O04"},
+	{"INT ADDA Playback", NULL, "INT ADDA O03_O04"},
+	{"INT ADDA Playback", NULL, "ADDA_DL_CH1"},
+	{"INT ADDA Playback", NULL, "ADDA_DL_CH2"},
+	{"AIN Mux", "INT ADC", "INT ADDA Capture"},
+	{"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},
+	{"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},
+};
+
+int mt8365_dai_adda_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+	list_add(&dai->list, &afe->sub_dais);
+	dai->dai_drivers = mtk_dai_adda_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+	dai->dapm_widgets = mtk_dai_adda_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+	dai->dapm_routes = mtk_dai_adda_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+	return 0;
+}

-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 07/18] ASoC: mediatek: mt8365: Add I2S DAI support
From: Alexandre Mergnat @ 2024-04-09 10:13 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Lee Jones, Flora Fu, Jaroslav Kysela, Takashi Iwai, Sumit Semwal,
	Christian König, Catalin Marinas, Will Deacon, Rob Herring
  Cc: linux-sound, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-media, dri-devel, linaro-mm-sig,
	Alexandre Mergnat
In-Reply-To: <20240226-audio-i350-v2-0-3043d483de0d@baylibre.com>

Add I2S Device Audio Interface support for MT8365 SoC.

Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
 sound/soc/mediatek/mt8365/mt8365-dai-i2s.c | 854 +++++++++++++++++++++++++++++
 1 file changed, 854 insertions(+)

diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
new file mode 100644
index 000000000000..c12d75dfe215
--- /dev/null
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
@@ -0,0 +1,854 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek 8365 ALSA SoC Audio DAI I2S Control
+ *
+ * Copyright (c) 2024 MediaTek Inc.
+ * Authors: Jia Zeng <jia.zeng@mediatek.com>
+ *          Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8365-afe-clk.h"
+#include "mt8365-afe-common.h"
+
+struct mtk_afe_i2s_priv {
+	bool adda_link;
+	int i2s_out_on_ref_cnt;
+	int id;
+	int low_jitter_en;
+	int mclk_id;
+	int share_i2s_id;
+	unsigned int clk_id_in;
+	unsigned int clk_id_in_m_sel;
+	unsigned int clk_id_out;
+	unsigned int clk_id_out_m_sel;
+	unsigned int clk_in_mult;
+	unsigned int clk_out_mult;
+	unsigned int config_val_in;
+	unsigned int config_val_out;
+	unsigned int dynamic_bck;
+	unsigned int reg_off_in;
+	unsigned int reg_off_out;
+};
+
+/* This enum is merely for mtk_afe_i2s_priv declare */
+enum {
+	DAI_I2S0 = 0,
+	DAI_I2S3,
+	DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8365_i2s_priv[DAI_I2S_NUM] = {
+	[DAI_I2S0] = {
+		.id = MT8365_AFE_IO_I2S,
+		.mclk_id = MT8365_I2S0_MCK,
+		.share_i2s_id = -1,
+		.clk_id_in = MT8365_CLK_AUD_I2S2_M,
+		.clk_id_out = MT8365_CLK_AUD_I2S1_M,
+		.clk_id_in_m_sel = MT8365_CLK_I2S2_M_SEL,
+		.clk_id_out_m_sel = MT8365_CLK_I2S1_M_SEL,
+		.clk_in_mult = 256,
+		.clk_out_mult = 256,
+		.adda_link = true,
+		.config_val_out = AFE_I2S_CON1_I2S2_TO_PAD,
+		.reg_off_in = AFE_I2S_CON2,
+		.reg_off_out = AFE_I2S_CON1,
+	},
+	[DAI_I2S3] = {
+		.id = MT8365_AFE_IO_2ND_I2S,
+		.mclk_id = MT8365_I2S3_MCK,
+		.share_i2s_id = -1,
+		.clk_id_in = MT8365_CLK_AUD_I2S0_M,
+		.clk_id_out = MT8365_CLK_AUD_I2S3_M,
+		.clk_id_in_m_sel = MT8365_CLK_I2S0_M_SEL,
+		.clk_id_out_m_sel = MT8365_CLK_I2S3_M_SEL,
+		.clk_in_mult = 256,
+		.clk_out_mult = 256,
+		.adda_link = false,
+		.config_val_in = AFE_I2S_CON_FROM_IO_MUX,
+		.reg_off_in = AFE_I2S_CON,
+		.reg_off_out = AFE_I2S_CON3,
+	},
+};
+
+static const u32 *get_iir_coef(unsigned int input_fs,
+			       unsigned int output_fs, unsigned int *count)
+{
+#define RATIOVER 9
+#define INV_COEF 10
+#define NO_NEED 11
+
+	static const u32 IIR_COEF_48_TO_44p1[30] = {
+		0x061fb0, 0x0bd256, 0x061fb0, 0xe3a3e6, 0xf0a300, 0x000003,
+		0x0e416d, 0x1bb577, 0x0e416d, 0xe59178, 0xf23637, 0x000003,
+		0x0c7d72, 0x189060, 0x0c7d72, 0xe96f09, 0xf505b2, 0x000003,
+		0x126054, 0x249143, 0x126054, 0xe1fc0c, 0xf4b20a, 0x000002,
+		0x000000, 0x323c85, 0x323c85, 0xf76d4e, 0x000000, 0x000002,
+	};
+
+	static const u32 IIR_COEF_44p1_TO_32[42] = {
+		0x0a6074, 0x0d237a, 0x0a6074, 0xdd8d6c, 0xe0b3f6, 0x000002,
+		0x0e41f8, 0x128d48, 0x0e41f8, 0xefc14e, 0xf12d7a, 0x000003,
+		0x0cfa60, 0x11e89c, 0x0cfa60, 0xf1b09e, 0xf27205, 0x000003,
+		0x15b69c, 0x20e7e4, 0x15b69c, 0xea799a, 0xe9314a, 0x000002,
+		0x0f79e2, 0x1a7064, 0x0f79e2, 0xf65e4a, 0xf03d8e, 0x000002,
+		0x10c34f, 0x1ffe4b, 0x10c34f, 0x0bbecb, 0xf2bc4b, 0x000001,
+		0x000000, 0x23b063, 0x23b063, 0x07335f, 0x000000, 0x000002,
+	};
+
+	static const u32 IIR_COEF_48_TO_32[42] = {
+		0x0a2a9b, 0x0a2f05, 0x0a2a9b, 0xe73873, 0xe0c525, 0x000002,
+		0x0dd4ad, 0x0e765a, 0x0dd4ad, 0xf49808, 0xf14844, 0x000003,
+		0x18a8cd, 0x1c40d0, 0x18a8cd, 0xed2aab, 0xe542ec, 0x000002,
+		0x13e044, 0x1a47c4, 0x13e044, 0xf44aed, 0xe9acc7, 0x000002,
+		0x1abd9c, 0x2a5429, 0x1abd9c, 0xff3441, 0xe0fc5f, 0x000001,
+		0x0d86db, 0x193e2e, 0x0d86db, 0x1a6f15, 0xf14507, 0x000001,
+		0x000000, 0x1f820c, 0x1f820c, 0x0a1b1f, 0x000000, 0x000002,
+	};
+
+	static const u32 IIR_COEF_32_TO_16[48] = {
+		0x122893, 0xffadd4, 0x122893, 0x0bc205, 0xc0ee1c, 0x000001,
+		0x1bab8a, 0x00750d, 0x1bab8a, 0x06a983, 0xe18a5c, 0x000002,
+		0x18f68e, 0x02706f, 0x18f68e, 0x0886a9, 0xe31bcb, 0x000002,
+		0x149c05, 0x054487, 0x149c05, 0x0bec31, 0xe5973e, 0x000002,
+		0x0ea303, 0x07f24a, 0x0ea303, 0x115ff9, 0xe967b6, 0x000002,
+		0x0823fd, 0x085531, 0x0823fd, 0x18d5b4, 0xee8d21, 0x000002,
+		0x06888e, 0x0acbbb, 0x06888e, 0x40b55c, 0xe76dce, 0x000001,
+		0x000000, 0x2d31a9, 0x2d31a9, 0x23ba4f, 0x000000, 0x000001,
+	};
+
+	static const u32 IIR_COEF_96_TO_44p1[48] = {
+		0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002,
+		0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002,
+		0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002,
+		0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002,
+		0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002,
+		0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002,
+		0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001,
+		0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001,
+	};
+
+	static const u32 IIR_COEF_44p1_TO_16[48] = {
+		0x0998fb, 0xf7f925, 0x0998fb, 0x1e54a0, 0xe06605, 0x000002,
+		0x0d828e, 0xf50f97, 0x0d828e, 0x0f41b5, 0xf0a999, 0x000003,
+		0x17ebeb, 0xee30d8, 0x17ebeb, 0x1f48ca, 0xe2ae88, 0x000002,
+		0x12fab5, 0xf46ddc, 0x12fab5, 0x20cc51, 0xe4d068, 0x000002,
+		0x0c7ac6, 0xfbd00e, 0x0c7ac6, 0x2337da, 0xe8028c, 0x000002,
+		0x060ddc, 0x015b3e, 0x060ddc, 0x266754, 0xec21b6, 0x000002,
+		0x0407b5, 0x04f827, 0x0407b5, 0x52e3d0, 0xe0149f, 0x000001,
+		0x000000, 0x1f9521, 0x1f9521, 0x2ac116, 0x000000, 0x000001,
+	};
+
+	static const u32 IIR_COEF_48_TO_16[48] = {
+		0x0955ff, 0xf6544a, 0x0955ff, 0x2474e5, 0xe062e6, 0x000002,
+		0x0d4180, 0xf297f4, 0x0d4180, 0x12415b, 0xf0a3b0, 0x000003,
+		0x0ba079, 0xf4f0b0, 0x0ba079, 0x1285d3, 0xf1488b, 0x000003,
+		0x12247c, 0xf1033c, 0x12247c, 0x2625be, 0xe48e0d, 0x000002,
+		0x0b98e0, 0xf96d1a, 0x0b98e0, 0x27e79c, 0xe7798a, 0x000002,
+		0x055e3b, 0xffed09, 0x055e3b, 0x2a2e2d, 0xeb2854, 0x000002,
+		0x01a934, 0x01ca03, 0x01a934, 0x2c4fea, 0xee93ab, 0x000002,
+		0x000000, 0x1c46c5, 0x1c46c5, 0x2d37dc, 0x000000, 0x000001,
+	};
+
+	static const u32 IIR_COEF_96_TO_16[48] = {
+		0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002,
+		0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003,
+		0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003,
+		0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003,
+		0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002,
+		0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002,
+		0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002,
+		0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001,
+	};
+
+	static const struct {
+		const u32 *coef;
+		unsigned int cnt;
+	} iir_coef_tbl_list[8] = {
+		/* 0: 0.9188 */
+		{ IIR_COEF_48_TO_44p1, ARRAY_SIZE(IIR_COEF_48_TO_44p1) },
+		/* 1: 0.7256 */
+		{ IIR_COEF_44p1_TO_32, ARRAY_SIZE(IIR_COEF_44p1_TO_32) },
+		/* 2: 0.6667 */
+		{ IIR_COEF_48_TO_32, ARRAY_SIZE(IIR_COEF_48_TO_32) },
+		/* 3: 0.5 */
+		{ IIR_COEF_32_TO_16, ARRAY_SIZE(IIR_COEF_32_TO_16) },
+		/* 4: 0.4594 */
+		{ IIR_COEF_96_TO_44p1, ARRAY_SIZE(IIR_COEF_96_TO_44p1) },
+		/* 5: 0.3628 */
+		{ IIR_COEF_44p1_TO_16, ARRAY_SIZE(IIR_COEF_44p1_TO_16) },
+		/* 6: 0.3333 */
+		{ IIR_COEF_48_TO_16, ARRAY_SIZE(IIR_COEF_48_TO_16) },
+		/* 7: 0.1667 */
+		{ IIR_COEF_96_TO_16, ARRAY_SIZE(IIR_COEF_96_TO_16) },
+	};
+
+	static const u32 freq_new_index[16] = {
+		0, 1, 2, 99, 3, 4, 5, 99, 6, 7, 8, 9, 10, 11, 12, 99
+	};
+
+	static const u32 iir_coef_tbl_matrix[13][13] = {
+		{/*0*/
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*1*/
+			1, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*2*/
+			2, 0, NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*3*/
+			3, INV_COEF, INV_COEF, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*4*/
+			5, 3, INV_COEF, 2, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*5*/
+			6, 4, 3, 2, 0, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED
+		},
+		{/*6*/
+			INV_COEF, INV_COEF, INV_COEF, 3, INV_COEF,
+			INV_COEF, NO_NEED, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*7*/
+			INV_COEF, INV_COEF, INV_COEF, 5, 3,
+			INV_COEF, 1, NO_NEED, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*8*/
+			7, INV_COEF, INV_COEF, 6, 4, 3, 2, 0, NO_NEED,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*9*/
+			INV_COEF, INV_COEF, INV_COEF, INV_COEF,
+			INV_COEF, INV_COEF, 5, 3, INV_COEF,
+			NO_NEED, NO_NEED, NO_NEED, NO_NEED
+		},
+		{/*10*/
+			INV_COEF, INV_COEF, INV_COEF, 7, INV_COEF,
+			INV_COEF, 6, 4, 3, 0,
+			NO_NEED, NO_NEED, NO_NEED
+		},
+		{ /*11*/
+			RATIOVER, INV_COEF, INV_COEF, INV_COEF,
+			INV_COEF, INV_COEF, INV_COEF, INV_COEF,
+			INV_COEF, 3, INV_COEF, NO_NEED, NO_NEED
+		},
+		{/*12*/
+			RATIOVER, RATIOVER, INV_COEF, INV_COEF,
+			INV_COEF, INV_COEF, 7, INV_COEF,
+			INV_COEF, 4, 3, 0, NO_NEED
+		},
+	};
+
+	const u32 *coef = NULL;
+	unsigned int cnt = 0;
+	u32 i = freq_new_index[input_fs];
+	u32 j = freq_new_index[output_fs];
+
+	if (i >= 13 || j >= 13) {
+	} else {
+		u32 k = iir_coef_tbl_matrix[i][j];
+
+		if (k >= NO_NEED) {
+		} else if (k == RATIOVER) {
+		} else if (k == INV_COEF) {
+		} else {
+			coef = iir_coef_tbl_list[k].coef;
+			cnt = iir_coef_tbl_list[k].cnt;
+		}
+	}
+	*count = cnt;
+	return coef;
+}
+
+static int mt8365_dai_set_config(struct mtk_base_afe *afe,
+				 struct mtk_afe_i2s_priv *i2s_data,
+				 bool is_input, unsigned int rate,
+				 int bit_width)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be =
+	&afe_priv->be_data[i2s_data->id - MT8365_AFE_BACKEND_BASE];
+	unsigned int val, reg_off;
+	int fs = mt8365_afe_fs_timing(rate);
+
+	if (fs < 0)
+		return -EINVAL;
+
+	val = AFE_I2S_CON_LOW_JITTER_CLK |
+	      FIELD_PREP(AFE_I2S_CON_RATE_MASK, fs) |
+	      AFE_I2S_CON_FORMAT_I2S;
+
+	if (is_input) {
+		reg_off = i2s_data->reg_off_in;
+		if (i2s_data->adda_link)
+			val |= i2s_data->config_val_in;
+	} else {
+		reg_off = i2s_data->reg_off_out;
+		val |= i2s_data->config_val_in;
+	}
+
+	/* 1:bck=32lrck(16bit) or bck=64lrck(32bit) 0:fix bck=64lrck */
+	if (i2s_data->dynamic_bck) {
+		if (bit_width > 16)
+			val |= AFE_I2S_CON_WLEN_32BIT;
+		else
+			val &= ~(u32)AFE_I2S_CON_WLEN_32BIT;
+	} else {
+		val |= AFE_I2S_CON_WLEN_32BIT;
+	}
+
+	if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+	    SND_SOC_DAIFMT_CBM_CFM) {
+		val |= AFE_I2S_CON_SRC_SLAVE;
+		val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys
+	}
+
+	regmap_update_bits(afe->regmap, reg_off, ~(u32)AFE_I2S_CON_EN, val);
+
+	if (i2s_data->adda_link && is_input)
+		regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x1);
+
+	return 0;
+}
+
+int mt8365_afe_set_i2s_out(struct mtk_base_afe *afe,
+			   unsigned int rate, int bit_width)
+{
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_data =
+		afe_priv->dai_priv[MT8365_AFE_IO_I2S];
+
+	return mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width);
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc(struct mtk_base_afe *afe,
+				       unsigned int rate_in,
+				       unsigned int rate_out,
+				       unsigned int width,
+				       unsigned int mono,
+				       int o16bit, int tracking)
+{
+	int ifs, ofs = 0;
+	unsigned int val = 0;
+	unsigned int mask = 0;
+	const u32 *coef;
+	u32 iir_stage;
+	unsigned int coef_count = 0;
+
+	ifs = mt8365_afe_fs_timing(rate_in);
+
+	if (ifs < 0)
+		return -EINVAL;
+
+	ofs = mt8365_afe_fs_timing(rate_out);
+
+	if (ofs < 0)
+		return -EINVAL;
+
+	val = FIELD_PREP(O16BIT, o16bit) | FIELD_PREP(IS_MONO, mono);
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+			   O16BIT | IS_MONO, val);
+
+	coef = get_iir_coef(ifs, ofs, &coef_count);
+	iir_stage = ((u32)coef_count / 6) - 1;
+
+	if (coef) {
+		unsigned int i;
+
+		/* CPU control IIR coeff SRAM */
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+				   COEFF_SRAM_CTRL, COEFF_SRAM_CTRL);
+
+		/* set to 0, IIR coeff SRAM addr */
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON13,
+				   0xffffffff, 0x0);
+
+		for (i = 0; i < coef_count; ++i)
+			regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON12,
+					   0xffffffff, coef[i]);
+
+		/* disable IIR coeff SRAM access */
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+				   COEFF_SRAM_CTRL,
+				   (unsigned long)~COEFF_SRAM_CTRL);
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+				   CLR_IIR_HISTORY | IIR_EN | IIR_STAGE_MASK,
+				   CLR_IIR_HISTORY | IIR_EN |
+				   FIELD_PREP(IIR_STAGE_MASK, iir_stage));
+	} else {
+		/* disable IIR */
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+				   IIR_EN, (unsigned long)~IIR_EN);
+	}
+
+	/* CON3 setting (RX OFS) */
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON3,
+			   0x00FFFFFF, rx_frequency_palette(ofs));
+	/* CON4 setting (RX IFS) */
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON4,
+			   0x00FFFFFF, rx_frequency_palette(ifs));
+
+	/* CON5 setting */
+	if (tracking) {
+		val = CALI_64_CYCLE |
+		      CALI_AUTORST |
+		      AUTO_TUNE_FREQ5 |
+		      COMP_FREQ_RES |
+		      CALI_BP_DGL |
+		      CALI_AUTO_RESTART |
+		      CALI_USE_FREQ_OUT |
+		      CALI_SEL_01;
+
+		mask = CALI_CYCLE_MASK |
+		       CALI_AUTORST |
+		       AUTO_TUNE_FREQ5 |
+		       COMP_FREQ_RES |
+		       CALI_SEL_MASK |
+		       CALI_BP_DGL |
+		       AUTO_TUNE_FREQ4 |
+		       CALI_AUTO_RESTART |
+		       CALI_USE_FREQ_OUT |
+		       CALI_ON;
+
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+				   mask, val);
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+				   CALI_ON, CALI_ON);
+	} else {
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+				   0xffffffff, 0x0);
+	}
+	/* CON6 setting fix 8125 */
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON6,
+			   0x0000ffff, 0x1FBD);
+	/* CON9 setting (RX IFS) */
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON9,
+			   0x000fffff, AutoRstThHi(ifs));
+	/* CON10 setting (RX IFS) */
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON10,
+			   0x000fffff, AutoRstThLo(ifs));
+	regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+			   CHSET_STR_CLR, CHSET_STR_CLR);
+
+	return 0;
+}
+
+static int mt8365_afe_set_2nd_i2s_asrc_enable(struct mtk_base_afe *afe,
+					      bool enable)
+{
+	if (enable)
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+				   ASM_ON, ASM_ON);
+	else
+		regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+				   ASM_ON, (unsigned long)~ASM_ON);
+	return 0;
+}
+
+void mt8365_afe_set_i2s_out_enable(struct mtk_base_afe *afe, bool enable)
+{
+	int i;
+	unsigned long flags;
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_data;
+
+	for (i = 0; i < DAI_I2S_NUM; i++) {
+		if (mt8365_i2s_priv[i].adda_link)
+			i2s_data = afe_priv->dai_priv[mt8365_i2s_priv[i].id];
+	}
+
+	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
+
+	if (enable) {
+		i2s_data->i2s_out_on_ref_cnt++;
+		if (i2s_data->i2s_out_on_ref_cnt == 1)
+			regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+					   0x1, enable);
+	} else {
+		i2s_data->i2s_out_on_ref_cnt--;
+		if (i2s_data->i2s_out_on_ref_cnt == 0)
+			regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+					   0x1, enable);
+		else if (i2s_data->i2s_out_on_ref_cnt < 0)
+			i2s_data->i2s_out_on_ref_cnt = 0;
+	}
+
+	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
+}
+
+static void mt8365_dai_set_enable(struct mtk_base_afe *afe,
+				  struct mtk_afe_i2s_priv *i2s_data,
+				  bool is_input, bool enable)
+{
+	unsigned int reg_off;
+
+	if (is_input) {
+		reg_off = i2s_data->reg_off_in;
+	} else {
+		if (i2s_data->adda_link) {
+			mt8365_afe_set_i2s_out_enable(afe, enable);
+			return;
+		}
+		reg_off = i2s_data->reg_off_out;
+	}
+	regmap_update_bits(afe->regmap, reg_off,
+			   0x1, enable);
+}
+
+static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+	struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+	bool i2s_in_slave =
+		(substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
+		((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+		SND_SOC_DAIFMT_CBM_CFM);
+
+	mt8365_afe_enable_main_clk(afe);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		mt8365_afe_enable_clk(afe,
+				      afe_priv->clocks[i2s_data->clk_id_out]);
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && !i2s_in_slave)
+		mt8365_afe_enable_clk(afe,
+				      afe_priv->clocks[i2s_data->clk_id_in]);
+
+	if (i2s_in_slave)
+		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+	return 0;
+}
+
+static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+	struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+	bool reset_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	bool reset_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+	bool i2s_in_slave =
+		(substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
+		((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
+		SND_SOC_DAIFMT_CBM_CFM);
+
+	if (be->prepared[substream->stream]) {
+		if (reset_i2s_out_change)
+			mt8365_dai_set_enable(afe, i2s_data, false, false);
+
+		if (reset_i2s_in_change)
+			mt8365_dai_set_enable(afe, i2s_data, true, false);
+
+		if (substream->runtime->rate % 8000)
+			mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL1);
+		else
+			mt8365_afe_disable_apll_associated_cfg(afe, MT8365_AFE_APLL2);
+
+		if (reset_i2s_out_change)
+			be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = false;
+
+		if (reset_i2s_in_change)
+			be->prepared[SNDRV_PCM_STREAM_CAPTURE] = false;
+	}
+
+	if (reset_i2s_out_change)
+		mt8365_afe_disable_clk(afe,
+				       afe_priv->clocks[i2s_data->clk_id_out]);
+
+	if (reset_i2s_in_change && !i2s_in_slave)
+		mt8365_afe_disable_clk(afe,
+				       afe_priv->clocks[i2s_data->clk_id_in]);
+
+	if (i2s_in_slave)
+		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_I2S_IN);
+
+	mt8365_afe_disable_main_clk(afe);
+}
+
+static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_afe_i2s_priv *i2s_data = afe_priv->dai_priv[dai->id];
+	struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+	bool apply_i2s_out_change = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	bool apply_i2s_in_change = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+	unsigned int rate = substream->runtime->rate;
+	int bit_width = snd_pcm_format_width(substream->runtime->format);
+	int ret;
+
+	if (be->prepared[substream->stream]) {
+		dev_info(afe->dev, "%s '%s' prepared already\n",
+			 __func__, snd_pcm_stream_str(substream));
+		return 0;
+	}
+
+	if (apply_i2s_out_change) {
+		ret = mt8365_dai_set_config(afe, i2s_data, false, rate, bit_width);
+		if (ret)
+			return ret;
+	}
+
+	if (apply_i2s_in_change) {
+		if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+		    == SND_SOC_DAIFMT_CBM_CFM) {
+			ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate,
+							  (unsigned int)bit_width,
+							  0, 0, 1);
+			if (ret < 0)
+				return ret;
+		}
+		ret = mt8365_dai_set_config(afe, i2s_data, true, rate, bit_width);
+		if (ret)
+			return ret;
+	}
+
+	if (rate % 8000)
+		mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL1);
+	else
+		mt8365_afe_enable_apll_associated_cfg(afe, MT8365_AFE_APLL2);
+
+	if (apply_i2s_out_change) {
+		mt8365_afe_set_clk_parent(afe,
+					  afe_priv->clocks[i2s_data->clk_id_out_m_sel],
+					  ((rate % 8000) ?
+					  afe_priv->clocks[MT8365_CLK_AUD1] :
+					  afe_priv->clocks[MT8365_CLK_AUD2]));
+
+		mt8365_afe_set_clk_rate(afe,
+					afe_priv->clocks[i2s_data->clk_id_out],
+					rate * i2s_data->clk_out_mult);
+
+		mt8365_dai_set_enable(afe, i2s_data, false, true);
+		be->prepared[SNDRV_PCM_STREAM_PLAYBACK] = true;
+	}
+
+	if (apply_i2s_in_change) {
+		mt8365_afe_set_clk_parent(afe,
+					  afe_priv->clocks[i2s_data->clk_id_in_m_sel],
+					  ((rate % 8000) ?
+					  afe_priv->clocks[MT8365_CLK_AUD1] :
+					  afe_priv->clocks[MT8365_CLK_AUD2]));
+
+		mt8365_afe_set_clk_rate(afe,
+					afe_priv->clocks[i2s_data->clk_id_in],
+					rate * i2s_data->clk_in_mult);
+
+		mt8365_dai_set_enable(afe, i2s_data, true, true);
+
+		if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
+		    == SND_SOC_DAIFMT_CBM_CFM)
+			mt8365_afe_set_2nd_i2s_asrc_enable(afe, true);
+
+		be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
+	}
+	return 0;
+}
+
+static int mt8365_afe_2nd_i2s_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params,
+					struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	unsigned int width_val = params_width(params) > 16 ?
+		(AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01) : 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		regmap_update_bits(afe->regmap, AFE_CONN_24BIT,
+				   AFE_CONN_24BIT_O00 | AFE_CONN_24BIT_O01, width_val);
+
+	return 0;
+}
+
+static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+	struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
+
+	be->fmt_mode = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		be->fmt_mode |= SND_SOC_DAIFMT_I2S;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		be->fmt_mode |= SND_SOC_DAIFMT_LEFT_J;
+		break;
+	default:
+		dev_info(afe->dev, "invalid audio format for 2nd i2s!\n");
+		return -EINVAL;
+	}
+
+	if (((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) &&
+	    ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_IF) &&
+	    ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_NF) &&
+	    ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_IB_IF)) {
+		dev_info(afe->dev, "invalid audio format for 2nd i2s!\n");
+		return -EINVAL;
+	}
+
+	be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+	if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM))
+		be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mt8365_afe_i2s_ops = {
+	.startup	= mt8365_dai_i2s_startup,
+	.shutdown	= mt8365_dai_i2s_shutdown,
+	.prepare	= mt8365_dai_i2s_prepare,
+};
+
+static const struct snd_soc_dai_ops mt8365_afe_2nd_i2s_ops = {
+	.startup	= mt8365_dai_i2s_startup,
+	.shutdown	= mt8365_dai_i2s_shutdown,
+	.hw_params	= mt8365_afe_2nd_i2s_hw_params,
+	.prepare	= mt8365_dai_i2s_prepare,
+	.set_fmt	= mt8365_afe_2nd_i2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+	{
+		.name = "I2S",
+		.id = MT8365_AFE_IO_I2S,
+		.playback = {
+			.stream_name = "I2S Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "I2S Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_i2s_ops,
+	}, {
+		.name = "2ND I2S",
+		.id = MT8365_AFE_IO_2ND_I2S,
+		.playback = {
+			.stream_name = "2ND I2S Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.capture = {
+			.stream_name = "2ND I2S Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = SNDRV_PCM_RATE_8000_192000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE,
+		},
+		.ops = &mt8365_afe_2nd_i2s_ops,
+	}
+};
+
+/* low jitter control */
+static const char * const mt8365_i2s_hd_str[] = {
+	"Normal", "Low_Jitter"
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(mt8365_i2s_enum, mt8365_i2s_hd_str);
+
+static const char * const fmi2sin_text[] = {
+	"OPEN", "FM_2ND_I2S_IN"
+};
+
+static SOC_ENUM_SINGLE_VIRT_DECL(fmi2sin_enum, fmi2sin_text);
+
+static const struct snd_kcontrol_new fmi2sin_mux =
+	SOC_DAPM_ENUM("FM 2ND I2S Source", fmi2sin_enum);
+
+static const struct snd_kcontrol_new i2s_o03_o04_enable_ctl =
+	SOC_DAPM_SINGLE_VIRT("Switch", 1);
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+	SND_SOC_DAPM_SWITCH("I2S O03_O04", SND_SOC_NOPM, 0, 0,
+			    &i2s_o03_o04_enable_ctl),
+	SND_SOC_DAPM_MUX("FM 2ND I2S Mux", SND_SOC_NOPM, 0, 0, &fmi2sin_mux),
+	SND_SOC_DAPM_INPUT("2ND I2S In"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+	{"I2S O03_O04", "Switch", "O03"},
+	{"I2S O03_O04", "Switch", "O04"},
+	{"I2S Playback", NULL, "I2S O03_O04"},
+	{"2ND I2S Playback", NULL, "O00"},
+	{"2ND I2S Playback", NULL, "O01"},
+	{"2ND I2S Capture", NULL, "2ND I2S In"},
+	{"FM 2ND I2S Mux", "FM_2ND_I2S_IN", "2ND I2S Capture"},
+};
+
+static int mt8365_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+	int i, ret;
+	struct mt8365_afe_private *afe_priv = afe->platform_priv;
+
+	for (i = 0; i < DAI_I2S_NUM; i++) {
+		ret = mt8365_dai_set_priv(afe, mt8365_i2s_priv[i].id,
+					  sizeof(*afe_priv),
+					  &mt8365_i2s_priv[i]);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+int mt8365_dai_i2s_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_i2s_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+	dai->dapm_widgets = mtk_dai_i2s_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+	dai->dapm_routes = mtk_dai_i2s_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+	/* set all dai i2s private data */
+	return mt8365_dai_i2s_set_priv(afe);
+}

-- 
2.25.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox