blob: 4b1dec8415fe3b603c060dc6e87e1a52b595ee69 [file] [log] [blame]
From 4c7c1cce738efaa21c02cb1e8eb04ac7761b7bea Mon Sep 17 00:00:00 2001
From: YH Lin <yueherngl@google.com>
Date: Wed, 22 May 2019 08:42:37 -0700
Subject: [PATCH 5/8] Squash HQ ToT #37 against Kukui ISP ToT #139.
Change-Id: I119c34f6d51c2454780019a7b8b08349e626c298
---
.../bindings/iio/proximity/sx9311.txt | 19 +
README | 3 +-
arch/arm64/boot/dts/mediatek/Makefile | 4 +
arch/arm64/boot/dts/mediatek/mt6358.dtsi | 4 +-
.../mt8183-flapjack-rev4-sku1-hwconfig2.dts | 278 ++
.../mt8183-flapjack-rev4-sku1-hwconfig4.dts | 267 ++
.../mt8183-flapjack-rev4-sku3-hwconfig1.dts | 280 ++
.../mt8183-flapjack-rev4-sku3-hwconfig3.dts | 268 ++
.../boot/dts/mediatek/mt8183-flapjack.dtsi | 140 +
.../arm64/boot/dts/mediatek/mt8183-kukui.dtsi | 125 +
arch/arm64/boot/dts/mediatek/mt8183.dtsi | 11 +
.../arm64/chromiumos-arm64.flavour.config | 2 +-
.../arm64/chromiumos-mediatek.flavour.config | 5 +-
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/ite-it6505.c | 2948 +++++++++++++++++
drivers/gpu/drm/drm_panel.c | 38 +-
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 14 +
drivers/gpu/drm/mediatek/mtk_dpi.c | 69 +-
drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 28 +
drivers/gpu/drm/mediatek/mtk_dsi.c | 15 +
drivers/gpu/drm/panel/panel-boe-himax8279d.c | 954 +++++-
drivers/iio/proximity/Kconfig | 13 +
drivers/iio/proximity/Makefile | 1 +
drivers/iio/proximity/sx9311.c | 1144 +++++++
drivers/net/wireless/ath/ath10k/core.c | 2 +-
drivers/net/wireless/ath/ath10k/hif.h | 6 +-
drivers/net/wireless/ath/ath10k/sdio.c | 5 +-
drivers/thermal/mtk_thermal.c | 117 +-
include/drm/drm_panel.h | 11 +
sound/soc/codecs/max98357a.c | 96 +-
.../mediatek/mt8183/mt8183-da7219-max98357.c | 2 +-
31 files changed, 6826 insertions(+), 44 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/proximity/sx9311.txt
create mode 100755 arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig2.dts
create mode 100755 arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig4.dts
create mode 100755 arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig1.dts
create mode 100755 arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig3.dts
create mode 100644 arch/arm64/boot/dts/mediatek/mt8183-flapjack.dtsi
create mode 100755 drivers/gpu/drm/bridge/ite-it6505.c
create mode 100644 drivers/iio/proximity/sx9311.c
mode change 100644 => 100755 drivers/thermal/mtk_thermal.c
mode change 100644 => 100755 sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
diff --git a/Documentation/devicetree/bindings/iio/proximity/sx9311.txt b/Documentation/devicetree/bindings/iio/proximity/sx9311.txt
new file mode 100644
index 0000000000000..65a1114e4147e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/proximity/sx9311.txt
@@ -0,0 +1,19 @@
+Semtech's SX9311 capacitive proximity device driver
+
+Required properties:
+ - compatible: must be "semtech,sx9311"
+ - reg: i2c address where to find the device
+ - interrupts : the sole interrupt generated by the device
+
+ Refer to interrupt-controller/interrupts.txt for generic
+ interrupt client node bindings.
+
+Example:
+
+sx9311@28 {
+ compatible = "semtech,sx9311";
+ reg = <0x28>;
+ interrupt-parent = <&pio>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW 5 0>;
+ int-gpio = <&pio 5 0>;
+ };
diff --git a/README b/README
index 977bc3b04f5a3..7ef1f3441b8eb 100644
--- a/README
+++ b/README
@@ -1,5 +1,6 @@
+HUAQIN FLAPJACK TOT
ISP TOT
-
+MTK TOT
Linux kernel
============
diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
index 3a55c454b65dd..56a31a765632f 100644
--- a/arch/arm64/boot/dts/mediatek/Makefile
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -10,3 +10,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-evb.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-rev1.dtb
dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-rev2.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-flapjack-rev4-sku1-hwconfig2.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-flapjack-rev4-sku1-hwconfig4.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-flapjack-rev4-sku3-hwconfig1.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-flapjack-rev4-sku3-hwconfig3.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt6358.dtsi b/arch/arm64/boot/dts/mediatek/mt6358.dtsi
index e95cb4c0910a7..5dc7753b12d88 100644
--- a/arch/arm64/boot/dts/mediatek/mt6358.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt6358.dtsi
@@ -309,8 +309,8 @@
};
mt6358_vsim2_reg: ldo_vsim2 {
regulator-name = "vsim2";
- regulator-min-microvolt = <1700000>;
- regulator-max-microvolt = <3100000>;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
regulator-enable-ramp-delay = <540>;
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig2.dts b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig2.dts
new file mode 100755
index 0000000000000..baec567d4975a
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig2.dts
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 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.
+ *
+ */
+
+/dts-v1/;
+#include "mt8183-flapjack.dtsi"
+
+/ {
+ model = "MediaTek Flapjack Rev 4 board Sku 1 BOE TV080WUM NG0";
+
+ /* SKU_ID: 0x20001 BOE_TV080WUM_NG0 for REV >=3 */
+ compatible = "google,flapjack-rev3-sku131073",
+ "google,flapjack-rev4-sku131073",
+ "google,flapjack-rev5-sku131073",
+ "google,flapjack-sku131073",
+
+ /* SKU_ID: 0x1 for Rev 2 */
+ "google,flapjack-rev2-sku1",
+
+ /* SKU_ID: 0x50001 Panel Unknown */
+ "google,flapjack-rev2-sku327681",
+ "google,flapjack-rev3-sku327681",
+ "google,flapjack-rev4-sku327681",
+ "google,flapjack-rev5-sku327681",
+ "google,flapjack-sku327681",
+
+ "google,flapjack-rev2",
+ "google,flapjack-rev3",
+ "google,flapjack-rev4",
+ "google,flapjack",
+ "google,kukui", "mediatek,mt8183";
+};
+
+&dsi0 {
+ /delete-node/ panel@0;
+ panel: panel@0 {
+ compatible = "boe,tv080wum_ng0";
+ reg = <0>;
+ enable-gpios = <&pio 45 0>;
+ pp33-gpios = <&pio 35 0>;
+ pp18-gpios = <&pio 36 0>;
+ pinctrl-names = "default", "state_3300mv", "state_1800mv";
+ pinctrl-0 = <&panel_pins_default>;
+ pinctrl-1 = <&panel_pins_3300mv>;
+ pinctrl-2 = <&panel_pins_1800mv>;
+ backlight = <&backlight_lcd0>;
+ rotation = <180>;
+ status = "okay";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+
+&it6505dptx{
+ ovdd-supply = <&mt6358_vsim2_reg>;
+};
+
+&pio {
+ /* 192 lines */
+ gpio-line-names =
+ "SPI_AP_EC_CS_L",
+ "SPI_AP_EC_MOSI",
+ "SPI_AP_EC_CLK",
+ "I2S3_DO",
+ "USB_PD_INT_ODL",
+ "",
+ "",
+ "",
+ "",
+ "IT6505_HPD_L",
+ "I2S3_TDM_D3",
+ "SOC_I2C6_1V8_SCL",
+ "SOC_I2C6_1V8_SDA",
+ "DPI_D0",
+ "DPI_D1",
+ "DPI_D2",
+ "DPI_D3",
+ "DPI_D4",
+ "DPI_D5",
+ "DPI_D6",
+ "DPI_D7",
+ "DPI_D8",
+ "DPI_D9",
+ "DPI_D10",
+ "DPI_D11",
+ "DPI_HSYNC",
+ "DPI_VSYNC",
+ "DPI_DE",
+ "DPI_CK",
+ "AP_MSDC1_CLK",
+ "AP_MSDC1_DAT3",
+ "AP_MSDC1_CMD",
+ "AP_MSDC1_DAT0",
+ "AP_MSDC1_DAT2",
+ "AP_MSDC1_DAT1",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "OTG_EN",
+ "DRVBUS",
+ "DISP_PWM",
+ "DSI_TE",
+ "LCM_RST_1V8",
+ "AP_CTS_WIFI_RTS",
+ "AP_RTS_WIFI_CTS",
+ "SOC_I2C5_1V8_SCL",
+ "SOC_I2C5_1V8_SDA",
+ "SOC_I2C3_1V8_SCL",
+ "SOC_I2C3_1V8_SDA",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "SOC_I2C1_1V8_SDA",
+ "SOC_I2C0_1V8_SDA",
+ "SOC_I2C0_1V8_SCL",
+ "SOC_I2C1_1V8_SCL",
+ "AP_SPI_H1_MISO",
+ "AP_SPI_H1_CS_L",
+ "AP_SPI_H1_MOSI",
+ "AP_SPI_H1_CLK",
+ "I2S5_BCK",
+ "I2S5_LRCK",
+ "I2S5_DO",
+ "BOOTBLOCK_EN_L",
+ "MT8183_KPCOL0",
+ "SPI_AP_EC_MISO",
+ "UART_DBG_TX_AP_RX",
+ "UART_AP_TX_DBG_RX",
+ "I2S2_MCK",
+ "I2S2_BCK",
+ "CLK_5M_WCAM",
+ "CLK_2M_UCAM",
+ "I2S2_LRCK",
+ "I2S2_DI",
+ "SOC_I2C2_1V8_SCL",
+ "SOC_I2C2_1V8_SDA",
+ "SOC_I2C4_1V8_SCL",
+ "SOC_I2C4_1V8_SDA",
+ "",
+ "SCL8",
+ "SDA8",
+ "FCAM_PWDN_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ /*
+ * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics
+ * call it BIOS_FLASH_WP_R_L.
+ */
+ "AP_FLASH_WP_L",
+ "EC_AP_INT_ODL",
+ "IT6505_INT_ODL",
+ "H1_INT_OD_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "AP_SPI_FLASH_MISO",
+ "AP_SPI_FLASH_CS_L",
+ "AP_SPI_FLASH_MOSI",
+ "AP_SPI_FLASH_CLK",
+ "DA7219_IRQ",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "";
+};
+
+&scp_pins {
+ /* EINT pins are used for other purpose on rev2. */
+ /delete-node/ pins_eint;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig4.dts b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig4.dts
new file mode 100755
index 0000000000000..f341993d584ad
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku1-hwconfig4.dts
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 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.
+ *
+ */
+
+/dts-v1/;
+#include "mt8183-flapjack.dtsi"
+
+/ {
+ model = "MediaTek Flapjack Rev 4 board Sku 1 AUO NT51021D8P";
+
+ /* SKU_ID: 0x40001 AUO_NT51021D8P for REV >=3 */
+ compatible = "google,flapjack-rev3-sku262145",
+ "google,flapjack-rev4-sku262145",
+ "google,flapjack-rev5-sku262145",
+ "google,flapjack-sku262145",
+
+ "google,flapjack-rev3",
+ "google,flapjack-rev4",
+ "google,flapjack",
+ "google,kukui", "mediatek,mt8183";
+};
+
+&dsi0 {
+ /delete-node/ panel@0;
+ panel: panel@0 {
+ compatible = "auo,nt51021d8p";
+ reg = <0>;
+ enable-gpios = <&pio 45 0>;
+ pp33-gpios = <&pio 35 0>;
+ pp18-gpios = <&pio 36 0>;
+ pinctrl-names = "default", "state_3300mv", "state_1800mv";
+ pinctrl-0 = <&panel_pins_default>;
+ pinctrl-1 = <&panel_pins_3300mv>;
+ pinctrl-2 = <&panel_pins_1800mv>;
+ backlight = <&backlight_lcd0>;
+ rotation = <180>;
+ status = "okay";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+
+&it6505dptx{
+ ovdd-supply = <&mt6358_vsim2_reg>;
+};
+
+&pio {
+ /* 192 lines */
+ gpio-line-names =
+ "SPI_AP_EC_CS_L",
+ "SPI_AP_EC_MOSI",
+ "SPI_AP_EC_CLK",
+ "I2S3_DO",
+ "USB_PD_INT_ODL",
+ "",
+ "",
+ "",
+ "",
+ "IT6505_HPD_L",
+ "I2S3_TDM_D3",
+ "SOC_I2C6_1V8_SCL",
+ "SOC_I2C6_1V8_SDA",
+ "DPI_D0",
+ "DPI_D1",
+ "DPI_D2",
+ "DPI_D3",
+ "DPI_D4",
+ "DPI_D5",
+ "DPI_D6",
+ "DPI_D7",
+ "DPI_D8",
+ "DPI_D9",
+ "DPI_D10",
+ "DPI_D11",
+ "DPI_HSYNC",
+ "DPI_VSYNC",
+ "DPI_DE",
+ "DPI_CK",
+ "AP_MSDC1_CLK",
+ "AP_MSDC1_DAT3",
+ "AP_MSDC1_CMD",
+ "AP_MSDC1_DAT0",
+ "AP_MSDC1_DAT2",
+ "AP_MSDC1_DAT1",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "OTG_EN",
+ "DRVBUS",
+ "DISP_PWM",
+ "DSI_TE",
+ "LCM_RST_1V8",
+ "AP_CTS_WIFI_RTS",
+ "AP_RTS_WIFI_CTS",
+ "SOC_I2C5_1V8_SCL",
+ "SOC_I2C5_1V8_SDA",
+ "SOC_I2C3_1V8_SCL",
+ "SOC_I2C3_1V8_SDA",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "SOC_I2C1_1V8_SDA",
+ "SOC_I2C0_1V8_SDA",
+ "SOC_I2C0_1V8_SCL",
+ "SOC_I2C1_1V8_SCL",
+ "AP_SPI_H1_MISO",
+ "AP_SPI_H1_CS_L",
+ "AP_SPI_H1_MOSI",
+ "AP_SPI_H1_CLK",
+ "I2S5_BCK",
+ "I2S5_LRCK",
+ "I2S5_DO",
+ "BOOTBLOCK_EN_L",
+ "MT8183_KPCOL0",
+ "SPI_AP_EC_MISO",
+ "UART_DBG_TX_AP_RX",
+ "UART_AP_TX_DBG_RX",
+ "I2S2_MCK",
+ "I2S2_BCK",
+ "CLK_5M_WCAM",
+ "CLK_2M_UCAM",
+ "I2S2_LRCK",
+ "I2S2_DI",
+ "SOC_I2C2_1V8_SCL",
+ "SOC_I2C2_1V8_SDA",
+ "SOC_I2C4_1V8_SCL",
+ "SOC_I2C4_1V8_SDA",
+ "",
+ "SCL8",
+ "SDA8",
+ "FCAM_PWDN_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ /*
+ * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics
+ * call it BIOS_FLASH_WP_R_L.
+ */
+ "AP_FLASH_WP_L",
+ "EC_AP_INT_ODL",
+ "IT6505_INT_ODL",
+ "H1_INT_OD_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "AP_SPI_FLASH_MISO",
+ "AP_SPI_FLASH_CS_L",
+ "AP_SPI_FLASH_MOSI",
+ "AP_SPI_FLASH_CLK",
+ "DA7219_IRQ",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "";
+};
+
+&scp_pins {
+ /* EINT pins are used for other purpose on rev2. */
+ /delete-node/ pins_eint;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig1.dts b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig1.dts
new file mode 100755
index 0000000000000..7d4e3c4e3b601
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig1.dts
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Device Tree Source for the Google flapjack board
+ *
+ * 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.
+ *
+ */
+
+/dts-v1/;
+#include "mt8183-flapjack.dtsi"
+
+/ {
+ model = "MediaTek Flapjack Rev 4 board Sku 3 BOE TV101WUM NG0";
+
+ /* SKU_ID: 0x10003 BOE_TV101WUM_NG0 for REV >=3 */
+ compatible = "google,flapjack-rev3-sku65539",
+ "google,flapjack-rev4-sku65539",
+ "google,flapjack-rev5-sku65539",
+ "google,flapjack-sku65539",
+
+ /* SKU_ID: 0x3 for Rev 2 */
+ "google,flapjack-rev2-sku3",
+
+ /* SKU_ID: 0x50003 Panel Unknown */
+ "google,flapjack-rev2-sku327683",
+ "google,flapjack-rev3-sku327683",
+ "google,flapjack-rev4-sku327683",
+ "google,flapjack-rev5-sku327683",
+ "google,flapjack-sku327683",
+
+ "google,flapjack-rev2",
+ "google,flapjack-rev3",
+ "google,flapjack-rev4",
+ "google,flapjack",
+ "google,kukui", "mediatek,mt8183";
+};
+
+&dsi0 {
+ /delete-node/ panel@0;
+ panel: panel@0 {
+ compatible = "boe,tv101wum_ng0";
+ reg = <0>;
+ enable-gpios = <&pio 45 0>;
+ pp33-gpios = <&pio 35 0>;
+ pp18-gpios = <&pio 36 0>;
+ pinctrl-names = "default", "state_3300mv", "state_1800mv";
+ pinctrl-0 = <&panel_pins_default>;
+ pinctrl-1 = <&panel_pins_3300mv>;
+ pinctrl-2 = <&panel_pins_1800mv>;
+ backlight = <&backlight_lcd0>;
+ rotation = <180>;
+ status = "okay";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+
+&it6505dptx{
+ ovdd-supply = <&mt6358_vsim2_reg>;
+};
+
+&pio {
+ /* 192 lines */
+ gpio-line-names =
+ "SPI_AP_EC_CS_L",
+ "SPI_AP_EC_MOSI",
+ "SPI_AP_EC_CLK",
+ "I2S3_DO",
+ "USB_PD_INT_ODL",
+ "",
+ "",
+ "",
+ "",
+ "IT6505_HPD_L",
+ "I2S3_TDM_D3",
+ "SOC_I2C6_1V8_SCL",
+ "SOC_I2C6_1V8_SDA",
+ "DPI_D0",
+ "DPI_D1",
+ "DPI_D2",
+ "DPI_D3",
+ "DPI_D4",
+ "DPI_D5",
+ "DPI_D6",
+ "DPI_D7",
+ "DPI_D8",
+ "DPI_D9",
+ "DPI_D10",
+ "DPI_D11",
+ "DPI_HSYNC",
+ "DPI_VSYNC",
+ "DPI_DE",
+ "DPI_CK",
+ "AP_MSDC1_CLK",
+ "AP_MSDC1_DAT3",
+ "AP_MSDC1_CMD",
+ "AP_MSDC1_DAT0",
+ "AP_MSDC1_DAT2",
+ "AP_MSDC1_DAT1",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "OTG_EN",
+ "DRVBUS",
+ "DISP_PWM",
+ "DSI_TE",
+ "LCM_RST_1V8",
+ "AP_CTS_WIFI_RTS",
+ "AP_RTS_WIFI_CTS",
+ "SOC_I2C5_1V8_SCL",
+ "SOC_I2C5_1V8_SDA",
+ "SOC_I2C3_1V8_SCL",
+ "SOC_I2C3_1V8_SDA",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "SOC_I2C1_1V8_SDA",
+ "SOC_I2C0_1V8_SDA",
+ "SOC_I2C0_1V8_SCL",
+ "SOC_I2C1_1V8_SCL",
+ "AP_SPI_H1_MISO",
+ "AP_SPI_H1_CS_L",
+ "AP_SPI_H1_MOSI",
+ "AP_SPI_H1_CLK",
+ "I2S5_BCK",
+ "I2S5_LRCK",
+ "I2S5_DO",
+ "BOOTBLOCK_EN_L",
+ "MT8183_KPCOL0",
+ "SPI_AP_EC_MISO",
+ "UART_DBG_TX_AP_RX",
+ "UART_AP_TX_DBG_RX",
+ "I2S2_MCK",
+ "I2S2_BCK",
+ "CLK_5M_WCAM",
+ "CLK_2M_UCAM",
+ "I2S2_LRCK",
+ "I2S2_DI",
+ "SOC_I2C2_1V8_SCL",
+ "SOC_I2C2_1V8_SDA",
+ "SOC_I2C4_1V8_SCL",
+ "SOC_I2C4_1V8_SDA",
+ "",
+ "SCL8",
+ "SDA8",
+ "FCAM_PWDN_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ /*
+ * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics
+ * call it BIOS_FLASH_WP_R_L.
+ */
+ "AP_FLASH_WP_L",
+ "EC_AP_INT_ODL",
+ "IT6505_INT_ODL",
+ "H1_INT_OD_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "AP_SPI_FLASH_MISO",
+ "AP_SPI_FLASH_CS_L",
+ "AP_SPI_FLASH_MOSI",
+ "AP_SPI_FLASH_CLK",
+ "DA7219_IRQ",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "";
+};
+
+&scp_pins {
+ /* EINT pins are used for other purpose on rev2. */
+ /delete-node/ pins_eint;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig3.dts b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig3.dts
new file mode 100755
index 0000000000000..2a77a3f521b4e
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8183-flapjack-rev4-sku3-hwconfig3.dts
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Device Tree Source for the Google flapjack board
+ *
+ * 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.
+ *
+ */
+
+/dts-v1/;
+#include "mt8183-flapjack.dtsi"
+
+/ {
+ model = "MediaTek Flapjack Rev 3 board Sku 3 INX OTA7290D10P";
+ /* SKU_ID: 0x30003 INX OTA7290D10 for REV >=3 */
+ compatible = "google,flapjack-rev3-sku196611",
+ "google,flapjack-rev4-sku196611",
+ "google,flapjack-rev5-sku196611",
+ "google,flapjack-sku196611",
+
+
+ "google,flapjack-rev3",
+ "google,flapjack-rev4",
+ "google,flapjack",
+ "google,kukui", "mediatek,mt8183";
+};
+
+&dsi0 {
+ /delete-node/ panel@0;
+ panel: panel@0 {
+ compatible = "inx,ota7290d10p";
+ reg = <0>;
+ enable-gpios = <&pio 45 0>;
+ pp33-gpios = <&pio 35 0>;
+ pp18-gpios = <&pio 36 0>;
+ pinctrl-names = "default", "state_3300mv", "state_1800mv";
+ pinctrl-0 = <&panel_pins_default>;
+ pinctrl-1 = <&panel_pins_3300mv>;
+ pinctrl-2 = <&panel_pins_1800mv>;
+ backlight = <&backlight_lcd0>;
+ rotation = <180>;
+ status = "okay";
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
+};
+
+&it6505dptx{
+ ovdd-supply = <&mt6358_vsim2_reg>;
+};
+
+&pio {
+ /* 192 lines */
+ gpio-line-names =
+ "SPI_AP_EC_CS_L",
+ "SPI_AP_EC_MOSI",
+ "SPI_AP_EC_CLK",
+ "I2S3_DO",
+ "USB_PD_INT_ODL",
+ "",
+ "",
+ "",
+ "",
+ "IT6505_HPD_L",
+ "I2S3_TDM_D3",
+ "SOC_I2C6_1V8_SCL",
+ "SOC_I2C6_1V8_SDA",
+ "DPI_D0",
+ "DPI_D1",
+ "DPI_D2",
+ "DPI_D3",
+ "DPI_D4",
+ "DPI_D5",
+ "DPI_D6",
+ "DPI_D7",
+ "DPI_D8",
+ "DPI_D9",
+ "DPI_D10",
+ "DPI_D11",
+ "DPI_HSYNC",
+ "DPI_VSYNC",
+ "DPI_DE",
+ "DPI_CK",
+ "AP_MSDC1_CLK",
+ "AP_MSDC1_DAT3",
+ "AP_MSDC1_CMD",
+ "AP_MSDC1_DAT0",
+ "AP_MSDC1_DAT2",
+ "AP_MSDC1_DAT1",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "OTG_EN",
+ "DRVBUS",
+ "DISP_PWM",
+ "DSI_TE",
+ "LCM_RST_1V8",
+ "AP_CTS_WIFI_RTS",
+ "AP_RTS_WIFI_CTS",
+ "SOC_I2C5_1V8_SCL",
+ "SOC_I2C5_1V8_SDA",
+ "SOC_I2C3_1V8_SCL",
+ "SOC_I2C3_1V8_SDA",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "SOC_I2C1_1V8_SDA",
+ "SOC_I2C0_1V8_SDA",
+ "SOC_I2C0_1V8_SCL",
+ "SOC_I2C1_1V8_SCL",
+ "AP_SPI_H1_MISO",
+ "AP_SPI_H1_CS_L",
+ "AP_SPI_H1_MOSI",
+ "AP_SPI_H1_CLK",
+ "I2S5_BCK",
+ "I2S5_LRCK",
+ "I2S5_DO",
+ "BOOTBLOCK_EN_L",
+ "MT8183_KPCOL0",
+ "SPI_AP_EC_MISO",
+ "UART_DBG_TX_AP_RX",
+ "UART_AP_TX_DBG_RX",
+ "I2S2_MCK",
+ "I2S2_BCK",
+ "CLK_5M_WCAM",
+ "CLK_2M_UCAM",
+ "I2S2_LRCK",
+ "I2S2_DI",
+ "SOC_I2C2_1V8_SCL",
+ "SOC_I2C2_1V8_SDA",
+ "SOC_I2C4_1V8_SCL",
+ "SOC_I2C4_1V8_SDA",
+ "",
+ "SCL8",
+ "SDA8",
+ "FCAM_PWDN_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "I2S_PMIC",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ /*
+ * AP_FLASH_WP_L is crossystem ABI. Rev1 schematics
+ * call it BIOS_FLASH_WP_R_L.
+ */
+ "AP_FLASH_WP_L",
+ "EC_AP_INT_ODL",
+ "IT6505_INT_ODL",
+ "H1_INT_OD_L",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "AP_SPI_FLASH_MISO",
+ "AP_SPI_FLASH_CS_L",
+ "AP_SPI_FLASH_MOSI",
+ "AP_SPI_FLASH_CLK",
+ "DA7219_IRQ",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "";
+};
+
+&scp_pins {
+ /* EINT pins are used for other purpose on rev2. */
+ /delete-node/ pins_eint;
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-flapjack.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-flapjack.dtsi
new file mode 100644
index 0000000000000..7bcc6d8e5b629
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8183-flapjack.dtsi
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Device Tree Source for the Google flapjack board
+ *
+ * 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 "mt8183-kukui.dtsi"
+
+/ {
+ /delete-node/ mt8183-mt6358-ts3a227e-max98357a;
+
+ sound: mt8183-da7219-max98357a {
+ compatible = "mediatek,mt8183_da7219_max98357";
+ mediatek,platform = <&afe>;
+ mediatek,headset-codec = <&da7219>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&aud_pins>;
+ status = "okay";
+ };
+};
+
+&i2c0 {
+ /delete-node/ digitizer@9;
+ /delete-node/ touchscreen@10;
+
+ touchscreen@0a {
+ compatible = "hid-over-i2c";
+ reg = <0x0a>;
+ interrupt-parent = <&pio>;
+ interrupts = <155 IRQ_TYPE_LEVEL_LOW 155>;
+ int-gpio = <&pio 155 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&touch_default>;
+ hid-descr-addr = <0x1>;
+ wakeup-source;
+ };
+};
+
+&i2c1 {
+ sx9311@28 {
+ compatible = "semtech,sx9311";
+ reg = <0x28>;
+ interrupt-parent = <&pio>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sx9311_pins>;
+ };
+};
+
+&i2c5 {
+ /delete-node/ ts3a227e@3b;
+ da7219: da7219@1a {
+ pinctrl-names = "default";
+ pinctrl-0 = <&da7219_pins>;
+ compatible = "dlg,da7219";
+ reg = <0x1a>;
+ interrupt-parent = <&pio>;
+ interrupts = <165 IRQ_TYPE_LEVEL_LOW 165>;
+
+ dlg,micbias-lvl = <2600>;
+ dlg,mic-amp-in-sel = "diff";
+
+ da7219_aad {
+ dlg,adc-1bit-rpt = <1>;
+ dlg,btn-avg = <4>;
+ dlg,btn-cfg = <50>;
+ dlg,mic-det-thr = <500>;
+ dlg,jack-ins-deb = <20>;
+ dlg,jack-det-rate = "32ms_64ms";
+ dlg,jack-rem-deb = <1>;
+
+ dlg,a-d-btn-thr = <0xa>;
+ dlg,d-b-btn-thr = <0x16>;
+ dlg,b-c-btn-thr = <0x21>;
+ dlg,c-mic-btn-thr = <0x3E>;
+ };
+ };
+};
+
+&pio {
+ /delete-node/ ts3a227e_pins;
+
+ da7219_pins: da7219_pins {
+ pins1 {
+ pinmux = <PINMUX_GPIO165__FUNC_GPIO165>;
+ input-enable;
+ bias-enable;
+ bias-pull-up;
+ };
+ };
+
+ panel_pins_1800mv: panel_pins_1800mv {
+ pins_cmd_dat {
+ pinmux = <PINMUX_GPIO36__FUNC_GPIO36>;
+ output-low;
+ bias-pull-up;
+ };
+ };
+
+ panel_pins_3300mv: panel_pins_3300mv {
+ pins_cmd_dat {
+ pinmux = <PINMUX_GPIO35__FUNC_GPIO35>;
+ output-low;
+ bias-pull-up;
+ };
+ };
+
+ /delete-node/ touchdefault;
+ touch_default: touchdefault {
+ pin_irq {
+ pinmux = <PINMUX_GPIO155__FUNC_GPIO155>;
+ input-enable;
+ bias-pull-up;
+ };
+
+ touch_pin_reset: pin_reset {
+ pinmux = <PINMUX_GPIO156__FUNC_GPIO156>;
+ output-low;
+ };
+ };
+
+ sx9311_pins: sx9311_pins {
+ pins_eint {
+ pinmux = <PINMUX_GPIO5__FUNC_GPIO5>;
+ input-enable;
+ };
+ };
+};
+
diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
index fc61d7d25af5f..c0ae93c5aac83 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi
@@ -59,6 +59,29 @@
regulator-boot-on;
};
+ mmc1_fixed_power: regulator@3 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc1_power";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ mmc1_fixed_io: regulator@4 {
+ compatible = "regulator-fixed";
+ regulator-name = "mmc1_io";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ it6505_pp18_reg: regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "it6505_pp18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&pio 178 0>;
+ enable-active-high;
+ };
+
reserved_memory: reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -134,6 +157,18 @@
proc-supply = <&mt6358_vproc11_reg>;
};
+&dpi0 {
+ pinctrl-names = "default", "dpimode";
+ pinctrl-0 = <&dpi_pin_default>;
+ pinctrl-1 = <&dpi_pin_func>;
+ status = "okay";
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&it6505_in>;
+ };
+ };
+};
+
&dsi0 {
status = "okay";
#address-cells = <1>;
@@ -249,6 +284,29 @@
pinctrl-0 = <&i2c3_pins>;
status = "okay";
clock-frequency = <100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ it6505dptx: it6505dptx@5c {
+ compatible = "ite,it6505";
+ status = "okay";
+ interrupt-parent = <&pio>;
+ interrupts = <152 IRQ_TYPE_EDGE_RISING 152 0>;
+ reg = <0x5c>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&it6505_pins>;
+ ovdd-supply = <&mt6358_vsim1_reg>;
+ pwr18-supply = <&it6505_pp18_reg>;
+ reset-gpios = <&pio 179 1>;
+ hpd-gpios = <&pio 9 0>;
+ cros-ec = <&cros_ec>;
+ extcon = <&usbc_extcon0>;
+ port {
+ it6505_in: endpoint {
+ remote-endpoint = <&dpi_out>;
+ };
+ };
+ };
};
&i2c4 {
@@ -456,6 +514,51 @@
};
};
+ dpi_pin_default: dpi_pin_default{
+ pins_cmd_dat {
+ pinmux = <PINMUX_GPIO13__FUNC_GPIO13>,
+ <PINMUX_GPIO14__FUNC_GPIO14>,
+ <PINMUX_GPIO15__FUNC_GPIO15>,
+ <PINMUX_GPIO16__FUNC_GPIO16>,
+ <PINMUX_GPIO17__FUNC_GPIO17>,
+ <PINMUX_GPIO18__FUNC_GPIO18>,
+ <PINMUX_GPIO19__FUNC_GPIO19>,
+ <PINMUX_GPIO20__FUNC_GPIO20>,
+ <PINMUX_GPIO21__FUNC_GPIO21>,
+ <PINMUX_GPIO22__FUNC_GPIO22>,
+ <PINMUX_GPIO23__FUNC_GPIO23>,
+ <PINMUX_GPIO24__FUNC_GPIO24>,
+ <PINMUX_GPIO25__FUNC_GPIO25>,
+ <PINMUX_GPIO26__FUNC_GPIO26>,
+ <PINMUX_GPIO27__FUNC_GPIO27>,
+ <PINMUX_GPIO28__FUNC_GPIO28>;
+ drive-strength = <MTK_DRIVE_6mA>;
+ output-low;
+ };
+ };
+
+ dpi_pin_func: dpi_pin_func {
+ pins_cmd_dat {
+ pinmux = <PINMUX_GPIO13__FUNC_DBPI_D0>,
+ <PINMUX_GPIO14__FUNC_DBPI_D1>,
+ <PINMUX_GPIO15__FUNC_DBPI_D2>,
+ <PINMUX_GPIO16__FUNC_DBPI_D3>,
+ <PINMUX_GPIO17__FUNC_DBPI_D4>,
+ <PINMUX_GPIO18__FUNC_DBPI_D5>,
+ <PINMUX_GPIO19__FUNC_DBPI_D6>,
+ <PINMUX_GPIO20__FUNC_DBPI_D7>,
+ <PINMUX_GPIO21__FUNC_DBPI_D8>,
+ <PINMUX_GPIO22__FUNC_DBPI_D9>,
+ <PINMUX_GPIO23__FUNC_DBPI_D10>,
+ <PINMUX_GPIO24__FUNC_DBPI_D11>,
+ <PINMUX_GPIO25__FUNC_DBPI_HSYNC>,
+ <PINMUX_GPIO26__FUNC_DBPI_VSYNC>,
+ <PINMUX_GPIO27__FUNC_DBPI_DE>,
+ <PINMUX_GPIO28__FUNC_DBPI_CK>;
+ drive-strength = <MTK_DRIVE_6mA>;
+ };
+ };
+
ec_ap_int_odl: ec_ap_int_odl {
pins1 {
pinmux = <PINMUX_GPIO151__FUNC_GPIO151>;
@@ -554,6 +657,22 @@
};
};
+ it6505_pins: it6505_pins{
+ pins_cmd_dat {
+ pinmux = <PINMUX_GPIO178__FUNC_GPIO178>,
+ <PINMUX_GPIO179__FUNC_GPIO179>;
+ output-low;
+ bias-pull-up;
+ };
+
+ pins_cmd_dat1 {
+ pinmux = <PINMUX_GPIO9__FUNC_GPIO9>,
+ <PINMUX_GPIO152__FUNC_GPIO152>;
+ input-enable;
+ bias-pull-up;
+ };
+ };
+
mmc0_pins_default: mmc0default {
pins_cmd_dat {
pinmux = <PINMUX_GPIO123__FUNC_MSDC0_DAT0>,
@@ -885,6 +1004,12 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ usbc_extcon0: extcon@0 {
+ compatible = "google,extcon-usbc-cros-ec";
+ google,usb-port-id = <0>;
+ #extcon-cells = <0>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index f3ab0cf7afcad..5c7aac27bf655 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1737,6 +1737,17 @@
phy-names = "dphy";
};
+ dpi0: dpi@14015000 {
+ compatible = "mediatek,mt8183-dpi";
+ reg = <0 0x14015000 0 0x1000>;
+ interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_LOW 0>;
+ power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>;
+ clocks = <&mmsys CLK_MM_DPI_IF>,
+ <&mmsys CLK_MM_DPI_MM>,
+ <&apmixedsys CLK_APMIXED_TVDPLL>;
+ clock-names = "pixel", "engine", "pll";
+ };
+
mutex: mutex@14016000 {
compatible = "mediatek,mt8183-disp-mutex";
reg = <0 0x14016000 0 0x1000>;
diff --git a/chromeos/config/arm64/chromiumos-arm64.flavour.config b/chromeos/config/arm64/chromiumos-arm64.flavour.config
index 065254f448922..c3ed47888fbc3 100644
--- a/chromeos/config/arm64/chromiumos-arm64.flavour.config
+++ b/chromeos/config/arm64/chromiumos-arm64.flavour.config
@@ -903,7 +903,7 @@ CONFIG_SND_SOC_MT8173_RT5650=y
CONFIG_SND_SOC_MT8173_RT5650_RT5514=y
CONFIG_SND_SOC_MT8173_RT5650_RT5676=y
CONFIG_SND_SOC_MT8183=y
-# CONFIG_SND_SOC_MT8183_DA7219_MAX98357A is not set
+CONFIG_SND_SOC_MT8183_DA7219_MAX98357A=y
CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=y
# CONFIG_SND_SOC_QCOM is not set
# CONFIG_SND_SOC_RK3288_HDMI_ANALOG is not set
diff --git a/chromeos/config/arm64/chromiumos-mediatek.flavour.config b/chromeos/config/arm64/chromiumos-mediatek.flavour.config
index 1dec1fdc29321..8a2e7692450c5 100644
--- a/chromeos/config/arm64/chromiumos-mediatek.flavour.config
+++ b/chromeos/config/arm64/chromiumos-mediatek.flavour.config
@@ -67,7 +67,7 @@ CONFIG_DRM_GEM_CMA_HELPER=y
CONFIG_DRM_MEDIATEK=y
CONFIG_DRM_MEDIATEK_HDMI=y
CONFIG_DRM_MIPI_DSI=y
-# CONFIG_DRM_PANEL_BOE_HIMAX8279D is not set
+CONFIG_DRM_PANEL_BOE_HIMAX8279D=y
# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set
CONFIG_DRM_PANEL_INNOLUX_P079ZCA=y
# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set
@@ -226,7 +226,7 @@ CONFIG_SND_SOC_MT8173_RT5650=y
CONFIG_SND_SOC_MT8173_RT5650_RT5514=y
CONFIG_SND_SOC_MT8173_RT5650_RT5676=y
CONFIG_SND_SOC_MT8183=y
-# CONFIG_SND_SOC_MT8183_DA7219_MAX98357A is not set
+CONFIG_SND_SOC_MT8183_DA7219_MAX98357A=y
CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=y
CONFIG_SND_SOC_RL6231=y
CONFIG_SND_SOC_RT5514=y
@@ -302,3 +302,4 @@ CONFIG_VIRTIO=y
# CONFIG_VIRTIO_MMIO is not set
# CONFIG_VIRTIO_NET is not set
# CONFIG_VIRTIO_WL is not set
+CONFIG_SX9311=y
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 4934fcf5a6f82..a83507bf6300e 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
+obj-y += ite-it6505.o
obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
new file mode 100755
index 0000000000000..35f0bede1ace1
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -0,0 +1,2948 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/spi/spi.h>
+#include <linux/fs.h>
+#include <linux/bits.h>
+#include <linux/of_platform.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <crypto/sha.h>
+#include <crypto/hash.h>
+
+#define AX 0
+#define BX 1
+#define ENAUD 1
+#define AUDSEL I2S
+#define AUDTYPE LPCM
+#define AUDFS AUD48K
+#define AUDCH 2
+/* 0: Standard I2S;1: 32bit I2S */
+#define I2SINPUTFMT 1
+/* 0: Left-justified;1: Right-justified */
+#define I2SJUSTIFIED 0
+/* 0: Data delay 1T correspond to WS;1: No data delay correspond to WS */
+#define I2SDATADELAY 0
+/* 0: is left channel;1: is right channel */
+#define I2SWSCHANNEL 0
+/* 0: MSB shift first;1: LSB shift first */
+#define I2SDATASEQ 0
+
+#define LANESWAP 0
+#define LANE 4
+#define _HBR 1
+#define ENHFRAME 1
+#define ENSSC 1
+
+#define FLAGTRAINDOWN 100
+#define TRAINFAILCNT 5
+#define AUX_WAIT_TIMEOUT_MS 15
+#define PCLK_DELAY 1
+#define PCLK_INV 0
+#define EDIDRETRYTIME 5
+#define SHOWVIDEOTIMING 2
+#define PWROFFRETRYTIME 5
+
+/* AX or BX */
+#define CHIP_VERSION BX
+#define ENHDCP 1
+
+/* if use this define will enable power on/off option */
+#define ENPWRONOFF
+
+/* if use this define will power on in probe */
+/* #define TEST_MODE */
+
+/* if use this define will enable AUX debug option */
+/* #define ENAUX_TRANSFER_DEBUG */
+
+/* if use this define will enable SHA debug */
+/* #define SHA_DEBUG */
+
+/* register char device for it6505 */
+#define IT6505_CLASS_NAME "it6505_class"
+#define IT6505_DEVICE_NAME "it6505_device"
+#define IT6505_MAX_DEV 128
+/* The device-driver class struct pointer */
+static int it6505_major_num;
+
+enum sys_status {
+ SYS_UNPLUG = 0,
+ SYS_HPD,
+ SYS_AUTOTRAIN,
+ SYS_WAIT,
+ SYS_TRAINFAIL,
+ SYS_ReHDCP,
+ SYS_PWRDN,
+ SYS_NOROP,
+ SYS_Unknown,
+};
+
+enum it6505_aud_sel {
+ I2S = 0,
+ SPDIF,
+};
+
+enum it6505_aud_fs {
+ AUD24K = 0x6,
+ AUD32K = 0x3,
+ AUD48K = 0x2,
+ AUD96K = 0xA,
+ AUD192K = 0xE,
+ AUD44P1K = 0x0,
+ AUD88P2K = 0x8,
+ AUD176P4K = 0xC,
+};
+
+enum it6505_aud_type {
+ LPCM = 0,
+ NLPCM,
+ DSS,
+ HBR,
+};
+
+enum aud_word_length {
+ AUD16BIT = 0,
+ AUD18BIT,
+ AUD20BIT,
+ AUD24BIT,
+};
+
+/* Audio Sample Word Length: AUD16BIT, AUD18BIT, AUD20BIT, AUD24BIT */
+#define AUDWORDLENGTH AUD24BIT
+
+enum SWITCH {
+ Off = 0,
+ On
+};
+
+struct it6505_platform_data {
+ struct regulator *pwr18;
+ struct regulator *ovdd;
+ struct gpio_desc *gpiod_hpd;
+ struct gpio_desc *gpiod_pd;
+ struct gpio_desc *gpiod_reset;
+
+ int hpd_irq;
+ int intp_irq;
+};
+
+struct it6505_dp_port {
+ struct it6505 *it6505_dp;
+ struct notifier_block event_nb;
+ struct extcon_dev *extcon;
+ struct work_struct extcon_wq;
+ u8 id;
+};
+
+struct it6505 {
+ struct cros_ec_device *cros_ec;
+ struct drm_dp_aux aux;
+ struct drm_bridge bridge;
+ struct i2c_client *client;
+ struct edid *edid;
+ struct drm_connector connector;
+ struct drm_dp_link link;
+ struct it6505_platform_data pdata;
+ struct mutex lock;
+ struct regmap *regmap;
+ struct cdev cdev;
+ struct device class_dev;
+ struct it6505_dp_port *port;
+
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+ enum sys_status status;
+ u8 dumpdpcd[30];
+ u8 dpcd_rev;
+ bool hbr;
+ u8 lane;
+ u8 en_ssc;
+ bool en_hframe;
+ bool laneswap;
+ u8 hpd_status;
+
+ enum it6505_aud_sel aud_sel;
+ enum it6505_aud_fs aud_fs;
+ enum it6505_aud_type aud_type;
+ u8 aud_ch;
+ u8 i2s_input_fmt;
+ u8 i2s_justified;
+ u8 i2s_data_delay;
+ u8 i2s_ws_channel;
+ u8 i2s_data_seq;
+ u8 vidstable_done;
+ enum aud_word_length audwordlength;
+ u8 cntfsm;
+ u8 enhdcp;
+ bool cp_ready;
+ unsigned int bstatus;
+ bool cp_done;
+ u8 downstreamrepeater;
+ u8 am0[8];
+ u8 binfo[2];
+ u8 ksvlist[5*12];
+ unsigned int sha[5];
+ unsigned int w[80];
+ u8 shainput[64];
+ u8 av[5][4];
+ u8 bv[5][4];
+ u8 passsha;
+ bool powered;
+ /* it6505 driver hold option */
+ unsigned int it6505_drv_hold;
+};
+
+static int it6505_poweron(struct it6505 *it6505);
+#ifdef ENPWRONOFF
+static int it6505_poweroff(struct it6505 *it6505);
+#endif
+
+static const struct regmap_range it6505_bridge_volatile_ranges[] = {
+ { .range_min = 0, .range_max = 0xFF },
+};
+
+static const struct regmap_access_table it6505_bridge_volatile_table = {
+ .yes_ranges = it6505_bridge_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(it6505_bridge_volatile_ranges),
+};
+
+static const struct regmap_config it6505_bridge_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &it6505_bridge_volatile_table,
+ .cache_type = REGCACHE_NONE,
+};
+
+static int dptxrd(struct it6505 *it6505,
+ unsigned int reg_addr, unsigned int *value)
+{
+ int err;
+
+ err = regmap_read(it6505->regmap, reg_addr, value);
+ if (err < 0) {
+ DRM_ERROR("%s read fail err reg_addr[0x%x] err:%d\n",
+ __func__, reg_addr, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void it6505_dump(struct it6505 *it6505)
+{
+ unsigned int value, i;
+
+ DRM_DEBUG_DRIVER("\n----------%s start----------\n", __func__);
+ for (i = 0; i <= 0xff; i++) {
+ dptxrd(it6505, i, &value);
+ DRM_DEBUG_DRIVER("%s[0x%x] = 0x%x\n", __func__, i, value);
+ }
+ DRM_DEBUG_DRIVER("\n----------%s end----------\n\n", __func__);
+}
+
+static int dptxwr(struct it6505 *it6505,
+ unsigned int reg_addr, unsigned int reg_val)
+{
+ int err;
+
+ err = regmap_write(it6505->regmap, reg_addr, reg_val);
+
+ if (err < 0) {
+ DRM_ERROR(
+ "%s write fail err reg_addr[0x%x] = 0x%x err = %d\n",
+ __func__, reg_addr, reg_val, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int dptxset(struct it6505 *it6505, unsigned int reg,
+ unsigned int mask, unsigned int setvalue)
+{
+ int err;
+
+ err = regmap_update_bits(it6505->regmap, reg, mask, setvalue);
+ if (err < 0) {
+ DRM_ERROR("%s write fail err %d\n", __func__, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static inline struct it6505 *connector_to_it6505(struct drm_connector *c)
+{
+ return container_of(c, struct it6505, connector);
+}
+
+static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct it6505, bridge);
+}
+
+
+void it6505_initfsm(struct it6505 *it6505)
+{
+ it6505->aud_sel = AUDSEL;
+ it6505->aud_fs = AUDFS;
+ it6505->aud_ch = AUDCH;
+ it6505->aud_type = AUDTYPE;
+ it6505->i2s_input_fmt = I2SINPUTFMT;
+ it6505->i2s_justified = I2SJUSTIFIED;
+ it6505->i2s_data_delay = I2SDATADELAY;
+ it6505->i2s_ws_channel = I2SWSCHANNEL;
+ it6505->i2s_data_seq = I2SDATASEQ;
+ it6505->audwordlength = AUDWORDLENGTH;
+
+ it6505->status = SYS_Unknown;
+ it6505->enhdcp = ENHDCP;
+ it6505->hbr = _HBR;
+ it6505->lane = LANE;
+ it6505->en_ssc = ENSSC;
+ it6505->en_hframe = ENHFRAME;
+ it6505->laneswap = LANESWAP;
+ it6505->vidstable_done = 0;
+}
+
+#if (CHIP_VERSION == BX)
+void iTE6505_termination(struct it6505 *it6505, enum SWITCH s)
+{
+ DRM_DEBUG_DRIVER("%s switch!!\n", __func__);
+ if (s) {
+ dptxset(it6505, 0x5D, 0x80, 0x00);
+ dptxset(it6505, 0x5E, 0x02, 0x02);
+ DRM_DEBUG_DRIVER("%s ON!!\n", __func__);
+ } else {
+ dptxset(it6505, 0x5D, 0x80, 0x80);
+ dptxset(it6505, 0x5E, 0x02, 0x00);
+ dptxset(it6505, 0x5C, 0xF0, 0x00);
+ DRM_DEBUG_DRIVER("%s OFF!!\n", __func__);
+ }
+}
+#endif
+
+static bool dptx_getsinkhpd(struct it6505 *it6505)
+{
+ unsigned int value;
+ int ret;
+
+ ret = dptxrd(it6505, 0x0D, &value);
+
+ if (ret < 0)
+ return false;
+
+ return (value & 2) == 2;
+}
+
+void show_vid_info(struct it6505 *it6505)
+{
+ int HSyncPol, VSyncPol, InterLaced;
+ int HTotal, HDES, HDEW, HFPH, HSYNCW;
+ int VTotal, VDES, VDEW, VFPH, VSYNCW;
+ int rddata, rddata1, i;
+ int PCLK, sum;
+
+ usleep_range(10000, 15000);
+ dptxwr(it6505, 0x0F, 0x00);
+ dptxrd(it6505, 0xa0, &rddata);
+ HSyncPol = rddata & BIT(0);
+ VSyncPol = (rddata & BIT(2)) >> 2;
+ InterLaced = (rddata & BIT(4)) >> 4;
+
+ dptxrd(it6505, 0xa1, &rddata);
+ dptxrd(it6505, 0xa2, &rddata1);
+ HTotal = ((rddata1 & 0x1F) << 8) + rddata;
+
+ dptxrd(it6505, 0xa3, &rddata);
+ dptxrd(it6505, 0xa4, &rddata1);
+
+ HDES = ((rddata1 & 0x1F) << 8) + rddata;
+
+ dptxrd(it6505, 0xa5, &rddata);
+ dptxrd(it6505, 0xa6, &rddata1);
+
+ HDEW = ((rddata1 & 0x1F) << 8) + rddata;
+
+ dptxrd(it6505, 0xa7, &rddata);
+ dptxrd(it6505, 0xa8, &rddata1);
+
+ HFPH = ((rddata1 & 0x1F) << 8) + rddata;
+
+ dptxrd(it6505, 0xa9, &rddata);
+ dptxrd(it6505, 0xaa, &rddata1);
+
+ HSYNCW = ((rddata1 & 0x1F) << 8) + rddata;
+
+ dptxrd(it6505, 0xab, &rddata);
+ dptxrd(it6505, 0xac, &rddata1);
+ VTotal = ((rddata1 & 0x0F) << 8) + rddata;
+
+ dptxrd(it6505, 0xad, &rddata);
+ dptxrd(it6505, 0xae, &rddata1);
+ VDES = ((rddata1 & 0x0F) << 8) + rddata;
+
+ dptxrd(it6505, 0xaf, &rddata);
+ dptxrd(it6505, 0xb0, &rddata1);
+ VDEW = ((rddata1 & 0x0F) << 8) + rddata;
+
+ dptxrd(it6505, 0xb1, &rddata);
+ dptxrd(it6505, 0xb2, &rddata1);
+ VFPH = ((rddata1 & 0x0F) << 8) + rddata;
+
+ dptxrd(it6505, 0xb3, &rddata);
+ dptxrd(it6505, 0xb4, &rddata1);
+ VSYNCW = ((rddata1 & 0x0F) << 8) + rddata;
+
+ sum = 0;
+ for (i = 0; i < 100; i++) {
+ dptxset(it6505, 0x12, 0x80, 0x80);
+ usleep_range(10000, 15000);
+ dptxset(it6505, 0x12, 0x80, 0x00);
+
+ dptxrd(it6505, 0x13, &rddata);
+ dptxrd(it6505, 0x14, &rddata1);
+ rddata = ((rddata1 & 0x0F) << 8)+rddata;
+
+ sum += rddata;
+ }
+
+ sum /= 100;
+ PCLK = 13500 * 2048 / sum;
+
+ DRM_DEBUG_DRIVER("\n----------Video Input Timing----------\n");
+ DRM_DEBUG_DRIVER("PCLK = %d.%dMHz\n", PCLK / 1000, PCLK % 1000);
+ DRM_DEBUG_DRIVER("HTotal = %d\n", HTotal);
+ DRM_DEBUG_DRIVER("HActive = %d\n", HDEW);
+ DRM_DEBUG_DRIVER("HFrontPorch = %d\n", HFPH);
+ DRM_DEBUG_DRIVER("HSyncWidth = %d\n", HSYNCW);
+ DRM_DEBUG_DRIVER("HBackPorch = %d\n", HTotal - HDEW - HFPH - HSYNCW);
+ DRM_DEBUG_DRIVER("VTotal = %d\n", VTotal);
+ DRM_DEBUG_DRIVER("VActive = %d\n", VDEW);
+ DRM_DEBUG_DRIVER("VFrontPorch = %d\n", VFPH);
+ DRM_DEBUG_DRIVER("VSyncWidth = %d\n", VSYNCW);
+ DRM_DEBUG_DRIVER("VBackPorch = %d\n", VTotal - VDEW - VFPH - VSYNCW);
+}
+
+void dptx_sys_chg(struct it6505 *it6505, enum sys_status newstate)
+{
+ unsigned int i = 0;
+ unsigned int reg06, reg07, reg08, reg0d, reg0e;
+
+ dptxrd(it6505, 0x06, &reg06);
+ dptxrd(it6505, 0x07, &reg07);
+ dptxrd(it6505, 0x08, &reg08);
+ dptxrd(it6505, 0x0d, &reg0d);
+ dptxrd(it6505, 0x0e, &reg0e);
+
+ DRM_DEBUG_DRIVER("%s reg06 = 0x%x\n", __func__, reg06);
+ DRM_DEBUG_DRIVER("%s reg07 = 0x%x\n", __func__, reg07);
+ DRM_DEBUG_DRIVER("%s reg08 = 0x%x\n", __func__, reg08);
+ DRM_DEBUG_DRIVER("%s reg0d = 0x%x\n", __func__, reg0d);
+ DRM_DEBUG_DRIVER("%s reg0e = 0x%x\n", __func__, reg0e);
+
+ if (newstate != SYS_UNPLUG) {
+ if (!dptx_getsinkhpd(it6505))
+ newstate = SYS_UNPLUG;
+ }
+
+ it6505->status = newstate;
+
+ switch (it6505->status) {
+ case SYS_UNPLUG:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_UNPLUG!!\n");
+ kfree(it6505->edid);
+ it6505->edid = NULL;
+ DRM_DEBUG_DRIVER("Free it6505 EDID memory!!\n");
+#if (CHIP_VERSION == BX)
+ iTE6505_termination(it6505, Off);
+#endif
+ break;
+ case SYS_HPD:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_HPD!!\n");
+#if (CHIP_VERSION == BX)
+ iTE6505_termination(it6505, On);
+#endif
+ break;
+ case SYS_AUTOTRAIN:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_AUTOTRAIN!!\n");
+ break;
+ case SYS_WAIT:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_WAIT!!\n");
+ break;
+#if ENHDCP
+ case SYS_ReHDCP:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_ReHDCP!!\n");
+ break;
+#endif
+ case SYS_NOROP:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_NOROP!!\n");
+ for (i = 0; i < SHOWVIDEOTIMING; i++)
+ show_vid_info(it6505);
+#ifdef TEST_MODE
+ it6505->it6505_drv_hold = 1;
+ DRM_DEBUG_DRIVER("set it6505_drv_hold:%d",
+ it6505->it6505_drv_hold);
+#endif
+ break;
+ case SYS_PWRDN:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_PWRDN!!\n");
+ /* Reset and PwrDn AFE */
+ break;
+ default:
+ DRM_DEBUG_DRIVER("sys_state is changing to SYS_UNKNOWN!!\n");
+ break;
+ }
+}
+
+static bool it6505_aux_op_finished(struct it6505 *it6505)
+{
+ unsigned int value;
+ int err;
+
+ err = regmap_read(it6505->regmap, 0x2b, &value);
+ if (err < 0)
+ return false;
+
+ return (value & BIT(5)) == 0;
+}
+
+
+static int dptx_auxwait(struct it6505 *it6505)
+{
+ unsigned int status;
+ unsigned long timeout;
+ int err;
+
+ timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
+
+ while (!it6505_aux_op_finished(it6505)) {
+ if (time_after(jiffies, timeout)) {
+ DRM_DEBUG_DRIVER("Timed out waiting AUX to finish\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(1000, 2000);
+ }
+
+ err = dptxrd(it6505, 0x9f, &status);
+ if (err < 0) {
+ DRM_ERROR("Failed to read from AUX channel: %d\n", err);
+ return err;
+ }
+
+ if (status & 0x03) {
+ DRM_ERROR("Failed to wait for AUX channel (status: 0x%x)\n",
+ status);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int dptx_aux_r_edid(struct it6505 *it6505,
+ unsigned int nosegw, unsigned int block, unsigned int offset)
+{
+ unsigned int value, status;
+ int ret;
+
+ /* enable pc aux access */
+ dptxwr(it6505, 0x23, (nosegw << 6) + 0x03);
+ /* edid fifo clr */
+ dptxwr(it6505, 0x23, (nosegw << 6) + 0x82);
+ /* start address[7:0] */
+ dptxwr(it6505, 0x24, (block % 2) * 128 + offset);
+ /* start address[15:8] */
+ dptxwr(it6505, 0x25, block / 256);
+ /* writenum[3:0]+startadr[19:16] */
+ dptxwr(it6505, 0x26, 0xf0);
+ /* aux edid read fire */
+ dptxwr(it6505, 0x2b, 0x0b);
+ dptx_auxwait(it6505);
+
+ ret = dptxrd(it6505, 0x07, &value);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Failed to read reg07: %d\n", ret);
+ return ret;
+ }
+
+ if (value & BIT(0)) {
+ DRM_DEBUG_DRIVER("aux channel request fail interrupt\n");
+
+ ret = dptxrd(it6505, 0x9f, &status);
+ if (ret) {
+ DRM_DEBUG_DRIVER("AUX channel failed : %d !\n",
+ ret);
+ return ret;
+ }
+
+ switch ((status & 0xc0) >> 6) {
+ case 0:
+ DRM_DEBUG_DRIVER("no error !!!\n");
+ return 0;
+ case 1:
+ DRM_DEBUG_DRIVER("defer > 7 times status: 0x%x!!!\n",
+ status);
+ return -ETIMEDOUT;
+
+ case 2:
+ DRM_DEBUG_DRIVER("Nack response status: 0x%x!!!\n",
+ status);
+ return -ETIMEDOUT;
+
+ default:
+ DRM_DEBUG_DRIVER("timeout status: 0x%x!!!\n",
+ status);
+ return -ETIMEDOUT;
+ }
+
+ }
+ return 0;
+}
+
+unsigned int dptx_getedidblock(struct it6505 *it6505, u8 *pedidbuff,
+ unsigned int blockno)
+{
+ ushort i;
+ unsigned int offset, checksum, value;
+
+ if (pedidbuff == NULL)
+ return 0xff;
+
+ dptxset(it6505, 0x05, 0x08, 0x08);
+ dptxset(it6505, 0x05, 0x08, 0x00);
+
+ for (offset = 0; offset < 0x80; offset += 8) {
+ dptx_aux_r_edid(it6505, 1, blockno, offset);
+
+ for (i = 0; i < 8; i++) {
+ dptxrd(it6505, 0x2f, &value);
+ pedidbuff[offset + i] = value;
+ DRM_DEBUG_DRIVER("%s[%d][%d]: 0x%x !!\n",
+ __func__, blockno, i, value);
+ }
+ }
+ /* disable pc aux access */
+ dptxwr(it6505, 0x23, 1 << 6);
+ checksum = 0;
+ for (i = 0; i < 0x80; i++)
+ checksum += pedidbuff[i];
+
+ checksum &= 0xff;
+
+ return checksum;
+}
+
+static u8 it6505_get_extension_num(struct it6505 *it6505)
+{
+ unsigned int checksum = 0, retrytime = 0, reg0D;
+ u8 buff[EDID_LENGTH];
+
+ DRM_DEBUG_DRIVER("start %s!\n", __func__);
+
+ do {
+ dptxrd(it6505, 0x0D, &reg0D);
+ checksum = dptx_getedidblock(it6505, buff, 0);
+ retrytime++;
+ DRM_DEBUG_DRIVER("read EDID %d time", retrytime);
+ if (!(reg0D & BIT(1))) {
+ dptx_sys_chg(it6505, SYS_UNPLUG);
+ break;
+ }
+ } while (checksum != 0 && retrytime < EDIDRETRYTIME);
+
+ DRM_DEBUG_DRIVER("extension number:%d",buff[0x7e]);
+ DRM_DEBUG_DRIVER("end %s!\n", __func__);
+ return buff[0x7e];
+}
+
+static struct edid *it6505_get_edid(struct it6505 *it6505)
+{
+ unsigned int checksum = 0, retrytime = 0;
+ unsigned int i, block, reg0D, total_size;
+ u8 *pedidbuff = kmalloc(EDID_LENGTH, GFP_KERNEL);
+
+ DRM_DEBUG_DRIVER("start %s", __func__);
+ if (!pedidbuff) {
+ DRM_DEBUG_DRIVER("%s(null)!\n", __func__);
+ return NULL;
+ }
+
+ it6505_dump(it6505);
+ block = it6505_get_extension_num(it6505);
+
+ /* dp does not have the hdmi tx four block test requirement */
+ if (block > 2)
+ block = 2;
+
+ total_size = (block + 1) * EDID_LENGTH;
+ if (total_size > EDID_LENGTH)
+ pedidbuff = krealloc(pedidbuff, total_size, GFP_KERNEL);
+
+ for (i = 0; i <= block; i++) {
+ DRM_DEBUG_DRIVER("Read block 0x%x", i);
+ retrytime = 0;
+ do {
+ dptxrd(it6505, 0x0D, &reg0D);
+ checksum = dptx_getedidblock(it6505,
+ pedidbuff + i * EDID_LENGTH, i);
+ DRM_DEBUG_DRIVER("%s in block %d %s",
+ checksum ? "Fake" : "True", i,
+ checksum ? "and read again!" : "!");
+ retrytime++;
+ DRM_DEBUG_DRIVER("read EDID %d time", retrytime);
+ if (!(reg0D & BIT(1))) {
+ dptx_sys_chg(it6505, SYS_UNPLUG);
+ break;
+ }
+ } while (checksum != 0 && retrytime < EDIDRETRYTIME);
+ if (checksum || it6505->status == SYS_UNPLUG)
+ break;
+ }
+ DRM_DEBUG_DRIVER("end %s and edid correct!", __func__);
+ return (struct edid *)pedidbuff;
+}
+
+static int it6505_get_modes(struct drm_connector *connector)
+{
+ struct it6505 *ctx = connector_to_it6505(connector);
+ int err, num_modes = 0;
+ u8 *p;
+ unsigned int reg9F, reg0D;
+
+ DRM_DEBUG_DRIVER("start %s", __func__);
+ err = it6505_poweron(ctx);
+ if (err) {
+ DRM_DEBUG_DRIVER("power on fail!");
+ goto unlock;
+ }
+ DRM_DEBUG_DRIVER("power on success!");
+ if (ctx->edid) {
+ DRM_DEBUG_DRIVER("ctx->edid is exist\n");
+ return drm_add_edid_modes(connector, ctx->edid);
+ }
+ DRM_DEBUG_DRIVER("ctx->edid not exist\n");
+ DRM_DEBUG_DRIVER("call it6505_get_edid to get EDID!\n");
+ mutex_lock(&ctx->lock);
+ dptxrd(ctx, 0x0D, &reg0D);
+ if (reg0D & BIT(1))
+ dptx_sys_chg(ctx, SYS_HPD);
+ else
+ dptx_sys_chg(ctx, SYS_UNPLUG);
+
+ dptxrd(ctx, 0x9F, &reg9F);
+ DRM_DEBUG_DRIVER("Aux status reg9F:0x%02x\n", reg9F);
+ ctx->edid = it6505_get_edid(ctx);
+ DRM_DEBUG_DRIVER("After it6505_get_edid, show the EDID:\n");
+ err = 256;
+ p = (u8 *)ctx->edid;
+ while (err) {
+ DRM_DEBUG_DRIVER("err = %d\n", err);
+ DRM_DEBUG_DRIVER("0x%02x 0x%02x 0x%02x 0x%02x\n",
+ p[0], p[1], p[2], p[3]);
+ DRM_DEBUG_DRIVER("0x%02x 0x%02x 0x%02x 0x%02x\n",
+ p[4], p[5], p[6], p[7]);
+ DRM_DEBUG_DRIVER("0x%02x 0x%02x 0x%02x 0x%02x\n",
+ p[8], p[9], p[10], p[11]);
+ DRM_DEBUG_DRIVER("0x%02x 0x%02x 0x%02x 0x%02x\n",
+ p[12], p[13], p[14], p[15]);
+
+ err -= 16;
+ p += 16;
+ }
+ if (!ctx->edid) {
+ DRM_ERROR("Failed to read EDID\n");
+ goto unlock;
+ }
+
+ err = drm_connector_update_edid_property(connector, ctx->edid);
+ if (err) {
+ DRM_ERROR("Failed to update EDID property: %d\n", err);
+ goto unlock;
+ }
+
+ num_modes = drm_add_edid_modes(connector, ctx->edid);
+
+unlock:
+ mutex_unlock(&ctx->lock);
+
+ return num_modes;
+}
+
+static const struct drm_connector_helper_funcs it6505_connector_helper_funcs = {
+ .get_modes = it6505_get_modes,
+};
+
+static enum drm_connector_status it6505_detect(struct drm_connector *connector,
+ bool force)
+{
+ struct it6505 *ctx = connector_to_it6505(connector);
+
+ if (gpiod_get_value(ctx->pdata.gpiod_hpd))
+ return connector_status_disconnected;
+
+ return connector_status_connected;
+}
+
+static const struct drm_connector_funcs it6505_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = it6505_detect,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* reverved for future use */
+/*
+ *BYTE iTE6505_dptx_aux(char *RORW, char *addr,
+ * int offset, BYTE *array, BYTE size)
+ *{
+ * BYTE i = 0;
+ * if (!strcmp(RORW, "w") || !strcmp(RORW, "W")) {
+ * while (i < size) {
+ * if (!dptx_dpcdwr(offset++, array[i++])) {
+ * DRM_DEBUG_DRIVER(("DPCD write fail!!\n"));
+ * return 3;
+ * }
+ * else {
+ * DRM_DEBUG_DRIVER(("DPCD write success!!\n"));
+ * return 0;
+ * }
+ * }
+ * }
+ * else if (!strcmp(RORW, "r") || !strcmp(RORW, "R")) {
+ * if (!strcmp(addr, "EDID")) {
+ * BYTE blocknum = offset / 0x80;
+ * offset = offset%0x80;
+ * dptx_AUX_R_EDID(1, blocknum, offset);
+ * while (i < size) {
+ * array[i] = dptxrd(0x2F);
+ * i++;
+ * }
+ * return 0;
+ * }
+ * else if (!strcmp(addr, "DPCD")) {
+ * while (i < size) {
+ * array[i++] = dptx_dpcdrd(offset++);
+ * }
+ * return 0;
+ * }
+ * else {
+ * DRM_DEBUG_DRIVER(("%s second parameter error!!\n"));
+ * return 2;
+ * }
+ * }
+ * else {
+ * DRM_DEBUG_DRIVER(%s first parameter error!!\n",
+ __func__);
+ * return 1;
+ * }
+ *}
+ */
+
+
+static ssize_t it6505_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ /* reserved code for future debug using */
+#ifdef ENAUX_TRANSFER_DEBUG
+
+ struct it6505 *ctx = container_of(aux, struct it6505, aux);
+ u8 ctrl1 = msg->request;
+ u8 ctrl2 = SP_AUX_EN;
+ u8 *buffer = msg->buffer;
+ int err;
+
+ /* The DP AUX transmit and receive buffer has 16 bytes. */
+ if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
+ return -E2BIG;
+
+ /* Zero-sized messages specify address-only transactions. */
+ if (msg->size < 1)
+ ctrl2 |= SP_ADDR_ONLY;
+ else /* For non-zero-sized set the length field. */
+ ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
+
+ if ((msg->request & DP_AUX_I2C_READ) == 0) {
+ /* When WRITE | MOT write values to data buffer */
+ err = regmap_bulk_write(ctx->map[I2C_IDX_TX_P0],
+ SP_DP_BUF_DATA0_REG, buffer,
+ msg->size);
+ if (err)
+ return err;
+ }
+
+ /* Write address and request */
+ err = it6505_aux_address(ctx, msg->address);
+ if (err)
+ return err;
+
+ err = regmap_write(ctx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL1_REG,
+ ctrl1);
+ if (err)
+ return err;
+
+ /* Start transaction */
+ err = regmap_update_bits(ctx->map[I2C_IDX_TX_P0],
+ SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY |
+ SP_AUX_EN, ctrl2);
+ if (err)
+ return err;
+
+ err = it6505_aux_wait(ctx);
+ if (err)
+ return err;
+
+ msg->reply = DP_AUX_I2C_REPLY_ACK;
+
+ if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
+ /* Read values from data buffer */
+ err = regmap_bulk_read(ctx->map[I2C_IDX_TX_P0],
+ SP_DP_BUF_DATA0_REG, buffer,
+ msg->size);
+ if (err)
+ return err;
+ }
+
+ err = it6505_clear_bits(ctx->map[I2C_IDX_TX_P0],
+ SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY);
+ if (err)
+ return err;
+
+ return msg->size;
+
+#endif
+ return 0;
+}
+
+static int it6505_extcon_notifier(struct notifier_block *self,
+ unsigned long event, void *ptr)
+{
+ struct it6505_dp_port *port =
+ container_of(self, struct it6505_dp_port, event_nb);
+
+ schedule_work(&port->extcon_wq);
+ DRM_DEBUG_DRIVER("[%s]", __func__);
+ return NOTIFY_DONE;
+}
+
+static void it6505_extcon_work(struct work_struct *work)
+{
+ struct it6505_dp_port *port =
+ container_of(work, struct it6505_dp_port, extcon_wq);
+ struct it6505 *ctx = port->it6505_dp;
+ int state = extcon_get_state(port->extcon, EXTCON_DISP_DP);
+#ifdef ENPWRONOFF
+ unsigned int pwroffretry = 0;
+#endif
+
+ mutex_lock(&ctx->lock);
+ DRM_DEBUG_DRIVER("[%s] state:%d %s", __func__, state,
+ state ? "cable in": "cable out");
+ if (state > 0) {
+ DRM_DEBUG_DRIVER("[%s] state:%d",
+ __func__, state);
+ DRM_DEBUG_DRIVER("[%s] start to power on!", __func__);
+ it6505_poweron(ctx);
+ } else {
+ DRM_DEBUG_DRIVER("[%s] state:%d",
+ __func__, state);
+#ifdef ENPWRONOFF
+ DRM_DEBUG_DRIVER("[%s] start to power off!", __func__);
+ while (it6505_poweroff(ctx) &&
+ pwroffretry++ < PWROFFRETRYTIME) {
+ DRM_DEBUG_DRIVER("power off it6505 fail! %d times",
+ pwroffretry);
+ }
+ DRM_DEBUG_DRIVER("power off it6505 success!");
+#endif
+ }
+ mutex_unlock(&ctx->lock);
+}
+
+static int use_notifier_module(struct it6505 *ctx)
+{
+ struct it6505_dp_port *port = ctx->port;
+ int ret;
+
+ DRM_DEBUG_DRIVER("[%s]", __func__);
+ port->event_nb.notifier_call = it6505_extcon_notifier;
+ INIT_WORK(&port->extcon_wq, it6505_extcon_work);
+ ret = devm_extcon_register_notifier(&ctx->client->dev,
+ port->extcon, EXTCON_DISP_DP, &port->event_nb);
+ if (ret) {
+ DRM_DEBUG_DRIVER("failed to register notifier for DP");
+ return ret;
+ }
+ return 0;
+}
+
+static int it6505_bridge_attach(struct drm_bridge *bridge)
+{
+ struct it6505 *ctx = bridge_to_it6505(bridge);
+ struct cros_ec_device *cros_ec;
+ struct extcon_dev *extcon;
+ struct it6505_dp_port *port;
+ struct device *dev;
+ int err;
+
+ DRM_DEBUG_DRIVER(" This is %s~start!!\n", __func__);
+ dev = &ctx->client->dev;
+ if (!bridge->encoder) {
+ DRM_ERROR("Parent encoder object not found");
+ return -ENODEV;
+ }
+
+ /* Register aux channel */
+ ctx->aux.name = "DP-AUX";
+ ctx->aux.dev = &ctx->client->dev;
+ ctx->aux.transfer = it6505_aux_transfer;
+
+ err = drm_dp_aux_register(&ctx->aux);
+ if (err < 0) {
+ DRM_ERROR("Failed to register aux channel: %d\n", err);
+ return err;
+ }
+
+ err = drm_connector_init(bridge->dev, &ctx->connector,
+ &it6505_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort);
+ if (err) {
+ DRM_ERROR("Failed to initialize connector: %d\n", err);
+ return err;
+ }
+
+ drm_connector_helper_add(&ctx->connector,
+ &it6505_connector_helper_funcs);
+
+ err = drm_connector_register(&ctx->connector);
+ if (err) {
+ DRM_ERROR("Failed to register connector: %d\n", err);
+ return err;
+ }
+
+ ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ err = drm_connector_attach_encoder(&ctx->connector,
+ bridge->encoder);
+ if (err) {
+ DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
+ return err;
+ }
+
+ /* get extcon device from DTS */
+ extcon = extcon_get_edev_by_phandle(dev, 0);
+ if (PTR_ERR(extcon) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (IS_ERR(extcon)){
+ DRM_DEBUG_DRIVER("%s can not get extcon device!", __func__);
+ return -EINVAL;
+ } else
+ DRM_DEBUG_DRIVER("%s get extcon device!", __func__);
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+ port->extcon = extcon;
+ port->it6505_dp = ctx;
+ port->id = 0;
+ ctx->port = port;
+
+ err = use_notifier_module(ctx);
+ if (err < 0) {
+ DRM_DEBUG_DRIVER("%s fail to use notifier module!", __func__);
+ return err;
+ }
+ DRM_DEBUG_DRIVER("ctx->cros_ec = 0x%p\n", cros_ec);
+ DRM_DEBUG_DRIVER(" This is %s~end!!\n", __func__);
+ return 0;
+}
+
+static enum drm_mode_status
+it6505_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode)
+{
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return MODE_NO_INTERLACE;
+
+ /* Max 1200p at 5.4 Ghz, one lane */
+ if (mode->clock > 80000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static int it6505_send_video_infoframe(struct it6505 *it6505,
+ struct hdmi_avi_infoframe *frame)
+{
+ u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+ int err;
+
+ err = hdmi_avi_infoframe_pack(frame, buffer, sizeof(buffer));
+ if (err < 0) {
+ DRM_ERROR("Failed to pack AVI infoframe: %d\n", err);
+ return err;
+ }
+
+ err = dptxset(it6505, 0xe8, 1, 0);
+ if (err)
+ return err;
+
+ err = regmap_bulk_write(it6505->regmap, 0xe9, buffer, frame->length);
+ if (err)
+ return err;
+
+ err = dptxset(it6505, 0xe8, 1, 1);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void it6505_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct it6505 *ctx = bridge_to_it6505(bridge);
+ struct hdmi_avi_infoframe frame;
+ int err;
+
+ mutex_lock(&ctx->lock);
+
+ DRM_DEBUG_DRIVER("%s\n", __func__);
+
+ err = drm_hdmi_avi_infoframe_from_display_mode(&frame,
+ adjusted_mode, false);
+ if (err) {
+ DRM_ERROR("Failed to setup AVI infoframe: %d\n", err);
+ goto unlock;
+ }
+
+ err = it6505_send_video_infoframe(ctx, &frame);
+ if (err)
+ DRM_ERROR("Failed to send AVI infoframe: %d\n", err);
+
+unlock:
+ mutex_unlock(&ctx->lock);
+}
+
+void dptx_init(struct it6505 *it6505)
+{
+ dptxwr(it6505, 0x05, 0x3B);
+ usleep_range(1000, 2000);
+ dptxwr(it6505, 0x05, 0x1F);
+ usleep_range(1000, 1500);
+
+ DRM_DEBUG_DRIVER("this is %s end !!\n", __func__);
+}
+
+void iTE6505_INT_mask(struct it6505 *it6505)
+{
+#if ENHDCP
+ dptxwr(it6505, 0x09, 0x1F);
+#else
+ dptxwr(it6505, 0x09, 0x07);
+#endif
+
+#if ENAUD
+ dptxwr(it6505, 0x0A, 0x07);
+#else
+ dptxwr(it6505, 0x0A, 0x03);
+#endif
+ dptxwr(it6505, 0x0B, 0x90);
+}
+
+void dptx_set_aud_fmt(struct it6505 *it6505,
+ enum it6505_aud_sel audsel, unsigned int audch)
+{
+ unsigned int audsrc;
+ /* I2S MODE */
+ dptxwr(it6505, 0xB9, (it6505->audwordlength << 5)
+ | (it6505->i2s_data_seq << 4) | (it6505->i2s_ws_channel << 3)
+ | (it6505->i2s_data_delay << 2) | (it6505->i2s_justified << 1)
+ | it6505->i2s_input_fmt);
+ if (audsel == SPDIF) {
+ dptxwr(it6505, 0xBA, 0x00);
+ /* 0x30 = 128*FS */
+ dptxset(it6505, 0x11, 0xF0, 0x30);
+ } else {
+ dptxwr(it6505, 0xBA, 0xe4);
+ }
+
+ dptxwr(it6505, 0xBB, 0x00);
+ dptxwr(it6505, 0xBC, 0x00);
+ audsrc = 1;
+
+ if (audch > 2)
+ audsrc |= 2;
+
+ if (audch > 4)
+ audsrc |= 4;
+
+ if (audch == 8)
+ audsrc |= 8;
+
+ audsrc |= audsel << 4;
+
+ dptxwr(it6505, 0xB8, audsrc);
+}
+
+void dptx_set_aud_chsts(struct it6505 *it6505,
+ enum it6505_aud_type audtype, enum it6505_aud_fs audfs)
+{
+ /* Channel Status */
+ dptxwr(it6505, 0xBF, audtype << 1);
+ dptxwr(it6505, 0xC0, 0x00);
+ dptxwr(it6505, 0xC1, 0x00);
+ dptxwr(it6505, 0xC2, audfs);
+ switch (it6505->audwordlength) {
+ case AUD16BIT:
+ dptxwr(it6505, 0xC3, ((~audfs) << 4) + 0x02);
+ break;
+
+ case AUD18BIT:
+ dptxwr(it6505, 0xC3, ((~audfs) << 4) + 0x04);
+ break;
+
+ case AUD20BIT:
+ dptxwr(it6505, 0xC3, ((~audfs) << 4) + 0x03);
+ break;
+
+ case AUD24BIT:
+ dptxwr(it6505, 0xC3, ((~audfs) << 4) + 0x0B);
+ break;
+ }
+}
+
+
+void dptx_set_audio_infoframe(struct it6505 *it6505, unsigned int audch)
+{
+ dptxwr(it6505, 0xf7, audch - 1);
+
+ switch (audch) {
+ case 2:
+ dptxwr(it6505, 0xF9, 0x00);
+ break;
+ case 3:
+ dptxwr(it6505, 0xF9, 0x01);
+ break;
+ case 4:
+ dptxwr(it6505, 0xF9, 0x03);
+ break;
+ case 5:
+ dptxwr(it6505, 0xF9, 0x07);
+ break;
+ case 6:
+ dptxwr(it6505, 0xF9, 0x0B);
+ break;
+ case 7:
+ dptxwr(it6505, 0xF9, 0x0F);
+ break;
+ case 8:
+ dptxwr(it6505, 0xF9, 0x1F);
+ break;
+ default:
+ DRM_DEBUG_DRIVER("Error:Audio Channel Number Error !!!\n");
+ }
+ /* Enable Audio InfoFrame */
+ dptxset(it6505, 0xE8, 0x22, 0x22);
+}
+
+
+void iTE6505_SetAudio(struct it6505 *it6505, enum it6505_aud_sel audsel,
+ enum it6505_aud_type audtype, enum it6505_aud_fs audfs,
+ unsigned int audch)
+{
+ /* Audio Clock Domain Reset */
+ dptxset(it6505, 0x05, 0x02, 0x02);
+ /* Audio mute */
+ dptxset(it6505, 0xD3, 0x20, 0x20);
+ /* Release Audio Clock Domain Reset */
+ dptxset(it6505, 0x05, 0x02, 0x00);
+
+ dptx_set_aud_chsts(it6505, audtype, audfs);
+ dptx_set_audio_infoframe(it6505, audch);
+ dptx_set_aud_fmt(it6505, audsel, audch);
+ /* Enable Enhanced Audio TimeStmp Mode */
+ dptxset(it6505, 0xD4, 0x04, 0x04);
+ /* Disable Full Audio Packet */
+ dptxset(it6505, 0xBB, 0x10, 0x00);
+
+ dptxwr(it6505, 0xDE, 0x00);
+ dptxwr(it6505, 0xDF, 0x80);
+ dptxwr(it6505, 0xE0, 0x00);
+ dptxset(it6505, 0xD3, 0x20, 0x00);
+
+ /* Clear Video M Error Interrupt */
+ dptxset(it6505, 0x08, 0x08, 0x08);
+ /* Clear Audio FIFO OverFlow Interrupt */
+ dptxset(it6505, 0x07, 0x04, 0x04);
+}
+
+/***************************************************************************
+ * DPCD Read and EDID
+ ***************************************************************************/
+
+static unsigned int dptx_dpcdrd(struct it6505 *it6505,
+ unsigned long offset)
+{
+ unsigned int startadr0, startadr1, startadr2;
+
+ startadr0 = (unsigned int)((offset >> 0) & 0xFF);
+ startadr1 = (unsigned int)((offset >> 8) & 0xFF);
+ startadr2 = (unsigned int)((offset >> 16) & 0x0F);
+ /* Enable PC Aux Access */
+ dptxwr(it6505, 0x23, (0 << 6) + 0x02);
+ /* Start Address[7:0] */
+ dptxwr(it6505, 0x24, startadr0);
+ /* Start Address[15:8] */
+ dptxwr(it6505, 0x25, startadr1);
+ /* WriteNum[3:0]+StartAdr[19:16] */
+ dptxwr(it6505, 0x26, startadr2);
+ /* Aux Read Fire */
+ dptxwr(it6505, 0x2B, 0x00);
+ dptx_auxwait(it6505);
+ /* Disable PC Aux Access */
+ dptxwr(it6505, 0x23, (0 << 6) + 0x00);
+
+ dptxrd(it6505, 0x2C, &startadr0);
+
+ return startadr0;
+}
+
+static int dptx_dpcdwr(struct it6505 *it6505,
+ unsigned long offset, unsigned long datain)
+{
+ unsigned int startadr0, startadr1, startadr2;
+
+ startadr0 = (unsigned int)(offset >> 0) & 0xFF;
+ startadr1 = (unsigned int)(offset >> 8) & 0xFF;
+ startadr2 = (unsigned int)(offset >> 16) & 0x0F;
+ /* Enable PC Aux Access */
+ dptxwr(it6505, 0x23, (1 << 6) + 0x02);
+ /* Start Address[7:0] */
+ dptxwr(it6505, 0x24, startadr0);
+ /* Start Address[15:8] */
+ dptxwr(it6505, 0x25, startadr1);
+ /* WriteNum[3:0]+StartAdr[19:16] */
+ dptxwr(it6505, 0x26, startadr2);
+ /* WriteData Byte 1 */
+ dptxwr(it6505, 0x27, datain);
+ /* Aux Write Fire */
+ dptxwr(it6505, 0x2B, 0x05);
+ dptx_auxwait(it6505);
+ /* Aux Read Fire */
+ dptxwr(it6505, 0x2B, 0x00);
+ dptx_auxwait(it6505);
+ /* Disable PC Aux Access */
+ dptxwr(it6505, 0x23, (1 << 6) + 0x00);
+
+ dptxrd(it6505, 0x2C, &startadr0);
+
+ if (startadr0 != datain)
+ return -EINVAL;
+
+ return 0;
+}
+
+int iTE6505_GetSinkSupportHDCP(struct it6505 *it6505)
+{
+ unsigned int rddata;
+
+ dptxrd(it6505, 0x0D, &rddata);
+ if (!(rddata & BIT(1))) {
+ DRM_DEBUG_DRIVER("sys is unplug!! ...\n");
+ dptx_sys_chg(it6505, SYS_UNPLUG);
+ it6505->cp_ready = -1;
+ } else {
+ if (dptx_dpcdrd(it6505, 0x68028) & BIT(0)) {
+ DRM_DEBUG_DRIVER("Sink support HDCP!!\n");
+ it6505->cp_ready = 1;
+ DRM_DEBUG_DRIVER("Config ENHDCP, output with HDCP!!\n");
+ } else {
+ DRM_DEBUG_DRIVER("Sink not support HDCP !!\n");
+ it6505->cp_ready = 0;
+ DRM_DEBUG_DRIVER("Config ENHDCP, output no HDCP!\n");
+ }
+ }
+ return it6505->cp_ready;
+}
+
+static void iTE6505_GetDPCD(struct it6505 *it6505)
+{
+ unsigned int offset = 0;
+
+ DRM_DEBUG_DRIVER("\n ========== [DPCD] ===========\n");
+ for (offset = 0; offset < 0x10; offset++) {
+ it6505->dumpdpcd[offset] = dptx_dpcdrd(it6505, offset);
+ DRM_DEBUG_DRIVER("DPCD[0x%02x]=0x%02x ",
+ offset, it6505->dumpdpcd[offset]);
+ if (offset == 0x07)
+ DRM_DEBUG_DRIVER("\n");
+ }
+ DRM_DEBUG_DRIVER("\n =============================\n");
+}
+
+static void iTE6505_ParseDPCD(struct it6505 *it6505)
+{
+ it6505->dpcd_rev = it6505->dumpdpcd[0];
+ DRM_DEBUG_DRIVER(" =========== Start Parse DPCD! !===========\n");
+ DRM_DEBUG_DRIVER("#########DPCD Rev.: %d.%d###########\n",
+ it6505->dpcd_rev >> 4, it6505->dpcd_rev & 0x0F);
+
+ switch (it6505->dumpdpcd[1]) {
+ case 0x06:
+ DRM_DEBUG_DRIVER("Maximum Link Rate: 1.62Gbps per lane\n");
+ if (it6505->hbr) {
+ DRM_DEBUG_DRIVER("Not support HBR Mode");
+ DRM_DEBUG_DRIVER("will train LBR\n");
+ it6505->hbr = false;
+ } else
+ DRM_DEBUG_DRIVER("Training LBR\n");
+ break;
+
+ case 0x0A:
+ DRM_DEBUG_DRIVER("Maximum Link Rate: 2.7Gbps per lane\n");
+ if (!it6505->hbr) {
+ DRM_DEBUG_DRIVER("Support HBR Mode");
+ DRM_DEBUG_DRIVER("will train LBR\n");
+ it6505->hbr = false;
+ } else
+ DRM_DEBUG_DRIVER("Training HBR\n");
+ break;
+
+ case 0x14:
+ DRM_DEBUG_DRIVER("Maximum Link Rate: 2.7Gbps per lane\n");
+ break;
+
+ default:
+ DRM_DEBUG_DRIVER("Unknown Maximum Link Rate!!\n");
+ break;
+ }
+
+ switch (it6505->dumpdpcd[2] & 0x1F) {
+ case 1:
+ DRM_DEBUG_DRIVER("Maximum Lane Count : 1 lane\n");
+ if (it6505->lane > 1) {
+ DRM_DEBUG_DRIVER("Not support %d lane training\n",
+ it6505->lane);
+ DRM_DEBUG_DRIVER("Training 1 lane\n");
+ it6505->lane = 1;
+ } else
+ DRM_DEBUG_DRIVER("Training %d lane!!\n", it6505->lane);
+ break;
+ case 2:
+ DRM_DEBUG_DRIVER("Maximum Lane Count : 2 lanes\n");
+ if (it6505->lane > 2) {
+ DRM_DEBUG_DRIVER("Not support %d lane training\n",
+ it6505->lane);
+ DRM_DEBUG_DRIVER("Training 2 lane\n");
+ it6505->lane = 2;
+ } else
+ DRM_DEBUG_DRIVER("Training %d lane!!\n", it6505->lane);
+ break;
+ case 4:
+ DRM_DEBUG_DRIVER("Maximum Lane Count : 4 lanes\n");
+ if (it6505->lane > 4) {
+ DRM_DEBUG_DRIVER("Not support %d lane training\n",
+ it6505->lane);
+ DRM_DEBUG_DRIVER("Training 4 lane\n");
+ it6505->lane = 4;
+ } else
+ DRM_DEBUG_DRIVER("Training %d lane!!\n", it6505->lane);
+ break;
+ default:
+ DRM_DEBUG_DRIVER("Maximum Lane Count : Error !!!\n");
+ }
+
+ if (it6505->dpcd_rev == 0x11 && it6505->dumpdpcd[2] & BIT(7)) {
+ DRM_DEBUG_DRIVER("Support Enhanced Framing Mode\n");
+ } else {
+ DRM_DEBUG_DRIVER("Can not support Enhanced Framing Mode\n");
+ if (it6505->en_hframe) {
+ DRM_DEBUG_DRIVER("Can not support Enhanced Framing!\n");
+ it6505->en_hframe = 0;
+ }
+ }
+
+ if (it6505->dumpdpcd[3] & BIT(0)) {
+ DRM_DEBUG_DRIVER("Maximum Down-Spread: 0.5, support SSC!\n");
+ } else {
+ DRM_DEBUG_DRIVER("Maximum Down-Spread: 0, No support SSC!\n");
+ if (it6505->en_ssc) {
+ DRM_DEBUG_DRIVER("Can not support SSC!!\n");
+ it6505->en_ssc = 0;
+ }
+ }
+
+ if (it6505->dpcd_rev == 0x11 && it6505->dumpdpcd[3] & BIT(6))
+ DRM_DEBUG_DRIVER("Support No AUX Training\n");
+ else
+ DRM_DEBUG_DRIVER("Can not support No AUX Training\n");
+
+ if (dptx_dpcdrd(it6505, 0x68028) & BIT(0)) {
+ DRM_DEBUG_DRIVER("Sink support HDCP!\n");
+ it6505->cp_ready = true;
+#if ENHDCP
+ DRM_DEBUG_DRIVER("Config ENHDCP output with HDCP!\n");
+#else
+ DRM_DEBUG_DRIVER("Not config ENHDCP output no HDCP!\n");
+#endif
+ } else {
+ DRM_DEBUG_DRIVER("Sink not support HDCP !\n");
+ it6505->cp_ready = false;
+#if ENHDCP
+ DRM_DEBUG_DRIVER("Config ENHDCP output no HDCP!\n");
+#else
+ DRM_DEBUG_DRIVER("Not config ENHDCP output no HDCP!\n");
+#endif
+ }
+
+ if (dptx_dpcdrd(it6505, 0x68028) & BIT(1)) {
+ DRM_DEBUG_DRIVER("Downstream is repeater!!\n");
+ it6505->downstreamrepeater = true;
+ } else {
+ DRM_DEBUG_DRIVER("Downstream is receiver!!\n");
+ it6505->downstreamrepeater = false;
+ }
+
+ DRM_DEBUG_DRIVER(" ======== Parse DPCD END! ========\n");
+}
+
+void iTE6505_EnableHDCP(struct it6505 *it6505)
+{
+ int i;
+ u8 c;
+ unsigned long BKSV[5], bksv;
+
+ DRM_DEBUG_DRIVER("%s start!!", __func__);
+ /* Disable CP_Desired */
+ dptxset(it6505, 0x38, 0x0B, 0x00);
+ dptxset(it6505, 0x05, 0x10, 0x10);
+
+ usleep_range(1000, 1500);
+ c = dptx_dpcdrd(it6505, 0x68028);
+ DRM_DEBUG_DRIVER("DPCD[0x68028]:0x%x!!\n", c);
+ if (!c)
+ return;
+
+ dptxset(it6505, 0x05, 0x10, 0x00);
+ /* Disable CP_Desired */
+ dptxset(it6505, 0x38, 0x01, 0x00);
+ /* Use R0' 100ms waiting */
+ dptxset(it6505, 0x38, 0x08, 0x00);
+ /* clear the repeater List Chk Done and fail bit */
+ dptxset(it6505, 0x39, 0x30, 0x00);
+
+ for (i = 0; i < 5; i++)
+ BKSV[i] = dptx_dpcdrd(it6505, 0x68000 + i);
+
+ bksv = BKSV[0] + (BKSV[1] << 8) + (BKSV[2] << 16)
+ + (BKSV[3] << 24) + (BKSV[4] << 32);
+ DRM_DEBUG_DRIVER("Sink BKSV = 0x%lx", bksv);
+
+ /* Select An Generator */
+ dptxset(it6505, 0x3A, 0x01, 0x01);
+ /* Enable An Generator */
+ dptxset(it6505, 0x3A, 0x02, 0x02);
+ /* delay1ms(10);*/
+ usleep_range(10000, 15000);
+ /* Stop An Generator */
+ dptxset(it6505, 0x3A, 0x02, 0x00);
+
+ dptxset(it6505, 0x38, 0x01, 0x01);
+ dptxset(it6505, 0x39, 0x01, 0x01);
+
+ DRM_DEBUG_DRIVER("%s end !!\n", __func__);
+}
+
+void iTE6505_lanespeed_setup(struct it6505 *it6505)
+{
+ if (!it6505->hbr) {
+ dptxset(it6505, 0x16, 0x01, 1);
+ dptxset(it6505, 0x5C, 0x02, 0x00);
+ } else {
+ dptxset(it6505, 0x16, 0x01, 0);
+ dptxset(it6505, 0x5C, 0x02, 0x02);
+ }
+}
+
+void iTE6505_lane_swap(struct it6505 *it6505)
+{
+ int err;
+ union extcon_property_value property;
+
+ if (it6505->hpd_status == 0) {
+ err = extcon_get_property(it6505->port->extcon,
+ EXTCON_DISP_DP,
+ EXTCON_PROP_USB_TYPEC_POLARITY, &property);
+ if (err) {
+ DRM_DEBUG_DRIVER("%s get property fail!",
+ __func__);
+ }
+ it6505->laneswap = property.intval;
+ DRM_DEBUG_DRIVER("property.intval = 0x%d\n", property.intval);
+ }
+
+ dptxset(it6505, 0x16, 0x08, (it6505->laneswap) ? 8 : 0);
+ dptxset(it6505, 0x16, 0x06, (it6505->lane - 1) << 1);
+ DRM_DEBUG_DRIVER("it6505->laneswap = 0x%x\n", it6505->laneswap);
+
+ if (it6505->laneswap) {
+ switch (it6505->lane) {
+ case 1:
+ dptxset(it6505, 0x5C, 0xF1, 0x81);
+ break;
+ case 2:
+ dptxset(it6505, 0x5C, 0xF1, 0xC1);
+ break;
+ default:
+ dptxset(it6505, 0x5C, 0xF1, 0xF1);
+ break;
+ }
+ } else {
+ switch (it6505->lane) {
+ case 1:
+ dptxset(it6505, 0x5C, 0xF1, 0x11);
+ break;
+ case 2:
+ dptxset(it6505, 0x5C, 0xF1, 0x31);
+ break;
+ default:
+ dptxset(it6505, 0x5C, 0xF1, 0xF1);
+ break;
+ }
+ }
+}
+
+void iTE6505_lane_config(struct it6505 *it6505)
+{
+ iTE6505_lanespeed_setup(it6505);
+ iTE6505_lane_swap(it6505);
+}
+
+void dptx_chgbank(struct it6505 *it6505, unsigned int bank_id)
+{
+ dptxset(it6505, 0x0F, 0x01, bank_id & BIT(0));
+}
+
+void iTE6505_set_ssc(struct it6505 *it6505)
+{
+ dptxset(it6505, 0x16, 0x10, it6505->en_ssc << 4);
+ if (it6505->en_ssc) {
+ dptx_chgbank(it6505, 1);
+ dptxwr(it6505, 0x88, 0x9e);
+ dptxwr(it6505, 0x89, 0x1c);
+ dptxwr(it6505, 0x8A, 0x42);
+ dptx_chgbank(it6505, 0);
+ dptxwr(it6505, 0x58, 0x07);
+ dptxwr(it6505, 0x59, 0x29);
+ dptxwr(it6505, 0x5A, 0x03);
+ DRM_DEBUG_DRIVER("Enable 27M 4463 PPM SSC\n");
+ /* Stamp Interrupt Step */
+ dptxset(it6505, 0xD4, 0x30, 0x10);
+ dptx_dpcdwr(it6505, 0x107, 0x10);
+ } else {
+ dptx_dpcdwr(it6505, 0x107, 0x00);
+ dptxset(it6505, 0xD4, 0x30, 0x00);
+ }
+}
+
+void PCLK_phase(struct it6505 *it6505)
+{
+ dptxset(it6505, 0x10, 0x03, PCLK_DELAY);
+ dptxset(it6505, 0x12, 0x10, PCLK_INV << 4);
+}
+
+void AFE_driving_setting(struct it6505 *it6505)
+{
+ dptxset(it6505, 0x0F, 0x01, 0x01);
+ dptxwr(it6505, 0x7E, 0x93);
+ dptxwr(it6505, 0x7F, 0x2A);
+ dptxwr(it6505, 0x81, 0x85);
+ dptxset(it6505, 0x0F, 0x01, 0x00);
+}
+
+void dptx_output(struct it6505 *it6505, unsigned int HBR, unsigned int lane,
+ unsigned int laneswap, unsigned int en_ssc,
+ unsigned int EnhFraming)
+{
+ dptxwr(it6505, 0x05, 0x13);
+ /* change bank 0 */
+ dptxset(it6505, 0x0F, 0x01, 0x00);
+ /* RegTxFFRst set */
+ dptxset(it6505, 0x61, 0x02, 0x02);
+ /* RegTxFFRst clear */
+ dptxset(it6505, 0x61, 0x02, 0x00);
+ dptxwr(it6505, 0x64, 0x10);
+ dptxwr(it6505, 0x65, 0x80);
+ dptxwr(it6505, 0x66, 0x10);
+ dptxwr(it6505, 0x67, 0x4F);
+ dptxwr(it6505, 0x68, 0x09);
+ dptxwr(it6505, 0x69, 0xBA);
+ dptxwr(it6505, 0x6A, 0x3B);
+ dptxwr(it6505, 0x6B, 0x4B);
+ dptxwr(it6505, 0x6C, 0x3E);
+ dptxwr(it6505, 0x6D, 0x4F);
+ dptxwr(it6505, 0x6E, 0x09);
+ dptxwr(it6505, 0x6F, 0x56);
+ dptxwr(it6505, 0x70, 0x0E);
+ dptxwr(it6505, 0x71, 0x00);
+ dptxwr(it6505, 0x72, 0x00);
+ dptxwr(it6505, 0x73, 0x4F);
+ dptxwr(it6505, 0x74, 0x09);
+ dptxwr(it6505, 0x75, 0x00);
+ dptxwr(it6505, 0x76, 0x00);
+ dptxwr(it6505, 0x77, 0xE7);
+ dptxwr(it6505, 0x78, 0x10);
+ dptxwr(it6505, 0xE8, 0x00);
+ dptxset(it6505, 0xCE, 0x70, 0x60);
+ dptxset(it6505, 0xD0, 0xC0, 0x80);
+ dptxwr(it6505, 0xCA, 0x4D);
+ dptxwr(it6505, 0xC9, 0xF5);
+ dptxwr(it6505, 0x5C, 0x02);
+
+ dptx_dpcdwr(it6505, 0x600, 0x01);
+ dptxset(it6505, 0x59, 0x01, 0x01);
+ dptxset(it6505, 0x5A, 0x05, 0x01);
+ dptxwr(it6505, 0x12, 0x01);
+ dptxwr(it6505, 0xCB, 0x17);
+ dptxwr(it6505, 0x11, 0x09);
+ dptxwr(it6505, 0x20, 0x28);
+ dptxset(it6505, 0x23, 0x30, 00);
+ dptxset(it6505, 0x3A, 0x04, 0x04);
+ dptxset(it6505, 0x15, 0x01, 0x01);
+ dptxwr(it6505, 0x0C, 0x08);
+
+ dptxset(it6505, 0x5F, 0x20, 0x00);
+ iTE6505_lane_config(it6505);
+
+ iTE6505_set_ssc(it6505);
+
+ if (EnhFraming)
+ dptxwr(it6505, 0xD3, 0x33);
+ else
+ dptxwr(it6505, 0xD3, 0x32);
+
+ dptxset(it6505, 0x15, 0x02, 0x02);
+ dptxset(it6505, 0x15, 0x02, 0x00);
+ dptxset(it6505, 0x05, 0x03, 0x02);
+ dptxset(it6505, 0x05, 0x03, 0x00);
+
+ /* reg60[2] = InDDR */
+ dptxwr(it6505, 0x60, 0x44);
+ /* M444B24 foramt */
+ dptxwr(it6505, 0x62, 1);
+ /* select RGB Bypass CSC */
+ dptxwr(it6505, 0x63, 0);
+
+ PCLK_phase(it6505);
+ dptxset(it6505, 0x61, 0x01, 0x01);
+ dptxwr(it6505, 0x06, 0xFF);
+ dptxwr(it6505, 0x07, 0xFF);
+ dptxwr(it6505, 0x08, 0xFF);
+
+ dptxset(it6505, 0xd3, 0x30, 0x00);
+ dptxset(it6505, 0xd4, 0x41, 0x41);
+ dptxset(it6505, 0xe8, 0x11, 0x11);
+
+ AFE_driving_setting(it6505);
+ dptxwr(it6505, 0x17, 0x04);
+ dptxwr(it6505, 0x17, 0x01);
+ DRM_DEBUG_DRIVER(" ======= end main flow! !========\n");
+}
+
+
+void dptx_sys_fsm(struct it6505 *it6505)
+{
+ unsigned int value, temp1, temp2, temp3;
+ unsigned int count, dpcd1[0x09], dpcd2[0x18];
+ unsigned int temp, i, dpcdstart = 0x100;
+ int ret, reg0D, reg9F;
+#if ENHDCP
+ unsigned int Ar0_low, Ar0_high, Br0_low, Br0_high;
+#endif
+
+ DRM_DEBUG_DRIVER("%s start state: %d\n", __func__,
+ it6505->status);
+
+ dptxrd(it6505, 0x0D, &reg0D);
+
+ if (it6505->status != SYS_UNPLUG && !(reg0D & BIT(1)))
+ dptx_sys_chg(it6505, SYS_UNPLUG);
+
+ switch (it6505->status) {
+ case SYS_PWRDN:
+ break;
+ case SYS_UNPLUG:
+ DRM_DEBUG_DRIVER("sys_state is in SYS_UNPLUG!!\n");
+ break;
+
+ case SYS_HPD:
+ DRM_DEBUG_DRIVER("Is in SYS_HPD!!\n");
+ dptxrd(it6505, 0x9f, &reg9F);
+ DRM_DEBUG_DRIVER("Aux channel status reg9F=0x%02x\n", reg9F);
+ /* GETDPCD */
+ iTE6505_GetDPCD(it6505);
+ iTE6505_ParseDPCD(it6505);
+
+ /*
+ * training fail TRAINFAILCNT times,
+ * then change to HPD to restart
+ */
+ it6505->cntfsm = TRAINFAILCNT;
+ DRM_DEBUG_DRIVER("will Train %s %d lanes\n",
+ it6505->hbr ? "HBR" : "LBR", it6505->lane);
+ dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+ break;
+
+ case SYS_AUTOTRAIN:
+ DRM_DEBUG_DRIVER("%s in SYS_AUTOTRAIN!\n", __func__);
+ dptx_output(it6505,
+ it6505->hbr,
+ it6505->lane,
+ it6505->laneswap,
+ it6505->en_ssc,
+ it6505->en_hframe);
+
+ /*
+ * waiting for training down flag
+ * because we don't know
+ * how long this step will be completed
+ * so use step 1ms to wait
+ */
+ for (count = 0; count < FLAGTRAINDOWN; count++) {
+ msleep(1);
+ dptxrd(it6505, 0x0E, &temp3);
+ if (temp3 & BIT(4))
+ break;
+ }
+
+ dptx_sys_chg(it6505, SYS_WAIT);
+ break;
+
+ case SYS_WAIT:
+ DRM_DEBUG_DRIVER("%s in SYS_WAIT!!\n", __func__);
+ ret = dptxrd(it6505, 0x0E, &value);
+ i = dpcdstart;
+ temp = ARRAY_SIZE(dpcd1);
+ DRM_DEBUG_DRIVER("SYS_WAIT state parse %d dpcd offset!\n",
+ temp + ARRAY_SIZE(dpcd2));
+
+ for (i = 0; i < temp; i++) {
+ dpcd1[i] = dptx_dpcdrd(it6505, dpcdstart + i);
+ DRM_DEBUG_DRIVER("dpcd[0x%02x]:0x%02x",
+ dpcdstart + i, dpcd1[i]);
+ }
+ dpcdstart = 0x200;
+ i = dpcdstart;
+ temp = ARRAY_SIZE(dpcd2);
+
+ for (i = 0; i < temp; i++) {
+ dpcd2[i] = dptx_dpcdrd(it6505, dpcdstart + i);
+ DRM_DEBUG_DRIVER("dpcd[0x%02x]:0x%02x",
+ dpcdstart + i, dpcd2[i]);
+ }
+
+ if (value & BIT(4)) {
+ DRM_DEBUG_DRIVER("Auto Link Training Success ...\n");
+ DRM_DEBUG_DRIVER("Link State : 0x%X\n", value & 0x1F);
+#if ENAUD
+ iTE6505_SetAudio(it6505,
+ it6505->aud_sel, it6505->aud_type,
+ it6505->aud_fs, it6505->aud_ch);
+#endif
+ DRM_DEBUG_DRIVER("it6505->VidStable_Done = %02x\n",
+ it6505->vidstable_done);
+#if ENHDCP
+ DRM_DEBUG_DRIVER("Config ENHDCP\n");
+ if (it6505->cp_ready) {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%02x\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Support HDCP\n");
+ dptx_sys_chg(it6505, SYS_ReHDCP);
+ } else {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%02x\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Not support HDCP\n");
+ dptx_sys_chg(it6505, SYS_NOROP);
+ }
+#else
+ DRM_DEBUG_DRIVER("Not config ENHDCP\n");
+ dptx_sys_chg(it6505, SYS_NOROP);
+#endif
+ } else {
+ dptxrd(it6505, 0x0D, &temp2);
+ dptxrd(it6505, 0x0E, &temp1);
+ DRM_DEBUG_DRIVER("Auto Link Training fail step %d!\n",
+ it6505->cntfsm);
+ DRM_DEBUG_DRIVER("reg0E:0x%x, reg0D:0x%x!\n",
+ temp1, temp2);
+ if (it6505->cntfsm > 0) {
+ it6505->cntfsm--;
+ dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+ } else {
+ DRM_DEBUG_DRIVER("Auto Training Fail");
+ DRM_DEBUG_DRIVER("0x%x times\n",
+ TRAINFAILCNT);
+ DRM_DEBUG_DRIVER("Sys change to SYS_HPD!\n");
+ dptx_dpcdwr(it6505, 0x102, 0x00);
+ dptx_sys_chg(it6505, SYS_HPD);
+ }
+ }
+ break;
+
+#if ENHDCP
+ case SYS_ReHDCP:
+ msleep(600);
+ dptxrd(it6505, 0x3B, &Ar0_low);
+ dptxrd(it6505, 0x3C, &Ar0_high);
+ dptxrd(it6505, 0x45, &Br0_low);
+ dptxrd(it6505, 0x46, &Br0_high);
+ DRM_DEBUG_DRIVER("Before EnableHDCP\n");
+ DRM_DEBUG_DRIVER("Ar0_low:%x, Ar0_high:%x\n",
+ Ar0_low, Ar0_high);
+ DRM_DEBUG_DRIVER("Br0_low:%x, Br0_high:%x\n",
+ Br0_low, Br0_high);
+ iTE6505_EnableHDCP(it6505);
+ msleep(200);
+ DRM_DEBUG_DRIVER("SYS_ReHDCP end !!\n");
+ break;
+
+#endif
+ case SYS_NOROP:
+ break;
+
+ default:
+ DRM_DEBUG_DRIVER("sys_state change to unknown_state!!\n");
+ break;
+ }
+
+ DRM_DEBUG_DRIVER("%s end!!\n", __func__);
+
+}
+
+static int it6505_poweron(struct it6505 *it6505)
+{
+ struct it6505_platform_data *pdata = &it6505->pdata;
+ int err = 0;
+
+ DRM_DEBUG_DRIVER("%s\n", __func__);
+
+ if (it6505->powered) {
+ DRM_DEBUG_DRIVER("[%s] had already been power on!", __func__);
+ return 0;
+ }
+
+ DRM_DEBUG_DRIVER("it6505 start to power on\n");
+
+ err = regulator_enable(pdata->pwr18);
+ DRM_DEBUG_DRIVER("%s to enable pwr18 regulator",
+ err ? "Failed" : "Successed");
+ /* time interval between IVDD and OVDD at least be 1ms */
+ msleep(5);
+ err = regulator_enable(pdata->ovdd);
+ DRM_DEBUG_DRIVER("%s to enable ovdd regulator",
+ err ? "Failed" : "Successed");
+ /* time interval between OVDD and SYSRSTN at least be 10ms */
+ msleep(15);
+ usleep_range(10000, 20000);
+ gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
+ usleep_range(10000, 20000);
+
+ dptx_init(it6505);
+ if (err == 0)
+ it6505->powered = true;
+ return err;
+}
+
+#ifdef ENPWRONOFF
+static int it6505_poweroff(struct it6505 *it6505)
+{
+ struct it6505_platform_data *pdata = &it6505->pdata;
+ int err = 0;
+
+ DRM_DEBUG_DRIVER("[%s]\n", __func__);
+ if (!(it6505->powered)) {
+ DRM_DEBUG_DRIVER("[%s] power had been already off", __func__);
+ return 0;
+ }
+ gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+ err = regulator_disable(pdata->pwr18);
+ DRM_DEBUG_DRIVER("%s to disable pwr18 regulator",
+ err ? "Failed" : "Successed");
+
+ err = regulator_disable(pdata->ovdd);
+ DRM_DEBUG_DRIVER("%s to disable ovdd regulator",
+ err ? "Failed" : "Successed");
+ if (err == 0) {
+ kfree(it6505->edid);
+ it6505->edid = NULL;
+ it6505->powered = false;
+ }
+ return err;
+}
+#endif
+
+static irqreturn_t it6505_hpd_threaded_handler(int irq, void *data)
+{
+ struct it6505 *ctx = data;
+
+ DRM_DEBUG_DRIVER("start %s", __func__);
+
+ mutex_lock(&ctx->lock);
+
+ DRM_DEBUG_DRIVER("[%s]it6505->hpd_status = 0x%02x\n",
+ __func__, ctx->hpd_status);
+ DRM_DEBUG_DRIVER("[%s]GPIO hpd status = 0x%02x\n",
+ __func__,
+ gpiod_get_value(ctx->pdata.gpiod_hpd));
+
+ if ((ctx->it6505_drv_hold == 0)
+ && (ctx->hpd_status
+ != gpiod_get_value(ctx->pdata.gpiod_hpd))) {
+ drm_helper_hpd_irq_event(ctx->connector.dev);
+ DRM_DEBUG_DRIVER("it6505->hpd_status = 0x%02x",
+ ctx->hpd_status);
+ DRM_DEBUG_DRIVER("GPIO hpd status = 0x%02x",
+ gpiod_get_value(ctx->pdata.gpiod_hpd));
+ DRM_DEBUG_DRIVER("after drm_helper_hpd_irq_event!\n");
+ ctx->hpd_status = gpiod_get_value(ctx->pdata.gpiod_hpd);
+ }
+
+ mutex_unlock(&ctx->lock);
+
+ DRM_DEBUG_DRIVER("end %s", __func__);
+
+ return IRQ_HANDLED;
+}
+
+void SHA1_digest(u8 *sha1_input, u8 size, u8 *output_av)
+{
+ struct shash_desc *desc;
+ struct sha1_state *sha1_st;
+ struct crypto_shash *tfm = crypto_alloc_shash("sha1", 0, 0);
+
+ DRM_DEBUG_DRIVER("start %s",__func__);
+ DRM_DEBUG_DRIVER("sha_input size:%d", size);
+ desc = kzalloc(sizeof(*desc)
+ + crypto_shash_descsize(tfm), GFP_KERNEL);
+ desc->tfm = tfm;
+ DRM_DEBUG_DRIVER("crypto_alloc_shash %s!",
+ IS_ERR(desc->tfm) ? "fail" : "success");
+ DRM_DEBUG_DRIVER("crypto_shash_init %s!",
+ crypto_shash_init(desc) ? "fail" : "success");
+ DRM_DEBUG_DRIVER("crypto_shash_update %s!",
+ crypto_shash_update(desc, sha1_input, size)
+ ? "fail" : "success");
+ sha1_st = (struct sha1_state *)(desc->__ctx);
+#ifdef SHA_DEBUG
+ DRM_DEBUG_DRIVER("sha1_state.state[0]:0x%lx",
+ sha1_st->state[0]);
+ DRM_DEBUG_DRIVER("sha1_state.state[1]:0x%lx",
+ sha1_st->state[1]);
+ DRM_DEBUG_DRIVER("sha1_state.state[2]:0x%lx",
+ sha1_st->state[2]);
+ DRM_DEBUG_DRIVER("sha1_state.state[3]:0x%lx",
+ sha1_st->state[3]);
+ DRM_DEBUG_DRIVER("sha1_state.state[4]:0x%lx",
+ sha1_st->state[4]);
+#endif
+ memcpy(output_av, sha1_st->state, sizeof(u8)*20);
+ crypto_free_shash(tfm);
+ tfm = NULL;
+ kfree(desc);
+ desc = NULL;
+ sha1_st = NULL;
+ DRM_DEBUG_DRIVER("end %s", __func__);
+}
+
+void it6505_makeup_sha1_input(struct it6505 *it6505)
+{
+ int msgcnt = 0, i;
+ unsigned long ksvlist;
+
+ dptxset(it6505, 0x3A, 0x20, 0x20);
+ DRM_DEBUG_DRIVER("read am0: ");
+ for (i = 0; i < 8; i++) {
+ dptxrd(it6505,
+ 0x4C + i,
+ (unsigned int *)(it6505->am0 + i));
+ DRM_DEBUG_DRIVER("0x%02X , ", it6505->am0[i]);
+ }
+ DRM_DEBUG_DRIVER("\n\n");
+ dptxset(it6505, 0x3A, 0x20, 0x00);
+
+ it6505->binfo[0] = dptx_dpcdrd(it6505,
+ 0x6802A);
+ it6505->binfo[1] = dptx_dpcdrd(it6505,
+ 0x6802B);
+ DRM_DEBUG_DRIVER("read Binfo!!");
+ DRM_DEBUG_DRIVER("Attached devices:%02x\n",
+ it6505->binfo[0] & 0x7F);
+
+ DRM_DEBUG_DRIVER("%s 127 devices are attached\n",
+ ((it6505->binfo[0] & BIT(7)) >> 7) ?
+ "over" : "under");
+ DRM_DEBUG_DRIVER("depth, attached levels:%02x\n",
+ it6505->binfo[1] & 0x07);
+ DRM_DEBUG_DRIVER("%s seven levels cascaded\n",
+ ((it6505->binfo[1] & BIT(3)) >> 3) ?
+ "more than" : "less");
+
+ for (i = 0; i < (it6505->binfo[0] & 0x7F); i++) {
+ it6505->shainput[msgcnt]
+ = it6505->ksvlist[msgcnt]
+ = dptx_dpcdrd(it6505,
+ 0x6802C + (i % 3) * 5);
+ msgcnt++;
+ it6505->shainput[msgcnt]
+ = it6505->ksvlist[msgcnt]
+ = dptx_dpcdrd(it6505,
+ 0x6802D + (i % 3) * 5);
+ msgcnt++;
+ it6505->shainput[msgcnt]
+ = it6505->ksvlist[msgcnt]
+ = dptx_dpcdrd(it6505,
+ 0x6802E + (i % 3) * 5);
+ msgcnt++;
+ it6505->shainput[msgcnt]
+ = it6505->ksvlist[msgcnt]
+ = dptx_dpcdrd(it6505,
+ 0x6802F + (i % 3) * 5);
+ msgcnt++;
+ it6505->shainput[msgcnt]
+ = it6505->ksvlist[msgcnt]
+ = dptx_dpcdrd(it6505,
+ 0x68030 + (i % 3) * 5);
+ msgcnt++;
+ ksvlist
+ = ((unsigned long)
+ (it6505->ksvlist[i * 5 + 4]) << 32)
+ + (it6505->ksvlist[i * 5 + 3] << 24)
+ + (it6505->ksvlist[i * 5 + 2] << 16)
+ + (it6505->ksvlist[i * 5 + 1] << 8)
+ + it6505->ksvlist[i * 5];
+
+ DRM_DEBUG_DRIVER("KSV List %d device:0x%lx\n",
+ i, ksvlist);
+ }
+ DRM_DEBUG_DRIVER("\n");
+ it6505->shainput[msgcnt++] = it6505->binfo[0];
+ it6505->shainput[msgcnt++] = it6505->binfo[1];
+ for (i = 0; i < 8; i++) {
+ it6505->shainput[msgcnt++] =
+ it6505->am0[i];
+ }
+ DRM_DEBUG_DRIVER("SHA Message Count = %d\n", msgcnt);
+ it6505->shainput[msgcnt] = 0x80;
+
+ for (i = msgcnt+1; i < 62; i++)
+ it6505->shainput[i] = 0x00;
+
+ it6505->shainput[62] = ((8 * msgcnt) >> 8) & 0xFF;
+ it6505->shainput[63] = (8 * msgcnt) & 0xFF;
+}
+
+void it6505_check_sha1_result(struct it6505 *it6505)
+{
+ unsigned int i, value;
+
+ DRM_DEBUG_DRIVER("SHA calculate complete!\n");
+ for (i = 0; i < 5; i++) {
+ value
+ = (it6505->av[i][3] << 24)
+ + (it6505->av[i][2] << 16)
+ + (it6505->av[i][1] << 8)
+ + it6505->av[i][0];
+ DRM_DEBUG_DRIVER("av %d :0x%08x\n",
+ i, value);
+ }
+ DRM_DEBUG_DRIVER("\n");
+
+ it6505->passsha = 1;
+ for (i = 0; i < 5; i++) {
+ it6505->bv[i][0]
+ = dptx_dpcdrd(it6505, 0x68014 + i * 4);
+ it6505->bv[i][1]
+ = dptx_dpcdrd(it6505, 0x68015 + i * 4);
+ it6505->bv[i][2]
+ = dptx_dpcdrd(it6505, 0x68016 + i * 4);
+ it6505->bv[i][3]
+ = dptx_dpcdrd(it6505, 0x68017 + i * 4);
+ value
+ = (it6505->bv[i][3] << 24)
+ + (it6505->bv[i][2] << 16)
+ + (it6505->bv[i][1] << 8)
+ + it6505->bv[i][0];
+ DRM_DEBUG_DRIVER("bv %d :0x%08x\n",
+ i, value);
+ if ((it6505->bv[i][0]
+ != it6505->av[i][0]) ||
+ (it6505->bv[i][1]
+ != it6505->av[i][1]) ||
+ (it6505->bv[i][2]
+ != it6505->av[i][2]) ||
+ (it6505->bv[i][3]
+ != it6505->av[i][3])) {
+ it6505->passsha = 0;
+ }
+ }
+ if (it6505->passsha) {
+ DRM_DEBUG_DRIVER("SHA check result pass!\n");
+ DRM_DEBUG_DRIVER("trigger reg0x39[4] = 1\n");
+ dptxset(it6505, 0x39, 0x10, 0x10);
+ } else {
+ DRM_DEBUG_DRIVER("SHA check result fail\n");
+ DRM_DEBUG_DRIVER("trigger reg0x39[5] = 1\n");
+ dptxset(it6505, 0x39, 0x20, 0x20);
+ }
+}
+
+void HPD_IRQ(struct it6505 *it6505)
+{
+ unsigned int dpcd200, dpcd201, dpcd202, dpcd203;
+ unsigned int dpcd204, dpcd205, auxbusycnt, AuxBusy, value, reg55;
+ int ret;
+#ifdef SHA_DEBUG
+ int i;
+#endif
+
+ dpcd200 = dptx_dpcdrd(it6505, 0x200);
+ dpcd201 = dptx_dpcdrd(it6505, 0x201);
+ dpcd202 = dptx_dpcdrd(it6505, 0x202);
+ dpcd203 = dptx_dpcdrd(it6505, 0x203);
+ dpcd204 = dptx_dpcdrd(it6505, 0x204);
+ dpcd205 = dptx_dpcdrd(it6505, 0x205);
+
+ DRM_DEBUG_DRIVER("dpcd200 = 0x%x\n", dpcd200);
+ DRM_DEBUG_DRIVER("dpcd201 = 0x%x\n", dpcd201);
+ DRM_DEBUG_DRIVER("dpcd202 = 0x%x\n", dpcd202);
+ DRM_DEBUG_DRIVER("dpcd203 = 0x%x\n", dpcd203);
+ DRM_DEBUG_DRIVER("dpcd204 = 0x%x\n", dpcd204);
+ DRM_DEBUG_DRIVER("dpcd205 = 0x%x\n", dpcd205);
+
+ if (dpcd201 & BIT(2)) {
+ ret = dptxrd(it6505, 0x38, &value);
+ it6505->bstatus = dptx_dpcdrd(it6505, 0x68029);
+ dptxrd(it6505, 0x55, &reg55);
+ DRM_DEBUG_DRIVER("reg0x55 = 0x%02x, reg0x68029 = 0x%02x\n",
+ reg55, it6505->bstatus);
+ if (value & BIT(0)) {
+
+ if (it6505->cp_done) {
+ DRM_DEBUG_DRIVER("Received CP_IRQ");
+ DRM_DEBUG_DRIVER(" cp_done = '1'");
+ DRM_DEBUG_DRIVER("Current bstatus = 0x%x\n",
+ it6505->bstatus);
+ } else {
+ DRM_DEBUG_DRIVER("Received CP_IRQ\n");
+ DRM_DEBUG_DRIVER("cp_done = '0'\n");
+ }
+
+ if (!it6505->cp_done || it6505->bstatus & BIT(2)) {
+ DRM_DEBUG_DRIVER("Trigger CP_IRQ");
+ DRM_DEBUG_DRIVER(" to HDCP Engine\n");
+
+ dptxset(it6505, 0x39, 0x02, 0x02);
+
+ auxbusycnt = 0;
+ do {
+ usleep_range(1000, 1500);
+
+ auxbusycnt++;
+ ret = dptxrd(it6505, 0x2B, &value);
+ AuxBusy = (value & BIT(5)) >> 5;
+ } while (AuxBusy == 1 && auxbusycnt < 20);
+
+
+ if (AuxBusy) {
+ DRM_DEBUG_DRIVER("AUX Busy Period!");
+ } else {
+ msleep(1000);
+ dptxrd(it6505, 0x55, &it6505->bstatus);
+ DRM_DEBUG_DRIVER("Link Integrity Fail");
+ DRM_DEBUG_DRIVER(" = %d\n",
+ (it6505->bstatus & BIT(2)) >> 2);
+ DRM_DEBUG_DRIVER("R0' Available = %d\n",
+ (it6505->bstatus & BIT(1)) >> 1);
+ DRM_DEBUG_DRIVER("KSV List Ready=%d\n",
+ (it6505->bstatus & BIT(0)));
+ }
+ }
+ }
+ DRM_DEBUG_DRIVER("Receive CP_IRQ!\n");
+ it6505->bstatus = dptx_dpcdrd(it6505, 0x68029);
+ dptxrd(it6505, 0x55, &reg55);
+ DRM_DEBUG_DRIVER("Cause of the interrupt!");
+ DRM_DEBUG_DRIVER("reg0x68029 = 0x%02x, reg0x55 = 0x%02x\n",
+ it6505->bstatus, reg55);
+
+ if (it6505->bstatus & BIT(0)) {
+ DRM_DEBUG_DRIVER("HDCP KSV list ready!! ...\n");
+ it6505_makeup_sha1_input(it6505);
+ SHA1_digest(it6505->shainput,
+ sizeof(it6505->shainput), (u8 *)it6505->av);
+
+ /* for SHA debug */
+#ifdef SHA_DEBUG
+ DRM_DEBUG_DRIVER("SHA_input:\n");
+ for (i = 0; i < 64; i++) {
+ if (!(i % 16))
+ DRM_DEBUG_DRIVER("\n");
+ DRM_DEBUG_DRIVER("0x%02x", it6505->shainput[i]);
+ }
+#endif
+ it6505_check_sha1_result(it6505);
+ }
+ }
+
+ if ((dpcd204 & BIT(7)) == 0x80) {
+ if ((it6505->lane == 1 && (dpcd202 & BIT(2)) != 0x04) ||
+ (it6505->lane == 2 && (dpcd202 & 0x44) != 0x44) ||
+ (it6505->lane == 4 && ((dpcd202 & 0x44) != 0x44 ||
+ (dpcd203 & 0x44) != 0x44)) ||
+ (it6505->lane == 1 && (dpcd203 & BIT(6)) != 0x40) ||
+ (it6505->lane == 2 && (dpcd203 & 0x44) != 0x44) ||
+ (it6505->lane == 4 && ((dpcd203 & 0x44) != 0x44 ||
+ (dpcd202 & 0x44) != 0x44)) ||
+ (dpcd204 & BIT(0)) != 0x01) {
+
+ DRM_DEBUG_DRIVER("Link Re-Training\n");
+ dptxset(it6505, 0xD3, 0x30, 0x30);
+ dptxset(it6505, 0xE8, 0x33, 0x00);
+ msleep(500);
+ dptx_sys_chg(it6505, SYS_HPD);
+#if ENHDCP
+ DRM_DEBUG_DRIVER("INT_MODE:Config ENHDCP\n");
+ if (it6505->cp_ready) {
+ DRM_DEBUG_DRIVER("INT_MODE:Sink cp_ready:%d\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Support HDCP\n");
+ while (it6505->status != SYS_ReHDCP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status
+ == SYS_UNPLUG)
+ break;
+ }
+ dptx_sys_fsm(it6505);
+ if (it6505->downstreamrepeater) {
+ DRM_DEBUG_DRIVER("This is repeater!\n");
+ HPD_IRQ(it6505);
+ }
+ } else {
+ DRM_DEBUG_DRIVER("INT_MODE:Sink cp_ready:%d\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Not support HDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status
+ == SYS_UNPLUG)
+ break;
+ }
+ }
+#else
+ DRM_DEBUG_DRIVER("INT_MODE:Unconfig ENHDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status
+ == SYS_UNPLUG)
+ break;
+ }
+#endif
+ }
+ }
+}
+
+void it6505_check_reg06(struct it6505 *it6505, unsigned int reg06)
+{
+ unsigned int rddata, err;
+ union extcon_property_value property;
+
+ if (reg06 & BIT(0)) {
+ /* hpd pin status change */
+ DRM_DEBUG_DRIVER("HPD Change Interrupt\n");
+ dptxrd(it6505, 0x0D, &rddata);
+ if (rddata & BIT(1)) {
+ err = extcon_get_property(it6505->port->extcon,
+ EXTCON_DISP_DP,
+ EXTCON_PROP_USB_TYPEC_POLARITY, &property);
+ if (err) {
+ DRM_DEBUG_DRIVER("%s get property fail!",
+ __func__);
+ }
+
+ it6505->laneswap = property.intval;
+ DRM_DEBUG_DRIVER("laneswap:%d", it6505->laneswap);
+ dptx_sys_chg(it6505, SYS_HPD);
+ dptx_sys_fsm(it6505);
+#if ENHDCP
+ DRM_DEBUG_DRIVER("Config ENHDCP\n");
+ if (it6505->cp_ready) {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%d\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Support HDCP\n");
+ while (it6505->status != SYS_ReHDCP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status
+ == SYS_UNPLUG)
+ break;
+ }
+ dptx_sys_fsm(it6505);
+ if (it6505->downstreamrepeater) {
+ DRM_DEBUG_DRIVER("Is repeater");
+ HPD_IRQ(it6505);
+ }
+ } else {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%d\n",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Not support HDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status
+ == SYS_UNPLUG)
+ break;
+ }
+ }
+#else
+ DRM_DEBUG_DRIVER("Not config ENHDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status == SYS_UNPLUG)
+ break;
+ }
+#endif
+ } else {
+ dptx_sys_chg(it6505, SYS_UNPLUG);
+ }
+ }
+
+ if (reg06 & BIT(1)) {
+ DRM_DEBUG_DRIVER("HPD IRQ Interrupt\n");
+ HPD_IRQ(it6505);
+ }
+
+ if (reg06 & BIT(2)) {
+ dptxrd(it6505, 0x0D, &rddata);
+
+ if ((rddata & BIT(2)) >> 2) {
+ DRM_DEBUG_DRIVER("Video Stable On Interrupt\n");
+ it6505->vidstable_done = 1;
+ DRM_DEBUG_DRIVER("Set vidstable_done = 0x%x\n",
+ it6505->vidstable_done);
+ } else {
+ DRM_DEBUG_DRIVER("Video Stable Off Interrupt");
+ it6505->vidstable_done = 0;
+ DRM_DEBUG_DRIVER("Set vidstable_done = 0x%x\n",
+ it6505->vidstable_done);
+ }
+ }
+
+#if ENHDCP
+ if (reg06 & BIT(3)) {
+ DRM_DEBUG_DRIVER("HDCP encryption Fail Interrupt\n");
+ DRM_DEBUG_DRIVER("HDCP retry! ...\n");
+ it6505->cp_done = 0;
+ DRM_DEBUG_DRIVER("Set it6505->cp_done = 0x%x ...\n",
+ it6505->cp_done);
+ dptx_sys_fsm(it6505);
+ }
+
+ if (reg06 & BIT(4)) {
+ DRM_DEBUG_DRIVER("HDCP encryption Done Interrupt\n");
+ it6505->cp_done = 1;
+ DRM_DEBUG_DRIVER("Set it6505->cp_done = 0x%x ...\n",
+ it6505->cp_done);
+ dptx_sys_chg(it6505, SYS_NOROP);
+ }
+#endif
+}
+
+void it6505_check_reg07(struct it6505 *it6505, unsigned int reg07)
+{
+ if (reg07 & BIT(0))
+ DRM_DEBUG_DRIVER("AUX PC Request Fail Interrupt\n");
+
+ if (reg07 & BIT(1)) {
+ unsigned int Ar0_low, Ar0_high, Br0_low, Br0_high;
+
+ DRM_DEBUG_DRIVER("HDCP event Interrupt\n");
+ it6505->bstatus = dptx_dpcdrd(it6505, 0x68029);
+ dptxrd(it6505, 0x3B, &Ar0_low);
+ dptxrd(it6505, 0x3C, &Ar0_high);
+ dptxrd(it6505, 0x45, &Br0_low);
+ dptxrd(it6505, 0x46, &Br0_high);
+ /*
+ * Read Bstatus to determine what happened
+ */
+ DRM_DEBUG_DRIVER("Bstatus reg0x68029:%02x!\n",
+ it6505->bstatus);
+ if (!(it6505->bstatus & BIT(0))) {
+ DRM_DEBUG_DRIVER("R0' read back by TX!\n");
+ DRM_DEBUG_DRIVER("HDCP part I complete!");
+ DRM_DEBUG_DRIVER("Ar0_low:%02x",
+ Ar0_low);
+ DRM_DEBUG_DRIVER("Ar0_high:%02x\n",
+ Ar0_high);
+ DRM_DEBUG_DRIVER("Br0_low:%02x",
+ Br0_low);
+ DRM_DEBUG_DRIVER("Br0_high:%02x\n",
+ Br0_high);
+ }
+ }
+#if ENAUD
+ if (reg07 & BIT(2)) {
+ DRM_DEBUG_DRIVER("Audio FIFO OverFlow Interrupt\n");
+ dptxset(it6505, 0xD3, 0x20, 0x20);
+ dptxset(it6505, 0xE8, 0x22, 0x00);
+
+ dptxset(it6505, 0xB8, 0x80, 0x80);
+ dptxset(it6505, 0xB8, 0x80, 0x00);
+ iTE6505_SetAudio(it6505,
+ it6505->aud_sel,
+ it6505->aud_type,
+ it6505->aud_fs,
+ it6505->aud_ch);
+ }
+#endif
+}
+
+void it6505_check_reg08(struct it6505 *it6505, unsigned int reg08)
+{
+ if (reg08 & BIT(4)) {
+ DRM_DEBUG_DRIVER("Link Training Fail Interrupt\n");
+ /* restart training */
+ dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+#if ENHDCP
+ DRM_DEBUG_DRIVER("Config ENHDCP ...\n");
+ if (it6505->cp_ready) {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%d",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Support HDCP\n");
+ while (it6505->status != SYS_ReHDCP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status == SYS_UNPLUG)
+ break;
+ }
+ dptx_sys_fsm(it6505);
+ if (it6505->downstreamrepeater) {
+ DRM_DEBUG_DRIVER("This is repeater!\n");
+ HPD_IRQ(it6505);
+ }
+ } else {
+ DRM_DEBUG_DRIVER("Sink cp_ready:%d",
+ it6505->cp_ready);
+ DRM_DEBUG_DRIVER("Not support HDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status == SYS_UNPLUG)
+ break;
+ }
+ }
+#else
+ DRM_DEBUG_DRIVER("Not config ENHDCP\n");
+ while (it6505->status != SYS_NOROP) {
+ dptx_sys_fsm(it6505);
+ if (it6505->status == SYS_UNPLUG)
+ break;
+ }
+#endif
+ }
+
+ if (reg08 & BIT(7)) {
+ DRM_DEBUG_DRIVER("IO Latch FIFO OverFlow Interrupt\n");
+ dptxset(it6505, 0x61, 0x02, 0x02);
+ dptxset(it6505, 0x61, 0x02, 0x00);
+ }
+}
+
+void it6505_dptx_irq(struct it6505 *it6505)
+{
+ unsigned int reg06, reg07, reg08, reg0d;
+
+ dptxrd(it6505, 0x06, &reg06);
+ dptxrd(it6505, 0x07, &reg07);
+ dptxrd(it6505, 0x08, &reg08);
+ dptxrd(it6505, 0x0D, &reg0d);
+
+ dptxwr(it6505, 0x06, reg06);
+ dptxwr(it6505, 0x07, reg07);
+ dptxwr(it6505, 0x08, reg08);
+
+ DRM_DEBUG_DRIVER("[%s] reg06 = 0x%x\n", __func__, reg06);
+ DRM_DEBUG_DRIVER("reg07 = 0x%x\n", reg07);
+ DRM_DEBUG_DRIVER("reg08 = 0x%x\n", reg08);
+ DRM_DEBUG_DRIVER("reg0d = 0x%x\n", reg0d);
+
+ if (reg06 != 0)
+ it6505_check_reg06(it6505, reg06);
+
+ if (reg07 != 0)
+ it6505_check_reg07(it6505, reg07);
+
+ if (reg08 != 0)
+ it6505_check_reg08(it6505, reg08);
+}
+
+
+static void it6505_bridge_enable(struct drm_bridge *bridge)
+{
+ struct it6505 *ctx = bridge_to_it6505(bridge);
+
+ DRM_DEBUG_DRIVER("start %s\n", __func__);
+
+ it6505_initfsm(ctx);
+ iTE6505_INT_mask(ctx);
+ dptx_sys_chg(ctx, SYS_HPD);
+
+ DRM_DEBUG_DRIVER("%s end\n", __func__);
+}
+
+static void it6505_bridge_disable(struct drm_bridge *bridge)
+{
+ DRM_DEBUG_DRIVER("start %s\n", __func__);
+ DRM_DEBUG_DRIVER("end %s\n", __func__);
+}
+
+static const struct drm_bridge_funcs it6505_bridge_funcs = {
+ .attach = it6505_bridge_attach,
+ .mode_valid = it6505_bridge_mode_valid,
+ .disable = it6505_bridge_disable,
+ .mode_set = it6505_bridge_mode_set,
+ .enable = it6505_bridge_enable,
+};
+
+static irqreturn_t it6505_intp_threaded_handler(int unused, void *data)
+{
+ struct it6505 *ctx = data;
+
+ DRM_DEBUG_DRIVER("[%s] start\n", __func__);
+
+ if (ctx->it6505_drv_hold == 0 && ctx->powered) {
+ mutex_lock(&ctx->lock);
+
+ it6505_dptx_irq(ctx);
+
+ mutex_unlock(&ctx->lock);
+ }
+
+ DRM_DEBUG_DRIVER("[%s] end\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static int it6505_init_pdata(struct it6505 *it6505)
+{
+ struct it6505_platform_data *pdata = &it6505->pdata;
+ struct device *dev = &it6505->client->dev;
+
+ /* 1.0V digital core power regulator */
+ pdata->pwr18 = devm_regulator_get(dev, "pwr18");
+ if (IS_ERR(pdata->pwr18)) {
+ DRM_ERROR("pwr18 regulator not found\n");
+ return PTR_ERR(pdata->pwr18);
+ }
+
+ pdata->ovdd = devm_regulator_get(dev, "ovdd");
+ if (IS_ERR(pdata->ovdd)) {
+ DRM_ERROR("ovdd regulator not found\n");
+ return PTR_ERR(pdata->ovdd);
+ }
+
+ /* GPIO for HPD */
+ pdata->gpiod_hpd = devm_gpiod_get(dev, "hpd", GPIOD_IN);
+ if (IS_ERR(pdata->gpiod_hpd))
+ return PTR_ERR(pdata->gpiod_hpd);
+
+ /* GPIO for chip reset */
+ pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+
+ return PTR_ERR_OR_ZERO(pdata->gpiod_reset);
+}
+
+static int it6505_open(struct inode *inode,
+ struct file *file)
+{
+ struct it6505 *ctx = container_of(inode->i_cdev, struct it6505, cdev);
+
+ DRM_DEBUG_DRIVER("[%s]: successful", __func__);
+ if (!ctx)
+ DRM_DEBUG_DRIVER("[%s]:get it6505 struct fail!", __func__);
+ file->private_data = ctx;
+ return 0;
+}
+
+static int it6505_release(struct inode *inode,
+ struct file *file)
+{
+ struct it6505 *ctx = file->private_data;
+
+ DRM_DEBUG_DRIVER("[%s]: successful", __func__);
+ put_device(&ctx->class_dev);
+ return 0;
+}
+
+static ssize_t it6505_read(struct file *file,
+ char *buf, size_t count, loff_t *ptr)
+{
+ DRM_DEBUG_DRIVER("[%s]: successful", __func__);
+
+ DRM_DEBUG_DRIVER("it6505_drv_hold:%d",
+ ((struct it6505 *)(file->private_data))->it6505_drv_hold);
+ return count;
+}
+
+static ssize_t it6505_write(struct file *file,
+ const char *buff, size_t count, loff_t *ptr)
+{
+ unsigned int num;
+
+ DRM_DEBUG_DRIVER("[%s]:count=%d",__func__,count);
+ kstrtoint(buff, 10, &num);
+ ((struct it6505 *)(file->private_data))->it6505_drv_hold = num;
+ DRM_DEBUG_DRIVER("num:%d it6505_drv_hold:%d", num,
+ ((struct it6505 *)(file->private_data))->it6505_drv_hold);
+ DRM_DEBUG_DRIVER("[%s]: successful", __func__);
+ DRM_DEBUG_DRIVER("set it6505_drv_hold:%d",
+ ((struct it6505 *)(file->private_data))->it6505_drv_hold);
+ return count;
+}
+
+static struct class it6505_class_file = {
+ .owner = THIS_MODULE,
+ .name = IT6505_CLASS_NAME,
+};
+
+static struct file_operations it6505_fops = {
+ .owner = THIS_MODULE,
+ .read = it6505_read,
+ .write = it6505_write,
+ .open = it6505_open,
+ .release = it6505_release
+};
+
+static void it6505_release_device(struct device *dev)
+{
+ struct it6505 *ctx = container_of(dev, struct it6505, class_dev);
+
+ kfree(ctx);
+}
+
+static int it6505_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct it6505 *ctx;
+ struct it6505_platform_data *pdata;
+ int err = 0;
+
+ ctx = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL);
+ DRM_DEBUG_DRIVER("%s function~start!!\n", __func__);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_init(&ctx->lock);
+
+ pdata = &ctx->pdata;
+
+ ctx->bridge.of_node = client->dev.of_node;
+ ctx->client = client;
+ i2c_set_clientdata(client, ctx);
+
+ err = it6505_init_pdata(ctx);
+ if (err) {
+ DRM_ERROR("Failed to initialize pdata: %d\n", err);
+ goto exit;
+ }
+
+ ctx->regmap = devm_regmap_init_i2c(client,
+ &it6505_bridge_regmap_config);
+ if (IS_ERR(ctx->regmap)) {
+ DRM_ERROR("regmap i2c init failed\n");
+ return PTR_ERR(ctx->regmap);
+ }
+
+ pdata->hpd_irq = gpiod_to_irq(pdata->gpiod_hpd);
+ DRM_DEBUG_DRIVER("get HPD IRQ: %d\n", pdata->hpd_irq);
+ if (pdata->hpd_irq < 0) {
+ DRM_ERROR("Failed to get HPD IRQ: %d\n", pdata->hpd_irq);
+ return -ENODEV;
+ }
+
+ pdata->intp_irq = client->irq;
+ DRM_DEBUG_DRIVER("get IT6505: %d\n", pdata->intp_irq);
+ if (!pdata->intp_irq) {
+ DRM_ERROR("Failed to get CABLE_DET and INTP IRQ\n");
+ return -ENODEV;
+ }
+
+ err = devm_request_threaded_irq(&client->dev, pdata->hpd_irq, NULL,
+ it6505_hpd_threaded_handler,
+ IRQF_TRIGGER_RISING
+ | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "it6505-hpd", ctx);
+ if (err) {
+ DRM_ERROR("Failed to request CABLE_DET threaded IRQ: %d\n",
+ err);
+ goto exit;
+ }
+
+ err = devm_request_threaded_irq(&client->dev, pdata->intp_irq, NULL,
+ it6505_intp_threaded_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "it6505-intp", ctx);
+ if (err) {
+ DRM_ERROR("Failed to request INTP threaded IRQ: %d\n", err);
+ goto exit;
+ }
+
+ ctx->powered = 0;
+ ctx->hpd_status = 1;
+ DRM_DEBUG_DRIVER("Set it6505->hpd_status=0x%02x\n",
+ ctx->hpd_status);
+ ctx->it6505_drv_hold = 0;
+#ifdef TEST_MODE
+ err = it6505_poweron(ctx);
+ if (err) {
+ DRM_DEBUG_DRIVER("power on fail!");
+ goto exit;
+ }
+ DRM_DEBUG_DRIVER("power on success!");
+ ctx->it6505_drv_hold = 1;
+#endif
+
+ ctx->bridge.funcs = &it6505_bridge_funcs;
+
+ drm_bridge_add(&ctx->bridge);
+ device_initialize(&ctx->class_dev);
+ ctx->class_dev.parent = &client->dev;
+ ctx->class_dev.release = it6505_release_device;
+ cdev_init(&ctx->cdev, &it6505_fops);
+ err = dev_set_name(&ctx->class_dev, "%s", IT6505_DEVICE_NAME);
+ DRM_DEBUG_DRIVER("[%s] dev_set_name:%s",
+ __func__, err ? "failed" : "success");
+ if (err) {
+ DRM_DEBUG_DRIVER("dev_set_name failed => %d", err);
+ goto failed;
+ }
+ /*
+ * Add the class device
+ * Link to the character device for creating the /dev entry
+ * in devtmpfs.
+ */
+ ctx->class_dev.devt = MKDEV(it6505_major_num, 0);
+ ctx->class_dev.class = &it6505_class_file;
+
+ /* We can now add the sysfs class, we know which parameter to show */
+ err = cdev_device_add(&ctx->cdev, &ctx->class_dev);
+ if (err) {
+ DRM_DEBUG_DRIVER("cdev_device_add failed => %d",
+ err);
+ goto failed;
+ }
+ DRM_DEBUG_DRIVER("[%s] probe~end~Suss\n", __func__);
+ return 0;
+
+exit:
+ return err;
+failed:
+ put_device(&ctx->class_dev);
+ return err;
+}
+
+static int it6505_remove(struct i2c_client *client)
+{
+ struct it6505 *ctx = i2c_get_clientdata(client);
+
+ DRM_DEBUG_DRIVER("start %s\n", __func__);
+ drm_bridge_remove(&ctx->bridge);
+ kfree(ctx->edid);
+ ctx->edid = NULL;
+ DRM_DEBUG_DRIVER("end %s\n", __func__);
+ return 0;
+}
+
+static int __init it6505_init()
+{
+ int err;
+ dev_t dev = 0;
+
+ DRM_DEBUG_DRIVER("start %s", __func__);
+ /* Register the device class */
+ err = class_register(&it6505_class_file);
+ err = alloc_chrdev_region(&dev, 0, IT6505_MAX_DEV,
+ IT6505_DEVICE_NAME);
+ it6505_major_num = MAJOR(dev);
+ if (err < 0) {
+ DRM_DEBUG_DRIVER("alloc_chrdev_region() fail!");
+ goto failed_chrdevreg;
+ }
+
+ DRM_DEBUG_DRIVER("end %s", __func__);
+ return 0;
+
+failed_chrdevreg:
+ class_unregister(&it6505_class_file);
+ return err;
+}
+
+static void __exit it6505_exit()
+{
+ DRM_DEBUG_DRIVER("start %s", __func__);
+ unregister_chrdev(it6505_major_num, IT6505_DEVICE_NAME);
+ class_unregister(&it6505_class_file);
+ DRM_DEBUG_DRIVER("end %s", __func__);
+}
+
+static const struct i2c_device_id it6505_id[] = {
+ { "it6505", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, it6505_id);
+
+static const struct of_device_id it6505_of_match[] = {
+ { .compatible = "ite,it6505"},
+ { }
+};
+
+struct i2c_driver it6505_i2c_driver = {
+ .driver = {
+ .name = "it6505_dptx",
+ .owner = THIS_MODULE,
+ .of_match_table = it6505_of_match,
+ },
+ .probe = it6505_i2c_probe,
+ .remove = it6505_remove,
+ .id_table = it6505_id,
+};
+
+module_i2c_driver(it6505_i2c_driver);
+module_init(it6505_init);
+module_exit(it6505_exit);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_DESCRIPTION("IT6505 DisplayPort Transmitter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index c33f95e08e1b8..d54ebe8f26527 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -101,13 +101,23 @@ EXPORT_SYMBOL(drm_panel_remove);
*/
int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
{
+ int ret = 0;
+
if (panel->connector)
return -EBUSY;
panel->connector = connector;
panel->drm = connector->dev;
- return 0;
+ if (panel->funcs->attach) {
+ ret = panel->funcs->attach(panel);
+ if (ret < 0) {
+ panel->connector = NULL;
+ panel->drm = NULL;
+ }
+ }
+
+ return ret;
}
EXPORT_SYMBOL(drm_panel_attach);
@@ -125,6 +135,9 @@ EXPORT_SYMBOL(drm_panel_attach);
*/
int drm_panel_detach(struct drm_panel *panel)
{
+ if (panel->funcs->detach)
+ panel->funcs->detach(panel);
+
panel->connector = NULL;
panel->drm = NULL;
@@ -169,6 +182,29 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
+
+int of_drm_get_panel_orientation(const struct device_node *np, int *orientation)
+{
+ int rotation;
+
+ if (of_property_read_u32(np, "rotation", &rotation)) {
+ *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+ return 0;
+ }
+
+ if (rotation == 0)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
+ else if (rotation == 90)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
+ else if (rotation == 180)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
+ else if (rotation == 270)
+ *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
+ else
+ return -EINVAL;
+
+ return 0;
+}
#endif
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index ebadcfed3a0a9..b33fe170732b8 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -32,6 +32,8 @@
#define DISP_REG_OVL_ROI_BGCLR 0x0028
#define DISP_REG_OVL_SRC_CON 0x002c
#define DISP_REG_OVL_CON(n) (0x0030 + 0x20 * (n))
+#define DISP_REG_OVL_V_FLIP_EN BIT(9)
+#define DISP_REG_OVL_H_FLIP_EN BIT(10)
#define DISP_REG_OVL_SRC_SIZE(n) (0x0038 + 0x20 * (n))
#define DISP_REG_OVL_OFFSET(n) (0x003c + 0x20 * (n))
#define DISP_REG_OVL_PITCH(n) (0x0044 + 0x20 * (n))
@@ -228,14 +230,26 @@ static void mtk_ovl_layer_config(struct mtk_ddp_comp *comp, unsigned int idx,
unsigned int fmt = pending->format;
unsigned int offset = (pending->y << 16) | pending->x;
unsigned int src_size = (pending->height << 16) | pending->width;
+ unsigned int bpp = drm_format_plane_cpp(fmt, 0);
unsigned int con;
+ DRM_DEBUG_DRIVER(
+ "layer %d enable %d fmt 0x%x (%X %X %X %X) pitch %X addr 0x%X bpp %d\n",
+ idx, pending->enable, fmt,
+ pending->x, pending->y, pending->width, pending->height, pitch,
+ pending->addr, bpp);
+
if (!pending->enable)
mtk_ovl_layer_off(comp, idx);
con = ovl_fmt_convert(ovl, fmt);
if (idx != 0)
con |= OVL_CON_AEN | OVL_CON_ALPHA;
+ if (state->base.rotation & DRM_MODE_ROTATE_180) {
+ con |= (DISP_REG_OVL_V_FLIP_EN | DISP_REG_OVL_H_FLIP_EN);
+ addr += pitch * (pending->height - 1) +
+ pending->width * bpp - 1;
+ }
writel_relaxed(con, comp->regs + DISP_REG_OVL_CON(idx));
writel_relaxed(pitch, comp->regs + DISP_REG_OVL_PITCH(idx));
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 62a9d47df9487..e03815fa9e646 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -17,10 +17,12 @@
#include <drm/drm_of.h>
#include <linux/kernel.h>
#include <linux/component.h>
-#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/clk.h>
@@ -79,6 +81,9 @@ struct mtk_dpi {
enum mtk_dpi_out_yc_map yc_map;
enum mtk_dpi_out_bit_num bit_num;
enum mtk_dpi_out_channel_swap channel_swap;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_dpi;
int refcount;
};
@@ -117,6 +122,8 @@ struct mtk_dpi_conf {
unsigned int (*cal_factor)(int clock);
u32 reg_h_fre_con;
bool edge_sel_en;
+ bool dual_edge;
+ bool dpi_pin_ctrl;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -353,6 +360,15 @@ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi)
mtk_dpi_mask(dpi, dpi->conf->reg_h_fre_con, 0, EDGE_SEL_EN);
}
+static void mtk_dpi_config_dual_edge(struct mtk_dpi *dpi)
+{
+ if (dpi->conf->dual_edge) {
+ mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE,
+ DDR_EN | DDR_4PHASE);
+ mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, EDGE_SEL, EDGE_SEL);
+ }
+}
+
static void mtk_dpi_config_color_format(struct mtk_dpi *dpi,
enum mtk_dpi_out_color_format format)
{
@@ -384,6 +400,9 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi)
if (--dpi->refcount != 0)
return;
+ if (dpi->conf->dpi_pin_ctrl)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_default);
+
mtk_dpi_disable(dpi);
clk_disable_unprepare(dpi->pixel_clk);
clk_disable_unprepare(dpi->engine_clk);
@@ -408,6 +427,9 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi)
goto err_pixel;
}
+ if (dpi->conf->dpi_pin_ctrl)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
+
mtk_dpi_enable(dpi);
return 0;
@@ -444,7 +466,8 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
pll_rate = clk_get_rate(dpi->tvd_clk);
vm.pixelclock = pll_rate / factor;
- clk_set_rate(dpi->pixel_clk, vm.pixelclock);
+ clk_set_rate(dpi->pixel_clk,
+ vm.pixelclock * (dpi->conf->dual_edge ? 2 : 1));
vm.pixelclock = clk_get_rate(dpi->pixel_clk);
dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
@@ -509,6 +532,7 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_color_format(dpi, dpi->color_format);
mtk_dpi_config_2n_h_fre(dpi);
mtk_dpi_config_disable_edge(dpi);
+ mtk_dpi_config_dual_edge(dpi);
mtk_dpi_sw_reset(dpi, false);
return 0;
@@ -671,6 +695,16 @@ static unsigned int mt2701_calculate_factor(int clock)
return 2;
}
+static unsigned int mt8183_calculate_factor(int clock)
+{
+ if (clock <= 27000)
+ return 8;
+ else if (clock <= 167000)
+ return 4;
+ else
+ return 2;
+}
+
static const struct mtk_dpi_conf mt8173_conf = {
.cal_factor = mt8173_calculate_factor,
.reg_h_fre_con = 0xe0,
@@ -682,6 +716,13 @@ static const struct mtk_dpi_conf mt2701_conf = {
.edge_sel_en = true,
};
+static const struct mtk_dpi_conf mt8183_conf = {
+ .cal_factor = mt8183_calculate_factor,
+ .reg_h_fre_con = 0xe0,
+ .dual_edge = true,
+ .dpi_pin_ctrl = true,
+};
+
static int mtk_dpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -697,6 +738,27 @@ static int mtk_dpi_probe(struct platform_device *pdev)
dpi->dev = dev;
dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
+ if (dpi->conf->dpi_pin_ctrl) {
+ dpi->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(dpi->pinctrl)) {
+ dev_err(&pdev->dev, "Cannot find pinctrl!\n");
+ return PTR_ERR(dpi->pinctrl);
+ }
+
+ dpi->pins_default = pinctrl_lookup_state(dpi->pinctrl,
+ "default");
+ if (IS_ERR(dpi->pins_default)) {
+ dev_err(&pdev->dev, "Cannot find pinctrl default!\n");
+ return PTR_ERR(dpi->pins_default);
+ }
+
+ dpi->pins_dpi = pinctrl_lookup_state(dpi->pinctrl, "dpimode");
+ if (IS_ERR(dpi->pins_dpi)) {
+ dev_err(&pdev->dev, "Cannot find pinctrl dpimode!\n");
+ return PTR_ERR(dpi->pins_dpi);
+ }
+ }
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dpi->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(dpi->regs)) {
@@ -777,6 +839,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8173-dpi",
.data = &mt8173_conf,
},
+ { .compatible = "mediatek,mt8183-dpi",
+ .data = &mt8183_conf,
+ },
{ },
};
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 903883dd194c2..0c15443bde7d5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -470,14 +470,41 @@ static void mtk_drm_crtc_atomic_begin(struct drm_crtc *crtc,
}
}
+static struct drm_connector *mtk_drm_get_connector(struct drm_crtc *crtc)
+{
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc != crtc)
+ continue;
+
+ drm_connector_list_iter_begin(crtc->dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (connector->encoder == encoder)
+ return connector;
+ }
+ }
+
+ return NULL;
+}
+
static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_drm_private *priv = crtc->dev->dev_private;
+ struct drm_connector *connector;
unsigned int pending_planes = 0;
+ unsigned int rotation = DRM_MODE_ROTATE_0;
int i;
+ connector = mtk_drm_get_connector(crtc);
+ if (connector && connector->display_info.panel_orientation ==
+ DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP)
+ rotation = DRM_MODE_ROTATE_180;
+
if (mtk_crtc->event)
mtk_crtc->pending_needs_vblank = true;
for (i = 0; i < mtk_crtc->layer_nr; i++) {
@@ -488,6 +515,7 @@ static void mtk_drm_crtc_atomic_flush(struct drm_crtc *crtc,
if (plane_state->pending.dirty) {
plane_state->pending.config = true;
plane_state->pending.dirty = false;
+ plane_state->base.rotation = rotation;
pending_planes |= BIT(i);
}
}
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 5d8227c90371c..661566b3535ac 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -877,10 +877,25 @@ static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
DRM_ERROR("Failed to attach panel to drm\n");
goto err_connector_cleanup;
}
+
+ /*
+ * We don't need to put in accurate pixel heigh/width since we
+ * don't care about any of the panel quirks which are just x86
+ * BIOS hacks. We only care about the device tree settings which
+ * should be filled in for the connector in drm_panel_attach.
+ */
+ ret = drm_connector_init_panel_orientation_property(&dsi->conn,
+ 0, 0);
+ if (ret) {
+ DRM_ERROR("Failed to init panel orientation\n");
+ goto err_panel_detach;
+ }
}
return 0;
+err_panel_detach:
+ drm_panel_detach(dsi->panel);
err_connector_cleanup:
drm_connector_cleanup(&dsi->conn);
return ret;
diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
index ff5a89e38fd74..b854455c9d889 100644
--- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c
+++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c
@@ -61,6 +61,7 @@ struct panel_info {
struct gpio_desc *enable_gpio;
struct gpio_desc *pp33_gpio;
struct gpio_desc *pp18_gpio;
+ int orientation;
bool prepared;
bool enabled;
@@ -146,6 +147,18 @@ static int boe_panel_unprepare(struct drm_panel *panel)
return err;
}
+static int boe_panel_attach(struct drm_panel *panel)
+{
+ struct panel_info *pinfo = to_panel_info(panel);
+
+ panel->connector->display_info.width_mm = pinfo->desc->width_mm;
+ panel->connector->display_info.height_mm = pinfo->desc->height_mm;
+ panel->connector->display_info.bpc = pinfo->desc->bpc;
+ panel->connector->display_info.panel_orientation = pinfo->orientation;
+
+ return 0;
+}
+
static int boe_panel_prepare(struct drm_panel *panel)
{
struct panel_info *pinfo = to_panel_info(panel);
@@ -226,16 +239,13 @@ static int boe_panel_get_modes(struct drm_panel *panel)
drm_mode_probed_add(panel->connector, mode);
- panel->connector->display_info.width_mm = pinfo->desc->width_mm;
- panel->connector->display_info.height_mm = pinfo->desc->height_mm;
- panel->connector->display_info.bpc = pinfo->desc->bpc;
-
return 1;
}
static const struct drm_panel_funcs panel_funcs = {
.disable = boe_panel_disable,
.unprepare = boe_panel_unprepare,
+ .attach = boe_panel_attach,
.prepare = boe_panel_prepare,
.enable = boe_panel_enable,
.get_modes = boe_panel_get_modes,
@@ -587,6 +597,285 @@ static const struct panel_desc boe_himax8279d8p_panel_desc = {
.off_cmds = default_off_cmds,
};
+/* 8 inch Positive scanning*/
+static const struct panel_cmd boe_tv080wumng0_on_cmds[] = {
+ _INIT_CMD(0x22, 0x10),
+ _INIT_CMD(0x00, 0xB0, 0x05),
+ _INIT_CMD(0x00, 0xB3, 0x52),
+ _INIT_CMD(0x00, 0xB0, 0x01),
+ _INIT_CMD(0x00, 0xC8, 0x00),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCC, 0x26),
+ _INIT_CMD(0x00, 0xCD, 0x26),
+ _INIT_CMD(0x00, 0xDC, 0x00),
+ _INIT_CMD(0x00, 0xDD, 0x00),
+ _INIT_CMD(0x00, 0xE0, 0x26),
+ _INIT_CMD(0x00, 0xE1, 0x26),
+ _INIT_CMD(0x00, 0xB0, 0x03),
+ _INIT_CMD(0x00, 0xC3, 0x2A),
+ _INIT_CMD(0x00, 0xE7, 0x2A),
+ _INIT_CMD(0x00, 0xC5, 0x2A),
+ _INIT_CMD(0x00, 0xDE, 0x2A),
+ _INIT_CMD(0x00, 0xB0, 0x00),
+ _INIT_CMD(0x00, 0xB6, 0x03),
+ _INIT_CMD(0x00, 0xBA, 0x8B),
+ _INIT_CMD(0x00, 0xBF, 0x15),
+ _INIT_CMD(0x00, 0xC0, 0x18),
+ _INIT_CMD(0x00, 0xC2, 0x14),
+ _INIT_CMD(0x00, 0xC3, 0x02),
+ _INIT_CMD(0x00, 0xC4, 0x14),
+ _INIT_CMD(0x00, 0xC5, 0x02),
+ _INIT_CMD(0x00, 0xB0, 0x06),
+ _INIT_CMD(0x00, 0xC0, 0xA5),
+ _INIT_CMD(0x00, 0xD5, 0x20),
+ _INIT_CMD(0x00, 0xC0, 0x00),
+ _INIT_CMD(0x00, 0xB0, 0x02),
+ _INIT_CMD(0x00, 0xC0, 0x00),
+ _INIT_CMD(0x00, 0xC1, 0x02),
+ _INIT_CMD(0x00, 0xC2, 0x06),
+ _INIT_CMD(0x00, 0xC3, 0x16),
+ _INIT_CMD(0x00, 0xC4, 0x0E),
+ _INIT_CMD(0x00, 0xC5, 0x18),
+ _INIT_CMD(0x00, 0xC6, 0x26),
+ _INIT_CMD(0x00, 0xC7, 0x32),
+ _INIT_CMD(0x00, 0xC8, 0x3F),
+ _INIT_CMD(0x00, 0xC9, 0x3F),
+ _INIT_CMD(0x00, 0xCA, 0x3F),
+ _INIT_CMD(0x00, 0xCB, 0x3F),
+ _INIT_CMD(0x00, 0xCC, 0x3D),
+ _INIT_CMD(0x00, 0xCD, 0x2F),
+ _INIT_CMD(0x00, 0xCE, 0x2F),
+ _INIT_CMD(0x00, 0xCF, 0x2F),
+ _INIT_CMD(0x00, 0xD0, 0x07),
+ _INIT_CMD(0x00, 0xD2, 0x00),
+ _INIT_CMD(0x00, 0xD3, 0x02),
+ _INIT_CMD(0x00, 0xD4, 0x06),
+ _INIT_CMD(0x00, 0xD5, 0x12),
+ _INIT_CMD(0x00, 0xD6, 0x0A),
+ _INIT_CMD(0x00, 0xD7, 0x14),
+ _INIT_CMD(0x00, 0xD8, 0x22),
+ _INIT_CMD(0x00, 0xD9, 0x2E),
+ _INIT_CMD(0x00, 0xDA, 0x3D),
+ _INIT_CMD(0x00, 0xDB, 0x3F),
+ _INIT_CMD(0x00, 0xDC, 0x3F),
+ _INIT_CMD(0x00, 0xDD, 0x3F),
+ _INIT_CMD(0x00, 0xDE, 0x3D),
+ _INIT_CMD(0x00, 0xDF, 0x2F),
+ _INIT_CMD(0x00, 0xE0, 0x2F),
+ _INIT_CMD(0x00, 0xE1, 0x2F),
+ _INIT_CMD(0x00, 0xE2, 0x07),
+ _INIT_CMD(0x00, 0xB0, 0x07),
+ _INIT_CMD(0x00, 0xB1, 0x18),
+ _INIT_CMD(0x00, 0xB2, 0x19),
+ _INIT_CMD(0x00, 0xB3, 0x2E),
+ _INIT_CMD(0x00, 0xB4, 0x52),
+ _INIT_CMD(0x00, 0xB5, 0x72),
+ _INIT_CMD(0x00, 0xB6, 0x8C),
+ _INIT_CMD(0x00, 0xB7, 0xBD),
+ _INIT_CMD(0x00, 0xB8, 0xEB),
+ _INIT_CMD(0x00, 0xB9, 0x47),
+ _INIT_CMD(0x00, 0xBA, 0x96),
+ _INIT_CMD(0x00, 0xBB, 0x1E),
+ _INIT_CMD(0x00, 0xBC, 0x90),
+ _INIT_CMD(0x00, 0xBD, 0x93),
+ _INIT_CMD(0x00, 0xBE, 0xFA),
+ _INIT_CMD(0x00, 0xBF, 0x56),
+ _INIT_CMD(0x00, 0xC0, 0x8C),
+ _INIT_CMD(0x00, 0xC1, 0xB7),
+ _INIT_CMD(0x00, 0xC2, 0xCC),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x08),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x15),
+ _INIT_CMD(0x00, 0xB3, 0x2D),
+ _INIT_CMD(0x00, 0xB4, 0x51),
+ _INIT_CMD(0x00, 0xB5, 0x72),
+ _INIT_CMD(0x00, 0xB6, 0x8D),
+ _INIT_CMD(0x00, 0xB7, 0xBE),
+ _INIT_CMD(0x00, 0xB8, 0xED),
+ _INIT_CMD(0x00, 0xB9, 0x4A),
+ _INIT_CMD(0x00, 0xBA, 0x9A),
+ _INIT_CMD(0x00, 0xBB, 0x23),
+ _INIT_CMD(0x00, 0xBC, 0x95),
+ _INIT_CMD(0x00, 0xBD, 0x98),
+ _INIT_CMD(0x00, 0xBE, 0xFF),
+ _INIT_CMD(0x00, 0xBF, 0x59),
+ _INIT_CMD(0x00, 0xC0, 0x8E),
+ _INIT_CMD(0x00, 0xC1, 0xB9),
+ _INIT_CMD(0x00, 0xC2, 0xCD),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x09),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x2C),
+ _INIT_CMD(0x00, 0xB3, 0x36),
+ _INIT_CMD(0x00, 0xB4, 0x53),
+ _INIT_CMD(0x00, 0xB5, 0x73),
+ _INIT_CMD(0x00, 0xB6, 0x8E),
+ _INIT_CMD(0x00, 0xB7, 0xC0),
+ _INIT_CMD(0x00, 0xB8, 0xEF),
+ _INIT_CMD(0x00, 0xB9, 0x4C),
+ _INIT_CMD(0x00, 0xBA, 0x9D),
+ _INIT_CMD(0x00, 0xBB, 0x25),
+ _INIT_CMD(0x00, 0xBC, 0x96),
+ _INIT_CMD(0x00, 0xBD, 0x9A),
+ _INIT_CMD(0x00, 0xBE, 0x01),
+ _INIT_CMD(0x00, 0xBF, 0x59),
+ _INIT_CMD(0x00, 0xC0, 0x8E),
+ _INIT_CMD(0x00, 0xC1, 0xB9),
+ _INIT_CMD(0x00, 0xC2, 0xCD),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xBF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0A),
+ _INIT_CMD(0x00, 0xB1, 0x18),
+ _INIT_CMD(0x00, 0xB2, 0x19),
+ _INIT_CMD(0x00, 0xB3, 0x2E),
+ _INIT_CMD(0x00, 0xB4, 0x52),
+ _INIT_CMD(0x00, 0xB5, 0x72),
+ _INIT_CMD(0x00, 0xB6, 0x8C),
+ _INIT_CMD(0x00, 0xB7, 0xBD),
+ _INIT_CMD(0x00, 0xB8, 0xEB),
+ _INIT_CMD(0x00, 0xB9, 0x47),
+ _INIT_CMD(0x00, 0xBA, 0x96),
+ _INIT_CMD(0x00, 0xBB, 0x1E),
+ _INIT_CMD(0x00, 0xBC, 0x90),
+ _INIT_CMD(0x00, 0xBD, 0x93),
+ _INIT_CMD(0x00, 0xBE, 0xFA),
+ _INIT_CMD(0x00, 0xBF, 0x56),
+ _INIT_CMD(0x00, 0xC0, 0x8C),
+ _INIT_CMD(0x00, 0xC1, 0xB7),
+ _INIT_CMD(0x00, 0xC2, 0xCC),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0B),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x15),
+ _INIT_CMD(0x00, 0xB3, 0x2D),
+ _INIT_CMD(0x00, 0xB4, 0x51),
+ _INIT_CMD(0x00, 0xB5, 0x72),
+ _INIT_CMD(0x00, 0xB6, 0x8D),
+ _INIT_CMD(0x00, 0xB7, 0xBE),
+ _INIT_CMD(0x00, 0xB8, 0xED),
+ _INIT_CMD(0x00, 0xB9, 0x4A),
+ _INIT_CMD(0x00, 0xBA, 0x9A),
+ _INIT_CMD(0x00, 0xBB, 0x23),
+ _INIT_CMD(0x00, 0xBC, 0x95),
+ _INIT_CMD(0x00, 0xBD, 0x98),
+ _INIT_CMD(0x00, 0xBE, 0xFF),
+ _INIT_CMD(0x00, 0xBF, 0x59),
+ _INIT_CMD(0x00, 0xC0, 0x8E),
+ _INIT_CMD(0x00, 0xC1, 0xB9),
+ _INIT_CMD(0x00, 0xC2, 0xCD),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0C),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x2C),
+ _INIT_CMD(0x00, 0xB3, 0x36),
+ _INIT_CMD(0x00, 0xB4, 0x53),
+ _INIT_CMD(0x00, 0xB5, 0x73),
+ _INIT_CMD(0x00, 0xB6, 0x8E),
+ _INIT_CMD(0x00, 0xB7, 0xC0),
+ _INIT_CMD(0x00, 0xB8, 0xEF),
+ _INIT_CMD(0x00, 0xB9, 0x4C),
+ _INIT_CMD(0x00, 0xBA, 0x9D),
+ _INIT_CMD(0x00, 0xBB, 0x25),
+ _INIT_CMD(0x00, 0xBC, 0x96),
+ _INIT_CMD(0x00, 0xBD, 0x9A),
+ _INIT_CMD(0x00, 0xBE, 0x01),
+ _INIT_CMD(0x00, 0xBF, 0x59),
+ _INIT_CMD(0x00, 0xC0, 0x8E),
+ _INIT_CMD(0x00, 0xC1, 0xB9),
+ _INIT_CMD(0x00, 0xC2, 0xCD),
+ _INIT_CMD(0x00, 0xC3, 0xDF),
+ _INIT_CMD(0x00, 0xC4, 0xE8),
+ _INIT_CMD(0x00, 0xC5, 0xF0),
+ _INIT_CMD(0x00, 0xC6, 0xF8),
+ _INIT_CMD(0x00, 0xC7, 0xFA),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x5A),
+ _INIT_CMD(0x00, 0xCC, 0xBF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x04),
+ _INIT_CMD(0x00, 0xB5, 0x02),
+ _INIT_CMD(0x00, 0xB6, 0x01),
+ _INIT_CMD(0x64, 0x11),
+ _INIT_CMD(0x32, 0x29),
+ {},
+};
+
+static const struct panel_desc boe_tv080wumng0_panel_desc = {
+ .display_mode = &default_display_mode,
+ .bpc = 8,
+ .width_mm = 107,
+ .height_mm = 172,
+ .delay_t1 = 5000,
+ .reset_delay_t2 = 14000,
+ .reset_delay_t3 = 1000,
+ .reset_delay_t4 = 1000,
+ .reset_delay_t5 = 5000,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+ .on_cmds = boe_tv080wumng0_on_cmds,
+ .off_cmds = default_off_cmds,
+};
+
/* 10 inch */
static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
_INIT_CMD(0x00, 0xB0, 0x05),
@@ -910,11 +1199,664 @@ static const struct panel_desc boe_himax8279d10p_panel_desc = {
.off_cmds = default_off_cmds,
};
+/* 10 inch Positive scanning*/
+static const struct panel_cmd boe_tv101wumng0_on_cmds[] = {
+ _INIT_CMD(0x00, 0xB0, 0x05),
+ _INIT_CMD(0x00, 0xB1, 0xE5),
+ _INIT_CMD(0x00, 0xB3, 0x52),
+ _INIT_CMD(0x00, 0xB0, 0x00),
+ _INIT_CMD(0x00, 0xB3, 0x88),
+ _INIT_CMD(0x00, 0xB0, 0x04),
+ _INIT_CMD(0x00, 0xB8, 0x00),
+ _INIT_CMD(0x00, 0xB0, 0x00),
+ _INIT_CMD(0x00, 0xB6, 0x03),
+ _INIT_CMD(0x00, 0xBA, 0x8B),
+ _INIT_CMD(0x00, 0xBF, 0x1A),
+ _INIT_CMD(0x00, 0xC0, 0x0F),
+ _INIT_CMD(0x00, 0xC2, 0x0C),
+ _INIT_CMD(0x00, 0xC3, 0x02),
+ _INIT_CMD(0x00, 0xC4, 0x0C),
+ _INIT_CMD(0x00, 0xC5, 0x02),
+ _INIT_CMD(0x00, 0xB0, 0x01),
+ _INIT_CMD(0x00, 0xE0, 0x26),
+ _INIT_CMD(0x00, 0xE1, 0x26),
+ _INIT_CMD(0x00, 0xDC, 0x00),
+ _INIT_CMD(0x00, 0xDD, 0x00),
+ _INIT_CMD(0x00, 0xCC, 0x26),
+ _INIT_CMD(0x00, 0xCD, 0x26),
+ _INIT_CMD(0x00, 0xC8, 0x00),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xD2, 0x03),
+ _INIT_CMD(0x00, 0xD3, 0x03),
+ _INIT_CMD(0x00, 0xE6, 0x04),
+ _INIT_CMD(0x00, 0xE7, 0x04),
+ _INIT_CMD(0x00, 0xC4, 0x09),
+ _INIT_CMD(0x00, 0xC5, 0x09),
+ _INIT_CMD(0x00, 0xD8, 0x0A),
+ _INIT_CMD(0x00, 0xD9, 0x0A),
+ _INIT_CMD(0x00, 0xC2, 0x0B),
+ _INIT_CMD(0x00, 0xC3, 0x0B),
+ _INIT_CMD(0x00, 0xD6, 0x0C),
+ _INIT_CMD(0x00, 0xD7, 0x0C),
+ _INIT_CMD(0x00, 0xC0, 0x05),
+ _INIT_CMD(0x00, 0xC1, 0x05),
+ _INIT_CMD(0x00, 0xD4, 0x06),
+ _INIT_CMD(0x00, 0xD5, 0x06),
+ _INIT_CMD(0x00, 0xCA, 0x07),
+ _INIT_CMD(0x00, 0xCB, 0x07),
+ _INIT_CMD(0x00, 0xDE, 0x08),
+ _INIT_CMD(0x00, 0xDF, 0x08),
+ _INIT_CMD(0x00, 0xB0, 0x02),
+ _INIT_CMD(0x00, 0xC0, 0x00),
+ _INIT_CMD(0x00, 0xC1, 0x07),
+ _INIT_CMD(0x00, 0xC2, 0x0D),
+ _INIT_CMD(0x00, 0xC3, 0x18),
+ _INIT_CMD(0x00, 0xC4, 0x27),
+ _INIT_CMD(0x00, 0xC5, 0x28),
+ _INIT_CMD(0x00, 0xC6, 0x30),
+ _INIT_CMD(0x00, 0xC7, 0x2E),
+ _INIT_CMD(0x00, 0xC8, 0x2F),
+ _INIT_CMD(0x00, 0xC9, 0x1A),
+ _INIT_CMD(0x00, 0xCA, 0x20),
+ _INIT_CMD(0x00, 0xCB, 0x29),
+ _INIT_CMD(0x00, 0xCC, 0x26),
+ _INIT_CMD(0x00, 0xCD, 0x32),
+ _INIT_CMD(0x00, 0xCE, 0x33),
+ _INIT_CMD(0x00, 0xCF, 0x31),
+ _INIT_CMD(0x00, 0xD0, 0x06),
+ _INIT_CMD(0x00, 0xD2, 0x00),
+ _INIT_CMD(0x00, 0xD3, 0x07),
+ _INIT_CMD(0x00, 0xD4, 0x12),
+ _INIT_CMD(0x00, 0xD5, 0x26),
+ _INIT_CMD(0x00, 0xD6, 0x3D),
+ _INIT_CMD(0x00, 0xD7, 0x3F),
+ _INIT_CMD(0x00, 0xD8, 0x3F),
+ _INIT_CMD(0x00, 0xD9, 0x3F),
+ _INIT_CMD(0x00, 0xDA, 0x3F),
+ _INIT_CMD(0x00, 0xDB, 0x3F),
+ _INIT_CMD(0x00, 0xDC, 0x3F),
+ _INIT_CMD(0x00, 0xDD, 0x3F),
+ _INIT_CMD(0x00, 0xDE, 0x3F),
+ _INIT_CMD(0x00, 0xDF, 0x3A),
+ _INIT_CMD(0x00, 0xE0, 0x37),
+ _INIT_CMD(0x00, 0xE1, 0x35),
+ _INIT_CMD(0x00, 0xE2, 0x07),
+ _INIT_CMD(0x00, 0xB0, 0x03),
+ _INIT_CMD(0x00, 0xC8, 0x0B),
+ _INIT_CMD(0x00, 0xC9, 0x07),
+ _INIT_CMD(0x00, 0xC3, 0x00),
+ _INIT_CMD(0x00, 0xE7, 0x00),
+ _INIT_CMD(0x00, 0xC5, 0x2A),
+ _INIT_CMD(0x00, 0xDE, 0x2A),
+ _INIT_CMD(0x00, 0xCA, 0x43),
+ _INIT_CMD(0x00, 0xC9, 0x07),
+ _INIT_CMD(0x00, 0xE4, 0xC0),
+ _INIT_CMD(0x00, 0xE5, 0x0D),
+ _INIT_CMD(0x00, 0xCB, 0x00),
+ _INIT_CMD(0x00, 0xB0, 0x06),
+ _INIT_CMD(0x00, 0xB8, 0xA5),
+ _INIT_CMD(0x00, 0xC0, 0xA5),
+ _INIT_CMD(0x00, 0xC7, 0x0F),
+ _INIT_CMD(0x00, 0xD5, 0x32),
+ _INIT_CMD(0x00, 0xB8, 0x00),
+ _INIT_CMD(0x00, 0xC0, 0x00),
+ _INIT_CMD(0x00, 0xBC, 0x00),
+ _INIT_CMD(0x00, 0xB0, 0x07),
+ _INIT_CMD(0x00, 0xB1, 0x00),
+ _INIT_CMD(0x00, 0xB2, 0x07),
+ _INIT_CMD(0x00, 0xB3, 0x18),
+ _INIT_CMD(0x00, 0xB4, 0x31),
+ _INIT_CMD(0x00, 0xB5, 0x47),
+ _INIT_CMD(0x00, 0xB6, 0x56),
+ _INIT_CMD(0x00, 0xB7, 0x70),
+ _INIT_CMD(0x00, 0xB8, 0x98),
+ _INIT_CMD(0x00, 0xB9, 0xDB),
+ _INIT_CMD(0x00, 0xBA, 0x2A),
+ _INIT_CMD(0x00, 0xBB, 0xAE),
+ _INIT_CMD(0x00, 0xBC, 0x39),
+ _INIT_CMD(0x00, 0xBD, 0x3D),
+ _INIT_CMD(0x00, 0xBE, 0xC6),
+ _INIT_CMD(0x00, 0xBF, 0x2A),
+ _INIT_CMD(0x00, 0xC0, 0x59),
+ _INIT_CMD(0x00, 0xC1, 0x91),
+ _INIT_CMD(0x00, 0xC2, 0xA1),
+ _INIT_CMD(0x00, 0xC3, 0xB1),
+ _INIT_CMD(0x00, 0xC4, 0xBA),
+ _INIT_CMD(0x00, 0xC5, 0xC5),
+ _INIT_CMD(0x00, 0xC6, 0xD4),
+ _INIT_CMD(0x00, 0xC7, 0xDC),
+ _INIT_CMD(0x00, 0xC8, 0xE0),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x08),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x07),
+ _INIT_CMD(0x00, 0xB3, 0x19),
+ _INIT_CMD(0x00, 0xB4, 0x32),
+ _INIT_CMD(0x00, 0xB5, 0x48),
+ _INIT_CMD(0x00, 0xB6, 0x58),
+ _INIT_CMD(0x00, 0xB7, 0x74),
+ _INIT_CMD(0x00, 0xB8, 0x9D),
+ _INIT_CMD(0x00, 0xB9, 0xE2),
+ _INIT_CMD(0x00, 0xBA, 0x34),
+ _INIT_CMD(0x00, 0xBB, 0xBB),
+ _INIT_CMD(0x00, 0xBC, 0x4A),
+ _INIT_CMD(0x00, 0xBD, 0x4F),
+ _INIT_CMD(0x00, 0xBE, 0xD5),
+ _INIT_CMD(0x00, 0xBF, 0x3C),
+ _INIT_CMD(0x00, 0xC0, 0x70),
+ _INIT_CMD(0x00, 0xC1, 0x9F),
+ _INIT_CMD(0x00, 0xC2, 0xAF),
+ _INIT_CMD(0x00, 0xC3, 0xC2),
+ _INIT_CMD(0x00, 0xC4, 0xD2),
+ _INIT_CMD(0x00, 0xC5, 0xE1),
+ _INIT_CMD(0x00, 0xC6, 0xF0),
+ _INIT_CMD(0x00, 0xC7, 0xF9),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x09),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x05),
+ _INIT_CMD(0x00, 0xB3, 0x18),
+ _INIT_CMD(0x00, 0xB4, 0x31),
+ _INIT_CMD(0x00, 0xB5, 0x47),
+ _INIT_CMD(0x00, 0xB6, 0x57),
+ _INIT_CMD(0x00, 0xB7, 0x72),
+ _INIT_CMD(0x00, 0xB8, 0x9B),
+ _INIT_CMD(0x00, 0xB9, 0xE0),
+ _INIT_CMD(0x00, 0xBA, 0x32),
+ _INIT_CMD(0x00, 0xBB, 0xB8),
+ _INIT_CMD(0x00, 0xBC, 0x46),
+ _INIT_CMD(0x00, 0xBD, 0x4A),
+ _INIT_CMD(0x00, 0xBE, 0xD0),
+ _INIT_CMD(0x00, 0xBF, 0x35),
+ _INIT_CMD(0x00, 0xC0, 0x65),
+ _INIT_CMD(0x00, 0xC1, 0x97),
+ _INIT_CMD(0x00, 0xC2, 0xA7),
+ _INIT_CMD(0x00, 0xC3, 0xB7),
+ _INIT_CMD(0x00, 0xC4, 0xC0),
+ _INIT_CMD(0x00, 0xC5, 0xCF),
+ _INIT_CMD(0x00, 0xC6, 0xDC),
+ _INIT_CMD(0x00, 0xC7, 0xE4),
+ _INIT_CMD(0x00, 0xC8, 0xE8),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0A),
+ _INIT_CMD(0x00, 0xB1, 0x00),
+ _INIT_CMD(0x00, 0xB2, 0x07),
+ _INIT_CMD(0x00, 0xB3, 0x18),
+ _INIT_CMD(0x00, 0xB4, 0x31),
+ _INIT_CMD(0x00, 0xB5, 0x47),
+ _INIT_CMD(0x00, 0xB6, 0x56),
+ _INIT_CMD(0x00, 0xB7, 0x70),
+ _INIT_CMD(0x00, 0xB8, 0x98),
+ _INIT_CMD(0x00, 0xB9, 0xDB),
+ _INIT_CMD(0x00, 0xBA, 0x2A),
+ _INIT_CMD(0x00, 0xBB, 0xAE),
+ _INIT_CMD(0x00, 0xBC, 0x39),
+ _INIT_CMD(0x00, 0xBD, 0x3D),
+ _INIT_CMD(0x00, 0xBE, 0xC6),
+ _INIT_CMD(0x00, 0xBF, 0x2A),
+ _INIT_CMD(0x00, 0xC0, 0x59),
+ _INIT_CMD(0x00, 0xC1, 0x91),
+ _INIT_CMD(0x00, 0xC2, 0xA1),
+ _INIT_CMD(0x00, 0xC3, 0xB1),
+ _INIT_CMD(0x00, 0xC4, 0xBA),
+ _INIT_CMD(0x00, 0xC5, 0xC5),
+ _INIT_CMD(0x00, 0xC6, 0xD4),
+ _INIT_CMD(0x00, 0xC7, 0xDC),
+ _INIT_CMD(0x00, 0xC8, 0xE0),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0B),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x07),
+ _INIT_CMD(0x00, 0xB3, 0x19),
+ _INIT_CMD(0x00, 0xB4, 0x32),
+ _INIT_CMD(0x00, 0xB5, 0x48),
+ _INIT_CMD(0x00, 0xB6, 0x58),
+ _INIT_CMD(0x00, 0xB7, 0x74),
+ _INIT_CMD(0x00, 0xB8, 0x9D),
+ _INIT_CMD(0x00, 0xB9, 0xE2),
+ _INIT_CMD(0x00, 0xBA, 0x34),
+ _INIT_CMD(0x00, 0xBB, 0xBB),
+ _INIT_CMD(0x00, 0xBC, 0x4A),
+ _INIT_CMD(0x00, 0xBD, 0x4F),
+ _INIT_CMD(0x00, 0xBE, 0xD5),
+ _INIT_CMD(0x00, 0xBF, 0x3C),
+ _INIT_CMD(0x00, 0xC0, 0x70),
+ _INIT_CMD(0x00, 0xC1, 0x9F),
+ _INIT_CMD(0x00, 0xC2, 0xAF),
+ _INIT_CMD(0x00, 0xC3, 0xC2),
+ _INIT_CMD(0x00, 0xC4, 0xD2),
+ _INIT_CMD(0x00, 0xC5, 0xE1),
+ _INIT_CMD(0x00, 0xC6, 0xF0),
+ _INIT_CMD(0x00, 0xC7, 0xF9),
+ _INIT_CMD(0x00, 0xC8, 0xFC),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x0C),
+ _INIT_CMD(0x00, 0xB1, 0x04),
+ _INIT_CMD(0x00, 0xB2, 0x05),
+ _INIT_CMD(0x00, 0xB3, 0x18),
+ _INIT_CMD(0x00, 0xB4, 0x31),
+ _INIT_CMD(0x00, 0xB5, 0x47),
+ _INIT_CMD(0x00, 0xB6, 0x57),
+ _INIT_CMD(0x00, 0xB7, 0x72),
+ _INIT_CMD(0x00, 0xB8, 0x9B),
+ _INIT_CMD(0x00, 0xB9, 0xE0),
+ _INIT_CMD(0x00, 0xBA, 0x32),
+ _INIT_CMD(0x00, 0xBB, 0xB8),
+ _INIT_CMD(0x00, 0xBC, 0x46),
+ _INIT_CMD(0x00, 0xBD, 0x4A),
+ _INIT_CMD(0x00, 0xBE, 0xD0),
+ _INIT_CMD(0x00, 0xBF, 0x35),
+ _INIT_CMD(0x00, 0xC0, 0x65),
+ _INIT_CMD(0x00, 0xC1, 0x97),
+ _INIT_CMD(0x00, 0xC2, 0xA7),
+ _INIT_CMD(0x00, 0xC3, 0xB7),
+ _INIT_CMD(0x00, 0xC4, 0xC0),
+ _INIT_CMD(0x00, 0xC5, 0xCF),
+ _INIT_CMD(0x00, 0xC6, 0xDC),
+ _INIT_CMD(0x00, 0xC7, 0xE4),
+ _INIT_CMD(0x00, 0xC8, 0xE8),
+ _INIT_CMD(0x00, 0xC9, 0x00),
+ _INIT_CMD(0x00, 0xCA, 0x00),
+ _INIT_CMD(0x00, 0xCB, 0x16),
+ _INIT_CMD(0x00, 0xCC, 0xAF),
+ _INIT_CMD(0x00, 0xCD, 0xFF),
+ _INIT_CMD(0x00, 0xCE, 0xFF),
+ _INIT_CMD(0x00, 0xB0, 0x00),
+ _INIT_CMD(0x00, 0xB3, 0x08),
+ _INIT_CMD(0x00, 0xB0, 0x04),
+ _INIT_CMD(0x64, 0xB8, 0x68),
+ {},
+};
+
+static const struct panel_desc boe_tv101wumng0_panel_desc = {
+ .display_mode = &default_display_mode,
+ .bpc = 8,
+ .width_mm = 135,
+ .height_mm = 216,
+ .delay_t1 = 5000,
+ .reset_delay_t2 = 14000,
+ .reset_delay_t3 = 1000,
+ .reset_delay_t4 = 1000,
+ .reset_delay_t5 = 5000,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+ .on_cmds = boe_tv101wumng0_on_cmds,
+ .off_cmds = default_off_cmds,
+};
+
+/* auo,nt51021d8p */
+static const struct drm_display_mode auo_nt51021d8p_display_mode = {
+ .clock = 159420,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 80,
+ .hsync_end = 1200 + 80 + 60,
+ .htotal = 1200 + 80 + 60 + 1,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 35,
+ .vsync_end = 1920 + 35 + 25,
+ .vtotal = 1920 + 35 + 25 + 1,
+ .vrefresh = 60,
+};
+
+static const struct panel_cmd auo_nt51021d8p_on_cmds[] = {
+ _INIT_CMD(0x78, 0x11),
+ _INIT_CMD(0x14, 0x29),
+
+ {},
+};
+
+static const struct panel_cmd auo_nt51021d8p_off_cmds[] = {
+ _INIT_CMD(0x00, 0x28),
+ _INIT_CMD(0x01, 0x10),
+
+ {},
+};
+
+static const struct panel_desc auo_nt51021d8p_panel_desc = {
+ .display_mode = &auo_nt51021d8p_display_mode,
+ .bpc = 8,
+ .width_mm = 107,
+ .height_mm = 172,
+ .delay_t1 = 5000,
+ .reset_delay_t2 = 14000,
+ .reset_delay_t3 = 1000,
+ .reset_delay_t4 = 1000,
+ .reset_delay_t5 = 5000,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+ .on_cmds = auo_nt51021d8p_on_cmds,
+ .off_cmds = auo_nt51021d8p_off_cmds,
+};
+
+/* inx,ota7290d10p */
+static const struct panel_cmd inx_ota7290d10p_on_cmds[] = {
+ _INIT_CMD(0x00, 0xB0, 0x5A),
+ _INIT_CMD(0x00, 0xB1, 0x00),
+ _INIT_CMD(0x00, 0x89, 0x01),
+ _INIT_CMD(0x00, 0x91, 0x17),
+ _INIT_CMD(0x00, 0xB1, 0x03),
+ _INIT_CMD(0x00, 0x2C, 0x28),
+ _INIT_CMD(0x00, 0x00, 0xF1),
+ _INIT_CMD(0x00, 0x01, 0x78),
+ _INIT_CMD(0x00, 0x02, 0x3C),
+ _INIT_CMD(0x00, 0x03, 0x1E),
+ _INIT_CMD(0x00, 0x04, 0x8F),
+ _INIT_CMD(0x00, 0x05, 0x01),
+ _INIT_CMD(0x00, 0x06, 0x00),
+ _INIT_CMD(0x00, 0x07, 0x00),
+ _INIT_CMD(0x00, 0x08, 0x00),
+ _INIT_CMD(0x00, 0x09, 0x00),
+ _INIT_CMD(0x00, 0x0A, 0x01),
+ _INIT_CMD(0x00, 0x0B, 0x3C),
+ _INIT_CMD(0x00, 0x0C, 0x00),
+ _INIT_CMD(0x00, 0x0D, 0x00),
+ _INIT_CMD(0x00, 0x0E, 0x24),
+ _INIT_CMD(0x00, 0x0F, 0x1C),
+ _INIT_CMD(0x00, 0x10, 0xC8),
+ _INIT_CMD(0x00, 0x11, 0x60),
+ _INIT_CMD(0x00, 0x12, 0x70),
+ _INIT_CMD(0x00, 0x13, 0x01),
+ _INIT_CMD(0x00, 0x14, 0xE3),
+ _INIT_CMD(0x00, 0x15, 0xFF),
+ _INIT_CMD(0x00, 0x16, 0x3D),
+ _INIT_CMD(0x00, 0x17, 0x0E),
+ _INIT_CMD(0x00, 0x18, 0x01),
+ _INIT_CMD(0x00, 0x19, 0x00),
+ _INIT_CMD(0x00, 0x1A, 0x00),
+ _INIT_CMD(0x00, 0x1B, 0xFC),
+ _INIT_CMD(0x00, 0x1C, 0x0B),
+ _INIT_CMD(0x00, 0x1D, 0xA0),
+ _INIT_CMD(0x00, 0x1E, 0x03),
+ _INIT_CMD(0x00, 0x1F, 0x04),
+ _INIT_CMD(0x00, 0x20, 0x0C),
+ _INIT_CMD(0x00, 0x21, 0x00),
+ _INIT_CMD(0x00, 0x22, 0x04),
+ _INIT_CMD(0x00, 0x23, 0x81),
+ _INIT_CMD(0x00, 0x24, 0x1F),
+ _INIT_CMD(0x00, 0x25, 0x10),
+ _INIT_CMD(0x00, 0x26, 0x9B),
+ _INIT_CMD(0x00, 0x2D, 0x01),
+ _INIT_CMD(0x00, 0x2E, 0x84),
+ _INIT_CMD(0x00, 0x2F, 0x00),
+ _INIT_CMD(0x00, 0x30, 0x02),
+ _INIT_CMD(0x00, 0x31, 0x08),
+ _INIT_CMD(0x00, 0x32, 0x01),
+ _INIT_CMD(0x00, 0x33, 0x1C),
+ _INIT_CMD(0x00, 0x34, 0x70),
+ _INIT_CMD(0x00, 0x35, 0xFF),
+ _INIT_CMD(0x00, 0x36, 0xFF),
+ _INIT_CMD(0x00, 0x37, 0xFF),
+ _INIT_CMD(0x00, 0x38, 0xFF),
+ _INIT_CMD(0x00, 0x39, 0xFF),
+ _INIT_CMD(0x00, 0x3A, 0x05),
+ _INIT_CMD(0x00, 0x3B, 0x00),
+ _INIT_CMD(0x00, 0x3C, 0x00),
+ _INIT_CMD(0x00, 0x3D, 0x00),
+ _INIT_CMD(0x00, 0x3E, 0x0F),
+ _INIT_CMD(0x00, 0x3F, 0xA4),
+ _INIT_CMD(0x00, 0x40, 0x28),
+ _INIT_CMD(0x00, 0x41, 0xFC),
+ _INIT_CMD(0x00, 0x42, 0x01),
+ _INIT_CMD(0x00, 0x43, 0x08),
+ _INIT_CMD(0x00, 0x44, 0x05),
+ _INIT_CMD(0x00, 0x45, 0xF0),
+ _INIT_CMD(0x00, 0x46, 0x01),
+ _INIT_CMD(0x00, 0x47, 0x02),
+ _INIT_CMD(0x00, 0x48, 0x00),
+ _INIT_CMD(0x00, 0x49, 0x58),
+ _INIT_CMD(0x00, 0x4A, 0x00),
+ _INIT_CMD(0x00, 0x4B, 0x05),
+ _INIT_CMD(0x00, 0x4C, 0x03),
+ _INIT_CMD(0x00, 0x4D, 0xD0),
+ _INIT_CMD(0x00, 0x4E, 0x13),
+ _INIT_CMD(0x00, 0x4F, 0xFF),
+ _INIT_CMD(0x00, 0x50, 0x0A),
+ _INIT_CMD(0x00, 0x51, 0x53),
+ _INIT_CMD(0x00, 0x52, 0x26),
+ _INIT_CMD(0x00, 0x53, 0x22),
+ _INIT_CMD(0x00, 0x54, 0x09),
+ _INIT_CMD(0x00, 0x55, 0x22),
+ _INIT_CMD(0x00, 0x56, 0x00),
+ _INIT_CMD(0x00, 0x57, 0x1C),
+ _INIT_CMD(0x00, 0x58, 0x03),
+ _INIT_CMD(0x00, 0x59, 0x3F),
+ _INIT_CMD(0x00, 0x5A, 0x28),
+ _INIT_CMD(0x00, 0x5B, 0x01),
+ _INIT_CMD(0x00, 0x5C, 0xCC),
+ _INIT_CMD(0x00, 0x5D, 0x21),
+ _INIT_CMD(0x00, 0x5E, 0x04),
+ _INIT_CMD(0x00, 0x5F, 0x13),
+ _INIT_CMD(0x00, 0x60, 0x42),
+ _INIT_CMD(0x00, 0x61, 0x08),
+ _INIT_CMD(0x00, 0x62, 0x64),
+ _INIT_CMD(0x00, 0x63, 0xEB),
+ _INIT_CMD(0x00, 0x64, 0x10),
+ _INIT_CMD(0x00, 0x65, 0xA8),
+ _INIT_CMD(0x00, 0x66, 0x84),
+ _INIT_CMD(0x00, 0x67, 0x8E),
+ _INIT_CMD(0x00, 0x68, 0x29),
+ _INIT_CMD(0x00, 0x69, 0x11),
+ _INIT_CMD(0x00, 0x6A, 0x42),
+ _INIT_CMD(0x00, 0x6B, 0x38),
+ _INIT_CMD(0x00, 0x6C, 0x21),
+ _INIT_CMD(0x00, 0x6D, 0x84),
+ _INIT_CMD(0x00, 0x6E, 0x50),
+ _INIT_CMD(0x00, 0x6F, 0xB6),
+ _INIT_CMD(0x00, 0x70, 0x0E),
+ _INIT_CMD(0x00, 0x71, 0xA1),
+ _INIT_CMD(0x00, 0x72, 0xCE),
+ _INIT_CMD(0x00, 0x73, 0xF8),
+ _INIT_CMD(0x00, 0x74, 0xDA),
+ _INIT_CMD(0x00, 0x75, 0x1A),
+ _INIT_CMD(0x00, 0x76, 0x00),
+ _INIT_CMD(0x00, 0x77, 0x00),
+ _INIT_CMD(0x00, 0x78, 0x5F),
+ _INIT_CMD(0x00, 0x79, 0xE0),
+ _INIT_CMD(0x00, 0x7A, 0x01),
+ _INIT_CMD(0x00, 0x7B, 0xFF),
+ _INIT_CMD(0x00, 0x7C, 0xFF),
+ _INIT_CMD(0x00, 0x7D, 0xFF),
+ _INIT_CMD(0x00, 0x7E, 0xFF),
+ _INIT_CMD(0x00, 0x7F, 0xFE),
+ _INIT_CMD(0x00, 0xB1, 0x02),
+ _INIT_CMD(0x00, 0x00, 0xFF),
+ _INIT_CMD(0x00, 0x01, 0x01),
+ _INIT_CMD(0x00, 0x02, 0x00),
+ _INIT_CMD(0x00, 0x03, 0x00),
+ _INIT_CMD(0x00, 0x04, 0x00),
+ _INIT_CMD(0x00, 0x05, 0x00),
+ _INIT_CMD(0x00, 0x06, 0x00),
+ _INIT_CMD(0x00, 0x07, 0x00),
+ _INIT_CMD(0x00, 0x08, 0xC0),
+ _INIT_CMD(0x00, 0x09, 0x00),
+ _INIT_CMD(0x00, 0x0A, 0x00),
+ _INIT_CMD(0x00, 0x0B, 0x04),
+ _INIT_CMD(0x00, 0x0C, 0xE6),
+ _INIT_CMD(0x00, 0x0D, 0x0D),
+ _INIT_CMD(0x00, 0x0F, 0x08),
+ _INIT_CMD(0x00, 0x10, 0xE5),
+ _INIT_CMD(0x00, 0x11, 0xA8),
+ _INIT_CMD(0x00, 0x12, 0xEC),
+ _INIT_CMD(0x00, 0x13, 0x54),
+ _INIT_CMD(0x00, 0x14, 0x5A),
+ _INIT_CMD(0x00, 0x15, 0xD5),
+ _INIT_CMD(0x00, 0x16, 0x23),
+ _INIT_CMD(0x00, 0x17, 0x11),
+ _INIT_CMD(0x00, 0x18, 0x2F),
+ _INIT_CMD(0x00, 0x19, 0x93),
+ _INIT_CMD(0x00, 0x1A, 0xA6),
+ _INIT_CMD(0x00, 0x1B, 0x0F),
+ _INIT_CMD(0x00, 0x1C, 0xFF),
+ _INIT_CMD(0x00, 0x1D, 0xFF),
+ _INIT_CMD(0x00, 0x1E, 0xFF),
+ _INIT_CMD(0x00, 0x1F, 0xFF),
+ _INIT_CMD(0x00, 0x20, 0xFF),
+ _INIT_CMD(0x00, 0x21, 0xFF),
+ _INIT_CMD(0x00, 0x22, 0xFF),
+ _INIT_CMD(0x00, 0x23, 0xFF),
+ _INIT_CMD(0x00, 0x24, 0xFF),
+ _INIT_CMD(0x00, 0x25, 0xFF),
+ _INIT_CMD(0x00, 0x26, 0xFF),
+ _INIT_CMD(0x00, 0x27, 0x1F),
+ _INIT_CMD(0x00, 0x28, 0xC8),
+ _INIT_CMD(0x00, 0x29, 0xFF),
+ _INIT_CMD(0x00, 0x2A, 0xFF),
+ _INIT_CMD(0x00, 0x2B, 0xFF),
+ _INIT_CMD(0x00, 0x2C, 0x07),
+ _INIT_CMD(0x00, 0x2D, 0x03),
+ _INIT_CMD(0x00, 0x33, 0x09),
+ _INIT_CMD(0x00, 0x35, 0x7F),
+ _INIT_CMD(0x00, 0x36, 0x0C),
+ _INIT_CMD(0x00, 0x38, 0x7F),
+ _INIT_CMD(0x00, 0x3A, 0x80),
+ _INIT_CMD(0x00, 0x3B, 0x55),
+ _INIT_CMD(0x00, 0x3C, 0xE2),
+ _INIT_CMD(0x00, 0x3D, 0x32),
+ _INIT_CMD(0x00, 0x3E, 0x00),
+ _INIT_CMD(0x00, 0x3F, 0x58),
+ _INIT_CMD(0x00, 0x40, 0x06),
+ _INIT_CMD(0x00, 0x41, 0x80),
+ _INIT_CMD(0x00, 0x42, 0xCB),
+ _INIT_CMD(0x00, 0x43, 0x2C),
+ _INIT_CMD(0x00, 0x44, 0x61),
+ _INIT_CMD(0x00, 0x45, 0x39),
+ _INIT_CMD(0x00, 0x46, 0x00),
+ _INIT_CMD(0x00, 0x47, 0x00),
+ _INIT_CMD(0x00, 0x48, 0x8B),
+ _INIT_CMD(0x00, 0x49, 0xD2),
+ _INIT_CMD(0x00, 0x4A, 0x01),
+ _INIT_CMD(0x00, 0x4B, 0x00),
+ _INIT_CMD(0x00, 0x4C, 0x10),
+ _INIT_CMD(0x00, 0x4D, 0xC0),
+ _INIT_CMD(0x00, 0x4E, 0x0F),
+ _INIT_CMD(0x00, 0x4F, 0xF1),
+ _INIT_CMD(0x00, 0x50, 0x78),
+ _INIT_CMD(0x00, 0x51, 0x7A),
+ _INIT_CMD(0x00, 0x52, 0x34),
+ _INIT_CMD(0x00, 0x53, 0x99),
+ _INIT_CMD(0x00, 0x54, 0xA2),
+ _INIT_CMD(0x00, 0x55, 0x03),
+ _INIT_CMD(0x00, 0x56, 0x6C),
+ _INIT_CMD(0x00, 0x57, 0x1A),
+ _INIT_CMD(0x00, 0x58, 0x05),
+ _INIT_CMD(0x00, 0x59, 0x30),
+ _INIT_CMD(0x00, 0x5A, 0x1E),
+ _INIT_CMD(0x00, 0x5B, 0x8F),
+ _INIT_CMD(0x00, 0x5C, 0xC7),
+ _INIT_CMD(0x00, 0x5D, 0xE3),
+ _INIT_CMD(0x00, 0x5E, 0xF1),
+ _INIT_CMD(0x00, 0x5F, 0x78),
+ _INIT_CMD(0x00, 0x60, 0x3C),
+ _INIT_CMD(0x00, 0x61, 0x36),
+ _INIT_CMD(0x00, 0x62, 0x1E),
+ _INIT_CMD(0x00, 0x63, 0x1B),
+ _INIT_CMD(0x00, 0x64, 0x8F),
+ _INIT_CMD(0x00, 0x65, 0xC7),
+ _INIT_CMD(0x00, 0x66, 0xE3),
+ _INIT_CMD(0x00, 0x67, 0x31),
+ _INIT_CMD(0x00, 0x68, 0x14),
+ _INIT_CMD(0x00, 0x69, 0x89),
+ _INIT_CMD(0x00, 0x6A, 0x70),
+ _INIT_CMD(0x00, 0x6B, 0x8C),
+ _INIT_CMD(0x00, 0x6C, 0x8D),
+ _INIT_CMD(0x00, 0x6D, 0x8D),
+ _INIT_CMD(0x00, 0x6E, 0x8D),
+ _INIT_CMD(0x00, 0x6F, 0x8D),
+ _INIT_CMD(0x00, 0x70, 0xC7),
+ _INIT_CMD(0x00, 0x71, 0xE3),
+ _INIT_CMD(0x00, 0x72, 0xF1),
+ _INIT_CMD(0x00, 0x73, 0xD8),
+ _INIT_CMD(0x00, 0x74, 0xD8),
+ _INIT_CMD(0x00, 0x75, 0xD8),
+ _INIT_CMD(0x00, 0x76, 0x18),
+ _INIT_CMD(0x00, 0x77, 0x00),
+ _INIT_CMD(0x00, 0x78, 0x00),
+ _INIT_CMD(0x00, 0x79, 0x00),
+ _INIT_CMD(0x00, 0x7A, 0xC6),
+ _INIT_CMD(0x00, 0x7B, 0xC6),
+ _INIT_CMD(0x00, 0x7C, 0xC6),
+ _INIT_CMD(0x00, 0x7D, 0xC6),
+ _INIT_CMD(0x00, 0x7E, 0xC6),
+ _INIT_CMD(0x00, 0x7F, 0xE3),
+ _INIT_CMD(0x00, 0x0B, 0x04),
+ _INIT_CMD(0x00, 0xB1, 0x03),
+ _INIT_CMD(0x00, 0x2C, 0x2C),
+ _INIT_CMD(0x00, 0xB1, 0x00),
+ _INIT_CMD(0x00, 0x89, 0x03),
+ _INIT_CMD(0x78, 0x11),
+ _INIT_CMD(0x14, 0x29),
+
+ {},
+};
+
+static const struct panel_cmd inx_ota7290d10p_off_cmds[] = {
+ _INIT_CMD(0x00, 0x28),
+ _INIT_CMD(0x01, 0x10),
+
+ {},
+};
+
+static const struct panel_desc inx_ota7290d10p_panel_desc = {
+ .display_mode = &default_display_mode,
+ .bpc = 8,
+ .width_mm = 107,
+ .height_mm = 172,
+ .delay_t1 = 5000,
+ .reset_delay_t2 = 14000,
+ .reset_delay_t3 = 1000,
+ .reset_delay_t4 = 1000,
+ .reset_delay_t5 = 5000,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
+ .format = MIPI_DSI_FMT_RGB888,
+ .lanes = 4,
+ .on_cmds = inx_ota7290d10p_on_cmds,
+ .off_cmds = inx_ota7290d10p_off_cmds,
+};
+
static const struct of_device_id panel_of_match[] = {
{ .compatible = "boe,himax8279d8p",
.data = &boe_himax8279d8p_panel_desc
}, { .compatible = "boe,himax8279d10p",
.data = &boe_himax8279d10p_panel_desc
+ }, { .compatible = "auo,nt51021d8p",
+ .data = &auo_nt51021d8p_panel_desc
+ }, { .compatible = "inx,ota7290d10p",
+ .data = &inx_ota7290d10p_panel_desc
+ }, { .compatible = "boe,tv080wum_ng0",
+ .data = &boe_tv080wumng0_panel_desc
+ }, { .compatible = "boe,tv101wum_ng0",
+ .data = &boe_tv101wumng0_panel_desc
}, {
/* sentinel */
}
@@ -958,6 +1900,10 @@ static int panel_add(struct panel_info *pinfo)
if (IS_ERR(pinfo->backlight))
return PTR_ERR(pinfo->backlight);
+ ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation);
+ if (ret < 0)
+ return ret;
+
drm_panel_init(&pinfo->base);
pinfo->base.funcs = &panel_funcs;
pinfo->base.dev = &pinfo->link->dev;
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 388ef70c11d24..d16c1d4649ce2 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -79,6 +79,19 @@ config SX9500
To compile this driver as a module, choose M here: the
module will be called sx9500.
+config SX9311
+ tristate "SX9311 Semtech proximity sensor"
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Say Y here to build a driver for Semtech's SX9311 capacitive
+ proximity/button sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sx9311.
+
config SRF08
tristate "Devantech SRF02/SRF08/SRF10 ultrasonic ranger sensor"
select IIO_BUFFER
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index cac3d7d3325e3..c0ac5af120154 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
+obj-$(CONFIG_SX9311) += sx9311.o
diff --git a/drivers/iio/proximity/sx9311.c b/drivers/iio/proximity/sx9311.c
new file mode 100644
index 0000000000000..408c349dd4368
--- /dev/null
+++ b/drivers/iio/proximity/sx9311.c
@@ -0,0 +1,1144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, Google LLC.
+ *
+ * Driver for Semtech's SX9311 capacitive proximity/button solution.
+ * Datasheet available at
+ * <http://www.semtech.com/images/datasheet/sx9311.pdf>.
+ * Based on SX9310 driver and Semtech driver using the input framework
+ * <https://my.syncplicity.com/share/teouwsim8niiaud/
+ * linux-driver-SX9311_NoSmartHSensing>.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define SX9311_DRIVER_NAME "sx9311"
+#define SX9311_ACPI_NAME "STH9311"
+#define SX9311_IRQ_NAME "sx9311_event"
+
+#define SX9311_GPIO_INT "interrupt"
+
+/* Register definitions. */
+#define SX9311_REG_IRQ_SRC 0x00
+#define SX9311_REG_STAT0 0x01
+#define SX9311_REG_STAT1 0x02
+#define SX9311_REG_IRQ_MSK 0x03
+#define SX9311_REG_IRQ_FUNC 0x04
+
+#define SX9311_REG_PROX_CTRL0 0x10
+#define SX9311_REG_PROX_CTRL1 0x11
+#define SX9311_REG_PROX_CTRL2 0x12
+#define SX9311_REG_PROX_CTRL3 0x13
+#define SX9311_REG_PROX_CTRL4 0x14
+#define SX9311_REG_PROX_CTRL5 0x15
+#define SX9311_REG_PROX_CTRL6 0x16
+#define SX9311_REG_PROX_CTRL7 0x17
+#define SX9311_REG_PROX_CTRL8 0x18
+#define SX9311_REG_PROX_CTRL9 0x19
+#define SX9311_REG_PROX_CTRL10 0x1A
+#define SX9311_REG_PROX_CTRL11 0x1B
+#define SX9311_REG_PROX_CTRL12 0x1C
+#define SX9311_REG_PROX_CTRL13 0x1D
+#define SX9311_REG_PROX_CTRL14 0x1E
+#define SX9311_REG_PROX_CTRL15 0x1F
+#define SX9311_REG_PROX_CTRL16 0x20
+#define SX9311_REG_PROX_CTRL17 0x21
+#define SX9311_REG_PROX_CTRL18 0x22
+#define SX9311_REG_PROX_CTRL19 0x23
+#define SX9311_REG_SAR_CTRL0 0x2A
+#define SX9311_REG_SAR_CTRL1 0x2B
+#define SX9311_REG_SAR_CTRL2 0x2C
+
+#define SX9311_REG_SENSOR_SEL 0x30
+
+#define SX9311_REG_USE_MSB 0x31
+#define SX9311_REG_USE_LSB 0x32
+
+#define SX9311_REG_AVG_MSB 0x33
+#define SX9311_REG_AVG_LSB 0x34
+
+#define SX9311_REG_DIFF_MSB 0x35
+#define SX9311_REG_DIFF_LSB 0x36
+
+#define SX9311_REG_OFFSET_MSB 0x37
+#define SX9311_REG_OFFSET_LSB 0x38
+
+#define SX9311_REG_SAR_MSB 0x39
+#define SX9311_REG_SAR_LSB 0x3A
+
+#define SX9311_REG_I2CADDR 0x40
+#define SX9311_REG_PAUSE 0x41
+#define SX9311_REG_WHOAMI 0x42
+/* Expected content of the WHOAMI register. */
+#define SX9311_WHOAMI_VALUE 0x02
+
+#define SX9311_REG_RESET 0x7f
+/* Write this to REG_RESET to do a soft reset. */
+#define SX9311_SOFT_RESET 0xde
+
+
+/* Sensor Readback */
+
+/*
+ * These serve for identifying IRQ source in the IRQ_SRC register, and
+ * also for masking the IRQs in the IRQ_MSK register.
+ */
+#define SX9311_RESET_IRQ BIT(7)
+#define SX9311_CLOSE_IRQ BIT(6)
+#define SX9311_FAR_IRQ BIT(5)
+#define SX9311_COMPDONE_IRQ BIT(4)
+#define SX9311_CONVDONE_IRQ BIT(3)
+
+#define SX9311_SCAN_PERIOD_MASK GENMASK(7, 4)
+#define SX9311_SCAN_PERIOD_SHIFT 4
+
+#define SX9311_COMPSTAT_MASK GENMASK(3, 0)
+
+/* 4 channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
+#define SX9311_NUM_CHANNELS 4
+#define SX9311_CHAN_MASK GENMASK(2, 0)
+
+struct sx9311_data {
+ struct mutex mutex;
+ struct i2c_client *client;
+ struct iio_trigger *trig;
+ struct regmap *regmap;
+ /*
+ * Last reading of the proximity status for each channel.
+ * We only send an event to user space when this changes.
+ */
+ bool prox_stat[SX9311_NUM_CHANNELS];
+ bool event_enabled[SX9311_NUM_CHANNELS];
+ bool trigger_enabled;
+ u16 *buffer;
+ /* Remember enabled channels and sample rate during suspend. */
+ unsigned int suspend_ctrl0;
+ struct completion completion;
+ int data_rdy_users, close_far_users;
+ int channel_users[SX9311_NUM_CHANNELS];
+ unsigned int num_irqs;
+};
+
+static const struct iio_event_spec sx9311_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+#define SX9311_CHANNEL(idx, name, addr) \
+ { \
+ .type = IIO_PROXIMITY, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .indexed = 1, \
+ .channel = idx, \
+ .address = addr, \
+ .event_spec = sx9311_events, \
+ .num_event_specs = ARRAY_SIZE(sx9311_events), \
+ .extend_name = name, \
+ .scan_index = idx, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .shift = 0, \
+ }, \
+ }
+
+static const struct iio_chan_spec sx9311_channels[] = {
+ SX9311_CHANNEL(0, "USE_CS0", SX9311_REG_USE_MSB),
+ SX9311_CHANNEL(1, "USE_CS1", SX9311_REG_USE_MSB),
+ SX9311_CHANNEL(2, "USE_CS2", SX9311_REG_USE_MSB),
+ SX9311_CHANNEL(3, "USE_COMB", SX9311_REG_USE_MSB),
+
+ SX9311_CHANNEL(4, "DIFF_CS0", SX9311_REG_DIFF_MSB),
+ SX9311_CHANNEL(5, "DIFF_CS1", SX9311_REG_DIFF_MSB),
+ SX9311_CHANNEL(6, "DIFF_CS2", SX9311_REG_DIFF_MSB),
+ SX9311_CHANNEL(7, "DIFF_COMB", SX9311_REG_DIFF_MSB),
+
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+/*
+ * Each entry contains the integer part (val) and the fractional part, in micro
+ * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO.
+ */
+static const struct {
+ int val;
+ int val2;
+} sx9311_samp_freq_table[] = {
+ {500, 0}, /* 0000: Min (no idle time) */
+ {66, 666666}, /* 0001: 15 ms */
+ {33, 333333}, /* 0010: 30 ms (Typ.) */
+ {22, 222222}, /* 0011: 45 ms */
+ {16, 666666}, /* 0100: 60 ms */
+ {11, 111111}, /* 0101: 90 ms */
+ {8, 333333}, /* 0110: 120 ms */
+ {5, 0}, /* 0111: 200 ms */
+ {2, 500000}, /* 1000: 400 ms */
+ {1, 666666}, /* 1001: 600 ms */
+ {1, 250000}, /* 1010: 800 ms */
+ {1, 0}, /* 1011: 1 s */
+ {0, 500000}, /* 1100: 2 s */
+ {8, 333333}, /* 1101: 3 s */
+ {0, 250000}, /* 1110: 4 s */
+ {0, 200000}, /* 1111: 5 s */
+};
+static const unsigned int sx9311_scan_period_table[] = {
+ 2, 15, 30, 45, 60, 90, 120, 200, 400, 800, 1000, 2000, 3000, 4000, 5000,
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+ "500.0 66.666666 33.333333 22.222222 16.666666 "
+ "11.111111 8.333333 5.0 2.500000 1.666666 1.250000 "
+ "1.0 0.500000 8.333333 0.250000 0.200000");
+
+
+static const struct regmap_range sx9311_writable_reg_ranges[] = {
+ regmap_reg_range(SX9311_REG_IRQ_MSK, SX9311_REG_IRQ_FUNC),
+ regmap_reg_range(SX9311_REG_PROX_CTRL0, SX9311_REG_PROX_CTRL19),
+ regmap_reg_range(SX9311_REG_SAR_CTRL0, SX9311_REG_SAR_CTRL2),
+ regmap_reg_range(SX9311_REG_SENSOR_SEL, SX9311_REG_SENSOR_SEL),
+ regmap_reg_range(SX9311_REG_OFFSET_MSB, SX9311_REG_OFFSET_LSB),
+ regmap_reg_range(SX9311_REG_PAUSE, SX9311_REG_PAUSE),
+ regmap_reg_range(SX9311_REG_RESET, SX9311_REG_RESET),
+};
+
+static const struct regmap_access_table sx9311_writeable_regs = {
+ .yes_ranges = sx9311_writable_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sx9311_writable_reg_ranges),
+};
+
+/*
+ * All allocated registers are readable, so we just list unallocated
+ * ones.
+ */
+static const struct regmap_range sx9311_non_readable_reg_ranges[] = {
+ regmap_reg_range(SX9311_REG_IRQ_FUNC + 1, SX9311_REG_PROX_CTRL0 - 1),
+ regmap_reg_range(SX9311_REG_SAR_CTRL2 + 1, SX9311_REG_SENSOR_SEL - 1),
+ regmap_reg_range(SX9311_REG_SAR_LSB + 1, SX9311_REG_I2CADDR - 1),
+ regmap_reg_range(SX9311_REG_WHOAMI + 1, SX9311_REG_RESET - 1),
+};
+
+static const struct regmap_access_table sx9311_readable_regs = {
+ .no_ranges = sx9311_non_readable_reg_ranges,
+ .n_no_ranges = ARRAY_SIZE(sx9311_non_readable_reg_ranges),
+};
+
+static const struct regmap_range sx9311_volatile_reg_ranges[] = {
+ regmap_reg_range(SX9311_REG_IRQ_SRC, SX9311_REG_STAT1),
+ regmap_reg_range(SX9311_REG_USE_MSB, SX9311_REG_DIFF_LSB),
+ regmap_reg_range(SX9311_REG_SAR_MSB, SX9311_REG_SAR_LSB),
+ regmap_reg_range(SX9311_REG_RESET, SX9311_REG_RESET),
+};
+
+static const struct regmap_access_table sx9311_volatile_regs = {
+ .yes_ranges = sx9311_volatile_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sx9311_volatile_reg_ranges),
+};
+
+static const struct regmap_config sx9311_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SX9311_REG_RESET,
+ .cache_type = REGCACHE_RBTREE,
+
+ .wr_table = &sx9311_writeable_regs,
+ .rd_table = &sx9311_readable_regs,
+ .volatile_table = &sx9311_volatile_regs,
+};
+
+static int sx9311_inc_users(struct sx9311_data *data, int *counter,
+ unsigned int reg, unsigned int bitmask)
+{
+ ++(*counter);
+ if (*counter != 1)
+ /* Bit is already active, nothing to do. */
+ return 0;
+
+ return regmap_update_bits(data->regmap, reg, bitmask, bitmask);
+}
+
+static int sx9311_dec_users(struct sx9311_data *data, int *counter,
+ unsigned int reg, unsigned int bitmask)
+{
+ --(*counter);
+ if (*counter != 0)
+ /* There are more users, do not deactivate. */
+ return 0;
+
+ return regmap_update_bits(data->regmap, reg, bitmask, 0);
+}
+
+static int sx9311_inc_chan_users(struct sx9311_data *data, int chan)
+{
+ return sx9311_inc_users(data, &data->channel_users[chan],
+ SX9311_REG_PROX_CTRL0, BIT(chan));
+}
+
+static int sx9311_dec_chan_users(struct sx9311_data *data, int chan)
+{
+ return sx9311_dec_users(data, &data->channel_users[chan],
+ SX9311_REG_PROX_CTRL0, BIT(chan));
+}
+
+static int sx9311_inc_data_rdy_users(struct sx9311_data *data)
+{
+ return sx9311_inc_users(data, &data->data_rdy_users,
+ SX9311_REG_IRQ_MSK, SX9311_CONVDONE_IRQ);
+}
+
+static int sx9311_dec_data_rdy_users(struct sx9311_data *data)
+{
+ return sx9311_dec_users(data, &data->data_rdy_users,
+ SX9311_REG_IRQ_MSK, SX9311_CONVDONE_IRQ);
+}
+
+static int sx9311_inc_close_far_users(struct sx9311_data *data)
+{
+ return sx9311_inc_users(data, &data->close_far_users,
+ SX9311_REG_IRQ_MSK,
+ SX9311_CLOSE_IRQ | SX9311_FAR_IRQ);
+}
+
+static int sx9311_dec_close_far_users(struct sx9311_data *data)
+{
+ return sx9311_dec_users(data, &data->close_far_users,
+ SX9311_REG_IRQ_MSK,
+ SX9311_CLOSE_IRQ | SX9311_FAR_IRQ);
+}
+
+static int sx9311_read_prox_data(struct sx9311_data *data,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ int ret;
+ __be16 regval;
+
+ ret = regmap_write(data->regmap, SX9311_REG_SENSOR_SEL, chan->channel);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, chan->address, &regval, 2);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(be16_to_cpu(regval),
+ (chan->address == SX9311_REG_DIFF_MSB ? 11 : 15));
+
+ return 0;
+}
+
+/*
+ * If we have no interrupt support, we have to wait for a scan period
+ * after enabling a channel to get a result.
+ */
+static int sx9311_wait_for_sample(struct sx9311_data *data)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(data->regmap, SX9311_REG_PROX_CTRL0, &val);
+ if (ret < 0)
+ return ret;
+
+ val = (val & SX9311_SCAN_PERIOD_MASK) >> SX9311_SCAN_PERIOD_SHIFT;
+
+ msleep(sx9311_scan_period_table[val]);
+
+ return 0;
+}
+
+static int sx9311_read_proximity(struct sx9311_data *data,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ int ret;
+
+ mutex_lock(&data->mutex);
+
+ ret = sx9311_inc_chan_users(data, chan->channel & SX9311_CHAN_MASK);
+ if (ret < 0)
+ goto out;
+
+ ret = sx9311_inc_data_rdy_users(data);
+ if (ret < 0)
+ goto out_dec_chan;
+
+ mutex_unlock(&data->mutex);
+
+ if (data->client->irq > 0)
+ ret = wait_for_completion_interruptible(&data->completion);
+ else
+ ret = sx9311_wait_for_sample(data);
+
+ mutex_lock(&data->mutex);
+
+ if (ret < 0)
+ goto out_dec_data_rdy;
+
+ ret = sx9311_read_prox_data(data, chan, val);
+ if (ret < 0)
+ goto out_dec_data_rdy;
+
+ ret = sx9311_dec_data_rdy_users(data);
+ if (ret < 0)
+ goto out_dec_chan;
+
+ ret = sx9311_dec_chan_users(data, chan->channel & SX9311_CHAN_MASK);
+ if (ret < 0)
+ goto out;
+
+ ret = IIO_VAL_INT;
+
+ goto out;
+
+out_dec_data_rdy:
+ sx9311_dec_data_rdy_users(data);
+out_dec_chan:
+ sx9311_dec_chan_users(data, chan->channel & SX9311_CHAN_MASK);
+out:
+ mutex_unlock(&data->mutex);
+ reinit_completion(&data->completion);
+
+ return ret;
+}
+
+static int sx9311_read_samp_freq(struct sx9311_data *data,
+ int *val, int *val2)
+{
+ int ret;
+ unsigned int regval;
+
+ mutex_lock(&data->mutex);
+ ret = regmap_read(data->regmap, SX9311_REG_PROX_CTRL0, &regval);
+
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+
+ regval = (regval & SX9311_SCAN_PERIOD_MASK) >> SX9311_SCAN_PERIOD_SHIFT;
+ *val = sx9311_samp_freq_table[regval].val;
+ *val2 = sx9311_samp_freq_table[regval].val2;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int sx9311_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+
+ if (iio_buffer_enabled(indio_dev)) {
+ mutex_unlock(&indio_dev->mlock);
+ return -EBUSY;
+ }
+ ret = sx9311_read_proximity(data, chan, val);
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return sx9311_read_samp_freq(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sx9311_set_samp_freq(struct sx9311_data *data,
+ int val, int val2)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(sx9311_samp_freq_table); i++)
+ if (val == sx9311_samp_freq_table[i].val &&
+ val2 == sx9311_samp_freq_table[i].val2)
+ break;
+
+ if (i == ARRAY_SIZE(sx9311_samp_freq_table))
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, SX9311_REG_PROX_CTRL0,
+ SX9311_SCAN_PERIOD_MASK,
+ i << SX9311_SCAN_PERIOD_SHIFT);
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9311_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int val, int val2, long mask)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return sx9311_set_samp_freq(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t sx9311_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ if (data->trigger_enabled)
+ iio_trigger_poll(data->trig);
+
+ /*
+ * Even if no event is enabled, we need to wake the thread to
+ * clear the interrupt state by reading SX9311_REG_IRQ_SRC. It
+ * is not possible to do that here because regmap_read takes a
+ * mutex.
+ */
+ return IRQ_WAKE_THREAD;
+}
+
+static void sx9311_push_events(struct iio_dev *indio_dev)
+{
+ int ret;
+ unsigned int val, chan;
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ ret = regmap_read(data->regmap, SX9311_REG_STAT0, &val);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+ return;
+ }
+
+ for (chan = 0; chan < SX9311_NUM_CHANNELS; chan++) {
+ int dir;
+ u64 ev;
+ bool new_prox = val & BIT(chan);
+
+ if (!data->event_enabled[chan])
+ continue;
+ if (new_prox == data->prox_stat[chan])
+ /* No change on this channel. */
+ continue;
+
+ dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
+ IIO_EV_TYPE_THRESH, dir);
+ iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
+ data->prox_stat[chan] = new_prox;
+ }
+}
+
+static irqreturn_t sx9311_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val;
+
+ mutex_lock(&data->mutex);
+
+ ret = regmap_read(data->regmap, SX9311_REG_IRQ_SRC, &val);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+ goto out;
+ }
+
+ if (val & (SX9311_CLOSE_IRQ | SX9311_FAR_IRQ))
+ sx9311_push_events(indio_dev);
+
+ if (val & SX9311_CONVDONE_IRQ)
+ complete(&data->completion);
+
+out:
+ mutex_unlock(&data->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int sx9311_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+ dir != IIO_EV_DIR_EITHER)
+ return -EINVAL;
+
+ return data->event_enabled[chan->channel & SX9311_CHAN_MASK];
+}
+
+static int sx9311_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret, sx_channel = chan->channel & SX9311_CHAN_MASK;
+
+ if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+ dir != IIO_EV_DIR_EITHER)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+
+ if (state == 1) {
+ ret = sx9311_inc_chan_users(data, sx_channel);
+ if (ret < 0)
+ goto out_unlock;
+ ret = sx9311_inc_close_far_users(data);
+ if (ret < 0)
+ goto out_undo_chan;
+ } else {
+ ret = sx9311_dec_chan_users(data, sx_channel);
+ if (ret < 0)
+ goto out_unlock;
+ ret = sx9311_dec_close_far_users(data);
+ if (ret < 0)
+ goto out_undo_chan;
+ }
+
+ data->event_enabled[sx_channel] = state;
+ goto out_unlock;
+
+out_undo_chan:
+ if (state == 1)
+ sx9311_dec_chan_users(data, sx_channel);
+ else
+ sx9311_inc_chan_users(data, sx_channel);
+out_unlock:
+ mutex_unlock(&data->mutex);
+ return ret;
+}
+
+static int sx9311_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->mutex);
+ kfree(data->buffer);
+ data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ mutex_unlock(&data->mutex);
+
+ if (data->buffer == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct attribute *sx9311_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group sx9311_attribute_group = {
+ .attrs = sx9311_attributes,
+};
+
+static const struct iio_info sx9311_info = {
+ .attrs = &sx9311_attribute_group,
+ .read_raw = &sx9311_read_raw,
+ .write_raw = &sx9311_write_raw,
+ .read_event_config = &sx9311_read_event_config,
+ .write_event_config = &sx9311_write_event_config,
+ .update_scan_mode = &sx9311_update_scan_mode,
+};
+
+static int sx9311_set_trigger_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+
+ if (state)
+ ret = sx9311_inc_data_rdy_users(data);
+ else
+ ret = sx9311_dec_data_rdy_users(data);
+ if (ret < 0)
+ goto out;
+
+ data->trigger_enabled = state;
+
+out:
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops sx9311_trigger_ops = {
+ .set_trigger_state = sx9311_set_trigger_state,
+};
+
+static irqreturn_t sx9311_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int val, bit, ret, i = 0;
+
+ mutex_lock(&data->mutex);
+
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ ret = sx9311_read_prox_data(data, &indio_dev->channels[bit],
+ &val);
+ if (ret < 0)
+ goto out;
+
+ data->buffer[i++] = val;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_get_time_ns(indio_dev));
+
+out:
+ mutex_unlock(&data->mutex);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int sx9311_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret = 0, i;
+
+ mutex_lock(&data->mutex);
+
+ for (i = 0; i < SX9311_NUM_CHANNELS; i++)
+ if (test_bit(i, indio_dev->active_scan_mask)) {
+ ret = sx9311_inc_chan_users(data, i);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ for (i = i - 1; i >= 0; i--)
+ if (test_bit(i, indio_dev->active_scan_mask))
+ sx9311_dec_chan_users(data, i);
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9311_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret = 0, i;
+
+ iio_triggered_buffer_predisable(indio_dev);
+
+ mutex_lock(&data->mutex);
+
+ for (i = 0; i < SX9311_NUM_CHANNELS; i++)
+ if (test_bit(i, indio_dev->active_scan_mask)) {
+ ret = sx9311_dec_chan_users(data, i);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ for (i = i - 1; i >= 0; i--)
+ if (test_bit(i, indio_dev->active_scan_mask))
+ sx9311_inc_chan_users(data, i);
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops sx9311_buffer_setup_ops = {
+ .preenable = sx9311_buffer_preenable,
+ .postenable = iio_triggered_buffer_postenable,
+ .predisable = sx9311_buffer_predisable,
+};
+
+struct sx9311_reg_config {
+ const char *register_name;
+ u8 reg;
+ u8 def;
+};
+
+#define SX9311_REG_CONFIG(_name, _reg, _def) \
+{ \
+ .register_name = SX9311_ACPI_NAME ",reg_" _name, \
+ .reg = SX9311_REG_##_reg, \
+ .def = _def \
+}
+
+static const struct sx9311_reg_config sx9311_default_regs[] = {
+ {
+ .register_name = NULL,
+ .reg = SX9311_REG_IRQ_MSK,
+ .def = 0x60,
+ },
+ {
+ .register_name = NULL,
+ .reg = SX9311_REG_IRQ_FUNC,
+ .def = 0x00,
+ },
+ /*
+ * The lower 4 bits should not be set as it enable sensors measurements.
+ * Turning the detection on before the configuration values are set to
+ * good values can cause the device to return erroneous readings.
+ */
+ SX9311_REG_CONFIG("prox_ctrl0", PROX_CTRL0, 0x23),
+ SX9311_REG_CONFIG("prox_ctrl1", PROX_CTRL1, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl2", PROX_CTRL2, 0x0B),
+ SX9311_REG_CONFIG("prox_ctrl3", PROX_CTRL3, 0x0F),
+ SX9311_REG_CONFIG("prox_ctrl4", PROX_CTRL4, 0x0D),
+ SX9311_REG_CONFIG("prox_ctrl5", PROX_CTRL5, 0xC3),
+ SX9311_REG_CONFIG("prox_ctrl6", PROX_CTRL6, 0x20),
+ SX9311_REG_CONFIG("prox_ctrl7", PROX_CTRL7, 0x4C),
+ SX9311_REG_CONFIG("prox_ctrl8", PROX_CTRL8, 0x68),
+ SX9311_REG_CONFIG("prox_ctrl9", PROX_CTRL9, 0x68),
+ SX9311_REG_CONFIG("prox_ctrl10", PROX_CTRL10, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl11", PROX_CTRL11, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl12", PROX_CTRL12, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl13", PROX_CTRL13, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl14", PROX_CTRL14, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl15", PROX_CTRL15, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl16", PROX_CTRL16, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl17", PROX_CTRL17, 0x04),
+ SX9311_REG_CONFIG("prox_ctrl18", PROX_CTRL18, 0x00),
+ SX9311_REG_CONFIG("prox_ctrl19", PROX_CTRL19, 0x00),
+ SX9311_REG_CONFIG("sar_ctrl0", SAR_CTRL0, 0x00),
+ SX9311_REG_CONFIG("sar_ctrl1", SAR_CTRL1, 0x80),
+ SX9311_REG_CONFIG("sar_ctrl2", SAR_CTRL2, 0x0C),
+};
+
+static int sx9311_read_register_property(struct acpi_device *adev,
+ const struct sx9311_reg_config *cfg,
+ u8 *value)
+{
+ /* FIXME: only ACPI supported. */
+ const union acpi_object *acpi_value = NULL;
+ int ret;
+
+ if ((adev == NULL) || (cfg->register_name == NULL)) {
+ *value = cfg->def;
+ return 0;
+ }
+
+ ret = acpi_dev_get_property(adev, cfg->register_name,
+ ACPI_TYPE_INTEGER, &acpi_value);
+ switch (ret) {
+ case -EPROTO:
+ break;
+ case -EINVAL:
+ break;
+ }
+
+ *value = acpi_value ? (u8)acpi_value->integer.value : cfg->def;
+ return 0;
+}
+
+static int sx9311_load_config(struct device *dev, struct regmap *regmap)
+{
+ u8 val;
+ int i, ret;
+ const struct sx9311_reg_config *cfg;
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+
+ if (adev == NULL)
+ dev_warn(dev, "ACPI configuration missing\n");
+
+ for (i = 0; i < ARRAY_SIZE(sx9311_default_regs); ++i) {
+ cfg = &sx9311_default_regs[i];
+ ret = sx9311_read_register_property(adev, cfg, &val);
+ if (ret < 0)
+ return ret;
+ ret = regmap_write(regmap, cfg->reg, val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Activate all channels and perform an initial compensation. */
+static int sx9311_init_compensation(struct iio_dev *indio_dev)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int i, ret;
+ unsigned int val;
+ unsigned int ctrl0;
+
+ ret = regmap_read(data->regmap, SX9311_REG_PROX_CTRL0, &ctrl0);
+ if (ret < 0)
+ return ret;
+
+ /* run the compensation phase on all channels */
+ ret = regmap_write(data->regmap, SX9311_REG_PROX_CTRL0, ctrl0 | 0xF);
+ if (ret < 0)
+ return ret;
+
+ for (i = 100; i >= 0; i--) {
+ usleep_range(10000, 20000);
+ ret = regmap_read(data->regmap, SX9311_REG_STAT1, &val);
+ if (ret < 0)
+ goto out;
+ if (!(val & SX9311_COMPSTAT_MASK))
+ break;
+ }
+
+ if (i < 0) {
+ dev_err(&data->client->dev,
+ "initial compensation timed out: 0x%02x", val);
+ ret = -ETIMEDOUT;
+ }
+
+out:
+ regmap_write(data->regmap, SX9311_REG_PROX_CTRL0, ctrl0);
+ return ret;
+}
+
+static int sx9311_init_device(struct iio_dev *indio_dev)
+{
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val;
+
+ ret = regmap_write(data->regmap, SX9311_REG_IRQ_MSK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, SX9311_REG_RESET,
+ SX9311_SOFT_RESET);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 2000); /* power-up time is ~1ms. */
+
+ ret = regmap_write(data->regmap, SX9311_REG_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, SX9311_REG_IRQ_SRC, &val);
+ if (ret < 0)
+ return ret;
+
+ ret = sx9311_load_config(&indio_dev->dev, data->regmap);
+ if (ret < 0)
+ return ret;
+
+ return sx9311_init_compensation(indio_dev);
+}
+
+static int sx9311_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct sx9311_data *data;
+ unsigned int whoami;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ mutex_init(&data->mutex);
+ init_completion(&data->completion);
+ data->trigger_enabled = false;
+
+ data->regmap = devm_regmap_init_i2c(client, &sx9311_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ ret = regmap_read(data->regmap, SX9311_REG_WHOAMI, &whoami);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "error in reading WHOAMI register: %d", ret);
+ return -ENODEV;
+ }
+ if (whoami != SX9311_WHOAMI_VALUE) {
+ dev_err(&client->dev, "unexpected WHOAMI response: %u", whoami);
+ return -ENODEV;
+ }
+
+ ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(&client->dev));
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = SX9311_DRIVER_NAME;
+ indio_dev->channels = sx9311_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sx9311_channels);
+ indio_dev->info = &sx9311_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = sx9311_init_device(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ if (client->irq <= 0)
+ dev_warn(&client->dev, "no valid irq found\n");
+ else {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ sx9311_irq_handler, sx9311_irq_thread_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ SX9311_IRQ_NAME, indio_dev);
+ if (ret < 0)
+ return ret;
+
+ data->trig = devm_iio_trigger_alloc(&client->dev,
+ "%s-dev%d", indio_dev->name, indio_dev->id);
+ if (!data->trig)
+ return -ENOMEM;
+
+ data->trig->dev.parent = &client->dev;
+ data->trig->ops = &sx9311_trigger_ops;
+ iio_trigger_set_drvdata(data->trig, indio_dev);
+
+ ret = iio_trigger_register(data->trig);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
+ NULL, sx9311_trigger_handler,
+ &sx9311_buffer_setup_ops);
+ if (ret < 0)
+ goto out_trigger_unregister;
+
+ ret = devm_iio_device_register(&client->dev, indio_dev);
+ if (ret < 0)
+ goto out_trigger_unregister;
+
+ return 0;
+
+out_trigger_unregister:
+ if (client->irq > 0)
+ iio_trigger_unregister(data->trig);
+
+ return ret;
+}
+
+static int sx9311_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct sx9311_data *data = iio_priv(indio_dev);
+
+ if (client->irq > 0)
+ iio_trigger_unregister(data->trig);
+ kfree(data->buffer);
+ return 0;
+}
+
+static int __maybe_unused sx9311_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+
+ disable_irq_nosync(data->client->irq);
+
+ mutex_lock(&data->mutex);
+ ret = regmap_write(data->regmap, SX9311_REG_PAUSE, 0);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int __maybe_unused sx9311_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct sx9311_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = regmap_write(data->regmap, SX9311_REG_PAUSE, 1);
+ mutex_unlock(&data->mutex);
+
+ enable_irq(data->client->irq);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sx9311_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sx9311_suspend, sx9311_resume)
+};
+
+static const struct acpi_device_id sx9311_acpi_match[] = {
+ {SX9311_ACPI_NAME, 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, sx9311_acpi_match);
+
+static const struct of_device_id sx9311_of_match[] = {
+ { .compatible = "semtech," SX9311_DRIVER_NAME, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sx9311_of_match);
+
+static const struct i2c_device_id sx9311_id[] = {
+ {SX9311_DRIVER_NAME, 0},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sx9311_id);
+
+static struct i2c_driver sx9311_driver = {
+ .driver = {
+ .name = SX9311_DRIVER_NAME,
+ .acpi_match_table = ACPI_PTR(sx9311_acpi_match),
+ .of_match_table = of_match_ptr(sx9311_of_match),
+ .pm = &sx9311_pm_ops,
+ },
+ .probe = sx9311_probe,
+ .remove = sx9311_remove,
+ .id_table = sx9311_id,
+};
+module_i2c_driver(sx9311_driver);
+
+MODULE_AUTHOR("Phoenix Wu <wujing6@huaqin.corp-partner.google.com>");
+MODULE_DESCRIPTION("Driver for Semtech SX9311 proximity sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 80a38ad0db15a..24cbdb04764da 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2454,7 +2454,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
goto err_hif_stop;
}
- status = ath10k_hif_swap_mailbox(ar);
+ status = ath10k_hif_swap_mailbox(ar, mode);
if (status) {
ath10k_err(ar, "failed to swap mailbox: %d\n", status);
goto err_hif_stop;
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 5f7f1e08866f8..5c342a1a2b9a7 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -59,7 +59,7 @@ struct ath10k_hif_ops {
*/
void (*stop)(struct ath10k *ar);
- int (*swap_mailbox)(struct ath10k *ar);
+ int (*swap_mailbox)(struct ath10k *ar, enum ath10k_firmware_mode mode);
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe);
@@ -141,10 +141,10 @@ static inline void ath10k_hif_stop(struct ath10k *ar)
return ar->hif.ops->stop(ar);
}
-static inline int ath10k_hif_swap_mailbox(struct ath10k *ar)
+static inline int ath10k_hif_swap_mailbox(struct ath10k *ar, enum ath10k_firmware_mode mode)
{
if (ar->hif.ops->swap_mailbox)
- return ar->hif.ops->swap_mailbox(ar);
+ return ar->hif.ops->swap_mailbox(ar, mode);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 1ea6d2dc2f290..938685a6d594b 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -1629,7 +1629,7 @@ static int ath10k_sdio_hif_diag_write_mem(struct ath10k *ar, u32 address,
return 0;
}
-static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
+static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar, enum ath10k_firmware_mode mode)
{
struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
u32 addr, val;
@@ -1648,6 +1648,9 @@ static int ath10k_sdio_hif_swap_mailbox(struct ath10k *ar)
"sdio mailbox swap service enabled\n");
ar_sdio->swap_mbox = true;
}
+
+ if(mode == ATH10K_FIRMWARE_MODE_UTF)
+ ar_sdio->swap_mbox = false;
return 0;
}
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
old mode 100644
new mode 100755
index e4ea7f6aef20e..61a18c0d271c7
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -219,6 +219,9 @@ enum {
/* The total number of temperature sensors in the MT8183 */
#define MT8183_NUM_SENSORS 6
+/* The number of banks in the MT8183 */
+#define MT8183_NUM_ZONES 5
+
/* The number of sensing points per bank */
#define MT8183_NUM_SENSORS_PER_ZONE 6
@@ -275,8 +278,12 @@ struct mtk_thermal {
};
/* MT8183 thermal sensor data */
-static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
- MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
+static const int mt8183_bank_data[MT8183_NUM_ZONES][2] = {
+ {MT8183_TS1},
+ {MT8183_TS2},
+ {MT8183_TS3},
+ {MT8183_TS4},
+ {MT8183_TS5},
};
static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
@@ -506,7 +513,7 @@ static const struct mtk_thermal_data mt7622_thermal_data = {
static const struct mtk_thermal_data mt8183_thermal_data = {
.auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
- .num_banks = MT8183_NUM_SENSORS_PER_ZONE,
+ .num_banks = MT8183_NUM_ZONES,
.num_sensors = MT8183_NUM_SENSORS,
.vts_index = mt8183_vts_index,
.cali_val = MT8183_CALIBRATION,
@@ -515,8 +522,24 @@ static const struct mtk_thermal_data mt8183_thermal_data = {
.need_switch_bank = false,
.bank_data = {
{
- .num_sensors = 6,
- .sensors = mt8183_bank_data,
+ .num_sensors = 1,
+ .sensors = mt8183_bank_data[0],
+ },
+ {
+ .num_sensors = 1,
+ .sensors = mt8183_bank_data[1],
+ },
+ {
+ .num_sensors = 1,
+ .sensors = mt8183_bank_data[2],
+ },
+ {
+ .num_sensors = 1,
+ .sensors = mt8183_bank_data[3],
+ },
+ {
+ .num_sensors = 1,
+ .sensors = mt8183_bank_data[4],
},
},
@@ -605,7 +628,6 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
temp = raw_to_mcelsius(mt,
conf->bank_data[bank->id].sensors[i],
raw);
-
/*
* The first read of a sensor often contains very high bogus
* temperature value. Filter these out so that the system does
@@ -617,7 +639,6 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
if (temp > max)
max = temp;
}
-
return max;
}
@@ -642,10 +663,80 @@ static int mtk_read_temp(void *data, int *temperature)
return 0;
}
+static int mtk_read_zone1_temp(void *data, int *temperature)
+{
+ struct mtk_thermal *mt = data;
+ struct mtk_thermal_bank *bank = &mt->banks[0];
+
+ *temperature = mtk_thermal_bank_temperature(bank);
+
+ return 0;
+}
+
+static int mtk_read_zone2_temp(void *data, int *temperature)
+{
+ struct mtk_thermal *mt = data;
+ struct mtk_thermal_bank *bank = &mt->banks[1];
+
+ *temperature = mtk_thermal_bank_temperature(bank);
+
+ return 0;
+}
+
+static int mtk_read_zone3_temp(void *data, int *temperature)
+{
+ struct mtk_thermal *mt = data;
+ struct mtk_thermal_bank *bank = &mt->banks[2];
+
+ *temperature = mtk_thermal_bank_temperature(bank);
+
+ return 0;
+}
+
+static int mtk_read_zone4_temp(void *data, int *temperature)
+{
+ struct mtk_thermal *mt = data;
+ struct mtk_thermal_bank *bank = &mt->banks[3];
+
+ *temperature = mtk_thermal_bank_temperature(bank);
+
+ return 0;
+}
+
+static int mtk_read_zone5_temp(void *data, int *temperature)
+{
+ struct mtk_thermal *mt = data;
+ struct mtk_thermal_bank *bank = &mt->banks[4];
+
+ *temperature = mtk_thermal_bank_temperature(bank);
+
+ return 0;
+}
+
static const struct thermal_zone_of_device_ops mtk_thermal_ops = {
.get_temp = mtk_read_temp,
};
+static const struct thermal_zone_of_device_ops mtk_thermal_zone1_ops = {
+ .get_temp = mtk_read_zone1_temp,
+};
+
+static const struct thermal_zone_of_device_ops mtk_thermal_zone2_ops = {
+ .get_temp = mtk_read_zone2_temp,
+};
+
+static const struct thermal_zone_of_device_ops mtk_thermal_zone3_ops = {
+ .get_temp = mtk_read_zone3_temp,
+};
+
+static const struct thermal_zone_of_device_ops mtk_thermal_zone4_ops = {
+ .get_temp = mtk_read_zone4_temp,
+};
+
+static const struct thermal_zone_of_device_ops mtk_thermal_zone5_ops = {
+ .get_temp = mtk_read_zone5_temp,
+};
+
static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
u32 apmixed_phys_base, u32 auxadc_phys_base,
int ctrl_id)
@@ -960,7 +1051,17 @@ static int mtk_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mt);
tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt,
- &mtk_thermal_ops);
+ &mtk_thermal_ops);
+ tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 1, mt,
+ &mtk_thermal_zone1_ops);
+ tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 2, mt,
+ &mtk_thermal_zone2_ops);
+ tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 3, mt,
+ &mtk_thermal_zone3_ops);
+ tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 4, mt,
+ &mtk_thermal_zone4_ops);
+ tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 5, mt,
+ &mtk_thermal_zone5_ops);
if (IS_ERR(tzdev)) {
ret = PTR_ERR(tzdev);
goto err_disable_clk_peri_therm;
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 8c738c0e6e9f7..e136e3a3c9964 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -37,6 +37,8 @@ struct display_timing;
* struct drm_panel_funcs - perform operations on a given panel
* @disable: disable panel (turn off back light, etc.)
* @unprepare: turn off panel
+ * @detach: detach panel->connector (clear internal state, etc.)
+ * @attach: attach panel->connector (update internal state, etc.)
* @prepare: turn on panel and perform set up
* @enable: enable panel (turn on back light, etc.)
* @get_modes: add modes to the connector that the panel is attached to and
@@ -70,6 +72,8 @@ struct display_timing;
struct drm_panel_funcs {
int (*disable)(struct drm_panel *panel);
int (*unprepare)(struct drm_panel *panel);
+ void (*detach)(struct drm_panel *panel);
+ int (*attach)(struct drm_panel *panel);
int (*prepare)(struct drm_panel *panel);
int (*enable)(struct drm_panel *panel);
int (*get_modes)(struct drm_panel *panel);
@@ -197,11 +201,18 @@ int drm_panel_detach(struct drm_panel *panel);
#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
+int of_drm_get_panel_orientation(const struct device_node *np,
+ int *orientation);
#else
static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
{
return ERR_PTR(-ENODEV);
}
+int of_drm_get_panel_orientation(const struct device_node *np,
+ int *orientation)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 9aac1fda94c88..cfecbdaa5853b 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -69,12 +69,54 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
return 0;
}
+static const char * const ext_spk_text[] = {
+ "Off", "On"
+};
+
+static const struct soc_enum ext_spk_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(ext_spk_text), ext_spk_text);
+
+
+static const struct snd_kcontrol_new ext_spk_mux =
+ SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum);
+
+
+static int max98357a_enable_spk_pa(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 max98357a_priv *max98357a = snd_soc_component_get_drvdata(cmpnt);
+
+ if (!max98357a->sdmode)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ queue_delayed_work(system_power_efficient_wq,
+ &max98357a->enable_sdmode_work,
+ msecs_to_jiffies(max98357a->sdmode_delay));
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ cancel_delayed_work(&max98357a->enable_sdmode_work);
+ gpiod_set_value(max98357a->sdmode, 0);
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Speaker"),
+ SND_SOC_DAPM_SPK("Spk PA", max98357a_enable_spk_pa),
+ SND_SOC_DAPM_MUX("Spk PA Switch", SND_SOC_NOPM, 0, 0,
+ &ext_spk_mux),
};
static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
{"Speaker", NULL, "HiFi Playback"},
+ {"Speaker", NULL, "Spk PA"},
+ {"Spk PA", NULL, "Spk PA Switch"},
+ {"Spk PA Switch", "On", "HiFi Playback1"},
};
static int max98357a_component_probe(struct snd_soc_component *component)
@@ -119,23 +161,43 @@ static const struct snd_soc_dai_ops max98357a_dai_ops = {
.trigger = max98357a_daiops_trigger,
};
-static struct snd_soc_dai_driver max98357a_dai_driver = {
- .name = "HiFi",
- .playback = {
- .stream_name = "HiFi Playback",
- .formats = SNDRV_PCM_FMTBIT_S16 |
- SNDRV_PCM_FMTBIT_S24 |
- SNDRV_PCM_FMTBIT_S32,
- .rates = SNDRV_PCM_RATE_8000 |
- SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_96000,
- .rate_min = 8000,
- .rate_max = 96000,
- .channels_min = 1,
- .channels_max = 2,
+static struct snd_soc_dai_driver max98357a_dai_driver[] = {
+ {
+ .name = "HiFi",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .formats = SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &max98357a_dai_ops,
+ },
+ {
+ .name = "max98357a-hifi",
+ .playback = {
+ .stream_name = "HiFi Playback1",
+ .formats = SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_S24 |
+ SNDRV_PCM_FMTBIT_S32,
+ .rates = SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = NULL,
},
- .ops = &max98357a_dai_ops,
};
static int max98357a_platform_probe(struct platform_device *pdev)
@@ -161,7 +223,7 @@ static int max98357a_platform_probe(struct platform_device *pdev)
return devm_snd_soc_register_component(&pdev->dev,
&max98357a_component_driver,
- &max98357a_dai_driver, 1);
+ max98357a_dai_driver, ARRAY_SIZE(max98357a_dai_driver));
}
static int max98357a_platform_remove(struct platform_device *pdev)
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
old mode 100644
new mode 100755
index 1e7e8aed87078..c25ed84e21175
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -34,7 +34,7 @@ static struct snd_soc_dai_link_component
mt8183_da7219_max98357_external_codecs[] = {
{
.name = "max98357a",
- .dai_name = "HiFi",
+ .dai_name = "max98357a-hifi",
},
{
.name = "da7219.5-001a",
--
2.22.0.rc1.257.g3120a18244-goog