Merge Upstream Baylibre 4.19 branch into Excelsior repo

* Update kernel to 4.19.125
* Enable USB OTG

Change-Id: Ib197c9a2e66ba31f7fedb38835c5e7deb779593b
diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 509111f..0045410 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -6,6 +6,8 @@
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt6797-x20-dev.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt7622-rfb1.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-coral.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-coral-evt2-overlay.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-coral-display-overlay.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb
 dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8167-coral-display-overlay.dts b/arch/arm64/boot/dts/mediatek/mt8167-coral-display-overlay.dts
new file mode 100644
index 0000000..0be0d31
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8167-coral-display-overlay.dts
@@ -0,0 +1,28 @@
+// Set display panel config
+/dts-v1/;
+/plugin/;
+
+#include "mt8167-pinfunc.h"
+
+/ {
+	compatible = "mediatek,mt8167";
+	fragment@0 {
+		target = <&pio>;
+			__overlay__ {
+				pwm0_pin_default: pwm0_pin_default {
+					pins1 {
+						pinmux = <MT8167_PIN_25_EINT25__FUNC_PWM_B>;
+					};
+				};
+			};
+	};
+
+	fragment@1 {
+		target = <&pwm>;
+			__overlay__ {
+				status = "okay";
+				pinctrl-names = "default";
+				pinctrl-0 = <&pwm0_pin_default>;
+			};
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8167-coral-evt2-overlay.dts b/arch/arm64/boot/dts/mediatek/mt8167-coral-evt2-overlay.dts
new file mode 100644
index 0000000..a9e0b9d
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8167-coral-evt2-overlay.dts
@@ -0,0 +1,13 @@
+// Set EVT2 config
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "mediatek,mt8167";
+	fragment@0 {
+		target = <&memory>;
+			__overlay__ {
+				reg = <0 0x40000000 0 0x80000000>;
+			};
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8167-coral.dts b/arch/arm64/boot/dts/mediatek/mt8167-coral.dts
index 0ac8355..fec8ffb 100644
--- a/arch/arm64/boot/dts/mediatek/mt8167-coral.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8167-coral.dts
@@ -22,7 +22,7 @@
 		stdout-path = "serial0:921600n8";
 	};
 
-	memory@40000000 {
+	memory: memory@40000000 {
 		device_type = "memory";
 		reg = <0 0x40000000 0 0x40000000>;
 	};
@@ -42,6 +42,54 @@
 		gpio = <&pio 17 GPIO_ACTIVE_LOW>;
 		regulator-always-on;
 	};
+
+	ga1600_pmic: ga1600_pmic {
+		compatible = "regulator-fixed";
+		regulator-name = "ga1600_pmic";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+		gpio = <&pio 56 GPIO_ACTIVE_HIGH>;
+		startup-delay-us = <0>;
+		enable-active-high;
+		regulator-always-on;
+	};
+	ga1600_reset: ga1600_reset {
+		compatible = "regulator-fixed";
+		regulator-name = "ga1600_reset";
+		regulator-min-microvolt = <1000000>;
+		regulator-max-microvolt = <1000000>;
+		gpio = <&pio 57 GPIO_ACTIVE_HIGH>;
+		startup-delay-us = <150>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+	mt8167_audio_codec: mt8167_audio_codec {
+		compatible = "mediatek,mt8167-codec";
+		status = "okay";
+		clocks = <&topckgen CLK_TOP_AUDIO>;
+		clock-names = "bus";
+		mediatek,afe-regmap = <&afe>;
+		mediatek,apmixedsys-regmap = <&apmixedsys>;
+		mediatek,pwrap-regmap = <&pwrap>;
+		mediatek,dmic-wire-mode = <1>; // TWO_WIRE
+		mediatek,headphone-cap-sel = <1>; // 22uF
+		mediatek,speaker-mode = <0>; // Class D
+	};
+
+	sound: sound {
+		compatible = "mediatek,snd-soc-mt8167-excelsior";
+		status = "okay";
+		mediatek,platform = <&afe>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&aud_pins_default>;
+		mediatek,jack-detect-gpio = <&pio 40 0>;
+	};
+};
+
+&afe {
+	status = "okay";
+	mediatek,tdm-out-mode = <0>; // HDMI
 };
 
 &cpu0 {
@@ -67,11 +115,56 @@
 	#interrupt-cells = <2>;
 };
 
+&mt6392_vcamaf_reg {
+	regulator-always-on;
+};
+
+&mt6392_vgp1_reg {
+	regulator-min-microvolt = <3300000>;
+	regulator-always-on;
+};
+
 &uart0 {
 	status = "okay";
 };
 
 &pio {
+	i2c0_pins_a: i2c0 {
+		pins1 {
+			pinmux = <MT8167_PIN_58_SDA0__FUNC_SDA0_0>,
+			         <MT8167_PIN_59_SCL0__FUNC_SCL0_0>;
+			bias-disable;
+		};
+	};
+
+	i2c1_pins_a: i2c1 {
+		pins1 {
+			pinmux = <MT8167_PIN_52_SDA1__FUNC_SDA1_0>,
+			         <MT8167_PIN_53_SCL1__FUNC_SCL1_0>;
+			bias-disable;
+		};
+	};
+
+	i2c2_pins_a: i2c2 {
+		pins1 {
+			pinmux = <MT8167_PIN_60_SDA2__FUNC_GPIO60>,
+			         <MT8167_PIN_61_SCL2__FUNC_GPIO61>;
+			bias-disable;
+		};
+		pins_a71ch_reset {
+			pinmux = <MT8516_PIN_23_EINT23__FUNC_GPIO23>;
+			output-high;
+		};
+	};
+
+	aud_pins_default: audiodefault {
+		pins1 {
+			pinmux = <MT8167_PIN_40_KPROW0__FUNC_GPIO40>;
+			input-enable;
+			bias-pull-up;
+		};
+	};
+
 	mmc0_pins_default: mmc0default {
 		pins_cmd_dat {
 			pinmux = <MT8167_PIN_120_MSDC0_DAT0__FUNC_MSDC0_DAT0>,
@@ -96,6 +189,11 @@
 			pinmux = <MT8167_PIN_114_MSDC0_RSTB__FUNC_MSDC0_RSTB>;
 			bias-pull-up;
 		};
+
+		pins_user {
+			pinmux = <MT8167_PIN_2_EINT2__FUNC_GPIO2>;
+			bias-pull-up;
+		};
 	};
 
 	mmc0_pins_uhs: mmc0@0{
@@ -126,6 +224,112 @@
 		};
 	};
 
+	mmc1_pins_default: mmc1default {
+		pins_cmd_dat {
+			pinmux = <MT8167_PIN_106_MSDC1_DAT0__FUNC_MSDC1_DAT0>,
+			         <MT8167_PIN_107_MSDC1_DAT1__FUNC_MSDC1_DAT1>,
+			         <MT8167_PIN_108_MSDC1_DAT2__FUNC_MSDC1_DAT2>,
+			         <MT8167_PIN_109_MSDC1_DAT3__FUNC_MSDC1_DAT3>,
+			         <MT8167_PIN_104_MSDC1_CMD__FUNC_MSDC1_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins_clk {
+			pinmux = <MT8167_PIN_105_MSDC1_CLK__FUNC_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins_pmu_en {
+			pinmux = <MT8167_PIN_48_SPI_CS__FUNC_GPIO48>;
+			output-low;
+		};
+
+		pins_test_en {
+			pinmux = <MT8167_PIN_38_MRG_DI__FUNC_GPIO38>;
+			output-low;
+		};
+
+		pins_sys_rst {
+			pinmux = <MT8167_PIN_47_JTDO__FUNC_GPIO47>;
+			output-high;
+		};
+	};
+
+	mmc1_pins_uhs: mmc1@0 {
+		pins_cmd_dat {
+			pinmux = <MT8167_PIN_106_MSDC1_DAT0__FUNC_MSDC1_DAT0>,
+			         <MT8167_PIN_107_MSDC1_DAT1__FUNC_MSDC1_DAT1>,
+			         <MT8167_PIN_108_MSDC1_DAT2__FUNC_MSDC1_DAT2>,
+			         <MT8167_PIN_109_MSDC1_DAT3__FUNC_MSDC1_DAT3>,
+			         <MT8167_PIN_104_MSDC1_CMD__FUNC_MSDC1_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins_clk {
+			pinmux = <MT8167_PIN_105_MSDC1_CLK__FUNC_MSDC1_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		pins_pmu_en {
+			pinmux = <MT8167_PIN_48_SPI_CS__FUNC_GPIO48>;
+			output-high;
+		};
+
+		pins_test_en {
+			pinmux = <MT8167_PIN_38_MRG_DI__FUNC_GPIO38>;
+			output-low;
+		};
+
+		pins_sys_rst {
+			pinmux = <MT8167_PIN_47_JTDO__FUNC_GPIO47>;
+			output-high;
+		};
+	};
+
+	mmc2_pins_default: mmc2default {
+		pins_cmd_dat {
+			pinmux = <MT8167_PIN_70_MSDC2_DAT0__FUNC_MSDC2_DAT0>,
+				<MT8167_PIN_71_MSDC2_DAT1__FUNC_MSDC2_DAT1>,
+				<MT8167_PIN_72_MSDC2_DAT2__FUNC_MSDC2_DAT2>,
+				<MT8167_PIN_73_MSDC2_DAT3__FUNC_MSDC2_DAT3>,
+				<MT8167_PIN_68_MSDC2_CMD__FUNC_MSDC2_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins_clk {
+			pinmux = <MT8167_PIN_69_MSDC2_CLK__FUNC_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
+	mmc2_pins_uhs: mmc2@0 {
+		pins_cmd_dat {
+			pinmux = <MT8167_PIN_70_MSDC2_DAT0__FUNC_MSDC2_DAT0>,
+				<MT8167_PIN_71_MSDC2_DAT1__FUNC_MSDC2_DAT1>,
+				<MT8167_PIN_72_MSDC2_DAT2__FUNC_MSDC2_DAT2>,
+				<MT8167_PIN_73_MSDC2_DAT3__FUNC_MSDC2_DAT3>,
+				<MT8167_PIN_68_MSDC2_CMD__FUNC_MSDC2_CMD>;
+			input-enable;
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins_clk {
+			pinmux = <MT8167_PIN_69_MSDC2_CLK__FUNC_MSDC2_CLK>;
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+	};
+
 	hdmi_pins_default: hdmi_pins_default {
 	};
 
@@ -135,6 +339,56 @@
 			bias-pull-down;
 		};
 	};
+
+	/* GA1600 GPIO start */
+	ga1600_boot_fail: boot_fail {
+		pins_cmd_dat {
+				pinmux = <MT8167_PIN_55_I2S_DATA_IN__FUNC_GPIO55>;
+				slew-rate = <1>;
+				input-enable;
+				bias-pull-up;
+		};
+	};
+
+	ga1600_pmic_en: pmic_en {
+		pins_cmd_dat {
+				pinmux = <MT8167_PIN_56_I2S_LRCK__FUNC_GPIO56>;
+				slew-rate = <1>;
+				output-high;
+		};
+	};
+
+	ga1600_reset_n: reset_n {
+		pins_cmd_dat {
+				pinmux = <MT8167_PIN_57_I2S_BCK__FUNC_GPIO57>;
+				slew-rate = <1>;
+				output-high;
+		};
+	};
+	/* GA1600 GPIO end */
+};
+
+&i2c0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	clock-div = <2>;
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	clock-div = <2>;
+};
+
+&i2c2 {
+	status = "okay";
+	compatible = "i2c-gpio";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	sda-gpios = <&pio 60 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
+	scl-gpios = <&pio 61 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
 };
 
 &mmc0 {
@@ -152,6 +406,50 @@
 	non-removable;
 };
 
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc1_pins_default>;
+	pinctrl-1 = <&mmc1_pins_uhs>;
+	vmmc-supply = <&mt6392_vemc3v3_reg>;
+	vqmmc-supply = <&mt6392_vio18_reg>;
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	keep-power-in-suspend;
+	cap-sd-highspeed;
+	enable-sdio-wakeup;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	cap-sdio-irq;
+	non-removable;
+
+	mt7668 {
+		wifi: mt7668-wifi@0 {
+			compatible = "mediatek,mt8516-wifi", "mediatek,mt7668-wifi";
+			mac-address = [00 00 00 00 00 00];
+		};
+		bluetooth: mt7668-bluetooth@0 {
+			compatible = "mediatek,mt8516-bluetooth", "mediatek,mt7668-bluetooth";
+			mac-address = [00 00 00 00 00 00];
+		};
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc2_pins_default>;
+	pinctrl-1 = <&mmc2_pins_uhs>;
+	status = "okay";
+	bus-width = <4>;
+	max-frequency = <200000000>;
+	cap-sd-highspeed;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	broken-cd;
+	vmmc-supply = <&mt6392_vmch_reg>;
+	vqmmc-supply = <&mt6392_vmc_reg>;
+};
+
 &dpi1 {
 	status = "okay";
 	ddc-i2c-bus = <&hdmiddc>;
@@ -226,3 +524,7 @@
 		};
 	};
 };
+
+&usb1 {
+	status = "okay";
+};
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 745b0d0..6551942 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -29,6 +29,7 @@
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/sched.h>
@@ -227,6 +228,8 @@ struct mtk_i2c {
 	unsigned char auto_restart;
 	bool ignore_restart_irq;
 	const struct mtk_i2c_compatible *dev_comp;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pins_default;
 };
 
 static const struct i2c_adapter_quirks mt6577_i2c_quirks = {
@@ -934,6 +937,19 @@ static int mtk_i2c_probe(struct platform_device *pdev)
 	if (irq <= 0)
 		return irq;
 
+	i2c->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(i2c->pinctrl)) {
+		dev_err(&pdev->dev, "Cannot find pinctrl!\n");
+		return PTR_ERR(i2c->pinctrl);
+	}
+
+	i2c->pins_default = pinctrl_lookup_state(i2c->pinctrl, "default");
+	if (IS_ERR(i2c->pins_default)) {
+		dev_err(&pdev->dev, "Cannot find default pinctrl group!\n");
+		return PTR_ERR(i2c->pins_default);
+	}
+	pinctrl_select_state(i2c->pinctrl, i2c->pins_default);
+
 	init_completion(&i2c->msg_complete);
 
 	i2c->dev_comp = of_device_get_match_data(&pdev->dev);
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 0f2a196..cf3acf8 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -36,6 +36,8 @@
 #define MT6397_RTC_BASE		0xe000
 #define MT6397_RTC_SIZE		0x3e
 #define MT6397_RTC_WRTGR_OFFSET	0x3c
+#define MT6392_TOP_RST_MISC_SYSRSTB_MASK 0x1
+#define MT6392_TOP_RST_MISC_SYSRSTB_SHIFT 1
 
 static const struct resource mt6358_rtc_resources[] = {
 	{
@@ -272,6 +274,9 @@ static int mt6397_probe(struct platform_device *pdev)
 		ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
 					   mt6392_devs, ARRAY_SIZE(mt6392_devs),
 					   NULL, 0, pmic->irq_domain);
+		regmap_update_bits(pmic->regmap, MT6392_TOP_RST_MISC,
+					   MT6392_TOP_RST_MISC_SYSRSTB_MASK << MT6392_TOP_RST_MISC_SYSRSTB_SHIFT,
+					   1 << MT6392_TOP_RST_MISC_SYSRSTB_SHIFT);
 		break;
 
 	default:
diff --git a/drivers/misc/mediatek/gpu/gpu_rgx/m1.11_5516664/physmem.c b/drivers/misc/mediatek/gpu/gpu_rgx/m1.11_5516664/physmem.c
index d224eaa..88e7d18 100644
--- a/drivers/misc/mediatek/gpu/gpu_rgx/m1.11_5516664/physmem.c
+++ b/drivers/misc/mediatek/gpu/gpu_rgx/m1.11_5516664/physmem.c
@@ -565,7 +565,7 @@ PVRSRVGetMaxDevMemSizeKM( CONNECTION_DATA * psConnection,
 			  IMG_DEVMEM_SIZE_T *puiLMASize,
 			  IMG_DEVMEM_SIZE_T *puiUMASize )
 {
-	IMG_BOOL bLMA = IMG_FALSE, bUMA = IMG_FALSE;
+	IMG_BOOL bLMA = IMG_FALSE, bUMA = IMG_TRUE;
 
 	*puiLMASize = 0;
 	*puiUMASize = 0;
diff --git a/drivers/misc/mediatek/usb11/musbfsh_host.c b/drivers/misc/mediatek/usb11/musbfsh_host.c
index 0dd58e7..a1bc443 100644
--- a/drivers/misc/mediatek/usb11/musbfsh_host.c
+++ b/drivers/misc/mediatek/usb11/musbfsh_host.c
@@ -492,6 +492,9 @@ __releases(musbfsh->lock) __acquires(musbfsh->lock)
 	 * urb->ep->desc.bEndpointAddress);
 	 */
 
+	if (is_dma_capable() && usb_pipein(urb->pipe) && usb_pipeendpoint(urb->pipe))
+		complete(&urb->done);
+
 	usb_hcd_unlink_urb_from_ep(musbfsh_to_hcd(musbfsh), urb);
 	spin_unlock(&musbfsh->lock);
 	usb_hcd_giveback_urb(musbfsh_to_hcd(musbfsh), urb, status);
@@ -720,9 +723,9 @@ u16 musbfsh_h_flush_rxfifo(struct musbfsh_hw_ep *hw_ep, u16 csr)
 	 * leave toggle alone (may not have been saved yet)
 	 */
 	INFO("%s++\r\n", __func__);
-	csr |= MUSBFSH_RXCSR_FLUSHFIFO | MUSBFSH_RXCSR_RXPKTRDY;
+	csr |= MUSBFSH_RXCSR_FLUSHFIFO;
 	csr &= ~(MUSBFSH_RXCSR_H_REQPKT | MUSBFSH_RXCSR_H_AUTOREQ |
-		MUSBFSH_RXCSR_AUTOCLEAR);
+		MUSBFSH_RXCSR_AUTOCLEAR | MUSBFSH_RXCSR_RXPKTRDY);
 
 	/* write 2x to allow double buffering */
 	musbfsh_writew(hw_ep->regs, MUSBFSH_RXCSR, csr);
@@ -1748,6 +1751,12 @@ void musbfsh_host_rx(struct musbfsh *musbfsh, u8 epnum)
 
 	urb = next_urb(qh);	/* current urb */
 	dma = is_dma_capable() ? hw_ep->rx_channel : NULL;
+
+	if (dma && (dma->status == MUSBFSH_DMA_STATUS_BUSY)) {
+		INFO("not Dma interrupt %s, @Line %d\n", __func__, __LINE__);
+		return;
+	}
+
 	status = 0;
 	xfer_len = 0;
 
@@ -1827,6 +1836,7 @@ void musbfsh_host_rx(struct musbfsh *musbfsh, u8 epnum)
 			dma->status = MUSBFSH_DMA_STATUS_CORE_ABORT;
 			(void)musbfsh->dma_controller->channel_abort(dma);
 			xfer_len = dma->actual_len;
+			dma->actual_len = 0L;
 		}
 		musbfsh_h_flush_rxfifo(hw_ep, 0);
 		musbfsh_writeb(epio, MUSBFSH_RXINTERVAL, 0);
@@ -1886,6 +1896,8 @@ void musbfsh_host_rx(struct musbfsh *musbfsh, u8 epnum)
 				urb->transfer_buffer_length ||
 				dma->actual_len < qh->maxpacket);
 
+		dma->actual_len = 0L;
+
 		/* send IN token for next packet, without AUTOREQ */
 		if (!done) {
 			val |= MUSBFSH_RXCSR_H_REQPKT;
@@ -2292,6 +2304,8 @@ static int musbfsh_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 		urb->transfer_flags &= ~URB_DMA_MAP_SINGLE;
 	spin_lock_irqsave(&musbfsh->lock, flags);
 
+	init_completion(&urb->done);
+
 	/* add the urb to the ep, return 0 for no error. */
 	ret = usb_hcd_link_urb_to_ep(hcd, urb);
 	qh = ret ? NULL : hep->hcpriv;
@@ -2520,6 +2534,7 @@ static int musbfsh_cleanup_urb(struct urb *urb, struct musbfsh_qh *qh)
 			WARNING("abort %cX%d DMA for urb %p --> %d\n",
 				is_in ? 'R' : 'T', ep->epnum, urb, stat);
 			urb->actual_length += dma->actual_len;
+			dma->actual_len = 0L;
 		}
 	}
 
@@ -2609,8 +2624,18 @@ static int musbfsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 				musbfsh_host_free_ep_fifo(musbfsh, qh, is_in);
 			kfree(qh);
 		}
-	} else
+	} else {
+		spin_unlock_irqrestore(&musbfsh->lock, flags);
+		if (is_dma_capable() && is_in && usb_pipeendpoint(urb->pipe)) {
+			ret = wait_for_completion_timeout(&urb->done, msecs_to_jiffies(50));
+			if (ret)
+				return status;
+
+			INFO("wait time out\n");
+		}
+		spin_lock_irqsave(&musbfsh->lock, flags);
 		ret = musbfsh_cleanup_urb(urb, qh);
+	}
 done:
 	spin_unlock_irqrestore(&musbfsh->lock, flags);
 	return ret;
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index ca0dad3..64a9ae3 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
@@ -75,6 +76,8 @@ struct mtk_pwm_chip {
 	void __iomem *regs;
 	struct clk *clks[MTK_CLK_MAX];
 	const struct mtk_pwm_platform_data *soc;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pins_default;
 };
 
 static const unsigned int mtk_pwm_reg_offset[] = {
@@ -256,6 +259,18 @@ static int mtk_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(pc->regs))
 		return PTR_ERR(pc->regs);
 
+	pc->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(pc->pinctrl)) {
+		dev_err(&pdev->dev, "Cannot find pinctrl!\n");
+		return PTR_ERR(pc->pinctrl);
+	}
+
+	pc->pins_default = pinctrl_lookup_state(pc->pinctrl, "default");
+	if (IS_ERR(pc->pins_default)) {
+		dev_err(&pdev->dev, "Cannot find default pinctrl group!\n");
+		return PTR_ERR(pc->pins_default);
+	}
+
 	for (i = 0; i < data->num_pwms + 2 && pc->soc->has_clks; i++) {
 		pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]);
 		if (IS_ERR(pc->clks[i])) {
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 4baf64f..47935e4 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -44,6 +44,11 @@
 #define WDT_SWRST		0x14
 #define WDT_SWRST_KEY		0x1209
 
+#define WDT_NONRST2		0x24
+#define REBOOT_BOOTLOADER_VALUE (1)
+#define REBOOT_BOOTLOADER_MASK  (1)
+#define REBOOT_BOOTLOADER_SHIFT (2)
+
 #define DRV_NAME		"mtk-wdt"
 #define DRV_VERSION		"1.0"
 
@@ -135,6 +140,17 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
 	return 0;
 }
 
+static void mtk_wdt_write_bootloader_flag(struct watchdog_device *wdt_dev) {
+	u32 reg;
+	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+	void __iomem *wdt_base = mtk_wdt->wdt_base;
+
+	reg = ioread32(wdt_base + WDT_NONRST2);
+	reg &= ~(REBOOT_BOOTLOADER_MASK << REBOOT_BOOTLOADER_SHIFT);
+	reg |= (REBOOT_BOOTLOADER_VALUE << REBOOT_BOOTLOADER_SHIFT);
+	iowrite32(reg, wdt_base + WDT_NONRST2);
+}
+
 static const struct watchdog_info mtk_wdt_info = {
 	.identity	= DRV_NAME,
 	.options	= WDIOF_SETTIMEOUT |
@@ -151,6 +167,23 @@ static const struct watchdog_ops mtk_wdt_ops = {
 	.restart	= mtk_wdt_restart,
 };
 
+static ssize_t reset_bootloader_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
+	struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);
+
+	mtk_wdt_write_bootloader_flag(&mtk_wdt->wdt_dev);
+	return count;
+}
+
+static DEVICE_ATTR_WO(reset_bootloader);
+
+static struct attribute *mtk_wdt_attrs[] = {
+	&dev_attr_reset_bootloader.attr,
+	NULL
+};
+static const struct attribute_group mtk_wdt_attr_group = {
+	.attrs = mtk_wdt_attrs,
+};
+
 static int mtk_wdt_probe(struct platform_device *pdev)
 {
 	struct mtk_wdt_dev *mtk_wdt;
@@ -187,6 +220,10 @@ static int mtk_wdt_probe(struct platform_device *pdev)
 	if (unlikely(err))
 		return err;
 
+	err = sysfs_create_group(&pdev->dev.kobj, &mtk_wdt_attr_group);
+	if (unlikely(err))
+		return err;
+
 	dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
 			mtk_wdt->wdt_dev.timeout, nowayout);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index ff010d1..6e09ecfb 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1575,6 +1575,7 @@ struct urb {
 	int error_count;		/* (return) number of ISO errors */
 	void *context;			/* (in) context for completion */
 	usb_complete_t complete;	/* (in) completion routine */
+	struct completion done; /* dma transfer done */
 	struct usb_iso_packet_descriptor iso_frame_desc[0];
 					/* (in) ISO ONLY */
 };
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3e7badb..38b3aba 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -577,6 +577,11 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
 	if (hci_dev_test_flag(hdev, HCI_SETUP) ||
 	    hci_dev_test_flag(hdev, HCI_CONFIG))
 		memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
+
+	if (strncmp(hdev->hw_info, "mt7668", strlen(hdev->hw_info)) == 0) {
+		hdev->commands[26] = 0x18;
+		hdev->commands[27] = 0x24;
+	}
 }
 
 static void hci_cc_read_local_features(struct hci_dev *hdev,
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 69102fd..fea676a 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -955,6 +955,12 @@ static int wireless_process_ioctl(struct net *net, struct iwreq *iwr,
 		else if (private)
 			return private(dev, iwr, cmd, info, handler);
 	}
+
+	/* Old driver API : call driver ioctl handler */
+	if (dev->netdev_ops->ndo_do_ioctl)
+		return dev->netdev_ops->ndo_do_ioctl(dev, (struct ifreq*)iwr, cmd);
+
+	dev_err(&dev->dev, "No handler found (wireless_process_ioctl)\n");
 	return -EOPNOTSUPP;
 }
 
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index a232741..6df4ca1 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -262,6 +262,9 @@
 	-Wproperty_name_chars_strict
 endif
 
+# Enable creation of __symbols__ node (used by overlay)
+DTC_FLAGS += -@
+
 DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
 
 # Generate an assembly file to wrap the output of the device tree compiler
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 99be3b3..cae5a00 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1283,6 +1283,9 @@
 config SND_SOC_MT8167_CODEC
 	tristate
 
+config SND_SOC_MT6392_CODEC
+	tristate
+
 # Amp
 config SND_SOC_LM4857
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bd9d656..039b119 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -519,6 +519,7 @@
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o
 obj-$(CONFIG_SND_SOC_MT8167_CODEC)	+= snd-soc-mt8167-codec.o
+obj-$(CONFIG_SND_SOC_MT6392_CODEC)	+= snd-soc-mt6392-codec.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/mt6392-codec.c b/sound/soc/codecs/mt6392-codec.c
index 23463f8..3f7caf9 100644
--- a/sound/soc/codecs/mt6392-codec.c
+++ b/sound/soc/codecs/mt6392-codec.c
@@ -13,11 +13,13 @@
  * GNU General Public License for more details.
  */
 
-#include <sound/soc.h>
-#include <sound/tlv.h>
+#include "mt6392-codec.h"
 #include <linux/debugfs.h>
 #include <linux/delay.h>
-#include "mt6392-codec.h"
+#include <linux/module.h>
+#include <linux/of.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
 
 /*
  * Class D: has HW Trim mode and SW Trim mode
@@ -25,6 +27,32 @@
  *
  * The option used to choose the trim mode of Class D
  */
+static int int_spk_amp_enable_get(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct mt6392_codec_priv *codec_data =
+	    snd_soc_component_get_drvdata(component);
+	uint32_t reg_value = snd_soc_component_read32(codec_data->codec, SPK_CON0);
+	ucontrol->value.integer.value[0] = reg_value & BIT(0) ? 1 : 0;
+	return 0;
+}
+
+static int int_spk_amp_enable_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct mt6392_codec_priv *codec_data =
+	    snd_soc_component_get_drvdata(component);
+
+	if (ucontrol->value.integer.value[0] == 0)
+		mt6392_int_spk_turn_off(codec_data->codec);
+	else
+		mt6392_int_spk_turn_on(codec_data->codec);
+
+	return 0;
+}
+
 #define USE_HW_TRIM_CLASS_D
 
 /* Int Spk Amp Playback Volume
@@ -32,19 +60,37 @@
  */
 static const unsigned int int_spk_amp_gain_tlv[] = {
 	TLV_DB_RANGE_HEAD(3),
-	0, 0, TLV_DB_SCALE_ITEM(0, 0, 1),
-	1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
-	2, 15, TLV_DB_SCALE_ITEM(400, 100, 0),
+	0,
+	0,
+	TLV_DB_SCALE_ITEM(0, 0, 1),
+	1,
+	1,
+	TLV_DB_SCALE_ITEM(0, 0, 0),
+	2,
+	15,
+	TLV_DB_SCALE_ITEM(400, 100, 0),
 };
 
 /* Audio_Speaker_PGA_gain
  * {mute, 0, 4, 5, 6, 7, 8, ..., 17} dB
  */
 static const char *const int_spk_amp_gain_text[] = {
-	"MUTE", "+0dB", "+4dB", "+5dB",
-	"+6dB", "+7dB", "+8dB", "+9dB",
-	"+10dB", "+11dB", "+12dB", "+13dB",
-	"+14dB", "+15dB", "+16dB", "+17dB",
+	"MUTE",
+	"+0dB",
+	"+4dB",
+	"+5dB",
+	"+6dB",
+	"+7dB",
+	"+8dB",
+	"+9dB",
+	"+10dB",
+	"+11dB",
+	"+12dB",
+	"+13dB",
+	"+14dB",
+	"+15dB",
+	"+16dB",
+	"+17dB",
 };
 
 static const struct soc_enum int_spk_amp_gain_enum =
@@ -52,11 +98,11 @@ static const struct soc_enum int_spk_amp_gain_enum =
 		int_spk_amp_gain_text);
 
 static int int_spk_amp_gain_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct mt6392_codec_priv *codec_data =
-		snd_soc_component_get_drvdata(component);
+	    snd_soc_component_get_drvdata(component);
 	uint32_t value = 0;
 
 	value = codec_data->spk_amp_gain;
@@ -67,71 +113,53 @@ static int int_spk_amp_gain_get(struct snd_kcontrol *kcontrol,
 }
 
 static int int_spk_amp_gain_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct mt6392_codec_priv *codec_data =
-		snd_soc_component_get_drvdata(component);
+	    snd_soc_component_get_drvdata(component);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	uint32_t value = ucontrol->value.integer.value[0];
 
 	if (value >= e->items)
 		return -EINVAL;
 
-	snd_soc_component_update_bits(codec_data->codec, SPK_CON9,
-		GENMASK(11, 8), value << 8);
+	snd_soc_component_update_bits(codec_data->codec, SPK_CON9, GENMASK(11, 8),
+			    value << 8);
 
 	codec_data->spk_amp_gain = value;
 
-	dev_dbg(codec_data->codec->dev, "%s value = %u\n",
-		__func__, value);
-
-	return 0;
-}
-
-static int int_spk_amp_gain_put_volsw(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	int ret = 0;
-	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
-	struct mt6392_codec_priv *codec_data =
-		snd_soc_component_get_drvdata(component);
-
-	ret = snd_soc_put_volsw(kcontrol, ucontrol);
-	if (ret < 0)
-		return ret;
-
-	codec_data->spk_amp_gain = ucontrol->value.integer.value[0];
+	dev_dbg(codec_data->codec->dev, "%s value = %u\n", __func__, value);
 
 	return 0;
 }
 
 /* Internal speaker mode (AB/D) */
-static const char * const int_spk_amp_mode_texts[] = {
+static const char *const int_spk_amp_mode_texts[] = {
 	"Class D",
 	"Class AB",
 };
 
 static SOC_ENUM_SINGLE_EXT_DECL(mt6392_speaker_mode_enum,
-		int_spk_amp_mode_texts);
+				int_spk_amp_mode_texts);
 
 static int mt6392_spk_mode_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
+			       struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(component);
+	    snd_soc_component_get_drvdata(component);
 
 	ucontrol->value.integer.value[0] = codec_data->speaker_mode;
 	return 0;
 }
 
 static int mt6392_spk_mode_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
+			       struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(component);
+	    snd_soc_component_get_drvdata(component);
 	int ret = 0;
 	uint32_t mode = ucontrol->value.integer.value[0];
 
@@ -148,7 +176,6 @@ static int mt6392_spk_mode_put(struct snd_kcontrol *kcontrol,
 	return ret;
 }
 
-
 /* Check OC Flag */
 static const char *const mt6392_speaker_oc_flag_texts[] = {
 	"NoOverCurrent",
@@ -156,51 +183,46 @@ static const char *const mt6392_speaker_oc_flag_texts[] = {
 };
 
 static SOC_ENUM_SINGLE_EXT_DECL(mt6392_speaker_oc_flag_enum,
-		mt6392_speaker_oc_flag_texts);
+				mt6392_speaker_oc_flag_texts);
 
 static int mt6392_speaker_oc_flag_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
+				      struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(component);
-	uint32_t reg_value = snd_soc_component_read32(codec_data->codec,
-						      SPK_CON6);
+	    snd_soc_component_get_drvdata(component);
+	uint32_t reg_value = snd_soc_component_read32(codec_data->codec, SPK_CON6);
 
 	if (codec_data->speaker_mode == MT6392_CLASS_AB)
 		ucontrol->value.integer.value[0] =
-			(reg_value & BIT(15)) ? 1 : 0;
+		    (reg_value & BIT(15)) ? 1 : 0;
 	else
 		ucontrol->value.integer.value[0] =
-			(reg_value & BIT(14)) ? 1 : 0;
+		    (reg_value & BIT(14)) ? 1 : 0;
 
 	return 0;
 }
 
 static const struct snd_kcontrol_new mt6392_codec_controls[] = {
 	/* Internal speaker PGA gain control */
-	SOC_SINGLE_EXT_TLV("Int Spk Amp Playback Volume",
-		SPK_CON9, 8, 15, 0,
-		snd_soc_get_volsw,
-		int_spk_amp_gain_put_volsw,
-		int_spk_amp_gain_tlv),
+	SOC_SINGLE_BOOL_EXT("Int Spk Amp Enable", 0, int_spk_amp_enable_get,
+			    int_spk_amp_enable_put),
+	SOC_SINGLE_TLV("Int Spk Amp Playback Volume", SPK_CON9, 8, 15, 0,
+		       int_spk_amp_gain_tlv),
 	/* Audio_Speaker_PGA_gain */
-	SOC_ENUM_EXT("Audio_Speaker_PGA_gain",
-		int_spk_amp_gain_enum,
-		int_spk_amp_gain_get,
-		int_spk_amp_gain_put),
+	SOC_ENUM_EXT("Audio_Speaker_PGA_gain", int_spk_amp_gain_enum,
+		     int_spk_amp_gain_get, int_spk_amp_gain_put),
 	/* Internal speaker mode (AB/D) */
 	SOC_ENUM_EXT("Int Spk Amp Mode", mt6392_speaker_mode_enum,
-		mt6392_spk_mode_get, mt6392_spk_mode_put),
+		     mt6392_spk_mode_get, mt6392_spk_mode_put),
 	/* Check OC Flag */
 	SOC_ENUM_EXT("Speaker_OC_Flag", mt6392_speaker_oc_flag_enum,
-		mt6392_speaker_oc_flag_get, NULL),
+		     mt6392_speaker_oc_flag_get, NULL),
 };
 
 static void mt6392_codec_get_spk_trim_offset(struct snd_soc_component *codec)
 {
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 
 	/* turn on spk (class D) and hw trim */
 	snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E, 0x000E);
@@ -213,7 +235,7 @@ static void mt6392_codec_get_spk_trim_offset(struct snd_soc_component *codec)
 
 	/* save trim offset */
 	codec_data->spk_trim_offset =
-		snd_soc_component_read32(codec, SPK_CON1) & GENMASK(4, 0);
+	    snd_soc_component_read32(codec, SPK_CON1) & GENMASK(4, 0);
 
 	/* turn off trim */
 	snd_soc_component_update_bits(codec, SPK_CON0, 0xFFFF, 0x3401);
@@ -242,8 +264,7 @@ static void mt6392_int_spk_on_with_trim(struct snd_soc_component *codec)
 	snd_soc_component_update_bits(codec, SPK_CON0, 0xFFFF, 0x3401);
 	snd_soc_component_update_bits(codec, SPK_CON9, 0xF0FF, 0x2000);
 #else
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 
 	/* turn on spk (class D) */
 	snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E, 0x000E);
@@ -260,8 +281,8 @@ static void mt6392_int_spk_on_with_trim(struct snd_soc_component *codec)
 	snd_soc_component_update_bits(codec, SPK_CON12, 0xFFFF, 0x2A81);
 	snd_soc_component_update_bits(codec, SPK_CON1, 0xFFFF, 0x6000);
 	/* class D and class AB use the same trim offset value */
-	snd_soc_component_update_bits(codec, SPK_CON1,
-		GENMASK(12, 8), (codec_data->spk_trim_offset << 8));
+	snd_soc_component_update_bits(codec, SPK_CON1, GENMASK(12, 8),
+			    (codec_data->spk_trim_offset << 8));
 
 	/* trim stop */
 	snd_soc_component_update_bits(codec, SPK_CON12, 0xFFFF, 0xAA81);
@@ -271,8 +292,7 @@ static void mt6392_int_spk_on_with_trim(struct snd_soc_component *codec)
 
 int mt6392_int_spk_turn_on(struct snd_soc_component *codec)
 {
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 	int ret = 0;
 
 	dev_dbg(codec->dev, "%s\n", __func__);
@@ -282,16 +302,15 @@ int mt6392_int_spk_turn_on(struct snd_soc_component *codec)
 		mt6392_int_spk_on_with_trim(codec);
 		break;
 	case MT6392_CLASS_AB:
-		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E,
-					      0x000E);
+		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E, 0x000E);
 		snd_soc_component_update_bits(codec, SPK_CON7, 0xFFFF, 0x48F4);
 		snd_soc_component_update_bits(codec, SPK_CON2, 0xFFFF, 0x0414);
 		snd_soc_component_update_bits(codec, SPK_CON0, 0xFFFF, 0x3005);
 		snd_soc_component_update_bits(codec, SPK_CON9, 0xF0FF, 0x2000);
 		snd_soc_component_update_bits(codec, SPK_CON1, 0xFFFF, 0x6000);
 		/* class D and class AB use the same trim offset value */
-		snd_soc_component_update_bits(codec, SPK_CON1,
-			GENMASK(12, 8), (codec_data->spk_trim_offset << 8));
+		snd_soc_component_update_bits(codec, SPK_CON1, GENMASK(12, 8),
+				    (codec_data->spk_trim_offset << 8));
 		usleep_range(2000, 3000);
 		break;
 	default:
@@ -301,12 +320,12 @@ int mt6392_int_spk_turn_on(struct snd_soc_component *codec)
 
 	return ret;
 }
+
 EXPORT_SYMBOL_GPL(mt6392_int_spk_turn_on);
 
 int mt6392_int_spk_turn_off(struct snd_soc_component *codec)
 {
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 	int ret = 0;
 
 	dev_dbg(codec->dev, "%s\n", __func__);
@@ -315,13 +334,11 @@ int mt6392_int_spk_turn_off(struct snd_soc_component *codec)
 	case MT6392_CLASS_D:
 		snd_soc_component_update_bits(codec, SPK_CON12, 0xFFFF, 0x0000);
 		snd_soc_component_update_bits(codec, SPK_CON0, 0xFFFF, 0x3400);
-		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E,
-					      0x0000);
+		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E, 0x0000);
 		break;
 	case MT6392_CLASS_AB:
 		snd_soc_component_update_bits(codec, SPK_CON0, 0xFFFF, 0x3404);
-		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E,
-					      0x0000);
+		snd_soc_component_update_bits(codec, TOP_CKPDN1_CLR, 0x000E, 0x0000);
 		break;
 	default:
 		ret = -EINVAL;
@@ -330,10 +347,11 @@ int mt6392_int_spk_turn_off(struct snd_soc_component *codec)
 
 	return ret;
 }
+
 EXPORT_SYMBOL_GPL(mt6392_int_spk_turn_off);
 
 static int mt6392_int_spk_amp_wevent(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
+				     struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
 
@@ -363,7 +381,10 @@ struct mt6392_codec_reg_attr {
 	char *name;
 };
 
-#define DUMP_REG_ENTRY(reg) {reg, #reg}
+#define DUMP_REG_ENTRY(reg)                                                    \
+	{                                                                      \
+		reg, #reg                                                      \
+	}
 
 static const struct mt6392_codec_reg_attr mt6392_codec_dump_reg_list[] = {
 	DUMP_REG_ENTRY(SPK_CON0),
@@ -382,8 +403,8 @@ static const struct mt6392_codec_reg_attr mt6392_codec_dump_reg_list[] = {
 };
 
 static ssize_t mt6392_codec_debug_read(struct file *file,
-			char __user *user_buf,
-			size_t count, loff_t *pos)
+				       char __user * user_buf, size_t count,
+				       loff_t * pos)
 {
 	struct mt6392_codec_priv *codec_data = file->private_data;
 	ssize_t ret, i;
@@ -399,9 +420,10 @@ static ssize_t mt6392_codec_debug_read(struct file *file,
 
 	for (i = 0; i < ARRAY_SIZE(mt6392_codec_dump_reg_list); i++) {
 		n += scnprintf(buf + n, count - n, "%s = 0x%x\n",
-			mt6392_codec_dump_reg_list[i].name,
-			snd_soc_component_read32(codec_data->codec,
-				mt6392_codec_dump_reg_list[i].offset));
+			       mt6392_codec_dump_reg_list[i].name,
+			       snd_soc_component_read32(codec_data->codec,
+					    mt6392_codec_dump_reg_list[i].
+					    offset));
 	}
 
 	ret = simple_read_from_buffer(user_buf, count, pos, buf, n);
@@ -426,25 +448,24 @@ static void mt6392_codec_init_regs(struct mt6392_codec_priv *codec_data)
 
 	/* default PGA gain: 12dB */
 	codec_data->spk_amp_gain = 0xA;
-	snd_soc_component_update_bits(codec, SPK_CON9,
-		GENMASK(11, 8), (codec_data->spk_amp_gain) << 8);
+	snd_soc_component_update_bits(codec, SPK_CON9, GENMASK(11, 8),
+			    (codec_data->spk_amp_gain) << 8);
 }
 
 static int mt6392_codec_parse_dt(struct snd_soc_component *codec)
 {
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 	struct device *dev = codec->dev;
 	int ret = 0;
 
 	ret = of_property_read_u32(dev->of_node, "mediatek,speaker-mode",
-				&codec_data->speaker_mode);
+				   &codec_data->speaker_mode);
 	if (ret) {
 		dev_warn(dev, "%s fail to read speaker-mode in node %s\n",
-			__func__, dev->of_node->full_name);
+			 __func__, dev->of_node->full_name);
 		codec_data->speaker_mode = MT6392_CLASS_D;
 	} else if (codec_data->speaker_mode != MT6392_CLASS_D &&
-		codec_data->speaker_mode != MT6392_CLASS_AB) {
+		   codec_data->speaker_mode != MT6392_CLASS_AB) {
 		codec_data->speaker_mode = MT6392_CLASS_D;
 	}
 
@@ -459,18 +480,17 @@ static int mt6392_codec_parse_dt(struct snd_soc_component *codec)
  */
 int mt6392_codec_probe(struct snd_soc_component *codec)
 {
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
 	int ret = 0;
 
 	ret = snd_soc_add_component_controls(codec, mt6392_codec_controls,
-		ARRAY_SIZE(mt6392_codec_controls));
+					 ARRAY_SIZE(mt6392_codec_controls));
 	if (ret < 0)
 		goto error_probe;
 
 	ret = snd_soc_dapm_new_controls(dapm, mt6392_codec_dapm_widgets,
-		ARRAY_SIZE(mt6392_codec_dapm_widgets));
+					ARRAY_SIZE(mt6392_codec_dapm_widgets));
 	if (ret < 0)
 		goto error_probe;
 
@@ -484,22 +504,27 @@ int mt6392_codec_probe(struct snd_soc_component *codec)
 
 #ifdef CONFIG_DEBUG_FS
 	codec_data->debugfs = debugfs_create_file("mt6392_codec_regs",
-			S_IFREG | S_IRUGO,
-			NULL, codec_data, &mt6392_codec_debug_ops);
+						  S_IFREG | S_IRUGO, NULL,
+						  codec_data,
+						  &mt6392_codec_debug_ops);
 #endif
 error_probe:
 	return ret;
 }
+
 EXPORT_SYMBOL_GPL(mt6392_codec_probe);
 
 int mt6392_codec_remove(struct snd_soc_component *codec)
 {
 #ifdef CONFIG_DEBUG_FS
-	struct mt6392_codec_priv *codec_data =
-			snd_soc_component_get_drvdata(codec);
+	struct mt6392_codec_priv *codec_data = snd_soc_component_get_drvdata(codec);
 	debugfs_remove(codec_data->debugfs);
 #endif
 	dev_dbg(codec->dev, "%s\n", __func__);
 	return 0;
 }
+
 EXPORT_SYMBOL_GPL(mt6392_codec_remove);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE MT6392 Codec Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/mt6392-codec.h b/sound/soc/codecs/mt6392-codec.h
index 9ebb375..ba3c775 100644
--- a/sound/soc/codecs/mt6392-codec.h
+++ b/sound/soc/codecs/mt6392-codec.h
@@ -16,6 +16,8 @@
 #ifndef __MT6392_CODEC_H__
 #define __MT6392_CODEC_H__
 
+#include <linux/types.h>
+
 enum mt6392_speaker_mode {
 	MT6392_CLASS_D = 0,
 	MT6392_CLASS_AB,
@@ -51,6 +53,12 @@ struct mt6392_codec_priv {
 
 #define TOP_CKPDN1_CLR           PMIC_REG(0x010C)
 
+#define MT6392_NOT_DEFINED	0
+#define SPK_CON0_STRUP_AUXADC_START_SW	4
+#define SPK_CON0_AUXADC_RSTB_SW		5
+#define SPK_CON0_STRUP_AUXADC_START_SEL	6
+#define SPK_CON0_STRUP_AUXADC_RSTB_SEL 	7
+
 int mt6392_codec_probe(struct snd_soc_component *codec);
 int mt6392_codec_remove(struct snd_soc_component *codec);
 int mt6392_int_spk_turn_on(struct snd_soc_component *codec);
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 8f239a4..3aedb95 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -193,3 +193,24 @@
 	  This adds support for ASoC machine driver for Mediatek MT8516 Vesper
 	  Select Y if you have such device.
 	  If unsure select "N".
+
+config MTK_SPEAKER
+	bool "MTK SPEAKER AMP"
+	default n
+	help
+	  If you say Y, enable MTK_SPEAKER_AMP
+	  If the codec has internal speaker, enable this.
+	  This is a config for mediatek internal speaker amp.
+	  Generally you select "N", if unsupport it.
+
+config SND_SOC_MT8167_EXCELSIOR_MACH
+	tristate "ASoC Audio driver for MT8167 Excelsior"
+	select SND_SOC_MT8167
+	select SND_SOC_MT8167_CODEC
+	select SND_SOC_MT6392_CODEC
+	select MTK_SPEAKER
+	help
+	  This adds support for ASoC machine driver for Mediatek MT8167 Excelsior
+	  platforms with internal audio codec and internal speaker driver.
+	  Select Y if you have such device.
+	  If unsure select "N".
diff --git a/sound/soc/mediatek/mt8167/Makefile b/sound/soc/mediatek/mt8167/Makefile
index 2f37af5..902dc92 100644
--- a/sound/soc/mediatek/mt8167/Makefile
+++ b/sound/soc/mediatek/mt8167/Makefile
@@ -4,6 +4,10 @@
 snd-soc-mt8167-pcm-objs := \
     mt8167-afe-pcm.o mt8167-afe-util.o mt8167-afe-controls.o mt8167-afe-debug.o
 
+snd-soc-mt8167-excelsior-mach-objs := \
+    mt8167-excelsior.o
+
 obj-$(CONFIG_SND_SOC_MT8167) += snd-soc-mt8167-pcm.o
 obj-$(CONFIG_SND_SOC_MT8516_PUMPKIN_MACH) += mt8516-pumpkin.o
 obj-$(CONFIG_SND_SOC_MT8516_VESPER) += mt8516-vesper.o
+obj-$(CONFIG_SND_SOC_MT8167_EXCELSIOR_MACH) += snd-soc-mt8167-excelsior-mach.o
diff --git a/sound/soc/mediatek/mt8167/mt8167-excelsior.c b/sound/soc/mediatek/mt8167/mt8167-excelsior.c
new file mode 100644
index 0000000..a2469df
--- /dev/null
+++ b/sound/soc/mediatek/mt8167/mt8167-excelsior.c
@@ -0,0 +1,388 @@
+/*
+ * ASoC Driver for the Excelsior dev board
+ *
+ * Copyright (C) 2019 Google, LLC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+
+static struct snd_soc_jack mt8167_excelsior_jack;
+
+static struct snd_soc_jack_pin mt8167_excelsior_jack_pins[] = {
+	{
+	 .pin = "Headphone",
+	 .mask = SND_JACK_HEADSET,
+	 },
+};
+
+static struct snd_soc_jack_gpio mt8167_excelsior_jack_gpios[] = {
+	{
+	 .gpio = -1,
+	 .name = "headset-gpio",
+	 .report = SND_JACK_HEADSET,
+	 .invert = 0,
+	 .debounce_time = 200,
+	 },
+};
+
+enum PINCTRL_PIN_STATE { PIN_STATE_DEFAULT = 0, PIN_STATE_MAX };
+
+struct mt8167_excelsior_priv {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pin_states[PIN_STATE_MAX];
+	int jack_gpio;
+};
+
+static const char *const mt8167_excelsior_pinctrl_pin_str[PIN_STATE_MAX] = {
+	"default",
+};
+
+static int mt8167_excelsior_mic1_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+
+	dev_dbg(card->dev, "%s, event %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt8167_excelsior_mic2_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+
+	dev_dbg(card->dev, "%s, event %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt8167_excelsior_headset_mic_event(struct snd_soc_dapm_widget *w,
+					      struct snd_kcontrol *kcontrol,
+					      int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+
+	dev_dbg(card->dev, "%s, event %d\n", __func__, event);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mt8167_excelsior_int_adda_init(struct snd_soc_pcm_runtime *runtime)
+{
+	int ret = 0;
+	struct mt8167_excelsior_priv *card_data;
+	struct snd_soc_card *card = runtime->card;
+	card_data = snd_soc_card_get_drvdata(card);
+
+	dev_dbg(card->dev, "%s\n", __func__);
+
+	if (gpio_is_valid(card_data->jack_gpio)) {
+		ret = snd_soc_card_jack_new(card, "Headset Jack",
+					    SND_JACK_HEADSET,
+					    &mt8167_excelsior_jack,
+					    mt8167_excelsior_jack_pins,
+					    ARRAY_SIZE
+					    (mt8167_excelsior_jack_pins));
+		if (ret) {
+			dev_err(card->dev, "Can't snd_soc_jack_new %d\n", ret);
+			return ret;
+		}
+
+		mt8167_excelsior_jack_gpios[0].gpio = card_data->jack_gpio;
+		ret = snd_soc_jack_add_gpios(&mt8167_excelsior_jack,
+					     ARRAY_SIZE
+					     (mt8167_excelsior_jack_gpios),
+					     mt8167_excelsior_jack_gpios);
+		if (ret) {
+			dev_err(card->dev, "Can't snd_soc_jack_add_pins %d\n",
+				ret);
+			return ret;
+		}
+
+	} else {
+		dev_err(card->dev, "Invalid gpio for headphone jack.\n");
+	}
+	return ret;
+}
+
+static int mt8167_excelsior_card_remove(struct snd_soc_card *card)
+{
+	snd_soc_jack_free_gpios(&mt8167_excelsior_jack,
+				ARRAY_SIZE(mt8167_excelsior_jack_gpios),
+				mt8167_excelsior_jack_gpios);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget mt8167_excelsior_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Mic 1", mt8167_excelsior_mic1_event),
+	SND_SOC_DAPM_MIC("Mic 2", mt8167_excelsior_mic2_event),
+	SND_SOC_DAPM_MIC("Headset Mic", mt8167_excelsior_headset_mic_event),
+};
+
+static const struct snd_soc_dapm_route mt8167_excelsior_audio_map[] = {
+	/* Uplink */
+	{"AU_VIN0", NULL, "Mic 1"},
+	{"AU_VIN1", NULL, "Headset Mic"},
+
+	/* Downlink */
+	/* use internal spk amp of MT6392 */
+	{"Int Spk Amp", NULL, "AU_LOL"},
+	{"Headphone", NULL, "AU_HPL"},
+	{"Headphone", NULL, "AU_HPR"},
+};
+
+static struct snd_soc_dai_link mt8167_excelsior_dais[] = {
+	/* Front End DAI links */
+	{
+	 .name = "DL1 Playback",
+	 .stream_name = "MultiMedia1_PLayback",
+	 .cpu_dai_name = "DL1",
+	 .codec_name = "snd-soc-dummy",
+	 .codec_dai_name = "snd-soc-dummy-dai",
+	 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		     SND_SOC_DPCM_TRIGGER_POST},
+	 .init = mt8167_excelsior_int_adda_init,
+	 .dynamic = 1,
+	 .dpcm_playback = 1,
+	 },
+	{
+	 .name = "VUL Capture",
+	 .stream_name = "MultiMedia1_Capture",
+	 .cpu_dai_name = "VUL",
+	 .codec_name = "snd-soc-dummy",
+	 .codec_dai_name = "snd-soc-dummy-dai",
+	 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		     SND_SOC_DPCM_TRIGGER_POST},
+	 .dynamic = 1,
+	 .dpcm_capture = 1,
+	 },
+	{
+	 .name = "AWB Capture",
+	 .stream_name = "DL1_AWB_Record",
+	 .cpu_dai_name = "AWB",
+	 .codec_name = "snd-soc-dummy",
+	 .codec_dai_name = "snd-soc-dummy-dai",
+	 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		     SND_SOC_DPCM_TRIGGER_POST},
+	 .dynamic = 1,
+	 .dpcm_capture = 1,
+	 },
+	{
+	 .name = "DL2 Playback",
+	 .stream_name = "MultiMedia2_PLayback",
+	 .cpu_dai_name = "DL2",
+	 .codec_name = "snd-soc-dummy",
+	 .codec_dai_name = "snd-soc-dummy-dai",
+	 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+		     SND_SOC_DPCM_TRIGGER_POST},
+	 .dynamic = 1,
+	 .dpcm_playback = 1,
+	 },
+	/* Back End DAI links */
+	{
+	 .name = "MTK Codec",
+	 .cpu_dai_name = "INT ADDA",
+	 .no_pcm = 1,
+	 .codec_name = "mt8167-codec",
+	 .codec_dai_name = "mt8167-codec-dai",
+	 .dpcm_playback = 1,
+	 .dpcm_capture = 1,
+	 },
+};
+
+static const struct snd_kcontrol_new mt8167_excelsior_card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+};
+
+static struct snd_soc_card mt8167_excelsior_card = {
+	.name = "excelsior-card",
+	.owner = THIS_MODULE,
+	.remove = mt8167_excelsior_card_remove,
+	.dai_link = mt8167_excelsior_dais,
+	.num_links = ARRAY_SIZE(mt8167_excelsior_dais),
+	.dapm_widgets = mt8167_excelsior_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt8167_excelsior_dapm_widgets),
+	.controls = mt8167_excelsior_card_controls,
+	.num_controls = ARRAY_SIZE(mt8167_excelsior_card_controls),
+	.dapm_routes = mt8167_excelsior_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(mt8167_excelsior_audio_map),
+};
+
+static int mt8167_excelsior_gpio_probe(struct snd_soc_card *card)
+{
+	struct mt8167_excelsior_priv *card_data;
+	int ret = 0;
+	int i;
+
+	dev_dbg(card->dev, "%s\n", __func__);
+
+	card_data = snd_soc_card_get_drvdata(card);
+
+	card_data->pinctrl = devm_pinctrl_get(card->dev);
+	if (IS_ERR(card_data->pinctrl)) {
+		ret = PTR_ERR(card_data->pinctrl);
+		dev_err(card->dev, "%s pinctrl_get failed %d\n", __func__, ret);
+		goto exit;
+	}
+
+	for (i = 0; i < PIN_STATE_MAX; i++) {
+		card_data->pin_states[i] =
+		    pinctrl_lookup_state(card_data->pinctrl,
+					 mt8167_excelsior_pinctrl_pin_str[i]);
+		if (IS_ERR(card_data->pin_states[i])) {
+			ret = PTR_ERR(card_data->pin_states[i]);
+			dev_warn(card->dev,
+				 "%s Can't find pinctrl state %s %d\n",
+				 __func__, mt8167_excelsior_pinctrl_pin_str[i],
+				 ret);
+		} else {
+			dev_warn(card->dev, "%s Set pinctrl state %s %d\n",
+				 __func__, mt8167_excelsior_pinctrl_pin_str[i],
+				 ret);
+		}
+	}
+
+	/* default state */
+	if (!IS_ERR(card_data->pin_states[PIN_STATE_DEFAULT])) {
+		ret = pinctrl_select_state(card_data->pinctrl,
+					   card_data->
+					   pin_states[PIN_STATE_DEFAULT]);
+		if (ret) {
+			dev_err(card->dev, "%s failed to select state %d\n",
+				__func__, ret);
+			goto exit;
+		}
+	}
+
+	card_data->jack_gpio =
+	    of_get_named_gpio(card->dev->of_node, "mediatek,jack-detect-gpio",
+			      0);
+	dev_dbg(card->dev, "jack gpio: %d\n", card_data->jack_gpio);
+
+exit:
+	return ret;
+}
+
+static int mt8167_excelsior_dev_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt8167_excelsior_card;
+	struct device_node *platform_node;
+	int ret, i;
+	struct mt8167_excelsior_priv *card_data;
+
+	dev_dbg(card->dev, "%s\n", __func__);
+
+	platform_node =
+	    of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
+	if (!platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < card->num_links; i++) {
+		if (mt8167_excelsior_dais[i].platform_name)
+			continue;
+		mt8167_excelsior_dais[i].platform_of_node = platform_node;
+	}
+
+	card->dev = &pdev->dev;
+
+	card_data =
+	    devm_kzalloc(&pdev->dev, sizeof(struct mt8167_excelsior_priv),
+			 GFP_KERNEL);
+
+	if (!card_data) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "%s allocate card private data fail %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	snd_soc_card_set_drvdata(card, card_data);
+
+	mt8167_excelsior_gpio_probe(card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static int mt8167_excelsior_dev_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id mt8167_excelsior_dt_match[] = {
+	{
+	 .compatible = "mediatek,snd-soc-mt8167-excelsior",
+	 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mt8167_excelsior_dt_match);
+
+static struct platform_driver mt8167_excelsior_mach_driver = {
+	.driver = {
+		   .name = "mt8167-excelsior",
+		   .of_match_table = mt8167_excelsior_dt_match,
+#ifdef CONFIG_PM
+		   .pm = &snd_soc_pm_ops,
+#endif
+		   },
+	.probe = mt8167_excelsior_dev_probe,
+	.remove = mt8167_excelsior_dev_remove,
+};
+
+module_platform_driver(mt8167_excelsior_mach_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8167 Excelsior ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mt8167-excelsior");