diff -Naur a/src/meta-mediatek-bsp/classes/image_type_aiotflash.bbclass b/src/meta-mediatek-bsp/classes/image_type_aiotflash.bbclass --- a/src/meta-mediatek-bsp/classes/image_type_aiotflash.bbclass 2023-06-06 14:42:15.379971818 +0800 +++ b/src/meta-mediatek-bsp/classes/image_type_aiotflash.bbclass 2023-06-06 11:40:50.464905651 +0800 @@ -44,6 +44,7 @@ cp -a ${DEPLOY_DIR_IMAGE}/rity.json ${tmp_pack_dir} cp -a ${DEPLOY_DIR_IMAGE}/partitions.json ${tmp_pack_dir} cp -a ${DEPLOY_DIR_IMAGE}/lk.bin ${tmp_pack_dir} + cp -a ${DEPLOY_DIR_IMAGE}/devicetree ${tmp_pack_dir} if [ "${@oe.utils.conditional('BL2_SIGN_ENABLE', '1', '1', '', d)}" = "1" ]; then cp -a ${DEPLOY_DIR_IMAGE}/efuse.cfg ${tmp_pack_dir} diff -Naur a/src/meta-mediatek-bsp/conf/machine/mt8365-sb35.conf b/src/meta-mediatek-bsp/conf/machine/mt8365-sb35.conf --- a/src/meta-mediatek-bsp/conf/machine/mt8365-sb35.conf 2023-06-06 14:42:15.383971808 +0800 +++ b/src/meta-mediatek-bsp/conf/machine/mt8365-sb35.conf 2023-06-06 11:40:50.464905651 +0800 @@ -5,11 +5,11 @@ KERNEL_DEVICETREE = "mediatek/mt8365-sb35.dtb" # U-Boot -UBOOT_MACHINE = "mt8365_pumpkin_defconfig" +UBOOT_MACHINE = "mt8365_sb35_defconfig" # libdram LIBDRAM_BOARD_NAME = "mt8365-sb35" -MACHINE_FEATURES:append = " alsa usbgadget usbhost wifi" +MACHINE_FEATURES:append = " alsa usbgadget usbhost wifi screen" MACHINEOVERRIDES =. "mt8365-sb35:i350-sb35:genio-350-sb35:" diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.conf b/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.conf --- a/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.conf 2023-06-06 14:42:15.387971797 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.conf 2023-06-06 11:40:50.468905742 +0800 @@ -22,6 +22,14 @@ } } +pcm.speaker { + type plug + slave { + pcm "hw:mtsndcard,1,0" + channels 2 + } +} + pcm.line { type asym playback.pcm "jack_speaker" diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.state b/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.state --- a/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.state 2023-06-06 14:42:15.387971797 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/alsa-state/mt8365-sb35/asound.state 2023-06-06 11:40:50.468905742 +0800 @@ -12,7 +12,7 @@ control.2 { iface MIXER name 'O00 I07 Switch' - value false + value true comment { access 'read write' type BOOLEAN @@ -32,7 +32,7 @@ control.4 { iface MIXER name 'O01 I08 Switch' - value false + value true comment { access 'read write' type BOOLEAN diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-mtk_2.6.inc b/src/meta-mediatek-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-mtk_2.6.inc --- a/src/meta-mediatek-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-mtk_2.6.inc 2023-06-06 14:42:15.391971786 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/trusted-firmware-a/trusted-firmware-a-mtk_2.6.inc 2023-06-06 11:40:50.472905833 +0800 @@ -5,6 +5,6 @@ " SRC_URI = "${AIOT_BSP_URI}/trusted-firmware-a.git;name=tfa;branch=mtk-v2.6;protocol=ssh" -SRCREV_tfa = "739772abf2fea0ffa8ea68613a9ea4ebe7c1af47" +SRCREV_tfa = "31d4d84a48551686f5ae1916c8fb6416ca16a83b" SRC_URI += "file://rot_key.pem" diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Add-dedicated-sb35-defconfig-and-dts-files.patch b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Add-dedicated-sb35-defconfig-and-dts-files.patch --- a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Add-dedicated-sb35-defconfig-and-dts-files.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Add-dedicated-sb35-defconfig-and-dts-files.patch 2023-06-06 11:40:50.472905833 +0800 @@ -0,0 +1,302 @@ +From 05bb8f47e4d376d05f30ef95b170ac51aaac6478 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Wed, 24 May 2023 12:18:47 +0800 +Subject: [PATCH 1/1] Add dedicated sb35 defconfig and dts files + +The defconfig and dts files are copied from mt8365-pumpkin. +--- + arch/arm/dts/Makefile | 1 + + arch/arm/dts/mt8365-sb35.dts | 164 ++++++++++++++++++++++++++++++++++ + configs/mt8365_sb35_defconfig | 97 ++++++++++++++++++++ + 3 files changed, 262 insertions(+) + create mode 100644 arch/arm/dts/mt8365-sb35.dts + create mode 100644 configs/mt8365_sb35_defconfig + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +index 7b216bf62a..ac852fab60 100644 +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -1237,6 +1237,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt8195-demo.dtb \ + mt8195-evb-ufs.dtb \ + mt8365-pumpkin.dtb \ ++ mt8365-sb35.dtb \ + mt8512-bm1-emmc.dtb \ + mt8516-pumpkin.dtb \ + mt8518-ap1-emmc.dtb \ +diff --git a/arch/arm/dts/mt8365-sb35.dts b/arch/arm/dts/mt8365-sb35.dts +new file mode 100644 +index 0000000000..5f57657026 +--- /dev/null ++++ b/arch/arm/dts/mt8365-sb35.dts +@@ -0,0 +1,164 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2021 BayLibre SAS. ++ * Author: Fabien Parent ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "mt8365.dtsi" ++#include "mt6357.dtsi" ++ ++/ { ++ model = "MT8365 SB35 board"; ++ compatible = "mediatek,mt8365-sb35", "mediatek,mt8365"; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0 0x40000000 0 0x40000000>; ++ }; ++ ++ firmware: firmware { ++ optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ }; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ ++ bl31_secmon_reserved: secmon@43000000 { ++ no-map; ++ reg = <0 0x43000000 0 0x30000>; ++ }; ++ ++ /* 12 MiB reserved for OP-TEE (BL32) ++ * +-----------------------+ 0x43e0_0000 ++ * | SHMEM 2MiB | ++ * +-----------------------+ 0x43c0_0000 ++ * | | TA_RAM 8MiB | ++ * + TZDRAM +--------------+ 0x4340_0000 ++ * | | TEE_RAM 2MiB | ++ * +-----------------------+ 0x4320_0000 ++ */ ++ optee_reserved: optee@43200000 { ++ no-map; ++ reg = <0 0x43200000 0 0x00c00000>; ++ }; ++ }; ++ ++ chosen { ++ stdout-path = &uart0; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&mmc0 { ++ bus-width = <4>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ cap-mmc-hw-reset; ++ vmmc-supply = <&mt6357_vemc_reg>; ++ vqmmc-supply = <&mt6357_vio18_reg>; ++ non-removable; ++ status = "okay"; ++}; ++ ++&usb { ++ status = "okay"; ++}; ++ ++&ssusb { ++ mediatek,force-vbus; ++ maximum-speed = "high-speed"; ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&dpi0 { ++ dpi_dual_edge; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&dpi_pin_func>; ++ pinctrl-1 = <&dpi_pin_gpio>; ++ status = "okay"; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins_default>; ++ clock-frequency = <100000>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins_default>; ++ clock-frequency = <100000>; ++ status = "okay"; ++ ++ it66121hdmitx { ++ compatible = "ite,it66121"; ++ reg = <0x4c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ite_pins_default>; ++ vcn33-supply = <&mt6357_vcn33_bt_reg>; ++ vcn18-supply = <&mt6357_vcn18_reg>; ++ vrf12-supply = <&mt6357_vrf12_reg>; ++ reset-gpios = <&gpio 69 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_pins_default>; ++ clock-frequency = <100000>; ++ status = "okay"; ++}; ++ ++&pio { ++ dpi_pin_func: dpi_pin_func { ++ function = "dpi"; ++ groups = "dpi_enable"; ++ }; ++ ++ dpi_pin_gpio: dpi_pin_gpio { ++ function = "dpi"; ++ groups = "dpi_sleep"; ++ }; ++ ++ i2c0_pins_default: i2c0_pins_default { ++ function = "i2c"; ++ groups = "i2c0"; ++ }; ++ ++ i2c1_pins_default: i2c1_pins_default { ++ function = "i2c"; ++ groups = "i2c1"; ++ }; ++ ++ i2c2_pins_default: i2c2_pins_default { ++ function = "i2c"; ++ groups = "i2c2"; ++ }; ++ ++ ite_pins_default: ite_pins_default { ++ pins_rst_ite { ++ pinmux = ; ++ output-high; ++ }; ++ ++ pins_irq_ite { ++ pinmux = ; ++ input-enable; ++ }; ++ }; ++}; +diff --git a/configs/mt8365_sb35_defconfig b/configs/mt8365_sb35_defconfig +new file mode 100644 +index 0000000000..3c25705aab +--- /dev/null ++++ b/configs/mt8365_sb35_defconfig +@@ -0,0 +1,97 @@ ++CONFIG_ARM=y ++CONFIG_COUNTER_FREQUENCY=13000000 ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_SYS_TEXT_BASE=0x4c000000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_ENV_SIZE=0x1000 ++CONFIG_ENV_OFFSET=0x0 ++CONFIG_DM_GPIO=y ++CONFIG_DEFAULT_DEVICE_TREE="mt8365-sb35" ++CONFIG_TARGET_MT8365=y ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=26000000 ++CONFIG_SYS_LOAD_ADDR=0x4c000000 ++CONFIG_DEBUG_UART=y ++CONFIG_ENV_VARS_UBOOT_CONFIG=y ++# CONFIG_ANDROID_BOOT_IMAGE is not set ++CONFIG_FIT=y ++# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set ++CONFIG_USE_BOOTCOMMAND=y ++CONFIG_BOOTCOMMAND="run distro_bootcmd" ++CONFIG_DEFAULT_FDT_FILE="mt8365-sb35" ++# CONFIG_DISPLAY_BOARDINFO is not set ++CONFIG_HUSH_PARSER=y ++# CONFIG_CMD_CONSOLE is not set ++# CONFIG_CMD_BOOTD is not set ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_GO is not set ++# CONFIG_CMD_IMI is not set ++# CONFIG_CMD_XIMG is not set ++# CONFIG_CMD_CRC32 is not set ++CONFIG_CMD_CLK=y ++CONFIG_CMD_DFU=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_GPT=y ++# CONFIG_RANDOM_UUID is not set ++CONFIG_CMD_I2C=y ++# CONFIG_CMD_LOADB is not set ++# CONFIG_CMD_LOADS is not set ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_USB_MASS_STORAGE=y ++# CONFIG_CMD_ITEST is not set ++CONFIG_CMD_DHCP=y ++# CONFIG_CMD_BLOCK_CACHE is not set ++CONFIG_CMD_SYSBOOT=y ++CONFIG_CMD_EXT4=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_ISO_PARTITION=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_SYS_MMC_ENV_PART=2 ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_ENV_IMPORT_FDT=y ++CONFIG_DEVRES=y ++CONFIG_CLK=y ++CONFIG_DFU_MMC=y ++CONFIG_USB_FUNCTION_FASTBOOT=y ++CONFIG_FASTBOOT_BUF_ADDR=0x4d000000 ++CONFIG_FASTBOOT_BUF_SIZE=0x8000000 ++CONFIG_FASTBOOT_FLASH=y ++CONFIG_FASTBOOT_FLASH_MMC_DEV=0 ++CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y ++CONFIG_DM_I2C=y ++CONFIG_SYS_I2C_MTK=y ++# CONFIG_INPUT is not set ++# CONFIG_MMC_QUIRKS is not set ++CONFIG_MMC_MTK=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT8365=y ++CONFIG_DM_RTC=y ++CONFIG_RTC_EMULATION=y ++CONFIG_BAUDRATE=921600 ++CONFIG_DM_SERIAL=y ++CONFIG_DEBUG_UART_ANNOUNCE=y ++CONFIG_MTK_SERIAL=y ++CONFIG_USB=y ++CONFIG_DM_USB_GADGET=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_MTU3=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_KEYBOARD=y ++CONFIG_USB_HOST_ETHER=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_VENDOR_NUM=0x0e8d ++CONFIG_USB_GADGET_PRODUCT_NUM=0x201c ++CONFIG_USB_ETHER=y ++CONFIG_WDT=y ++CONFIG_WDT_MTK=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_LMB_MAX_REGIONS=16 +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Set-bootdelay-to-0-to-save-3secs-of-booting-time.patch b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Set-bootdelay-to-0-to-save-3secs-of-booting-time.patch --- a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Set-bootdelay-to-0-to-save-3secs-of-booting-time.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0001-Set-bootdelay-to-0-to-save-3secs-of-booting-time.patch 2023-06-06 11:40:50.472905833 +0800 @@ -0,0 +1,22 @@ +From 6061bcfb8f1dfc47714beae179be4bc4e4223062 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Fri, 7 Apr 2023 03:29:44 +0000 +Subject: [PATCH] Set bootdelay to 0 to save ~3secs of booting time + +Set bootdelay to 0 to save ~3secs of booting time +--- + configs/mt8365_sb35_defconfig | 1 + + 1 files changed, 1 insertions(+) + +diff --git a/configs/mt8365_sb35_defconfig b/configs/mt8365_sb35_defconfig +index 204b97244b..ccf8c26892 100644 +--- a/configs/mt8365_sb35_defconfig ++++ b/configs/mt8365_sb35_defconfig +@@ -96,3 +96,4 @@ CONFIG_WDT=y + CONFIG_WDT_MTK=y + CONFIG_OF_LIBFDT_OVERLAY=y + CONFIG_LMB_MAX_REGIONS=16 ++CONFIG_BOOTDELAY=0 +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0002-Remove-DPI-and-it66121-from-sb35-dts.patch b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0002-Remove-DPI-and-it66121-from-sb35-dts.patch --- a/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0002-Remove-DPI-and-it66121-from-sb35-dts.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/u-boot/files/0002-Remove-DPI-and-it66121-from-sb35-dts.patch 2023-06-06 11:40:50.472905833 +0800 @@ -0,0 +1,120 @@ +From 29ec664a6ac95151a2967527c1a9d04603aa62c3 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Wed, 24 May 2023 12:57:31 +0800 +Subject: [PATCH 1/1] Remove DPI and it66121 from sb35 dts + +The HDMI bridge on SB35 EVK is lt9611 and interface is DSI, so remove +DPI and it66121 nodes. + +The lt9611 node is added but disable it because MTK DSI is still not supported yet. +--- + arch/arm/dts/mt8365-sb35.dts | 66 +++++++++++++++++++----------------- + 1 file changed, 35 insertions(+), 31 deletions(-) + +diff --git a/arch/arm/dts/mt8365-sb35.dts b/arch/arm/dts/mt8365-sb35.dts +index 5f57657026..b645d276a6 100644 +--- a/arch/arm/dts/mt8365-sb35.dts ++++ b/arch/arm/dts/mt8365-sb35.dts +@@ -84,14 +84,6 @@ + status = "okay"; + }; + +-&dpi0 { +- dpi_dual_edge; +- pinctrl-names = "default", "sleep"; +- pinctrl-0 = <&dpi_pin_func>; +- pinctrl-1 = <&dpi_pin_gpio>; +- status = "okay"; +-}; +- + &i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_default>; +@@ -105,16 +97,15 @@ + clock-frequency = <100000>; + status = "okay"; + +- it66121hdmitx { +- compatible = "ite,it66121"; ++#if 0 ++ lt9611hdmitx { ++ compatible = "lontium,lt9611"; + reg = <0x4c>; + pinctrl-names = "default"; +- pinctrl-0 = <&ite_pins_default>; +- vcn33-supply = <&mt6357_vcn33_bt_reg>; +- vcn18-supply = <&mt6357_vcn18_reg>; +- vrf12-supply = <&mt6357_vrf12_reg>; +- reset-gpios = <&gpio 69 GPIO_ACTIVE_LOW>; ++ pinctrl-0 = <&hdmi_pins_default>; ++ reset-gpios = <&gpio 20 GPIO_ACTIVE_LOW>; + }; ++#endif + }; + + &i2c2 { +@@ -125,16 +116,6 @@ + }; + + &pio { +- dpi_pin_func: dpi_pin_func { +- function = "dpi"; +- groups = "dpi_enable"; +- }; +- +- dpi_pin_gpio: dpi_pin_gpio { +- function = "dpi"; +- groups = "dpi_sleep"; +- }; +- + i2c0_pins_default: i2c0_pins_default { + function = "i2c"; + groups = "i2c0"; +@@ -150,15 +131,38 @@ + groups = "i2c2"; + }; + +- ite_pins_default: ite_pins_default { +- pins_rst_ite { +- pinmux = ; +- output-high; ++#if 0 ++ hdmi_pins_default: hdmi_pins_default { ++ pin_pwr_en { ++ pinmux = ; ++ output-low; + }; + +- pins_irq_ite { +- pinmux = ; ++ pin_lt9611_1v8_en { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_rst { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_3v3_en { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_intr { ++ pinmux = ; + input-enable; ++ bias-pull-up; ++ }; ++ ++ pin_dsi_sel { ++ pinmux = ; ++ output-low; + }; + }; ++#endif + }; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-bsp/u-boot/u-boot_git.bb b/src/meta-mediatek-bsp/recipes-bsp/u-boot/u-boot_git.bb --- a/src/meta-mediatek-bsp/recipes-bsp/u-boot/u-boot_git.bb 2023-06-06 14:42:15.391971786 +0800 +++ b/src/meta-mediatek-bsp/recipes-bsp/u-boot/u-boot_git.bb 2023-06-06 11:40:50.472905833 +0800 @@ -4,4 +4,7 @@ SRC_URI += " \ file://0001-Revert-cmd-pxe_utils-Check-fdtcontroladdr-in-label_b.patch \ file://fw_env.config \ + file://0001-Add-dedicated-sb35-defconfig-and-dts-files.patch \ + file://0002-Remove-DPI-and-it66121-from-sb35-dts.patch \ + file://0001-Set-bootdelay-to-0-to-save-3secs-of-booting-time.patch \ " diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/dtbo/dtbo.bb b/src/meta-mediatek-bsp/recipes-kernel/dtbo/dtbo.bb --- a/src/meta-mediatek-bsp/recipes-kernel/dtbo/dtbo.bb 2023-06-06 14:42:15.391971786 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/dtbo/dtbo.bb 2023-06-06 11:40:50.472905833 +0800 @@ -99,6 +99,8 @@ SRC_URI:append:mt8365-sb35 = " \ file://panel-raspberrypi.dts \ + file://rs232.dts \ + file://spidev.dts \ " SRC_URI:append:mt8516-pumpkin = " \ diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/rs232.dts b/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/rs232.dts --- a/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/rs232.dts 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/rs232.dts 2023-06-06 11:40:50.476905923 +0800 @@ -0,0 +1,42 @@ +/dts-v1/; +/plugin/; + +#include +#include + +/ { + fragment@0 { + target = <&pio>; + __overlay__ { + rs232_pins: rs232-pins { + pins_rx { + pinmux = ; + input-enable; + bias-pull-up; + }; + pins_tx_cts_rts { + pinmux = , + , + ; + }; + pins_rs232_shdn { + pinmux = ; + output-high; + }; + pins_rs232_en { + pinmux = ; + output-high; + }; + }; + }; + }; + + fragment@1 { + target = <&uart1>; + __overlay__ { + pinctrl-0 = <&rs232_pins>; + pinctrl-names = "default"; + status = "okay"; + }; + }; +}; diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/spidev.dts b/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/spidev.dts --- a/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/spidev.dts 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/dtbo/mt8365-sb35/spidev.dts 2023-06-06 11:40:50.476905923 +0800 @@ -0,0 +1,38 @@ +/dts-v1/; +/plugin/; + +#include +#include + +/ { + fragment@0 { + target = <&pio>; + __overlay__ { + spi_pins: spi-pins { + pins { + pinmux = , + , + , + ; + bias-disable; + }; + }; + }; + }; + + fragment@1 { + target = <&spi>; + __overlay__ { + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + mediatek,pad-select = <0>; + status = "okay"; + + spidev@0 { + compatible = "mediatek,aiot-board"; + spi-max-frequency = <5000000>; + reg = <0>; + }; + }; + }; +}; diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Add-stereo-mode-support.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Add-stereo-mode-support.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Add-stereo-mode-support.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Add-stereo-mode-support.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,246 @@ +From f0a65dcb3dbd37388aa40250611fb07037eb3e97 Mon Sep 17 00:00:00 2001 +From: Roy Chen +Date: Fri, 26 May 2023 15:33:28 +0800 +Subject: [PATCH] Add stereo mode support + +--- + arch/arm64/boot/dts/mediatek/mt8365-sb35.dts | 23 ++++--- + sound/soc/codecs/rt5509.c | 66 ++++++++++++++------ + sound/soc/codecs/rt5509.h | 7 +++ + sound/soc/mediatek/mt8365/mt8365-sb35.c | 14 ++++- + 4 files changed, 80 insertions(+), 30 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +index bae04d1ab18d..aa57f3444ea2 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +@@ -75,14 +75,19 @@ sound: sound { + pinctrl-5 = <&aud_pins_dmic>; + status = "okay"; + +- dai-link { +- sound-dai = <&afe>; ++ dai-link@0 { + dai-link-name = "2ND I2S BE"; +- +- codec-0 { ++ codec { + sound-dai = <&speaker_amp_left>; + }; + }; ++ ++ dai-link@1 { ++ dai-link-name = "2ND I2S BE 2"; ++ codec { ++ sound-dai = <&speaker_amp_right>; ++ }; ++ }; + }; + + reserved-memory { +@@ -321,17 +326,15 @@ speaker_amp_left:speaker_amp@34 { + reg = <0x34>; + status = "okay"; + #sound-dai-cells = <0>; +- rt5509,boost-mode = <1>; +- rt5509,reg-settings = <0x1f 0x0352>; ++ rt5509,lrs = "left"; + }; + + speaker_amp_right:speaker_amp@35 { + compatible = "richtek,rt5509"; + reg = <0x35>; +- status = "okay"; +- #sound-dai-cells = <0>; +- rt5509,boost-mode = <1>; +- rt5509,reg-settings = <0x1f 0x0352>; ++ status = "okay"; ++ #sound-dai-cells = <0>; ++ rt5509,lrs = "right"; + }; + + hdmi-bridge@3b { +diff --git a/sound/soc/codecs/rt5509.c b/sound/soc/codecs/rt5509.c +index a641797e407e..a43e9d67cd64 100644 +--- a/sound/soc/codecs/rt5509.c ++++ b/sound/soc/codecs/rt5509.c +@@ -2705,8 +2705,6 @@ static const struct snd_kcontrol_new rt5509_component_snd_controls[] = { + rt5509_recv_model_put), + SOC_SINGLE_EXT("Calib_Start", SND_SOC_NOPM, 0, 0, 0, + rt5509_get_calib_flag, rt5509_put_calib_start), +- +- + }; + + static const struct snd_kcontrol_new rt5509_component_snd2_controls[] = { +@@ -2753,7 +2751,6 @@ static const struct snd_kcontrol_new rt5509_component_snd2_controls[] = { + rt5509_recv_model_put), + SOC_SINGLE_EXT("Ch2 Calib_Start", SND_SOC_NOPM, 0, 0, 0, + rt5509_get_calib_flag, rt5509_put_calib_start), +- + }; + + static int rt5509_component_setting(struct snd_soc_component *component) +@@ -3259,9 +3256,24 @@ static inline int rt5509_parse_dt(struct device *dev, + struct device_node *param_np = NULL; + struct property *prop = NULL; + struct rt5509_proprietary_param *p_param = NULL; ++ const char *left_right_sel; + u32 len = 0; + int i = 0; ++ int ret = 0; + ++ ret = device_property_read_string(dev, "rt5509,lrs", &left_right_sel); ++ if (ret >= 0) { ++ if (strcmp(left_right_sel, "left") == 0) { ++ pdata->left_right_sel = RT5509_LEFT_CHANNEL; ++ } else if (strcmp(left_right_sel, "right") == 0) { ++ pdata->left_right_sel = RT5509_RIGHT_CHANNEL; ++ } else { ++ pdata->left_right_sel = RT5509_LEFT_RIGHT_CHANNEL_MIXED; ++ } ++ } else { ++ pdata->left_right_sel = RT5509_LEFT_RIGHT_CHANNEL_MIXED; ++ } ++ + param_np = of_find_node_by_name(dev->of_node, "proprietary_param"); + if (!param_np) + goto OUT_PARSE_DT; +@@ -3296,24 +3308,42 @@ static inline int rt5509_parse_dt(struct device *dev, + } + #endif /* #ifdef CONFIG_OF */ + ++static int rt5509_set_stereo_mode(const struct rt5509_chip *chip) { ++ int ret = 0; ++ u8 data = 0; ++ ++ if (chip->pdata->left_right_sel == RT5509_LEFT_CHANNEL) { ++ data = 0x00; ++ } else if (chip->pdata->left_right_sel == RT5509_RIGHT_CHANNEL) { ++ data = 0x08; ++ } else { ++ // RT5509_LEFT_RIGHT_CHANNEL_MIXED ++ data = 0x04; ++ } ++ ++ ret = rt5509_block_write(chip->i2c, RT5509_REG_I2SSEL, 1, &data); ++ if (ret < 0) { ++ dev_err(chip->dev, "channel selection failed ret=%d\n", ret); ++ } else { ++ dev_info(chip->dev, "channel selection = %d\n", chip->pdata->left_right_sel); ++ } ++ ++ return ret; ++} + + static inline int rt5509_component_register(struct rt5509_chip *chip) + { +- +- if (chip->dev_cnt) +- { +- return devm_snd_soc_register_component(chip->dev, +- &rt5509_component_driver2, +- rt5509_ch2_i2s_dais, +- ARRAY_SIZE(rt5509_ch2_i2s_dais)); +- }else +- { +- return devm_snd_soc_register_component(chip->dev, +- &rt5509_component_driver, +- rt5509_i2s_dais, +- ARRAY_SIZE(rt5509_i2s_dais)); ++ if (chip->dev_cnt) { ++ return devm_snd_soc_register_component(chip->dev, ++ &rt5509_component_driver2, ++ rt5509_ch2_i2s_dais, ++ ARRAY_SIZE(rt5509_ch2_i2s_dais)); ++ } else { ++ return devm_snd_soc_register_component(chip->dev, ++ &rt5509_component_driver, ++ rt5509_i2s_dais, ++ ARRAY_SIZE(rt5509_i2s_dais)); + } +- + } + + static struct regmap_config rt5509_regmap_config = { +@@ -3413,7 +3443,7 @@ int rt5509_i2c_probe(struct i2c_client *client, + if(chip->dev_cnt==0) + rt5509_cal_init(); + +- dev_info(chip->dev, "%s done\n", __func__); ++ rt5509_set_stereo_mode(chip); + return ret; + + probe_fail: +diff --git a/sound/soc/codecs/rt5509.h b/sound/soc/codecs/rt5509.h +index 203b8b2ceefc..1e0b63ae3599 100644 +--- a/sound/soc/codecs/rt5509.h ++++ b/sound/soc/codecs/rt5509.h +@@ -36,6 +36,12 @@ enum { + RT5509_CHIP_REVD, + }; + ++enum { ++ RT5509_LEFT_RIGHT_CHANNEL_MIXED, ++ RT5509_LEFT_CHANNEL, ++ RT5509_RIGHT_CHANNEL, ++}; ++ + enum { + RT5509_CFG_GENERAL, + RT5509_CFG_BOOSTCONV, +@@ -56,6 +62,7 @@ struct rt5509_proprietary_param { + + struct rt5509_pdata { + struct rt5509_proprietary_param *p_param; ++ int left_right_sel; + }; + + struct rt5509_calib_classdev { +diff --git a/sound/soc/mediatek/mt8365/mt8365-sb35.c b/sound/soc/mediatek/mt8365/mt8365-sb35.c +index 27acef137e74..defdcf474fd5 100644 +--- a/sound/soc/mediatek/mt8365/mt8365-sb35.c ++++ b/sound/soc/mediatek/mt8365/mt8365-sb35.c +@@ -67,6 +67,7 @@ enum { + DAI_LINK_VUL_CAPTURE, + /* BE */ + DAI_LINK_2ND_I2S_INTF, ++ DAI_LINK_2ND_I2S_INTF2, + DAI_LINK_DMIC, + DAI_LINK_INT_ADDA, + DAI_LINK_NUM +@@ -75,13 +76,11 @@ enum { + static const struct snd_soc_dapm_widget mt8365_sb35_widgets[] = { + SND_SOC_DAPM_MIC("PMIC MIC", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), +- SND_SOC_DAPM_OUTPUT("HDMI Out"), + }; + + static const struct snd_soc_dapm_route mt8365_sb35_routes[] = { + {"Headphone", NULL, "MT6357 Playback"}, + {"MT6357 Capture", NULL, "PMIC MIC"}, +- {"HDMI Out", NULL, "2ND I2S Playback"}, + }; + + static int mt8365_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -294,6 +293,17 @@ static struct snd_soc_dai_link mt8365_sb35_dais[] = { + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(i2s3), + }, ++ [DAI_LINK_2ND_I2S_INTF2] = { ++ .name = "2ND I2S BE 2", ++ .no_pcm = 1, ++ .id = DAI_LINK_2ND_I2S_INTF2, ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .dpcm_playback = 1, ++ .dpcm_capture = 1, ++ SND_SOC_DAILINK_REG(i2s3), ++ }, + [DAI_LINK_DMIC] = { + .name = "DMIC BE", + .no_pcm = 1, +-- +2.39.2 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Audio-RT5509-driver-porting.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Audio-RT5509-driver-porting.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Audio-RT5509-driver-porting.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Audio-RT5509-driver-porting.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,4206 @@ +From 3d835508c8f0ba77af87f35cf976adfcdd6a81d4 Mon Sep 17 00:00:00 2001 +From: Roy Chen +Date: Tue, 23 May 2023 09:46:04 +0800 +Subject: [PATCH] Audio RT5509 driver porting + +--- + arch/arm64/boot/dts/mediatek/mt8365-sb35.dts | 25 +- + sound/soc/codecs/Kconfig | 5 + + sound/soc/codecs/Makefile | 3 + + sound/soc/codecs/rt5509.c | 3483 ++++++++++++++++++ + sound/soc/codecs/rt5509.h | 481 +++ + sound/soc/mediatek/mt8365/mt8365-sb35.c | 33 +- + 6 files changed, 4024 insertions(+), 6 deletions(-) + create mode 100644 sound/soc/codecs/rt5509.c + create mode 100644 sound/soc/codecs/rt5509.h + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +index e8260faaab55..bae04d1ab18d 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +@@ -74,6 +74,15 @@ sound: sound { + pinctrl-4 = <&aud_pins_default>; + pinctrl-5 = <&aud_pins_dmic>; + status = "okay"; ++ ++ dai-link { ++ sound-dai = <&afe>; ++ dai-link-name = "2ND I2S BE"; ++ ++ codec-0 { ++ sound-dai = <&speaker_amp_left>; ++ }; ++ }; + }; + + reserved-memory { +@@ -307,14 +316,22 @@ &i2c1 { + clock-frequency = <100000>; + status = "okay"; + +- rt5509_left: codec@34 { +- compatible = "realtek,rt5514"; ++ speaker_amp_left:speaker_amp@34 { ++ compatible = "richtek,rt5509"; + reg = <0x34>; ++ status = "okay"; ++ #sound-dai-cells = <0>; ++ rt5509,boost-mode = <1>; ++ rt5509,reg-settings = <0x1f 0x0352>; + }; + +- rt5509_right: codec@35 { +- compatible = "realtek,rt5514"; ++ speaker_amp_right:speaker_amp@35 { ++ compatible = "richtek,rt5509"; + reg = <0x35>; ++ status = "okay"; ++ #sound-dai-cells = <0>; ++ rt5509,boost-mode = <1>; ++ rt5509,reg-settings = <0x1f 0x0352>; + }; + + hdmi-bridge@3b { +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index a2fb0031b342..3977d89674d1 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -226,6 +226,7 @@ config SND_SOC_ALL_CODECS + imply SND_SOC_TLV320AIC3X_I2C + imply SND_SOC_TLV320AIC3X_SPI + imply SND_SOC_TPA6130A2 ++ imply SND_SOC_RT5509 + imply SND_SOC_TLV320DAC33 + imply SND_SOC_TSCS42XX + imply SND_SOC_TSCS454 +@@ -1963,4 +1964,8 @@ config SND_SOC_LPASS_TX_MACRO + select REGMAP_MMIO + tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" + ++config SND_SOC_RT5509 ++ tristate "Richtek RT5509 Smart AMP" ++ depends on I2C ++ + endmenu +diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile +index 67423b98f96d..84bf12e93ca9 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -320,6 +320,8 @@ snd-soc-wm9713-objs := wm9713.o + snd-soc-wm-hubs-objs := wm_hubs.o + snd-soc-wsa881x-objs := wsa881x.o + snd-soc-zl38060-objs := zl38060.o ++snd-soc-rt5509-objs := rt5509.o ++ + # Amp + snd-soc-max9877-objs := max9877.o + snd-soc-max98504-objs := max98504.o +@@ -664,6 +666,7 @@ obj-$(CONFIG_SND_SOC_LPASS_WSA_MACRO) += snd-soc-lpass-wsa-macro.o + obj-$(CONFIG_SND_SOC_LPASS_VA_MACRO) += snd-soc-lpass-va-macro.o + obj-$(CONFIG_SND_SOC_LPASS_RX_MACRO) += snd-soc-lpass-rx-macro.o + obj-$(CONFIG_SND_SOC_LPASS_TX_MACRO) += snd-soc-lpass-tx-macro.o ++obj-$(CONFIG_SND_SOC_RT5509) += snd-soc-rt5509.o + + # Mux + obj-$(CONFIG_SND_SOC_SIMPLE_MUX) += snd-soc-simple-mux.o +diff --git a/sound/soc/codecs/rt5509.c b/sound/soc/codecs/rt5509.c +new file mode 100644 +index 000000000000..a641797e407e +--- /dev/null ++++ b/sound/soc/codecs/rt5509.c +@@ -0,0 +1,3483 @@ ++/* ++ * Copyright (C) 2019 MediaTek Inc. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rt5509.h" ++ ++#if IS_ENABLED(CONFIG_SND_SOC_MTK_AUDIO_DSP) ++#include "richtek_spm_cls.h" ++#endif ++ ++/*---------------------------------------------------*/ ++ ++#include ++#include ++#include ++/* alsa sound header */ ++#include ++/* 64bit integer */ ++#include ++#include ++ ++#define RT5509_CALIB_MAGIC (5526789) ++ ++static struct class *rt5509_cal_class; ++static int calib_status; ++ ++enum { ++ RT5509_CALIB_CTRL_START = 0, ++ RT5509_CALIB_CTRL_DCROFFSET, ++ RT5509_CALIB_CTRL_N20DB, ++ RT5509_CALIB_CTRL_N15DB, ++ RT5509_CALIB_CTRL_N10DB, ++ RT5509_CALIB_CTRL_READOTP, ++ RT5509_CALIB_CTRL_READRAPP, ++ RT5509_CALIB_CTRL_WRITEOTP, ++ RT5509_CALIB_CTRL_WRITEFILE, ++ RT5509_CALIB_CTRL_END, ++ RT5509_CALIB_CTRL_ALLINONE, ++ RT5509_CALIB_CTRL_MAX, ++}; ++ ++static int rt5509_calib_get_dcroffset(struct rt5509_chip *chip) ++{ ++ ++ uint32_t delta_v = 0, vtemp = 0; ++ int ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_VTEMP_TRIM); ++ if (ret < 0) ++ return ret; ++ vtemp = ret & 0xffff; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_VTHRMDATA); ++ if (ret < 0) ++ return ret; ++ ret &= 0xffff; ++ delta_v = (2730 - 400) * (ret - vtemp) / vtemp; ++ return delta_v; ++} ++ ++static int rt5509_calib_chosen_db(struct rt5509_chip *chip, int choose) ++{ ++ u32 data = 0; ++ uint8_t mode_store = 0; ++ int i = 0, ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_BST_MODE); ++ if (ret < 0) ++ return ret; ++ mode_store = ret; ++ ++ data = 0x0080; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_REQ, data); ++ if (ret < 0) ++ return ret; ++ switch (choose) { ++ case RT5509_CALIB_CTRL_N20DB: ++ data = 0x0ccc; ++ break; ++ case RT5509_CALIB_CTRL_N15DB: ++ data = 0x16c3; ++ break; ++ case RT5509_CALIB_CTRL_N10DB: ++ data = 0x287a; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_GAIN, data); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_CTRL); ++ if (ret < 0) ++ return ret; ++ data = ret; ++ data |= 0x80; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_CTRL, data); ++ if (ret < 0) ++ return ret; ++ mdelay(120); ++ while (i++ < 3) { ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_CTRL); ++ if (ret < 0) ++ return ret; ++ if (ret & 0x01) ++ break; ++ mdelay(20); ++ } ++ data &= ~(0x80); ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_CTRL, data); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(chip->component, RT5509_REG_BST_MODE, 0x03, mode_store); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (i > 3) { ++ dev_err(chip->dev, "over ready count\n"); ++ return -EINVAL; ++ } ++ return snd_soc_component_read(chip->component, RT5509_REG_CALIB_OUT0); ++} ++ ++static int rt5509_calib_read_otp(struct rt5509_chip *chip) ++{ ++ ++ int ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_ISENSEGAIN); ++ if (ret < 0) ++ return ret; ++ ret &= 0xffffff; ++ return ret; ++} ++ ++static int rt5509_calib_write_otp(struct rt5509_chip *chip) ++{ ++ uint8_t mode_store = 0; ++ uint32_t param = chip->calib_dev.rspk; ++ uint32_t param_store = 0; ++ uint32_t bst_th = 0; ++ int ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_BST_TH1); ++ if (ret < 0) ++ return ret; ++ bst_th = ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_BST_MODE); ++ if (ret < 0) ++ return ret; ++ mode_store = ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_BST_TH1, 0x029b); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(chip->component, RT5509_REG_BST_MODE, 0x03, 0x02); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_DCR, param); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_OTPDIN); ++ ret &= 0x00ffff; ++ ret |= 0xc50000; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_OTPDIN, ret); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_OTPDIN, 0x81); ++ if (ret < 0) ++ return ret; ++ msleep(100); ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_OTPCONF, 0x00); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(chip->component, RT5509_REG_BST_MODE,0x03, mode_store); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_BST_TH1, bst_th); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_CALIB_DCR, 0x00); ++ if (ret < 0) ++ return ret; ++ ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_OTPCONF, 0x82); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_OTPCONF, 0x00); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_DCR); ++ param_store = ret & 0xffffff; ++ dev_info(chip->dev, "store %08x, put %08x\n", param_store, ++ param); ++ if (param_store != param) ++ return -EINVAL; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_OTPDIN); ++ dev_info(chip->dev, "otp_din = 0x%08x\n", ret); ++ if ((ret & 0xff0000) != 0xc50000) ++ return -EINVAL; ++ chip->calibrated = 1; ++ return 0; ++} ++ ++static int rt5509_calib_rwotp(struct rt5509_chip *chip, int choose) ++{ ++ int ret = 0; ++ ++ dev_info(chip->dev, "%s\n", __func__); ++ switch (choose) { ++ case RT5509_CALIB_CTRL_READOTP: ++ ret = rt5509_calib_read_otp(chip); ++ break; ++ case RT5509_CALIB_CTRL_WRITEOTP: ++ ret = rt5509_calib_write_otp(chip); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static int rt5509_calib_read_rapp(struct rt5509_chip *chip) ++{ ++ int ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_RAPP); ++ if (ret < 0) ++ return ret; ++ ret &= 0xffffff; ++ return ret; ++} ++ ++static int rt5509_calib_write_file(struct rt5509_chip *chip) ++{ ++ return 0; ++} ++ ++static int rt5509_calib_start_process(struct rt5509_chip *chip) ++{ ++ int ret = 0; ++ ++ dev_info(chip->dev, "%s\n", __func__); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ if (!(ret & RT5509_SPKAMP_ENMASK)) { ++ dev_err(chip->dev, "class D not turn on\n"); ++ return -EINVAL; ++ } ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_I2CBCKLRCKCONF); ++ if (ret < 0) ++ return ret; ++ if (ret & 0x08) { ++ dev_err(chip->dev, "BCK loss\n"); ++ return -EINVAL; ++ } ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_REQ); ++ if (ret < 0) ++ return ret; ++ chip->pilot_freq = ret & 0xffff; ++ return 0; ++} ++ ++static int rt5509_calib_end_process(struct rt5509_chip *chip) ++{ ++ dev_info(chip->dev, "%s\n", __func__); ++ return snd_soc_component_write(chip->component, RT5509_REG_CALIB_REQ,chip->pilot_freq); ++} ++ ++static int rt5509_calib_trigger_read(struct rt5509_calib_classdev *cdev) ++{ ++ struct rt5509_chip *chip = container_of(cdev, ++ struct rt5509_chip, calib_dev); ++ int ret = 0; ++ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ ret = rt5509_calib_start_process(chip); ++ if (ret < 0) { ++ dev_err(chip->dev, "start fail\n"); ++ dev_err(chip->dev, "bck not valid or amp not turn on\n"); ++ goto out_trigger_read; ++ } ++ ret = rt5509_calib_get_dcroffset(chip); ++ if (ret < 0) { ++ cdev->dcr_offset = 0xffffffff; ++ goto out_trigger_read; ++ } ++ cdev->dcr_offset = ret; ++ dev_dbg(chip->dev, "dcr_offset -> %d\n", cdev->dcr_offset); ++ ret = rt5509_calib_chosen_db(chip, RT5509_CALIB_CTRL_N15DB); ++ if (ret < 0) { ++ cdev->n15db = 0xffffffff; ++ goto out_trigger_read; ++ } ++ cdev->n15db = ret; ++ dev_dbg(chip->dev, "n15db -> 0x%08x\n", cdev->n15db); ++ ret = rt5509_calib_rwotp(chip, RT5509_CALIB_CTRL_READOTP); ++ if (ret < 0) { ++ cdev->gsense_otp = 0xffffffff; ++ goto out_trigger_read; ++ } ++ cdev->gsense_otp = ret; ++ dev_dbg(chip->dev, "gsense_otp -> 0x%08x\n", cdev->gsense_otp); ++ ret = rt5509_calib_read_rapp(chip); ++ if (ret < 0) { ++ cdev->rapp = 0xffffffff; ++ goto out_trigger_read; ++ } ++ cdev->rapp = ret; ++ dev_dbg(chip->dev, "rapp -> 0x%08x\n", cdev->rapp); ++ return 0; ++out_trigger_read: ++ return ret; ++} ++ ++static int rt5509_calib_trigger_write(struct rt5509_calib_classdev *cdev) ++{ ++ struct rt5509_chip *chip = container_of(cdev, ++ struct rt5509_chip, calib_dev); ++ int ret = 0; ++ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ ret = rt5509_calib_rwotp(chip, RT5509_CALIB_CTRL_WRITEOTP); ++ if (ret < 0) ++ goto out_trigger_write; ++ ret = rt5509_calib_write_file(chip); ++ if (ret < 0) ++ goto out_trigger_write; ++ ret = rt5509_calib_end_process(chip); ++ if (ret < 0) ++ goto out_trigger_write; ++ return 0; ++out_trigger_write: ++ return ret; ++} ++ ++static int64_t rt5509_integer_dcr_calculation(int index, uint32_t n_db) ++{ ++ int64_t a = 0, x = 0; ++ int64_t coeffi = 0; ++ int i = 0; ++ int64_t ret = 0; ++ ++ switch (index) { ++ case RT5509_CALIB_CTRL_N20DB: ++ coeffi = 81051042; ++ break; ++ case RT5509_CALIB_CTRL_N15DB: ++ coeffi = 25630590; ++ break; ++ case RT5509_CALIB_CTRL_N10DB: ++ coeffi = 8105104; ++ break; ++ default: ++ return -1; ++ } ++ a = n_db * coeffi; ++ x = 1 << 24; ++ for (i = 0; i < 10; i++) ++ x = div_s64(((x * x + a) >> 1), x); ++ ret = 1; ++ ret <<= 32; ++ ret *= 10000000; ++ return div_s64(ret, x); ++} ++ ++#define RefT (-40) ++#define alpha_r (265) ++static int rt5509_calib_trigger_calculation(struct rt5509_calib_classdev *cdev) ++{ ++ struct rt5509_chip *chip = container_of(cdev, ++ struct rt5509_chip, calib_dev); ++ int64_t dcr_n15i = 0, dcr_i = 0; ++ int64_t alpha_rappi = 0, rappi = 0; ++ int64_t rspki = 0; ++ int64_t rspk_mini = 0, rspk_maxi = 0; ++ ++ dev_info(chip->dev, "dcr_offset = 0x%08x\n", cdev->dcr_offset); ++ dev_info(chip->dev, "n15db reg = 0x%08x\n", cdev->n15db); ++ dev_info(chip->dev, "gsense_otp reg = 0x%08x\n", cdev->gsense_otp); ++ dcr_n15i = rt5509_integer_dcr_calculation(RT5509_CALIB_CTRL_N15DB, ++ cdev->n15db); ++ if (dcr_n15i < 0) ++ return -EINVAL; ++ dcr_i = dcr_n15i; ++ alpha_rappi = cdev->alphaspk; ++ rappi = cdev->rapp; ++ rappi <<= 9; ++ dev_info(chip->dev, "rappi = %llx\n", rappi); ++ rspki = div_s64((dcr_i * cdev->gsense_otp), 8); ++ rspki *= (cdev->alphaspk + 25); ++ rspki = div_s64(rspki, (alpha_r + RefT)); ++ rspki = div_s64(rspki, 1048576); ++ dev_info(chip->dev, "pre rspki = %llx\n", rspki); ++ rspki -= (div_s64((rappi * (alpha_rappi + 25)), (alpha_rappi + 50))); ++ dev_info(chip->dev, "post rspki = %llx\n", rspki); ++ rspk_mini = cdev->rspkmin; ++ rspk_mini <<= 32; ++ rspk_maxi = cdev->rspkmax; ++ rspk_maxi <<= 32; ++ if ((rspki * 80) < rspk_mini || (rspki * 80) > rspk_maxi) { ++ dev_err(chip->dev, "rspki over range\n"); ++ return -EINVAL; ++ } ++ rspki >>= 9; ++ cdev->rspk = (uint32_t)rspki; ++ cdev->rspk &= 0xffffff; ++ dev_info(chip->dev, "rspk = 0x%08x\n", cdev->rspk); ++ return 0; ++} ++ ++void rt5509_calib_destroy(struct rt5509_chip *chip) ++{ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ device_unregister(chip->calib_dev.dev); ++} ++EXPORT_SYMBOL_GPL(rt5509_calib_destroy); ++ ++int rt5509_calib_create(struct rt5509_chip *chip) ++{ ++ struct rt5509_calib_classdev *pcalib_dev = &chip->calib_dev; ++ int ret = 0; ++ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_OTPDIN); ++ ret &= 0xff0000; ++ ++ if (ret == 0xc50000) ++ chip->calibrated = 1; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_DCR); ++ ret &= 0xffffff; ++ pcalib_dev->rspk = ret; ++ /* default rspk min,max,alphspk */ ++ pcalib_dev->rspkmin = 10; ++ pcalib_dev->rspkmax = 160; ++ pcalib_dev->alphaspk = 265; ++ pcalib_dev->trigger_read = rt5509_calib_trigger_read; ++ pcalib_dev->trigger_write = rt5509_calib_trigger_write; ++ pcalib_dev->trigger_calculation = rt5509_calib_trigger_calculation; ++ pcalib_dev->dev = device_create(rt5509_cal_class, NULL, 0, ++ pcalib_dev, "rt5509.%d", chip->pdev->id); ++ //if (IS_ERR(pcalib_dev->dev)) ++ // return -EINVAL; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(rt5509_calib_create); ++ ++static ssize_t rt_calib_dev_attr_show(struct device *, ++ struct device_attribute *, char *); ++static ssize_t rt_calib_dev_attr_store(struct device *, ++ struct device_attribute *, const char *, size_t); ++static struct device_attribute rt5509_dev_attrs[] = { ++ __ATTR(n20db, 0444, rt_calib_dev_attr_show, rt_calib_dev_attr_store), ++ __ATTR(n15db, 0444, rt_calib_dev_attr_show, rt_calib_dev_attr_store), ++ __ATTR(n10db, 0444, rt_calib_dev_attr_show, rt_calib_dev_attr_store), ++ __ATTR(gsense_otp, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(rapp, 0444, rt_calib_dev_attr_show, rt_calib_dev_attr_store), ++ __ATTR(rspk, 0664, rt_calib_dev_attr_show, rt_calib_dev_attr_store), ++ __ATTR(calib_data, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(dcr_offset, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(calibrated, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(chip_rev, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(rspkmin, 0644, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(rspkmax, 0644, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(alphaspk, 0644, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR(event_read, 0444, rt_calib_dev_attr_show, ++ rt_calib_dev_attr_store), ++ __ATTR_NULL, ++}; ++ ++static struct attribute *rt5509_cal_dev_attrs[] = { ++ &rt5509_dev_attrs[0].attr, ++ &rt5509_dev_attrs[1].attr, ++ &rt5509_dev_attrs[2].attr, ++ &rt5509_dev_attrs[3].attr, ++ &rt5509_dev_attrs[4].attr, ++ &rt5509_dev_attrs[5].attr, ++ &rt5509_dev_attrs[6].attr, ++ &rt5509_dev_attrs[7].attr, ++ &rt5509_dev_attrs[8].attr, ++ &rt5509_dev_attrs[9].attr, ++ &rt5509_dev_attrs[10].attr, ++ &rt5509_dev_attrs[11].attr, ++ &rt5509_dev_attrs[12].attr, ++ &rt5509_dev_attrs[13].attr, ++ NULL, ++}; ++ ++static const struct attribute_group rt5509_cal_group = { ++ .attrs = rt5509_cal_dev_attrs, ++}; ++ ++static const struct attribute_group *rt5509_cal_groups[] = { ++ &rt5509_cal_group, ++ NULL, ++}; ++ ++enum { ++ RT5509_CALIB_DEV_N20DB = 0, ++ RT5509_CALIB_DEV_N15DB, ++ RT5509_CALIB_DEV_N10DB, ++ RT5509_CALIB_DEV_GSENSE_OTP, ++ RT5509_CALIB_DEV_RAPP, ++ RT5509_CALIB_DEV_RSPK, ++ RT5509_CALIB_DEV_CALIB_DATA, ++ RT5509_CALIB_DEV_DCROFFSET, ++ RT5509_CALIB_DEV_CALIBRATED, ++ RT5509_CALIB_DEV_CHIPREV, ++ RT5509_CALIB_DEV_RSPKMIN, ++ RT5509_CALIB_DEV_RSPKMAX, ++ RT5509_CALIB_DEV_ALPHASPK, ++ RT5509_CALIB_DEV_EVENT_READ, ++ RT5509_CALIB_DEV_MAX, ++}; ++ ++static int calib_data_file_read(struct rt5509_chip *chip, char *buf) ++{ ++ return -EINVAL; ++} ++ ++static int rt_dev_event_read(struct rt5509_chip *chip, char *buf) ++{ ++ int i = 0, index = 0, ret = 0; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ if (!(ret & RT5509_SPKAMP_ENMASK)) { ++ dev_err(chip->dev, "amp not turn on\n"); ++ return -EINVAL; ++ } ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "important reg dump ++\n"); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x03) -> 0x%02x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CHIPREV); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x00) -> 0x%02x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_EVENTINFO); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x01) -> 0x%02x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_DMGFLAG); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x02) -> 0x%02x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_BST_MODE); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x1e) -> 0x%02x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_ISENSEGAIN); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x46) -> 0x%06x\n", ret & 0xffffff); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_CALIB_DCR); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x4e) -> 0x%06x\n", ret & 0xffffff); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_VTEMP_TRIM); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0xc4) -> 0x%04x\n", ret); ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_INTERRUPT); ++ if (ret < 0) ++ return ret; ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "events -> 0x%04x\n", ret); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "important reg dump --\n"); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "impedance curve ++\n"); ++ for (i = 0x10; i <= 0x1a; i++) { ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_SPKRPTSEL, i); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_SPKRPT); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x%02x) -> 0x%06x\n", i, ret & 0xffffff); ++ } ++ ++ ret = snd_soc_component_write(chip->component, RT5509_REG_SPKRPTSEL, 0x0d); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_read(chip->component, RT5509_REG_SPKRPT); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "i(0x0d) -> 0x%06x\n", ret & 0xffffff); ++ index += scnprintf(buf + index, PAGE_SIZE - index, ++ "impedance curve --\n"); ++ ret = index; ++ return ret; ++} ++ ++static ssize_t rt_calib_dev_attr_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct rt5509_calib_classdev *calib_dev = dev_get_drvdata(dev); ++ struct rt5509_chip *chip = container_of(calib_dev, ++ struct rt5509_chip, calib_dev); ++ const ptrdiff_t offset = attr - rt5509_dev_attrs; ++ int ret = 0; ++ ++ switch (offset) { ++ case RT5509_CALIB_DEV_N20DB: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", calib_dev->n20db); ++ break; ++ case RT5509_CALIB_DEV_N15DB: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", calib_dev->n15db); ++ break; ++ case RT5509_CALIB_DEV_N10DB: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", calib_dev->n10db); ++ break; ++ case RT5509_CALIB_DEV_GSENSE_OTP: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", ++ calib_dev->gsense_otp); ++ break; ++ case RT5509_CALIB_DEV_RAPP: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", calib_dev->rapp); ++ break; ++ case RT5509_CALIB_DEV_RSPK: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", calib_dev->rspk); ++ break; ++ case RT5509_CALIB_DEV_CALIB_DATA: ++ ret = calib_data_file_read(chip, buf); ++ break; ++ case RT5509_CALIB_DEV_DCROFFSET: ++ ret = scnprintf(buf, PAGE_SIZE, "0x%08x\n", ++ calib_dev->dcr_offset); ++ break; ++ case RT5509_CALIB_DEV_CALIBRATED: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->calibrated); ++ break; ++ case RT5509_CALIB_DEV_CHIPREV: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", chip->chip_rev); ++ break; ++ case RT5509_CALIB_DEV_RSPKMIN: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", calib_dev->rspkmin); ++ break; ++ case RT5509_CALIB_DEV_RSPKMAX: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", calib_dev->rspkmax); ++ break; ++ case RT5509_CALIB_DEV_ALPHASPK: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", calib_dev->alphaspk); ++ break; ++ case RT5509_CALIB_DEV_EVENT_READ: ++ ret = rt_dev_event_read(chip, buf); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static ssize_t rt_calib_dev_attr_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct rt5509_calib_classdev *calib_dev = dev_get_drvdata(dev); ++ const ptrdiff_t offset = attr - rt5509_dev_attrs; ++ uint32_t tmp = 0; ++ int32_t tmp2 = 0; ++ ++ switch (offset) { ++ case RT5509_CALIB_DEV_RSPK: ++ if (sscanf(buf, "0x%08x", &tmp) != 1) ++ return -EINVAL; ++ calib_dev->rspk = tmp; ++ break; ++ case RT5509_CALIB_DEV_RSPKMIN: ++ if (kstrtoint(buf, 10, &tmp2) < 0) ++ return -EINVAL; ++ calib_dev->rspkmin = tmp2; ++ break; ++ case RT5509_CALIB_DEV_RSPKMAX: ++ if (kstrtoint(buf, 10, &tmp2) < 0) ++ return -EINVAL; ++ calib_dev->rspkmax = tmp2; ++ break; ++ case RT5509_CALIB_DEV_ALPHASPK: ++ if (kstrtoint(buf, 10, &tmp2) < 0) ++ return -EINVAL; ++ calib_dev->alphaspk = tmp2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return count; ++} ++ ++static ssize_t rt_calib_class_attr_show(struct class *, ++ struct class_attribute *, char *); ++static ssize_t rt_calib_class_attr_store(struct class *, ++ struct class_attribute *, const char *, size_t); ++static struct class_attribute rt5509_class_attrs[] = { ++ __ATTR(trigger, 0220, rt_calib_class_attr_show, ++ rt_calib_class_attr_store), ++ __ATTR(status, 0444, rt_calib_class_attr_show, ++ rt_calib_class_attr_store), ++ __ATTR_NULL, ++}; ++ ++enum { ++ RT5509_CALIB_CLASS_TRIGGER = 0, ++ RT5509_CALIB_CLASS_STATUS, ++ RT5509_CALIB_CLASS_MAX, ++}; ++ ++static ssize_t rt_calib_class_attr_show(struct class *cls, ++ struct class_attribute *attr, char *buf) ++{ ++ const ptrdiff_t offset = attr - rt5509_class_attrs; ++ int ret = 0; ++ ++ switch (offset) { ++ case RT5509_CALIB_CLASS_STATUS: ++ ret = scnprintf(buf, PAGE_SIZE, "%d\n", calib_status); ++ break; ++ case RT5509_CALIB_CLASS_TRIGGER: ++ default: ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static int rt_calib_trigger_read(struct device *dev, void *data) ++{ ++ struct rt5509_calib_classdev *calib_dev = dev_get_drvdata(dev); ++ ++ return calib_dev->trigger_read ? ++ calib_dev->trigger_read(calib_dev) : -EINVAL; ++} ++ ++static int rt_calib_trigger_write(struct device *dev, void *data) ++{ ++ struct rt5509_calib_classdev *calib_dev = dev_get_drvdata(dev); ++ ++ return calib_dev->trigger_write ? ++ calib_dev->trigger_write(calib_dev) : -EINVAL; ++} ++ ++static int rt_calib_trigger_calculation(struct device *dev, void *data) ++{ ++ struct rt5509_calib_classdev *calib_dev = dev_get_drvdata(dev); ++ ++ return calib_dev->trigger_calculation ? ++ calib_dev->trigger_calculation(calib_dev) : -EINVAL; ++} ++ ++static int rt_calib_trigger_sequence(struct class *cls, int seq) ++{ ++ int ret = 0; ++ ++ switch (seq) { ++ case RT5509_CALIB_CTRL_START: ++ ret = class_for_each_device(cls, NULL, NULL, ++ rt_calib_trigger_read); ++ break; ++ case RT5509_CALIB_CTRL_END: ++ ret = class_for_each_device(cls, NULL, NULL, ++ rt_calib_trigger_write); ++ break; ++ case RT5509_CALIB_CTRL_ALLINONE: ++ ret = rt_calib_trigger_sequence(cls, RT5509_CALIB_CTRL_START); ++ if (ret < 0) { ++ pr_err("%s: trigger read fail\n", cls->name); ++ return ret; ++ } ++ ret = class_for_each_device(cls, NULL, NULL, ++ rt_calib_trigger_calculation); ++ if (ret < 0) { ++ pr_err("%s: trigger calculation fail\n", cls->name); ++ return ret; ++ } ++ ret = rt_calib_trigger_sequence(cls, RT5509_CALIB_CTRL_END); ++ if (ret < 0) { ++ pr_err("%s: trigger write fail\n", cls->name); ++ return ret; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++static ssize_t rt_calib_class_attr_store(struct class *cls, ++ struct class_attribute *attr, const char *buf, size_t cnt) ++{ ++ const ptrdiff_t offset = attr - rt5509_class_attrs; ++ int parse_val = 0; ++ int ret = 0; ++ ++ switch (offset) { ++ case RT5509_CALIB_CLASS_TRIGGER: ++ if (kstrtoint(buf, 10, &parse_val) < 0) ++ return -EINVAL; ++ parse_val -= RT5509_CALIB_MAGIC; ++ ret = rt_calib_trigger_sequence(cls, parse_val); ++ calib_status = ret; ++ if (ret < 0) ++ return ret; ++ break; ++ case RT5509_CALIB_CLASS_STATUS: ++ default: ++ return -EINVAL; ++ } ++ return cnt; ++} ++ ++static int __init rt5509_cal_init(void) ++{ ++ int i = 0, ret = 0; ++ ++ rt5509_cal_class = class_create(THIS_MODULE, "rt5509_cal"); ++ if (IS_ERR(rt5509_cal_class)) ++ return PTR_ERR(rt5509_cal_class); ++ for (i = 0; rt5509_class_attrs[i].attr.name; i++) { ++ ret = class_create_file(rt5509_cal_class, ++ &rt5509_class_attrs[i]); ++ if (ret < 0) ++ goto out_cal_init; ++ } ++ rt5509_cal_class->dev_groups = rt5509_cal_groups; ++ return 0; ++out_cal_init: ++ while (--i >= 0) ++ class_remove_file(rt5509_cal_class, &rt5509_class_attrs[i]); ++ class_destroy(rt5509_cal_class); ++ return ret; ++} ++#if 1 ++static void __exit rt5509_cal_exit(void) ++{ ++ int i = 0; ++ ++ for (i = 0; rt5509_class_attrs[i].attr.name; i++) ++ class_remove_file(rt5509_cal_class, &rt5509_class_attrs[i]); ++ class_destroy(rt5509_cal_class); ++} ++#endif ++ ++/*---------------------------------------------------*/ ++ ++struct reg_config { ++ uint8_t reg_addr; ++ uint32_t reg_data; ++}; ++ ++static const char * const prop_str[RT5509_CFG_MAX] = { ++ "general", ++ "boost_converter", ++ "speaker_protect", ++ "safe_guard", ++ "eq", ++ "bwe", ++ "dcr", ++ "mbdrc", ++ "alc", ++}; ++ ++static const struct reg_config battmode_config[] = { ++}; ++ ++static const struct reg_config adaptive_config[] = { ++}; ++ ++static const struct reg_config general_config[] = { ++ { 0x1e, 0x0b}, ++ { 0x8a, 0x02}, ++ { 0x94, 0x12}, ++ { 0x15, 0x00}, ++ { 0x81, 0x99}, ++ { 0x50, 0x00}, ++ { 0x2c, 0x00}, ++ { 0x5b, 0x00}, ++ { 0x82, 0x42}, ++ { 0x83, 0xc0}, ++ { 0x84, 0xb5}, ++ { 0x85, 0xd5}, ++ { 0xb3, 0x00}, ++ { 0x88, 0x90}, ++ { 0x96, 0xfd}, ++ { 0x93, 0x55}, ++ { 0x26, 0x00}, ++ { 0x8d, 0xe0}, ++ { 0x14, 0x7fff}, ++ { 0xea, 0x81}, ++ { 0xeb, 0xa1}, ++ { 0xc3, 0x10}, ++ { 0xfd, 0xf0}, ++ { 0xee, 0x06}, ++ { 0x86, 0x18}, ++ { 0x13, 0x3bbb}, ++ { 0x14, 0x6c00}, ++ { 0x16, 0x4c}, ++ { 0x18, 0x4a}, ++ { 0x19, 0x016a}, ++ { 0x1a, 0x0200}, ++ { 0x1b, 0x77}, ++ { 0x1c, 0x70}, ++ { 0x1d, 0x80}, ++ { 0x1f, 0x05d3}, ++ { 0x20, 0x03cd}, ++ { 0x21, 0x0209}, ++ { 0x22, 0x07}, ++ { 0x23, 0x47}, ++ { 0x24, 0xc1}, ++ { 0x25, 0x4f}, ++ { 0x43, 0x44}, ++ { 0x44, 0xb3}, ++ { 0x45, 0x1a}, ++ { 0x46, 0x800000}, ++ { 0x81, 0xb9}, ++ { 0x84, 0x35}, ++ { 0x86, 0x14}, ++ { 0x87, 0x04}, ++ { 0x92, 0x57}, ++ { 0x93, 0x54}, ++ { 0xc0, 0x20}, ++ { 0xc2, 0x000097}, ++ { 0xeb, 0xa2}, ++ { 0xec, 0x7474}, ++ { 0xef, 0x001201}, ++ { 0xf8, 0x55}, ++ { 0xf9, 0x01}, ++ { 0xfa, 0x0711}, ++}; ++ ++static const struct reg_config revc_general_config[] = { ++ { 0x14, 0x6000}, ++ { 0x15, 0xB8}, ++ { 0x16, 0x5d}, ++ { 0x18, 0x0a}, ++ { 0x19, 0x016a}, ++ { 0x1a, 0x0000}, ++ { 0x1c, 0x70}, ++ { 0x1d, 0x80}, ++ { 0x1e, 0x0b}, ++ { 0x1f, 0x085b}, ++ { 0x20, 0x05cf}, ++ { 0x21, 0x02c7}, ++ { 0x22, 0x0d}, ++ { 0x23, 0x6f}, ++ { 0x24, 0xb1}, ++ { 0x25, 0x08}, ++ { 0x2c, 0x00}, ++ { 0x2d, 0x0100}, ++ { 0x2f, 0x0559}, ++ { 0x45, 0x0b}, ++ { 0x5a, 0x07dc}, ++ { 0x81, 0xbb}, ++ { 0x82, 0x43}, ++ { 0x83, 0x54}, ++ { 0x86, 0x3f}, ++ { 0x87, 0x1f}, ++ { 0x8a, 0x02}, ++ { 0x8d, 0xc0}, ++ { 0x93, 0xd4}, ++ { 0x94, 0x12}, ++ { 0x96, 0x0d}, ++ { 0x97, 0xa5}, ++ { 0xb8, 0x80}, ++ { 0xea, 0x91}, ++ { 0xeb, 0xa4}, ++ { 0xec, 0x7474}, ++ { 0xee, 0x06}, ++ { 0xf8, 0xd7}, ++ { 0xfd, 0xd0}, ++ { 0xef, 0x001201}, ++ { 0xb4, 0x81}, ++}; ++ ++static const struct reg_config revd_general_config[] = { ++ { 0x14, 0x6800}, ++ { 0x16, 0x95}, ++ { 0x18, 0xaa}, ++ { 0x19, 0x016a}, ++ { 0x1a, 0x0000}, ++ { 0x1c, 0x50}, ++ { 0x1d, 0x00}, ++ { 0x1e, 0x0b}, ++ { 0x1f, 0x085b}, ++ { 0x20, 0x05cf}, ++ { 0x21, 0x02c7}, ++ { 0x22, 0x05}, ++ { 0x24, 0xb1}, ++ { 0x25, 0x04}, ++ { 0x2c, 0x00}, ++ { 0x2f, 0x0559}, ++ { 0x45, 0x08}, ++ { 0x5b, 0x00}, ++ { 0x81, 0xbb}, ++ { 0x82, 0x43}, ++ { 0x83, 0x54}, ++ { 0x86, 0x38}, ++ { 0x87, 0x1f}, ++ { 0x92, 0x54}, ++ { 0x93, 0xd4}, ++ { 0x94, 0x12}, ++ { 0x9a, 0xdc}, ++ { 0xb3, 0x00}, ++ { 0xea, 0x80}, ++ { 0xf9, 0x01}, ++ { 0xfd, 0xd0}, ++ { 0xef, 0x001201}, ++ { 0xee, 0x05}, ++ { 0xb4, 0x81}, ++ { 0xba, 0x80}, ++ { 0x2b, 0x67}, ++}; ++ ++ ++ ++ ++static int rt5509_block_read( ++ const struct i2c_client *client, u32 reg, int bytes, void *dest) ++{ ++ return i2c_smbus_read_i2c_block_data(client, reg, bytes, dest); ++} ++ ++static int rt5509_block_write(const struct i2c_client *client, u32 reg, ++ int bytes, const void *src) ++{ ++ return i2c_smbus_write_i2c_block_data(client, reg, bytes, src); ++} ++ ++ ++static int rt5509_update_bits(struct i2c_client *i2c, u32 reg, ++ u32 mask, u32 data, int bytes) ++{ ++ struct rt5509_chip *chip = i2c_get_clientdata(i2c); ++#ifdef T_REGMAP //CONFIG_RT_REGMAP ++ ++ struct rt_reg_data rrd; ++ ++ return rt_regmap_update_bits(chip->rd, &rrd, reg, mask, data); ++#else ++ u32 read_data = 0; ++ u8 *p_data = (u8 *)&read_data; ++ int i = 0, j = 0, ret = 0; ++ ++ down(&chip->io_semaphore); ++ ret = rt5509_block_read(chip->i2c, reg, bytes, &read_data); ++ if (ret < 0) ++ goto err_bits; ++ j = (bytes / 2); ++ for (i = 0; i < j; i++) ++ swap(p_data[i], p_data[bytes - i]); ++ ret = rt5509_block_write(chip->i2c, reg, bytes, &read_data); ++ if (ret < 0) ++ goto err_bits; ++err_bits: ++ up(&chip->io_semaphore); ++ return ret; ++#endif /* #ifdef CONFIG_RT_REGMAP */ ++} ++ ++#if 0 ++static int rt5509_set_bits(struct i2c_client *i2c, u32 reg, u8 mask) ++{ ++ return rt5509_update_bits(i2c, reg, mask, mask, 1); ++} ++#endif ++static int rt5509_clr_bits(struct i2c_client *i2c, u32 reg, u8 mask) ++{ ++ return rt5509_update_bits(i2c, reg, mask, 0, 1); ++} ++ ++static unsigned int rt5509_io_read(struct snd_soc_component *component, ++ unsigned int reg) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ int ret = 0; ++ unsigned int rd_data; ++ ++ ret = regmap_read(chip->regmap,reg ,&rd_data); ++ return (ret < 0 ? ret : rd_data); ++ ++} ++ ++ ++ ++static int rt5509_io_write(struct snd_soc_component *component, ++ unsigned int reg, unsigned int data) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ return regmap_write(chip->regmap, reg, data); ++ ++} ++ ++ ++static inline int rt5509_power_on(struct rt5509_chip *chip, bool en) ++{ ++ int ret = 0; ++ dev_dbg(chip->dev, "%s: en %d\n", __func__, en); ++ if (en) { ++ ret = rt5509_update_bits(chip->i2c, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, 0 , 1); ++ } else { ++ ret = rt5509_update_bits(chip->i2c, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ RT5509_CHIPPD_ENMASK , 1); ++ } ++ mdelay(1); ++ return ret; ++} ++ ++static int rt5509_set_bias_level(struct snd_soc_component *component, ++ enum snd_soc_bias_level level) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); ++ ++ int ret = 0; ++ ++ switch (level) { ++ case SND_SOC_BIAS_ON: ++ case SND_SOC_BIAS_PREPARE: ++ dapm->bias_level = level; ++ break; ++ case SND_SOC_BIAS_STANDBY: ++ ++ if (dapm->bias_level != SND_SOC_BIAS_OFF) { ++ dapm->bias_level = level; ++ break; ++ } ++ ++ ret = rt5509_power_on(chip, true); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF5, ++ RT5509_VBG_ENMASK, RT5509_VBG_ENMASK); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKEN1, ++ RT5509_BIAS_ENMASK, RT5509_BIAS_ENMASK); ++ if (ret < 0) ++ goto out_set_bias; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_BST_MODE, ++ chip->mode_store); ++ if (ret < 0) ++ goto out_set_bias; ++ ++ dapm->bias_level = level; ++ ret = 0; ++ break; ++ case SND_SOC_BIAS_OFF: ++ ret = snd_soc_component_read(component, RT5509_REG_BST_MODE); ++ if (ret < 0) ++ goto out_set_bias; ++ chip->mode_store = ret; ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_BST_MODE, ++ 0x03, 0x00); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKEN1, ++ RT5509_BIAS_ENMASK, ~RT5509_BIAS_ENMASK); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF5, ++ RT5509_VBG_ENMASK, ~RT5509_VBG_ENMASK); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = snd_soc_component_read(component, RT5509_REG_INTERRUPT); ++ if (ret < 0) ++ goto out_set_bias; ++ ret = rt5509_power_on(chip, false); ++ if (ret < 0) ++ goto out_set_bias; ++ dapm->bias_level = level; ++ ret = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++out_set_bias: ++ ++ return ret; ++} ++ ++ ++static int rt5509_init_battmode_setting(struct snd_soc_component *component) ++{ ++ int i = 0, ret = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(battmode_config); i++) { ++ ret = snd_soc_component_write(component, battmode_config[i].reg_addr, ++ battmode_config[i].reg_data); ++ if (ret < 0) ++ break; ++ } ++ return ret; ++} ++ ++static int rt5509_init_adaptive_setting(struct snd_soc_component *component) ++{ ++ int i = 0, ret = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(adaptive_config); i++) { ++ ret = snd_soc_component_write(component, adaptive_config[i].reg_addr, ++ adaptive_config[i].reg_data); ++ if (ret < 0) ++ break; ++ } ++ return ret; ++} ++ ++static int rt5509_init_general_setting(struct snd_soc_component *component) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ const struct reg_config *reg_cfg = NULL; ++ int reg_cfg_size = 0; ++ int i = 0, ret = 0; ++ ++ if (chip->chip_rev >= RT5509_CHIP_REVD) { ++ ++ reg_cfg = revd_general_config; ++ reg_cfg_size = ARRAY_SIZE(revd_general_config); ++ } else if (chip->chip_rev >= RT5509_CHIP_REVC) { ++ ++ reg_cfg = revc_general_config; ++ reg_cfg_size = ARRAY_SIZE(revc_general_config); ++ } else { ++ ++ reg_cfg = general_config; ++ reg_cfg_size = ARRAY_SIZE(general_config); ++ } ++ for (i = 0; i < reg_cfg_size; i++) { ++ ret = snd_soc_component_write(component, reg_cfg[i].reg_addr, ++ reg_cfg[i].reg_data); ++ if (ret < 0) ++ break; ++ } ++ return ret; ++} ++ ++static int rt5509_do_tcsense_fix(struct snd_soc_component *component) ++{ ++ uint32_t tc_sense = 0, vtemp = 0; ++ int ret = 0; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWB, 0x40, 0x40); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_OTPCONF, 0x82); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_OTPCONF, 0x00); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWB, 0x40, 0x00); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_read(component, RT5509_REG_VTEMP_TRIM); ++ if (ret < 0) ++ return ret; ++ vtemp = ret & 0xffff; ++ if (vtemp < 0x4250) { ++ tc_sense = 0xffff; ++ goto bypass_tcsense_overflow; ++ } ++ tc_sense = (1073741824U / vtemp * (273 - 40) / (265 - 40)) << 1; ++ if (tc_sense & 0x10000) ++ tc_sense = (tc_sense & 0xffff) + 1; ++ tc_sense &= 0xffff; ++bypass_tcsense_overflow: ++ ++ return snd_soc_component_write(component, RT5509_REG_TCOEFF, tc_sense); ++} ++ ++static int rt5509_adap_coefficent_fix(struct snd_soc_component *component) ++{ ++ int i = 0, ret = 0; ++ int64_t x = 0, y = 0, z = 0, w = 0; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_ISENSEGAIN); ++ ret &= 0xffffff; ++ ++ /* gsense otp value */ ++ x = ret; ++ ret = snd_soc_component_read(component, RT5509_REG_CALIB_DCR); ++ ret &= 0xffffff; ++ ++ if (ret == 0xffffff) ++ ret = 0x800000; ++ /* rspk otp value */ ++ w = ret; ++ for (i = 0; i < 6; i++) { ++ ret = snd_soc_component_read(component, RT5509_REG_ADAPTB0 + i); ++ ret &= 0xffffff; ++ ++ /* y = phi factor */ ++ y = ret; ++ if (ret < 0x800000) { ++ z = div64_s64(x * 1000000, w) * y; ++ z = div_s64(z, 1000000); ++ } else { ++ y = ((int64_t)0xffffff - y) * div64_s64(x * 1000000, w); ++ z = (int64_t)0xffffff * (int64_t)1000000; ++ z = z - y; ++ z = div_s64(z, 1000000); ++ } ++ ret = z & 0xffffff; ++ //dev_info(codec->dev, "b factor after 0x%08x\n", ret); ++ ret = snd_soc_component_write(component, RT5509_REG_ADAPTB0 + i, ret); ++ if (ret < 0) { ++ //dev_err(codec->dev, "fix b factor fail %d\n", i); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int rt5509_init_impedance_ctrl_fix(struct snd_soc_component *component) ++{ ++ u32 gsense_otp = 0, rspk_otp = 0, result = 0; ++ int ret = 0; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_ISENSEGAIN); ++ if (ret == 0) ++ ret = 0x800000; ++ gsense_otp = ret & 0xffffff; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_CALIB_DCR); ++ if (ret == 0) ++ ret = 0x800000; ++ rspk_otp = ret & 0xffffff; ++ ++ result = ((rspk_otp << 7) / gsense_otp) << 16; ++ result &= 0xffffff; ++ ++ return snd_soc_component_write(component, RT5509_REG_DELAYRES, result); ++} ++ ++static int rt5509_init_proprietary_setting(struct snd_soc_component *component) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ struct rt5509_proprietary_param *p_param = chip->pdata->p_param; ++ const u8 *cfg = NULL; ++ u32 cfg_size = 0; ++ int i = 0, j = 0; ++ int ret = 0; ++ ++ if (!p_param) ++ goto out_init_proprietary; ++ for (i = 0; i < RT5509_CFG_MAX; i++) { ++ cfg = p_param->cfg[i]; ++ cfg_size = p_param->cfg_size[i]; ++ if (!cfg) ++ continue; ++ dev_dbg(chip->dev, "%s start\n", prop_str[i]); ++ for (j = 0; j < cfg_size;) { ++#ifdef T_REGMAP //CONFIG_RT_REGMAP ++ ret = rt_regmap_block_write(chip->rd, cfg[0], cfg[1], ++ cfg + 2); ++#else ++ ret = rt5509_block_write(chip->i2c, cfg[0], cfg[1], ++ cfg + 2); ++#endif /* #ifdef CONFIG_RT_REGMAP */ ++ if (ret < 0) ++ dev_err(chip->dev, "set %02x fail\n", cfg[0]); ++ j += (2 + cfg[1]); ++ cfg += (2 + cfg[1]); ++ } ++ dev_dbg(chip->dev, "%s end\n", prop_str[i]); ++ } ++ ret = rt5509_adap_coefficent_fix(component); ++ if (ret < 0) ++ dev_err(chip->dev, "fix adap coefficient fail\n"); ++ ret = rt5509_init_impedance_ctrl_fix(component); ++ if (ret < 0) ++ dev_err(chip->dev, "init impedance ctrl fix fail\n"); ++ if (p_param->cfg_size[RT5509_CFG_SPEAKERPROT]) { ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, RT5509_SPKPROT_ENMASK); ++ } ++out_init_proprietary: ++ return ret; ++} ++ ++static int rt5509_init_reg_setting(struct snd_soc_component *component) ++{ ++ ++ return 0; ++} ++struct rt5509_param_platform_data { ++ struct rt5509_chip *chip; ++}; ++ ++static int rt5509_param_create(struct rt5509_chip *chip) ++{ ++ struct rt5509_param_platform_data param_data; ++ ++ param_data.chip = chip; ++ chip->pdev = platform_device_register_data(NULL, "rt5509_param", ++ chip->dev_cnt, ¶m_data, ++ sizeof(param_data)); ++ if (!chip->pdev) ++ return -EFAULT; ++ return 0; ++} ++ ++ ++#if 1 ++static ssize_t rt5509_proprietary_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct rt5509_chip *chip = dev_get_drvdata(dev); ++ struct rt5509_proprietary_param *param = chip->pdata->p_param; ++ int i = 0, j = 0; ++ const u8 *cfg = NULL; ++ u32 cfg_size = 0; ++ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ ++ ++ if (!param) { ++ i += scnprintf(buf + i, PAGE_SIZE - i, "no proprietary parm\n"); ++ goto out_show; ++ } ++ for (j = 0; j < RT5509_CFG_MAX; j++) { ++ cfg = param->cfg[j]; ++ cfg_size = param->cfg_size[j]; ++ if (!cfg) { ++ i += scnprintf(buf + i, PAGE_SIZE - i, "no %s cfg\n", ++ prop_str[j]); ++ continue; ++ } ++ i += scnprintf(buf + i, PAGE_SIZE - i, "%s size %d\n", ++ prop_str[j], cfg_size); ++ } ++out_show: ++ return i; ++} ++ ++static ssize_t rt5509_proprietary_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t cnt) ++{ ++ struct rt5509_chip *chip = dev_get_drvdata(dev); ++ ++ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(chip->component); ++ struct rt5509_proprietary_param *param = NULL; ++ int i = 0, size = 0; ++ const u8 *bin_offset = NULL; ++ u32 *sptr; ++ ++ dev_dbg(chip->dev, "%s, size %d\n", __func__, (int)cnt); ++ /* do mark check */ ++ if (cnt < 7) { ++ dev_err(chip->dev, "data is invalid\n"); ++ goto out_param_write; ++ } ++ if (strncmp("richtek", buf, 7)) { ++ dev_err(chip->dev, "data is invalid\n"); ++ goto out_param_write; ++ } ++ /* do size check */ ++ sptr = (u32 *)(buf + cnt - 4); ++ size = *sptr; ++ dev_dbg(chip->dev, "size %d\n", size); ++ if (cnt < 47 || (size + 47) != cnt) { ++ dev_err(chip->dev, "sorry bin size is wrong\n"); ++ goto out_param_write; ++ } ++ for (i = 0; i < RT5509_CFG_MAX; i++) { ++ sptr = (u32 *)(buf + cnt - 40 + i * 4); ++ size -= *sptr; ++ } ++ if (size != 0) { ++ dev_err(chip->dev, "sorry, bin format is wrong\n"); ++ goto out_param_write; ++ } ++ /* if previous one is existed, release it */ ++ param = chip->pdata->p_param; ++ if (param) { ++ dev_dbg(chip->dev, "previous existed\n"); ++ for (i = 0; i < RT5509_CFG_MAX; i++) ++ devm_kfree(chip->dev, param->cfg[i]); ++ devm_kfree(chip->dev, param); ++ chip->pdata->p_param = NULL; ++ } ++ /* start to copy */ ++ param = devm_kzalloc(chip->dev, sizeof(*param), GFP_KERNEL); ++ if (!param) ++ goto out_param_write; ++ ++ bin_offset = buf + 7; ++ for (i = 0; i < RT5509_CFG_MAX; i++) { ++ sptr = (u32 *)(buf + cnt - 40 + i * 4); ++ param->cfg_size[i] = *sptr; ++ param->cfg[i] = devm_kzalloc(chip->dev, ++ sizeof(u8) * param->cfg_size[i], ++ GFP_KERNEL); ++ memcpy(param->cfg[i], bin_offset, param->cfg_size[i]); ++ bin_offset += param->cfg_size[i]; ++ } ++ chip->pdata->p_param = param; ++ if (dapm->bias_level != SND_SOC_BIAS_OFF) ++ goto out_param_write; ++ rt5509_power_on(chip, true); ++ rt5509_do_tcsense_fix(chip->component); ++ rt5509_init_proprietary_setting(chip->component); ++ rt5509_power_on(chip, false); ++ return cnt; ++out_param_write: ++ return -EINVAL; ++} ++ ++static DEVICE_ATTR(prop_param, 0644, rt5509_proprietary_show, rt5509_proprietary_store); ++ ++#if 0 ++static struct device_attribute rt5509_proprietary_attr = { ++ .attr = { ++ .name = "prop_param", ++ .mode = 0644, ++ }, ++ .show = rt5509_proprietary_show, ++ .store = rt5509_proprietary_store, ++}; ++ ++static int rt5509_param_probe(struct platform_device *pdev) ++{ ++ struct rt5509_param_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ int ret = 0; ++ ++ ret = device_create_file(&pdev->dev, &rt5509_proprietary_attr); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "create file error\n"); ++ return ret; ++ } ++ platform_set_drvdata(pdev, pdata->chip); ++ return 0; ++} ++ ++static int rt5509_param_remove(struct platform_device *pdev) ++{ ++ device_remove_file(&pdev->dev, &rt5509_proprietary_attr); ++ return 0; ++} ++ ++static struct platform_driver rt5509_param_driver = { ++ .driver = { ++ .name = "rt5509_param", ++ .owner = THIS_MODULE, ++ }, ++ .probe = rt5509_param_probe, ++ .remove = rt5509_param_remove, ++}; ++ ++ ++static void rt5509_param_destroy(struct rt5509_chip *chip) ++{ ++ platform_device_unregister(chip->pdev); ++} ++ ++static int __init rt5509_driver_init(void) ++{ ++ pr_info("%s\n", __func__); ++ platform_driver_register(&rt5509_param_driver); ++ return 0; ++} ++module_init(rt5509_driver_init); ++ ++static void __exit rt5509_driver_exit(void) ++{ ++ pr_info("%s\n", __func__); ++ platform_driver_unregister(&rt5509_param_driver); ++} ++module_exit(rt5509_driver_exit); ++#endif ++ ++ ++#endif ++ ++static int rt5509_clk_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_to_component(w->dapm); ++ ++ int ret = 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_PRE_PMU: ++ ++ ret = snd_soc_component_read(component, RT5509_REG_OTPCONF); ++ if (ret < 0) ++ return ret; ++ /* check bit 6 and 5 */ ++ ret &= 0x60; ++ if (ret) { ++ ++ return -EINVAL; ++ } ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_CLKEN1, ++ 0x40, 0x00); ++ if (ret < 0) ++ return ret; ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rt5509_boost_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, int event) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_to_component(w->dapm); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ int ret = 0; ++ ++ switch (event) { ++ case SND_SOC_DAPM_PRE_PMU: ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKVMID, ++ RT5509_VMID_ENMASK, RT5509_VMID_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_TRIWAVE_ENMASK, RT5509_TRIWAVE_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MSKFLAG, ++ 0x3F, 0x00); ++ ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_BSTTM, ++ 0x40, 0x40); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_OCPOTPEN, ++ 0x03, 0x03); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_OCPMAX, 0x7f); ++ if (ret < 0) ++ goto out_boost_event; ++ if (chip->chip_rev >= RT5509_CHIP_REVD) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_OVPUVPCTRL, ++ 0xe0, 0xe0); ++ if (ret < 0) ++ goto out_boost_event; ++ } else { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_OVPUVPCTRL, ++ 0x60, 0x60); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CLKEN1, ++ 0x40, 0x40); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_DSPKCONF4, 0xd9); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MSKFLAG, ++ 0x3F, 0x3F); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_BLOCKREF1, ++ 0x0300, 0x0100); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWA, ++ 0x10, 0x10); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKEN1, ++ RT5509_BUF_ENMASK, RT5509_BUF_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_AMPCONF, ++ 0x80, 0x80); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_VBATSENSE, ++ 0x20, 0x20); ++ if (ret < 0) ++ goto out_boost_event; ++ if (chip->chip_rev >= RT5509_CHIP_REVD) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_BIASRESISTOR, 0x0001, 0x0000); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ mdelay(6); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_AMPCONF, ++ 0x38, 0x38); ++ if (ret < 0) ++ goto out_boost_event; ++ ret = snd_soc_component_read(component, RT5509_REG_BST_MODE); ++ ++ if (ret < 0) ++ goto out_boost_event; ++ chip->mode_store = ret; ++ ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_BST_MODE, ++ 0x03, 0x01); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_ISENSE_CTRL, 0x97); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWA, ++ 0x04, 0x04); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ ++ break; ++ case SND_SOC_DAPM_POST_PMU: ++ mdelay(11); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_PILOTNISENSE, ++ 0x07, 0x03); ++ if (ret < 0) ++ goto out_boost_event; ++ if (chip->chip_rev >= RT5509_CHIP_REVD) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWA, ++ 0x01, 0x01); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ ++ if (!chip->recv_spec_set) { ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_PILOTEN, ++ 0x01, 0x01); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ break; ++ case SND_SOC_DAPM_PRE_PMD: ++ ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ goto out_boost_event; ++ if (ret & RT5509_SPKPROT_ENMASK) { ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, ~RT5509_SPKPROT_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, RT5509_SPKPROT_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_PILOTEN, ++ 0x01, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_PILOTNISENSE, ++ 0x07, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF1, ++ 0x20, 0x20); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ break; ++ case SND_SOC_DAPM_POST_PMD: ++ ++ mdelay(1); ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_DSPKCONF1, ++ 0x20, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_SPKAMP_ENMASK, RT5509_SPKAMP_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(11); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF1, ++ 0x20, 0x20); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_CHIPEN, ++ RT5509_SPKAMP_ENMASK, ~RT5509_SPKAMP_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF1, ++ 0x20, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ mdelay(1); ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWA, ++ 0x05, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_ISENSE_CTRL, 0x03); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_AMPCONF, ++ 0x38, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ if (chip->chip_rev >= RT5509_CHIP_REVD) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_BIASRESISTOR, 0x0001, 0x0001); ++ if (ret < 0) ++ goto out_boost_event; ++ } ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_VBATSENSE, ++ 0x20, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_AMPCONF, ++ 0x80, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKEN1, ++ RT5509_BUF_ENMASK, ~RT5509_BUF_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_MTPFLOWA, ++ 0x10, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_BLOCKREF1, ++ 0x0300, 0x0000); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_DSPKCONF4, 0x15); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_OVPUVPCTRL, ++ 0xe0, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_write(component,RT5509_REG_OCPMAX, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_OCPOTPEN, ++ 0x03, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_BSTTM, ++ 0x40, 0x00); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_CHIPEN, ++ RT5509_TRIWAVE_ENMASK, ~RT5509_TRIWAVE_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ ++ ret = snd_soc_component_update_bits(component,RT5509_REG_DSPKVMID, ++ RT5509_VMID_ENMASK, ~RT5509_VMID_ENMASK); ++ if (ret < 0) ++ goto out_boost_event; ++ break; ++ default: ++ break; ++ } ++out_boost_event: ++ ++ return ret; ++} ++ ++static const char * const rt5509_i2smux_text[] = { "I2S1", "I2S2"}; ++static const char * const rt5509_i2sdomux_text[] = { "I2SDOR/L", "DATAI3"}; ++static SOC_ENUM_SINGLE_DECL(rt5509_i2s_muxsel, ++ SND_SOC_NOPM, 0, rt5509_i2smux_text); ++static SOC_ENUM_SINGLE_DECL(rt5509_i2s_dosel, ++ RT5509_REG_I2SDOSEL, 1, rt5509_i2sdomux_text); ++static const struct snd_kcontrol_new rt5509_i2smux_ctrl = ++ SOC_DAPM_ENUM("Switch", rt5509_i2s_muxsel); ++static const struct snd_kcontrol_new rt5509_i2sdo_ctrl = ++ SOC_DAPM_ENUM("Switch", rt5509_i2s_dosel); ++static const struct snd_soc_dapm_widget rt5509_component_dapm_widgets[] = { ++ SND_SOC_DAPM_MUX("I2S Mux", SND_SOC_NOPM, 0, 0, &rt5509_i2smux_ctrl), ++ SND_SOC_DAPM_MUX("I2SDO Mux", RT5509_REG_I2SDOSEL, 0, 0, ++ &rt5509_i2sdo_ctrl), ++ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0), ++ SND_SOC_DAPM_OUT_DRV_E("BOOST", RT5509_REG_CHIPEN, RT5509_SPKAMP_ENSHFT, ++ 0, NULL, 0, rt5509_boost_event, SND_SOC_DAPM_PRE_PMU | ++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | ++ SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_SUPPLY("CLK", RT5509_REG_PLLCONF1, 0, 1, rt5509_clk_event, ++ SND_SOC_DAPM_PRE_PMU), ++ SND_SOC_DAPM_SPK("Speaker", NULL), ++}; ++ ++static const struct snd_soc_dapm_route rt5509_component_dapm_routes[] = { ++ { "I2S Mux", "I2S1", "AIF1 Playback"}, ++ { "I2S Mux", "I2S2", "AIF2 Playback"}, ++ /* DATAO path start */ ++ { "I2SDO Mux", "I2SDOR/L", "I2S Mux"}, ++ { "I2SDO Mux", "DATAI3", "I2S Mux"}, ++ { "AIF1 Capture", NULL, "I2SDO Mux"}, ++ /* DATAO path end */ ++ { "DAC", NULL, "I2S Mux"}, ++ { "DAC", NULL, "CLK"}, ++ { "PGA", NULL, "DAC"}, ++ { "BOOST", NULL, "PGA"}, ++ { "Speaker", NULL, "BOOST"}, ++ ++}; ++ ++ ++static const struct snd_soc_dapm_widget rt5509_component_dapm2_widgets[] = { ++ SND_SOC_DAPM_MUX("Ch2 I2S Mux", SND_SOC_NOPM, 0, 0, &rt5509_i2smux_ctrl), ++ SND_SOC_DAPM_MUX("Ch2 I2SDO Mux", RT5509_REG_I2SDOSEL, 0, 0, ++ &rt5509_i2sdo_ctrl), ++ SND_SOC_DAPM_DAC("Ch2 DAC", NULL, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_PGA("Ch2 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), ++ SND_SOC_DAPM_OUT_DRV_E("Ch2 BOOST", RT5509_REG_CHIPEN, RT5509_SPKAMP_ENSHFT, ++ 0, NULL, 0, rt5509_boost_event, SND_SOC_DAPM_PRE_PMU | ++ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | ++ SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_SUPPLY("Ch2 CLK", RT5509_REG_PLLCONF1, 0, 1, rt5509_clk_event, ++ SND_SOC_DAPM_PRE_PMU), ++ SND_SOC_DAPM_SPK("Ch2 Speaker", NULL), ++}; ++ ++ ++ ++ ++static const struct snd_soc_dapm_route rt5509_component_dapm2_routes[] = { ++ { "Ch2 I2S Mux", "I2S1", "Ch2 AIF1 Playback"}, ++ { "Ch2 I2S Mux", "I2S2", "Ch2 AIF2 Playback"}, ++ /* DATAO path start */ ++ { "Ch2 I2SDO Mux", "I2SDOR/L", "Ch2 I2S Mux"}, ++ { "Ch2 I2SDO Mux", "DATAI3", "Ch2 I2S Mux"}, ++// { "Ch2 AIF1 Capture", NULL, "Ch2 I2SDO Mux"}, ++ /* DATAO path end */ ++ { "Ch2 DAC", NULL, "Ch2 I2S Mux"}, ++ { "Ch2 DAC", NULL, "Ch2 CLK"}, ++ { "Ch2 PGA", NULL, "Ch2 DAC"}, ++ { "Ch2 BOOST", NULL, "Ch2 PGA"}, ++ { "Ch2 Speaker", NULL, "Ch2 BOOST"}, ++}; ++ ++ ++static int rt5509_alcfixed_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ int ret = 0; ++ ++ if (!chip->rlr_func) ++ return -EINVAL; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_ALCGAIN); ++ if (ret < 0) ++ return ret; ++ ucontrol->value.integer.value[0] = ret & 0x0f; ++ return 0; ++} ++ ++static int rt5509_alcfixed_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; ++ int orig_pwron = 0, val = 0, ret = 0; ++ ++ if (ucontrol->value.enumerated.item[0] >= se->items) ++ return -EINVAL; ++ if (!chip->rlr_func) ++ return -EINVAL; ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ orig_pwron = (ret & RT5509_CHIPPD_ENMASK) ? 0 : 1; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ~RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ val = ucontrol->value.enumerated.item[0]; ++ ++ ret = snd_soc_component_write(component,RT5509_REG_ALCMINGAIN, val); ++ if (ret < 0) ++ return ret; ++ val += (val << 4); ++ ++ ret = snd_soc_component_write(component, RT5509_REG_ALCGAIN, val); ++ if (ret < 0) ++ return ret; ++ if (!orig_pwron) { ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int rt5509_rlrfunc_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = chip->rlr_func; ++ return 0; ++} ++ ++static int rt5509_rlrfunc_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; ++ int orig_pwron = 0, orig_proton = 0, ret = 0; ++ ++ if (ucontrol->value.enumerated.item[0] >= se->items) ++ return -EINVAL; ++ ++ if (ucontrol->value.enumerated.item[0] == chip->rlr_func) ++ return 0; ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ ++ ++ if (ret < 0) ++ return ret; ++ orig_pwron = (ret & RT5509_CHIPPD_ENMASK) ? 0 : 1; ++ orig_proton = (ret & RT5509_SPKPROT_ENMASK) ? 1 : 0; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK | RT5509_SPKPROT_ENMASK, ++ 0); ++ if (ret < 0) ++ return ret; ++ if (ucontrol->value.enumerated.item[0]) { ++ ret = snd_soc_component_update_bits(component, RT5509_REG_FUNCEN, ++ 0x1f, 0x12); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_read(component, RT5509_REG_FUNCEN); ++ if (ret < 0) ++ return ret; ++ if (!(ret & 0x80)) { ++ ret = snd_soc_component_read(component, RT5509_REG_NDELAY); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_NDELAY, ++ ret + 0x128f5c); ++ if (ret < 0) ++ return ret; ++ } ++ ret =snd_soc_component_read(component, RT5509_REG_ALCGAIN); ++ if (ret < 0) ++ return ret; ++ chip->alc_gain = (u8)ret; ++ ret = snd_soc_component_read(component, RT5509_REG_ALCMINGAIN); ++ if (ret < 0) ++ return ret; ++ chip->alc_min_gain = (u8)ret; ++ ret = snd_soc_component_write(component, RT5509_REG_ALCGAIN, 0x00); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_ALCMINGAIN, 0x00); ++ if (ret < 0) ++ return ret; ++ } else { ++ ret = snd_soc_component_update_bits(component, RT5509_REG_FUNCEN, ++ 0x1f, 0x1f); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_read(component, RT5509_REG_FUNCEN); ++ if (ret < 0) ++ return ret; ++ if (!(ret & 0x80)) { ++ ret = snd_soc_component_read(component, RT5509_REG_NDELAY); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_NDELAY, ++ ret - 0x128f5c); ++ if (ret < 0) ++ return ret; ++ } ++ ret = snd_soc_component_write(component, RT5509_REG_ALCGAIN, chip->alc_gain); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_ALCMINGAIN, ++ chip->alc_min_gain); ++ if (ret < 0) ++ return ret; ++ } ++ if (orig_proton) { ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, 0xff); ++ if (ret < 0) ++ return ret; ++ } ++ if (!orig_pwron) { ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, 0xff); ++ if (ret < 0) ++ return ret; ++ } ++ chip->rlr_func = ucontrol->value.enumerated.item[0]; ++ return 0; ++} ++ ++ ++static int rt5509_recv_config_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = chip->recv_spec_set; ++ return 0; ++} ++ ++static int rt5509_recv_config_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; ++ int orig_pwron = 0, ret = 0; ++ ++ if (ucontrol->value.enumerated.item[0] >= se->items) ++ return -EINVAL; ++ if (ucontrol->value.enumerated.item[0] == chip->recv_spec_set) ++ return 0; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ orig_pwron = (ret & RT5509_CHIPPD_ENMASK) ? 0 : 1; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ~RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ if (ucontrol->value.enumerated.item[0]) { ++ /* backup gain ++ */ ++ ret = snd_soc_component_read(component, RT5509_REG_SPKGAIN); ++ if (ret < 0) ++ return ret; ++ chip->classd_gain_store = ret; ++ ret =snd_soc_component_read(component, RT5509_REG_DSPKCONF1); ++ if (ret < 0) ++ return ret; ++ chip->pgain_gain_store = ret; ++ ret = snd_soc_component_read(component, RT5509_REG_BST_SIG_GAIN); ++ if (ret < 0) ++ return ret; ++ chip->sig_gain_store = ret; ++ ret = snd_soc_component_read(component, RT5509_REG_CLIP_SIGMAX); ++ if (ret < 0) ++ return ret; ++ chip->sig_max_store = ret; ++ /* backup gain -- */ ++ /* default set to model 1 */ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_SPKGAIN , 0xe0, 0x00); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_BST_SIG_GAIN , 0x12); ++ if (ret < 0) ++ return ret; ++ ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_DSPKCONF1, ++ 0x03, 0x02); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CLIP_CTRL, ++ 0x80, 0x00); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_CLIP_SIGMAX, 0x7fff); ++ if (ret < 0) ++ return ret; ++ if (orig_pwron) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_PILOTEN, ++ 0x01, 0x00); ++ if (ret < 0) ++ return ret; ++ } ++ ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_TDEN, 0x20, 0x00); ++ ++ if (ret < 0) ++ return ret; ++ } else { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_TDEN, 0x20, 0x20); ++ if (ret < 0) ++ return ret; ++ if (orig_pwron) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_PILOTEN, ++ 0x01, 0x00); ++ if (ret < 0) ++ return ret; ++ } ++ /* restore gain ++ */ ++ ++ ret = snd_soc_component_write(component, RT5509_REG_CLIP_SIGMAX, ++ chip->sig_max_store); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_BST_SIG_GAIN, ++ chip->sig_gain_store); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_DSPKCONF1, ++ chip->pgain_gain_store); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_SPKGAIN, ++ chip->classd_gain_store); ++ if (ret < 0) ++ return ret; ++ /* restore gain -- */ ++ } ++ if (!orig_pwron) { ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ } ++ chip->recv_spec_set = ucontrol->value.enumerated.item[0]; ++ return 0; ++} ++ ++ ++ ++ ++static int rt5509_bypassdsp_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = chip->bypass_dsp; ++ return 0; ++} ++ ++static int rt5509_bypassdsp_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; ++ int orig_pwron = 0, ret = 0; ++ ++ if (ucontrol->value.enumerated.item[0] >= se->items) ++ return -EINVAL; ++ if (ucontrol->value.enumerated.item[0] == chip->bypass_dsp) ++ return 0; ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ orig_pwron = (ret & RT5509_CHIPPD_ENMASK) ? 0 : 1; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ~RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ if (ucontrol->value.enumerated.item[0]) { ++ ++ ret = snd_soc_component_read(component, RT5509_REG_FUNCEN); ++ if (ret < 0) ++ return ret; ++ chip->func_en = ret; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ chip->spk_prot_en = ret & RT5509_SPKPROT_ENMASK; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_FUNCEN, 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, 0); ++ if (ret < 0) ++ return ret; ++ } else { ++ ++ ret = snd_soc_component_write(component, RT5509_REG_FUNCEN, chip->func_en); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_FUNCEN, 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component, RT5509_REG_FUNCEN, chip->func_en); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENMASK, ++ chip->spk_prot_en); ++ if (ret < 0) ++ return ret; ++ } ++ if (!orig_pwron) { ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ } ++ chip->bypass_dsp = ucontrol->value.enumerated.item[0]; ++ return 0; ++} ++static int rt5509_put_spk_volsw(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct snd_soc_dapm_context *dapm = ++ snd_soc_component_get_dapm(component); ++ ++ int orig_pwron = 0, ret = 0; ++ ++ orig_pwron = (dapm->bias_level == SND_SOC_BIAS_OFF) ? 0 : 1; ++ if (!orig_pwron) { ++ ret = rt5509_set_bias_level(component, SND_SOC_BIAS_STANDBY); ++ if (ret < 0) ++ return ret; ++ } ++ ++ ret = snd_soc_put_volsw(kcontrol, ucontrol); ++ ++ ++ ++ if (ret < 0) ++ return ret; ++ if (!orig_pwron) { ++ ret = rt5509_set_bias_level(component, SND_SOC_BIAS_OFF); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int rt5509_put_enum_double(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct snd_soc_dapm_context *dapm = ++ snd_soc_component_get_dapm(component); ++ int orig_pwron = 0, ret = 0; ++ ++ orig_pwron = (dapm->bias_level == SND_SOC_BIAS_OFF) ? 0 : 1; ++ if (!orig_pwron) { ++ ret = rt5509_set_bias_level(component, SND_SOC_BIAS_STANDBY); ++ if (ret < 0) ++ return ret; ++ } ++ ret = snd_soc_put_enum_double(kcontrol, ucontrol); ++ ++ if (ret < 0) ++ return ret; ++ if (!orig_pwron) { ++ ret = rt5509_set_bias_level(component, SND_SOC_BIAS_OFF); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int rt5509_recv_model_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ int ret = 0; ++ ++ if (!chip->recv_spec_set) ++ return -EINVAL; ++ ++ ret = snd_soc_component_read(component, RT5509_REG_SPKGAIN); ++ ++ if (ret < 0) ++ return ret; ++ ++ ucontrol->value.integer.value[0] = (ret & 0xe0) >> 5; ++ return 0; ++} ++ ++static int rt5509_recv_model_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; ++ int orig_pwron = 0, ret = 0; ++ ++ if (ucontrol->value.enumerated.item[0] >= se->items) ++ return -EINVAL; ++ if (!chip->recv_spec_set) ++ return -EINVAL; ++ ret = snd_soc_component_read(component, RT5509_REG_CHIPEN); ++ if (ret < 0) ++ return ret; ++ orig_pwron = (ret & RT5509_CHIPPD_ENMASK) ? 0 : 1; ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ ~RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ if (ucontrol->value.enumerated.item[0]) { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_SPKGAIN, ++ 0xe0, 0x20); ++ if (ret < 0) ++ return ret; ++ ++ ret = snd_soc_component_write(component,RT5509_REG_BST_SIG_GAIN, 0x1a); ++ if (ret < 0) ++ return ret; ++ } else { ++ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_SPKGAIN, ++ 0xe0, 0x00); ++ if (ret < 0) ++ return ret; ++ ret = snd_soc_component_write(component, RT5509_REG_BST_SIG_GAIN, 0x12); ++ if (ret < 0) ++ return ret; ++ } ++ if (!orig_pwron) { ++ ret = snd_soc_component_update_bits(component, ++ RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, ++ RT5509_CHIPPD_ENMASK); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++static int rt5509_put_calib_start(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ struct rt5509_calib_classdev *cdev = &chip->calib_dev; ++ int ret = 0; ++ ++ if (ucontrol->value.integer.value[0] != 5526799) ++ return -EINVAL; ++ ++ ret = cdev->trigger_read(cdev); ++ if (ret < 0) { ++ dev_err(cdev->dev, "failed to trigger_read action\n"); ++ return ret; ++ } ++ ++ ret = cdev->trigger_calculation(cdev); ++ if (ret < 0) { ++ dev_err(cdev->dev, "failed to trigger_calculation action\n"); ++ return ret; ++ } ++ ++ ret = cdev->trigger_write(cdev); ++ if (ret < 0) { ++ dev_err(cdev->dev, "failed to trigger_write action\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rt5509_get_calib_flag(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_kcontrol_component(kcontrol); ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = chip->calibrated; ++ return 0; ++} ++ ++ ++//static const DECLARE_TLV_DB_SCALE(vol_ctl_tlv, -1155, 5, 0); ++static const DECLARE_TLV_DB_SCALE(dacvol_tlv, -1275, 5, 0); ++static const char * const rt5509_enable_text[] = { "Disable", "Enable"}; ++static const char * const rt5509_slots_text[] = { "Slot 0", "Slot 1"}; ++static const char * const rt5509_alcgain_text[] = { ++ "0dB", "3dB", "6dB", "9dB", "12dB", "15dB", "18dB", "21dB" }; ++static const DECLARE_TLV_DB_SCALE(predspvol_tlv, 0, 6, 0); ++static const char * const rt5509_recvmodel_text[] = { "model1", "model2"}; ++static const struct soc_enum rt5509_enum[] = { ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rt5509_enable_text), rt5509_enable_text), ++ SOC_ENUM_SINGLE(RT5509_REG_TDM_CTRL, 2, ARRAY_SIZE(rt5509_slots_text), ++ rt5509_slots_text), ++ SOC_ENUM_SINGLE(RT5509_REG_TDM_CTRL, 1, ARRAY_SIZE(rt5509_slots_text), ++ rt5509_slots_text), ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rt5509_alcgain_text), ++ rt5509_alcgain_text), ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rt5509_recvmodel_text), ++ rt5509_recvmodel_text), ++}; ++static const struct snd_kcontrol_new rt5509_component_snd_controls[] = { ++ SOC_SINGLE_EXT_TLV("DAC Volume", RT5509_REG_VOLUME, 0, 255, 1, ++ snd_soc_get_volsw, rt5509_put_spk_volsw, dacvol_tlv), ++ SOC_SINGLE_EXT("Speaker Protection", RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENSHFT, ++ 1, 0, snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Limiter Func", RT5509_REG_FUNCEN, ++ RT5509_LMTEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("ALC Func", RT5509_REG_FUNCEN, RT5509_ALCEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("CLIP Func", RT5509_REG_CLIP_CTRL, ++ RT5509_CLIPEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("BoostMode", RT5509_REG_BST_MODE, ++ RT5509_BSTMODE_SHFT, 3, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("I2S_Channel", RT5509_REG_I2SSEL, ++ RT5509_I2SLRSEL_SHFT, 3, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ext_DO_Enable", RT5509_REG_I2SDOSEL, 0, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("I2SDOL Mux", RT5509_REG_I2SDOLRSEL, 0, 15, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("I2SDOR Mux", RT5509_REG_I2SDOLRSEL, 4, 15, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_ENUM_EXT("BypassDSP", rt5509_enum[0], rt5509_bypassdsp_get, ++ rt5509_bypassdsp_put), ++ SOC_ENUM_EXT("Recv_Special_Set", rt5509_enum[0], rt5509_recv_config_get, ++ rt5509_recv_config_put), ++ SOC_ENUM_EXT("RLR Func", rt5509_enum[0], rt5509_rlrfunc_get, ++ rt5509_rlrfunc_put), ++ SOC_ENUM_EXT("TDM_ADC_SEL", rt5509_enum[1], snd_soc_get_enum_double, ++ rt5509_put_enum_double), ++ SOC_ENUM_EXT("TDM_DAC_SEL", rt5509_enum[2], snd_soc_get_enum_double, ++ rt5509_put_enum_double), ++ SOC_ENUM_EXT("ALC Fixed Gain", rt5509_enum[3], rt5509_alcfixed_gain_get, ++ rt5509_alcfixed_gain_put), ++ SOC_SINGLE_EXT_TLV("PreDSP Volume", RT5509_REG_ALCMINGAIN, 4, 2, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw, predspvol_tlv), ++ SOC_ENUM_EXT("Recv_Model_Set", rt5509_enum[4], rt5509_recv_model_get, ++ rt5509_recv_model_put), ++ SOC_SINGLE_EXT("Calib_Start", SND_SOC_NOPM, 0, 0, 0, ++ rt5509_get_calib_flag, rt5509_put_calib_start), ++ ++ ++}; ++ ++static const struct snd_kcontrol_new rt5509_component_snd2_controls[] = { ++ SOC_SINGLE_EXT_TLV("Ch2 DAC Volume", RT5509_REG_VOLUME, 0, 255, 1, ++ snd_soc_get_volsw, rt5509_put_spk_volsw, dacvol_tlv), ++ SOC_SINGLE_EXT("Ch2 Speaker Protection", RT5509_REG_CHIPEN, ++ RT5509_SPKPROT_ENSHFT, ++ 1, 0, snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 Limiter Func", RT5509_REG_FUNCEN, ++ RT5509_LMTEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 ALC Func", RT5509_REG_FUNCEN, RT5509_ALCEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 CLIP Func", RT5509_REG_CLIP_CTRL, ++ RT5509_CLIPEN_SHFT, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 BoostMode", RT5509_REG_BST_MODE, ++ RT5509_BSTMODE_SHFT, 3, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 I2S_Channel", RT5509_REG_I2SSEL, ++ RT5509_I2SLRSEL_SHFT, 3, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 Ext_DO_Enable", RT5509_REG_I2SDOSEL, 0, 1, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 I2SDOL Mux", RT5509_REG_I2SDOLRSEL, 0, 15, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_SINGLE_EXT("Ch2 I2SDOR Mux", RT5509_REG_I2SDOLRSEL, 4, 15, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw), ++ SOC_ENUM_EXT("Ch2 BypassDSP", rt5509_enum[0], rt5509_bypassdsp_get, ++ rt5509_bypassdsp_put), ++ SOC_ENUM_EXT("Ch2 Recv_Special_Set", rt5509_enum[0], rt5509_recv_config_get, ++ rt5509_recv_config_put), ++ SOC_ENUM_EXT("Ch2 RLR Func", rt5509_enum[0], rt5509_rlrfunc_get, ++ rt5509_rlrfunc_put), ++ SOC_ENUM_EXT("Ch2 TDM_ADC_SEL", rt5509_enum[1], snd_soc_get_enum_double, ++ rt5509_put_enum_double), ++ SOC_ENUM_EXT("Ch2 TDM_DAC_SEL", rt5509_enum[2], snd_soc_get_enum_double, ++ rt5509_put_enum_double), ++ SOC_ENUM_EXT("Ch2 ALC Fixed Gain", rt5509_enum[3], rt5509_alcfixed_gain_get, ++ rt5509_alcfixed_gain_put), ++ SOC_SINGLE_EXT_TLV("Ch2 PreDSP Volume", RT5509_REG_ALCMINGAIN, 4, 2, 0, ++ snd_soc_get_volsw, rt5509_put_spk_volsw, predspvol_tlv), ++ SOC_ENUM_EXT("Ch2 Recv_Model_Set", rt5509_enum[4], rt5509_recv_model_get, ++ rt5509_recv_model_put), ++ SOC_SINGLE_EXT("Ch2 Calib_Start", SND_SOC_NOPM, 0, 0, 0, ++ rt5509_get_calib_flag, rt5509_put_calib_start), ++ ++}; ++ ++static int rt5509_component_setting(struct snd_soc_component *component) ++{ ++ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ int ret = 0; ++ ++ ++ /* CHIP Enable */ ++ rt5509_power_on(chip, true); ++ ret = rt5509_init_general_setting(component); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ret = rt5509_init_adaptive_setting(component); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ret = rt5509_init_battmode_setting(component); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ret = rt5509_do_tcsense_fix(component); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ret = rt5509_init_proprietary_setting(component); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ret = rt5509_init_reg_setting(component); ++ ++ if (ret < 0) { ++ ++ goto err_out_probe; ++ } ++ ++ ret = rt5509_param_create(chip); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ++ ret = rt5509_calib_create(chip); ++ ++ if (ret < 0) ++ goto err_out_probe; ++ ++ return rt5509_set_bias_level(component, SND_SOC_BIAS_OFF); ++err_out_probe: ++ ++ /* Chip Disable */ ++ ret = snd_soc_component_update_bits(component, RT5509_REG_CHIPEN, ++ RT5509_CHIPPD_ENMASK, RT5509_CHIPPD_ENMASK); ++ ++ return ret < 0 ? ret : -EINVAL; ++ ++ return 0; ++} ++ ++static int rt5509_component_probe(struct snd_soc_component *component) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ int ret = 0; ++ ++ pm_runtime_get_sync(component->dev); ++ ++ chip->component = component; ++ snd_soc_component_init_regmap(component, chip->regmap); ++ ++ ret = rt5509_component_setting(component); ++ ++ if (ret < 0) { ++ goto component_probe_fail; ++ } ++ ++#if IS_ENABLED(CONFIG_SND_SOC_MTK_AUDIO_DSP) ++ chip->spm.max_pwr = 7000; ++ chip->spm.min_pwr = 5500; ++ chip->spm.id = chip->dev_cnt; ++ chip->spm.ops = &rt5509_spm_ops; ++ ret = richtek_spm_classdev_register(component->dev, &chip->spm); ++ ++#endif ++component_probe_fail: ++ pm_runtime_put_sync(component->dev); ++ ++ return ret; ++} ++ ++static void rt5509_component_remove(struct snd_soc_component *component) ++{ ++#if IS_ENABLED(CONFIG_SND_SOC_MTK_AUDIO_DSP) ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(component); ++ ++ richtek_spm_classdev_unregister(&chip->spm); ++#endif ++ snd_soc_component_exit_regmap(component); ++} ++ ++ ++ ++ ++ ++static const struct snd_soc_component_driver rt5509_component_driver = { ++ .probe = rt5509_component_probe, ++ .remove = rt5509_component_remove, ++ ++ .controls = rt5509_component_snd_controls, ++ .num_controls = ARRAY_SIZE(rt5509_component_snd_controls), ++ .dapm_widgets = rt5509_component_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(rt5509_component_dapm_widgets), ++ .dapm_routes = rt5509_component_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(rt5509_component_dapm_routes), ++ .set_bias_level = rt5509_set_bias_level, ++ .idle_bias_on = true, ++ .read = rt5509_io_read, ++ .write = rt5509_io_write, ++}; ++ ++static const struct snd_soc_component_driver rt5509_component_driver2 = { ++ .probe = rt5509_component_probe, ++ .remove = rt5509_component_remove, ++ ++ .controls = rt5509_component_snd2_controls, ++ .num_controls = ARRAY_SIZE(rt5509_component_snd2_controls), ++ .dapm_widgets = rt5509_component_dapm2_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(rt5509_component_dapm2_widgets), ++ .dapm_routes = rt5509_component_dapm2_routes, ++ .num_dapm_routes = ARRAY_SIZE(rt5509_component_dapm2_routes), ++ .set_bias_level = rt5509_set_bias_level, ++ ++ .idle_bias_on = true, ++ .read = rt5509_io_read, ++ .write = rt5509_io_write, ++}; ++ ++ ++static int rt5509_aif_set_tdm_slot(struct snd_soc_dai *dai, ++ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) ++{ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(dai->component); ++ ++ if (!slots) { ++ dev_dbg(dai->dev, "disable TDM\n"); ++ chip->tdm_mode = 0; ++ } else if (slots == 4) { ++ dev_dbg(dai->dev, "enable TDM\n"); ++ chip->tdm_mode = 1; ++ } else ++ return -EINVAL; ++ return snd_soc_component_update_bits(dai->component, RT5509_REG_TDM_CTRL, ++ RT5509_TDM_ENMASK, ++ chip->tdm_mode ? 0xff : 0); ++} ++ ++static int rt5509_aif_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ u8 regval = 0; ++ int ret = 0; ++ ++ dev_dbg(dai->dev, "%s: fmt:%d\n", __func__, fmt); ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ regval |= (RT5509_AUDFMT_I2S << RT5509_AUDFMT_SHFT); ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ regval |= (RT5509_AUDFMT_RIGHTJ << RT5509_AUDFMT_SHFT); ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ regval |= (RT5509_AUDFMT_LEFTJ << RT5509_AUDFMT_SHFT); ++ break; ++ case SND_SOC_DAIFMT_DSP_A: ++ regval |= (RT5509_DSP_MODEA << RT5509_DSPMODE_SHFT); ++ break; ++ case SND_SOC_DAIFMT_DSP_B: ++ regval |= (RT5509_DSP_MODEB << RT5509_DSPMODE_SHFT); ++ break; ++ default: ++ break; ++ } ++ ++ ret = snd_soc_component_update_bits(dai->component, ++ RT5509_REG_AUDFMT, ++ RT5509_DSPMODE_MASK | RT5509_AUDFMT_MASK, regval); ++ ++ if (ret < 0) ++ dev_err(dai->dev, "config dac audfmt error\n"); ++ // ret = 0; ++ return ret; ++} ++ ++static int rt5509_aif_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) ++ ++{ ++ ++ struct rt5509_chip *chip = snd_soc_component_get_drvdata(dai->component); ++ ++ unsigned int rate = params_rate(hw_params); ++ snd_pcm_format_t format = params_format(hw_params); ++ ++ /* 0 for sr and bckfs, 1 for audbits */ ++ u8 regval[2] = {0}; ++ u32 pll_divider = 0; ++ u8 word_len = 0; ++ int ret = 0; ++ ++ switch (format) { ++ case SNDRV_PCM_FORMAT_S16: ++ case SNDRV_PCM_FORMAT_U16: ++ regval[0] |= (RT5509_BCKMODE_32FS << RT5509_BCKMODE_SHFT); ++ regval[1] |= (RT5509_AUDBIT_16 << RT5509_AUDBIT_SHFT); ++ pll_divider = 0x00100000; ++ word_len = 16 * 4; ++ break; ++ case SNDRV_PCM_FORMAT_S18_3LE: ++ case SNDRV_PCM_FORMAT_U18_3LE: ++ case SNDRV_PCM_FORMAT_S18_3BE: ++ case SNDRV_PCM_FORMAT_U18_3BE: ++ regval[0] |= (RT5509_BCKMODE_48FS << RT5509_BCKMODE_SHFT); ++ regval[1] |= (RT5509_AUDBIT_18 << RT5509_AUDBIT_SHFT); ++ pll_divider = 0x000c0000; ++ word_len = 18 * 4; ++ break; ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ case SNDRV_PCM_FORMAT_U20_3LE: ++ case SNDRV_PCM_FORMAT_S20_3BE: ++ case SNDRV_PCM_FORMAT_U20_3BE: ++ regval[0] |= (RT5509_BCKMODE_48FS << RT5509_BCKMODE_SHFT); ++ regval[1] |= (RT5509_AUDBIT_20 << RT5509_AUDBIT_SHFT); ++ pll_divider = 0x000c0000; ++ word_len = 20 * 4; ++ break; ++ case SNDRV_PCM_FORMAT_S24_3LE: ++ case SNDRV_PCM_FORMAT_S24_3BE: ++ case SNDRV_PCM_FORMAT_U24_3LE: ++ case SNDRV_PCM_FORMAT_U24_3BE: ++ regval[0] |= (RT5509_BCKMODE_48FS << RT5509_BCKMODE_SHFT); ++ regval[1] |= (RT5509_AUDBIT_24 << RT5509_AUDBIT_SHFT); ++ pll_divider = 0x000c0000; ++ word_len = 24 * 4; ++ break; ++ case SNDRV_PCM_FORMAT_S32: ++ case SNDRV_PCM_FORMAT_U32: ++ regval[0] |= (RT5509_BCKMODE_64FS << RT5509_BCKMODE_SHFT); ++ regval[1] |= (RT5509_AUDBIT_24 << RT5509_AUDBIT_SHFT); ++ pll_divider = 0x00080000; ++ word_len = 24 * 4; ++ break; ++ default: ++ ret = -EINVAL; ++ goto out_hw_params; ++ } ++ ++ switch (rate) { ++ case 8000: ++ regval[0] |= (RT5509_SRMODE_8K << RT5509_SRMODE_SHFT); ++ pll_divider *= 6; ++ break; ++ case 11025: ++ case 12000: ++ regval[0] |= (RT5509_SRMODE_12K << RT5509_SRMODE_SHFT); ++ pll_divider *= 4; ++ break; ++ case 16000: ++ regval[0] |= (RT5509_SRMODE_16K << RT5509_SRMODE_SHFT); ++ pll_divider *= 3; ++ break; ++ case 22050: ++ case 24000: ++ regval[0] |= (RT5509_SRMODE_24K << RT5509_SRMODE_SHFT); ++ pll_divider *= 2; ++ break; ++ case 32000: ++ regval[0] |= (RT5509_SRMODE_32K << RT5509_SRMODE_SHFT); ++ pll_divider = (pll_divider * 3) >> 1; ++ break; ++ case 44100: ++ case 48000: ++ regval[0] |= (RT5509_SRMODE_48K << RT5509_SRMODE_SHFT); ++ break; ++ case 88200: ++ case 96000: ++ regval[0] |= (RT5509_SRMODE_96K << RT5509_SRMODE_SHFT); ++ pll_divider >>= 1; ++ break; ++ case 176400: ++ case 192000: ++ regval[0] |= (RT5509_SRMODE_192K << RT5509_SRMODE_SHFT); ++ pll_divider >>= 2; ++ break; ++ default: ++ ret = -EINVAL; ++ goto out_hw_params; ++ } ++ if (chip->tdm_mode) ++ pll_divider >>= 1; ++ ++ ret = snd_soc_component_update_bits(dai->component, RT5509_REG_AUDSR, ++ RT5509_BCKMODE_MASK | RT5509_SRMODE_MASK, regval[0]); ++ ++ if (ret < 0) { ++ dev_err(dai->dev, "configure bck and sr fail\n"); ++ goto out_hw_params; ++ } ++ ret = snd_soc_component_update_bits(dai->component, RT5509_REG_AUDFMT, ++ RT5509_AUDBIT_MASK, regval[1]); ++ ++ if (ret < 0) { ++ dev_err(dai->dev, "configure audbit fail\n"); ++ goto out_hw_params; ++ } ++ ++ ret = snd_soc_component_write(dai->component,RT5509_REG_PLLDIVISOR, pll_divider); ++ ++ if (ret < 0) { ++ dev_err(dai->dev, "configure pll divider fail\n"); ++ goto out_hw_params; ++ } ++ ret = snd_soc_component_write(dai->component, RT5509_REG_DMGFLAG, word_len); ++ ++ if (ret < 0) ++ dev_err(dai->dev, "configure word len fail\n"); ++ ++out_hw_params: ++ return ret; ++ ++} ++static int rt5509_aif_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ return 0; ++} ++ ++static int rt5509_aif_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ ++ dev_dbg(dai->dev, "%s\n", __func__); ++ return rt5509_set_bias_level(dai->component, SND_SOC_BIAS_STANDBY); ++} ++ ++ ++static void rt5509_aif_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ dev_dbg(dai->dev, "%s\n", __func__); ++} ++ ++static int rt5509_aif_trigger(struct snd_pcm_substream *substream, ++ int cmd, struct snd_soc_dai *dai) ++{ ++ ++ //dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd); ++ //dev_dbg(dai->dev, "%s: %c\n", __func__, capture ? 'c' : 'p'); ++ return 0; ++} ++ ++ ++static const struct snd_soc_dai_ops rt5509_component_aif_ops = { ++ .startup = rt5509_aif_startup, ++ .set_fmt = rt5509_aif_set_fmt, ++ .hw_params = rt5509_aif_hw_params, ++ .shutdown = rt5509_aif_shutdown, ++ .trigger = rt5509_aif_trigger, ++ .prepare = rt5509_aif_prepare, ++ .set_tdm_slot = rt5509_aif_set_tdm_slot, ++}; ++ ++#define RT5509_RATES SNDRV_PCM_RATE_8000_192000 ++#define RT5509_FORMATS (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S18_3LE |\ ++ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE |\ ++ SNDRV_PCM_FMTBIT_S32) ++ ++static struct snd_soc_dai_driver rt5509_i2s_dais[] = { ++ { ++ .name = "rt5509-aif1", ++ .playback = { ++ .stream_name = "AIF1 Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ ++ .capture = { ++ .stream_name = "AIF1 Capture", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ .ops = &rt5509_component_aif_ops, ++ }, ++ { ++ .name = "rt5509-aif1-1", ++ .playback = { ++ .stream_name = "AIF2 Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ ++ .ops = &rt5509_component_aif_ops, ++ }, ++}; ++ ++ ++static struct snd_soc_dai_driver rt5509_ch2_i2s_dais[] = { ++ { ++ .name = "rt5509-aif2", ++ .playback = { ++ .stream_name = "Ch2 AIF1 Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ .capture = { ++ .stream_name = "Ch2 AIF1 Capture", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ .ops = &rt5509_component_aif_ops, ++ }, ++ { ++ .name = "rt5509-aif2-1", ++ .playback = { ++ .stream_name = "Ch2 AIF2 Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = RT5509_RATES, ++ .formats = RT5509_FORMATS, ++ }, ++ .ops =&rt5509_component_aif_ops, ++ }, ++}; ++ ++static int rt5509_handle_pdata(struct rt5509_chip *chip) ++{ ++ return 0; ++} ++ ++static int rt5509_i2c_initreg(struct rt5509_chip *chip) ++{ ++ return rt5509_clr_bits(chip->i2c, RT5509_REG_CHIPEN, ++ RT5509_TRIWAVE_ENMASK); ++} ++ ++static int rt5509_get_chip_rev(struct rt5509_chip *chip) ++{ ++ int ret = 0; ++ u8 data = 0; ++ ++ ret = rt5509_block_read(chip->i2c, RT5509_REG_CHIPREV, 1, &data); ++ if (ret < 0) ++ return ret; ++ if ((data & RT5509_CHIPID_MASK) != RT5509_CHIP_ID) ++ return -ENODEV; ++ chip->chip_rev = (data & RT5509_CHIPREV_MASK) >> RT5509_CHIPREV_SHFT; ++ dev_info(chip->dev, "chip revision %d\n", chip->chip_rev); ++ ++ return 0; ++} ++ ++static int rt5509_sw_reset(struct rt5509_chip *chip) ++{ ++ int ret = 0; ++ u8 data = 0; ++ ++ dev_dbg(chip->dev, "%s\n", __func__); ++ ret = rt5509_block_read(chip->i2c, RT5509_REG_SWRESET, 1, &data); ++ if (ret < 0) ++ return ret; ++ data |= RT5509_SWRST_MASK; ++ ret = rt5509_block_write(chip->i2c, RT5509_REG_SWRESET, 1, &data); ++ mdelay(30); ++ return ret; ++} ++ ++static inline int _rt5509_power_on(struct rt5509_chip *chip, bool en) ++{ ++ int ret = 0; ++ u8 data = 0; ++ ++ dev_dbg(chip->dev, "%s: en %d\n", __func__, en); ++ ret = rt5509_block_read(chip->i2c, RT5509_REG_CHIPEN, 1, &data); ++ if (ret < 0) ++ return ret; ++ data = (en ? (data & ~0x01) : (data | 0x01)); ++ return rt5509_block_write(chip->i2c, RT5509_REG_CHIPEN, 1, &data); ++} ++ ++#ifdef CONFIG_OF ++static inline int rt5509_parse_dt(struct device *dev, ++ struct rt5509_pdata *pdata) ++{ ++ struct device_node *param_np = NULL; ++ struct property *prop = NULL; ++ struct rt5509_proprietary_param *p_param = NULL; ++ u32 len = 0; ++ int i = 0; ++ ++ param_np = of_find_node_by_name(dev->of_node, "proprietary_param"); ++ if (!param_np) ++ goto OUT_PARSE_DT; ++ p_param = devm_kzalloc(dev, sizeof(*p_param), GFP_KERNEL); ++ if (!p_param) ++ return -ENOMEM; ++ for (i = 0; i < RT5509_CFG_MAX; i++) { ++ prop = of_find_property(param_np, prop_str[i], &len); ++ if (!prop) ++ dev_warn(dev, "no %s setting\n", prop_str[i]); ++ else if (!len) ++ dev_warn(dev, "%s cfg size is zero\n", prop_str[i]); ++ else { ++ p_param->cfg[i] = devm_kzalloc(dev, len * sizeof(u8), ++ GFP_KERNEL); ++ if (!p_param->cfg[i]) ++ return -ENOMEM; ++ ++ memcpy(p_param->cfg[i], prop->value, len); ++ p_param->cfg_size[i] = len; ++ } ++ } ++ pdata->p_param = p_param; ++OUT_PARSE_DT: ++ return 0; ++} ++#else ++static inline int rt5509_parse_dt(struct device *dev, ++ struct rt5509_pdata *pdata) ++{ ++ return 0; ++} ++#endif /* #ifdef CONFIG_OF */ ++ ++ ++static inline int rt5509_component_register(struct rt5509_chip *chip) ++{ ++ ++ if (chip->dev_cnt) ++ { ++ return devm_snd_soc_register_component(chip->dev, ++ &rt5509_component_driver2, ++ rt5509_ch2_i2s_dais, ++ ARRAY_SIZE(rt5509_ch2_i2s_dais)); ++ }else ++ { ++ return devm_snd_soc_register_component(chip->dev, ++ &rt5509_component_driver, ++ rt5509_i2s_dais, ++ ARRAY_SIZE(rt5509_i2s_dais)); ++ } ++ ++} ++ ++static struct regmap_config rt5509_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 0xff, ++}; ++ ++int rt5509_i2c_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct rt5509_pdata *pdata = client->dev.platform_data; ++ struct rt5509_chip *chip = NULL; ++ static int dev_cnt; ++ int ret = 0; ++ ++ if (client->dev.of_node) { ++ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); ++ ret = rt5509_parse_dt(&client->dev, pdata); ++ ++ client->dev.platform_data = pdata; ++ } else { ++ if (!pdata) { ++ dev_err(&client->dev, "Failed, no pdata specified\n"); ++ return -EINVAL; ++ } ++ } ++ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ chip->i2c = client; ++ chip->dev = &client->dev; ++ chip->pdata = pdata; ++ chip->dev_cnt = dev_cnt; ++ //mutex_init(&chip->var_lock); ++ i2c_set_clientdata(client, chip); ++ ++ ret = device_create_file(&client->dev, &dev_attr_prop_param); ++ sema_init(&chip->io_semaphore, 1); ++ mutex_init(&chip->var_lock); ++ chip->power_count = 1; ++ ret = _rt5509_power_on(chip, true); ++ ++ if (ret < 0) { ++ dev_err(chip->dev, "power on fail 1\n"); ++ } ++ /* do software reset at default */ ++ ret = rt5509_sw_reset(chip); ++ ++ if (ret < 0) { ++ dev_err(chip->dev, "sw_reset fail\n"); ++ } ++ ret = _rt5509_power_on(chip, true); ++ ++ if (ret < 0) { ++ dev_err(chip->dev, "power on fail 2\n"); ++ } ++ /* get chip revisioin first */ ++ ret = rt5509_get_chip_rev(chip); ++ if (ret < 0) { ++ dev_err(chip->dev, "get chip rev fail\n"); ++ } ++ ++ chip->regmap = devm_regmap_init_i2c(client, &rt5509_regmap_config); ++ if (IS_ERR(chip->regmap)) { ++ ++ ret = PTR_ERR(chip->regmap); ++ dev_err(&client->dev, "failed to initialise regmap: %d\n", ret); ++ return ret; ++ } ++ ++ ret = rt5509_i2c_initreg(chip); ++ if (ret < 0) { ++ dev_err(chip->dev, "init_reg fail\n"); ++ goto probe_fail; ++ } ++ ret = rt5509_handle_pdata(chip); ++ if (ret < 0) { ++ dev_err(chip->dev, "init_pdata fail\n"); ++ goto probe_fail; ++ } ++ ++ ret = rt5509_power_on(chip, false); ++ ++ pm_runtime_set_active(chip->dev); ++ pm_runtime_use_autosuspend(chip->dev); ++ pm_runtime_set_autosuspend_delay(chip->dev, 50); ++ pm_runtime_enable(chip->dev); ++ ++ dev_set_name(chip->dev, "RT5509_MT_%d", chip->dev_cnt); ++ ++ ret = rt5509_component_register(chip); ++ if (ret == 0) { ++ dev_cnt++; ++ } ++ ++ if(chip->dev_cnt==0) ++ rt5509_cal_init(); ++ ++ dev_info(chip->dev, "%s done\n", __func__); ++ return ret; ++ ++probe_fail: ++ _rt5509_power_on(chip, 0); ++ mutex_destroy(&chip->var_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rt5509_i2c_probe); ++ ++int rt5509_i2c_remove(struct i2c_client *client) ++{ ++ struct rt5509_chip *chip = i2c_get_clientdata(client); ++ ++ rt5509_cal_exit(); ++ pm_runtime_disable(chip->dev); ++ pm_runtime_set_suspended(chip->dev); ++ ++ mutex_destroy(&chip->var_lock); ++ return 0; ++} ++EXPORT_SYMBOL(rt5509_i2c_remove); ++ ++static int __maybe_unused rt5509_i2c_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int __maybe_unused rt5509_i2c_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++ ++static const struct dev_pm_ops rt5509_dev_pm_ops = { ++ SET_RUNTIME_PM_OPS(rt5509_i2c_runtime_suspend, ++ rt5509_i2c_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id __maybe_unused rt5509_of_id[] = { ++ { .compatible = "richtek,rt5509",}, ++ { .compatible = "mediatek,speaker_amp",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt5509_of_id); ++ ++static const struct i2c_device_id rt5509_i2c_id[] = { ++ {"rt5509", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(i2c, rt5509_i2c_id); ++ ++static struct i2c_driver rt5509_i2c_driver = { ++ .driver = { ++ .name = "rt5509", ++ .of_match_table = of_match_ptr(rt5509_of_id), ++ .pm = &rt5509_dev_pm_ops, ++ }, ++ .probe = rt5509_i2c_probe, ++ .remove = rt5509_i2c_remove, ++ .id_table = rt5509_i2c_id, ++}; ++module_i2c_driver(rt5509_i2c_driver); ++ ++MODULE_AUTHOR("CY_Huang "); ++MODULE_DESCRIPTION("RT5509 SPKAMP Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(RT5509_DRV_VER); +diff --git a/sound/soc/codecs/rt5509.h b/sound/soc/codecs/rt5509.h +new file mode 100644 +index 000000000000..203b8b2ceefc +--- /dev/null ++++ b/sound/soc/codecs/rt5509.h +@@ -0,0 +1,481 @@ ++/* ++ * Copyright (C) 2019 MediaTek Inc. ++ * ++ * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. ++ */ ++ ++#ifndef __RT5509_H ++#define __RT5509_H ++#include ++#include ++ ++ ++#define RT5509_DEVICE_NAME "rt5509" ++#define RT5509_DRV_VER "1.0.15_M" ++ ++#ifdef CONFIG_RT_REGMAP ++#define RT5509_SIMULATE_DEVICE 0 ++#if RT5509_SIMULATE_DEVICE ++int rt5509_calculate_offset(int reg); ++int rt5509_calculate_total_size(void); ++#endif /* #if RT5509_SIMULATE_DEVICE */ ++#else ++#define RT5509_SIMULATE_DEVICE 0 ++#endif /* #ifdef CONFIG_RT_REGMAP */ ++ ++enum { ++ RT5509_CHIP_REVB = 0, ++ RT5509_CHIP_REVC = 2, ++ RT5509_CHIP_REVD, ++}; ++ ++enum { ++ RT5509_CFG_GENERAL, ++ RT5509_CFG_BOOSTCONV, ++ RT5509_CFG_SPEAKERPROT, ++ RT5509_CFG_SAFEGUARD, ++ RT5509_CFG_EQ, ++ RT5509_CFG_BEW, ++ RT5509_CFG_DCR, ++ RT5509_CFG_MBDRC, ++ RT5509_CFG_ALC, ++ RT5509_CFG_MAX, ++}; ++ ++struct rt5509_proprietary_param { ++ u8 *cfg[RT5509_CFG_MAX]; ++ u32 cfg_size[RT5509_CFG_MAX]; ++}; ++ ++struct rt5509_pdata { ++ struct rt5509_proprietary_param *p_param; ++}; ++ ++struct rt5509_calib_classdev { ++ struct device *dev; ++ uint32_t n20db; ++ uint32_t n15db; ++ uint32_t n10db; ++ uint32_t gsense_otp; ++ uint32_t rspk; ++ uint32_t dcr_offset; ++ uint32_t rapp; ++ int32_t rspkmin; ++ int32_t rspkmax; ++ int32_t alphaspk; ++ int (*trigger_read)(struct rt5509_calib_classdev *); ++ int (*trigger_write)(struct rt5509_calib_classdev *); ++ int (*trigger_calculation)(struct rt5509_calib_classdev *); ++}; ++ ++struct rt5509_chip { ++ struct i2c_client *i2c; ++ struct device *dev; ++ struct snd_soc_component *component; ++ struct rt5509_pdata *pdata; ++ struct snd_soc_codec *codec; ++ struct platform_device *pdev; ++ struct rt5509_calib_classdev calib_dev; ++ struct rt_regmap_device *rd; ++ struct regmap *regmap; ++#if RT5509_SIMULATE_DEVICE ++ void *sim; ++#endif /* #if RT5509_SIMULATE_DEVICE */ ++ struct semaphore io_semaphore; ++ struct mutex var_lock; ++ int power_count; ++ int bias_level; ++ u8 chip_rev; ++ u8 mode_store; ++ u8 func_en; ++ u8 spk_prot_en; ++ u8 alc_gain; ++ u8 alc_min_gain; ++ u8 classd_gain_store; ++ u8 pgain_gain_store; ++ u8 sig_gain_store; ++ u16 sig_max_store; ++ u16 pilot_freq; ++ u8 recv_spec_set:1; ++ u8 bypass_dsp:1; ++ u8 calibrated:1; ++ u8 tdm_mode:1; ++ u8 rlr_func:1; ++ int dev_cnt; ++}; ++ ++ ++ ++/* RT5509_REGISTER_LIST */ ++#define RT5509_REG_CHIPREV 0x00 ++#define RT5509_REG_EVENTINFO 0x01 ++#define RT5509_REG_DMGFLAG 0x02 ++#define RT5509_REG_CHIPEN 0x03 ++#define RT5509_REG_AUDFMT 0x04 ++#define RT5509_REG_AUDSR 0x05 ++#define RT5509_REG_I2SSEL 0x06 ++#define RT5509_REG_I2SDOLRSEL 0x07 ++#define RT5509_REG_I2SDOSEL 0x08 ++#define RT5509_REG_FUNCEN 0x09 ++#define RT5509_REG_CLIP_THR 0x10 ++#define RT5509_REG_CLIP_CTRL 0x11 ++#define RT5509_REG_CLIP_SLOPE 0x12 ++#define RT5509_REG_CLIP_VOMIN 0x13 ++#define RT5509_REG_CLIP_SIGMAX 0x14 ++#define RT5509_REG_AMPCONF 0x15 ++#define RT5509_REG_DACRNKGAIN 0x16 ++#define RT5509_REG_SAMPOFFS 0x17 ++#define RT5509_REG_SAMPCONF 0x18 ++#define RT5509_REG_DAGAIN 0x19 ++#define RT5509_REG_FFGAIN 0x1A ++#define RT5509_REG_VBATGAIN 0x1B ++#define RT5509_REG_RLDCOEF1 0x1C ++#define RT5509_REG_RLDCOEF2 0x1D ++#define RT5509_REG_BST_MODE 0x1E ++#define RT5509_REG_BST_TH1 0x1F ++#define RT5509_REG_BST_TH2 0x20 ++#define RT5509_REG_BST_TH3 0x21 ++#define RT5509_REG_BST_CONF1 0x22 ++#define RT5509_REG_BST_SIG_GAIN 0x23 ++#define RT5509_REG_BST_CONF2 0x24 ++#define RT5509_REG_BST_CONF3 0x25 ++#define RT5509_REG_OCPOTPEN 0x26 ++#define RT5509_REG_IDAC1TST 0x27 ++#define RT5509_REG_IDAC2TST 0x28 ++#define RT5509_REG_IDAC3TST 0x29 ++#define RT5509_REG_IDACTSTEN 0x2A ++#define RT5509_REG_CCMAX 0x2B ++#define RT5509_REG_OCPMAX 0x2C ++#define RT5509_REG_INTERRUPT 0x2D ++#define RT5509_REG_INTRMASK 0x2E ++#define RT5509_REG_DEGLITCH 0x2F ++#define RT5509_REG_SICRTNSTHACT 0x30 ++#define RT5509_REG_TIMEDET 0x31 ++#define RT5509_REG_TDELAY 0x32 ++#define RT5509_REG_TATKSEL 0x33 ++#define RT5509_REG_TREL 0x34 ++#define RT5509_REG_THOLDREL 0x35 ++#define RT5509_REG_STHLMT 0x38 ++#define RT5509_REG_XTHLMT 0x39 ++#define RT5509_REG_STHALC 0x3A ++#define RT5509_REG_XTHALC 0x3B ++#define RT5509_REG_INITUDT 0x3C ++#define RT5509_REG_UDT 0x3D ++#define RT5509_REG_DNHALFT 0x3E ++#define RT5509_REG_ALCGAIN 0x3F ++#define RT5509_REG_ADAPTCONF 0x40 ++#define RT5509_REG_INITIMPLDMU 0x41 ++#define RT5509_REG_IMPLDMU 0x42 ++#define RT5509_REG_GPILOT 0x43 ++#define RT5509_REG_PILOTEN 0x44 ++#define RT5509_REG_PILOTNISENSE 0x45 ++#define RT5509_REG_ISENSEGAIN 0x46 ++#define RT5509_REG_RAPP 0x47 ++#define RT5509_REG_DCR_MAX 0x48 ++#define RT5509_REG_DCR_KD 0x49 ++#define RT5509_REG_DCR_KP 0x4A ++#define RT5509_REG_DCR_KI 0x4B ++#define RT5509_REG_INITDCRIDMU 0x4C ++#define RT5509_REG_DCRIDMU 0x4D ++#define RT5509_REG_CALIB_DCR 0x4E ++#define RT5509_REG_CALIB_BL 0x4F ++#define RT5509_REG_CALIB_CTRL 0x50 ++#define RT5509_REG_CALIB_REQ 0x51 ++#define RT5509_REG_CALIB_GAIN 0x52 ++#define RT5509_REG_CALIB_OUT0 0x53 ++#define RT5509_REG_CALIB_OUT1 0x54 ++#define RT5509_REG_XTHLMTDAM 0x55 ++#define RT5509_REG_RMAXDAM 0x56 ++#define RT5509_REG_TSCALEDAM 0x57 ++#define RT5509_REG_RECOVERT 0x58 ++#define RT5509_REG_SETRESFREQ 0x59 ++#define RT5509_REG_GETRESFREQ 0x5A ++#define RT5509_REG_VOLCTL 0x5B ++#define RT5509_REG_VOLUME 0x5C ++#define RT5509_REG_CALIB_OUTX 0x5D ++#define RT5509_REG_CALIB_OUTY 0x5E ++#define RT5509_REG_BQ1 0x60 ++#define RT5509_REG_BQ2 0x61 ++#define RT5509_REG_BQ3 0x62 ++#define RT5509_REG_BQ4 0x63 ++#define RT5509_REG_BQ5 0x64 ++#define RT5509_REG_BQ6 0x65 ++#define RT5509_REG_BQ7 0x66 ++#define RT5509_REG_BQ8 0x67 ++#define RT5509_REG_BQ9 0x68 ++#define RT5509_REG_BQ10 0x69 ++#define RT5509_REG_VBBQ1 0x6A ++#define RT5509_REG_VBBQ2 0x6B ++#define RT5509_REG_VBBQ3 0x6C ++#define RT5509_REG_VBBQ4 0x6D ++#define RT5509_REG_VBBQ5 0x6E ++#define RT5509_REG_VBBQ6 0x6F ++#define RT5509_REG_VBBQ7 0x70 ++#define RT5509_REG_VBBQ8 0x71 ++#define RT5509_REG_VBBQ9 0x72 ++#define RT5509_REG_VBFCN 0x73 ++#define RT5509_REG_VBGAIN1 0x74 ++#define RT5509_REG_VBGAIN2 0x75 ++#define RT5509_REG_VBGAIN3 0x76 ++#define RT5509_REG_VBGAIN4 0x77 ++#define RT5509_REG_VBGAIN5 0x78 ++#define RT5509_REG_VBGAIN6 0x79 ++#define RT5509_REG_VBGAIN7 0x7A ++#define RT5509_REG_VBGAIN8 0x7B ++#define RT5509_REG_VBGAIN9 0x7C ++#define RT5509_REG_VBGAIN10 0x7D ++#define RT5509_REG_SLOPCONST 0x7E ++#define RT5509_REG_BWCOEFF 0x7F ++#define RT5509_REG_SWRESET 0x80 ++#define RT5509_REG_SPKGAIN 0x81 ++#define RT5509_REG_DSPKCONF1 0x82 ++#define RT5509_REG_DSPKCONF2 0x83 ++#define RT5509_REG_DSPKCONF3 0x84 ++#define RT5509_REG_DSPKCONF4 0x85 ++#define RT5509_REG_DSPKVMID 0x86 ++#define RT5509_REG_DSPKZCBOOST 0x87 ++#define RT5509_REG_ISENSE_CTRL 0x88 ++#define RT5509_REG_DIMADC 0x89 ++#define RT5509_REG_DSPKEN1 0x8A ++#define RT5509_REG_VBATDATA 0x8B ++#define RT5509_REG_VTHRMDATA 0x8C ++#define RT5509_REG_VBATSENSE 0x8D ++#define RT5509_REG_IDACTSTNINFO 0x8E ++#define RT5509_REG_IDACBOOST 0x8F ++#define RT5509_REG_DSPKEN2 0x90 ++#define RT5509_REG_DSPKIBCONF1 0x91 ++#define RT5509_REG_DSPKIBCONF2 0x92 ++#define RT5509_REG_DSPKIBCONF3 0x93 ++#define RT5509_REG_DSPKCONF5 0x94 ++#define RT5509_REG_DSPKCONF6 0x95 ++#define RT5509_REG_OVPUVPCTRL 0x96 ++#define RT5509_REG_PLLCONF1 0x97 ++#define RT5509_REG_PLLCONF2 0x98 ++#define RT5509_REG_PLLCONF3 0x99 ++#define RT5509_REG_PLLCONF4 0x9A ++#define RT5509_REG_PLLINFO 0x9B ++#define RT5509_REG_PLLDIVISOR 0x9C ++#define RT5509_REG_ZCCONF 0x9D ++#define RT5509_REG_DCADJ 0x9E ++#define RT5509_REG_I2CBCKLRCKCONF 0x9F ++#define RT5509_REG_TDEN 0xA0 ++#define RT5509_REG_ALPHACONF 0xA1 ++#define RT5509_REG_SPKRPTSEL 0xA2 ++#define RT5509_REG_SPKRPT 0xA3 ++#define RT5509_REG_NDELAY 0xA4 ++#define RT5509_REG_DELAYRES 0xA5 ++#define RT5509_REG_PHI1 0xA6 ++#define RT5509_REG_PHI2 0xA7 ++#define RT5509_REG_PHI3 0xA8 ++#define RT5509_REG_PHI4 0xA9 ++#define RT5509_REG_PHI5 0xAA ++#define RT5509_REG_ADAPTB0 0xAB ++#define RT5509_REG_ADAPTB1 0xAC ++#define RT5509_REG_ADAPTB2 0xAD ++#define RT5509_REG_ADAPTB3 0xAE ++#define RT5509_REG_ADAPTB4 0xAF ++#define RT5509_REG_ADAPTB5 0xB0 ++#define RT5509_REG_COEFSIERA 0xB1 ++#define RT5509_REG_COEFHPF 0xB2 ++#define RT5509_REG_MIMATC_CTRL 0xB3 ++#define RT5509_REG_TDM_CTRL 0xB4 ++#define RT5509_REG_ECO_CTRL 0xB5 ++#define RT5509_REG_BSTTM 0xB8 ++#define RT5509_REG_ALCMINGAIN 0xB9 ++#define RT5509_REG_RESVECO0 0xBA ++#define RT5509_REG_OTPCONF 0xC0 ++#define RT5509_REG_OTPADDR 0xC1 ++#define RT5509_REG_OTPDIN 0xC2 ++#define RT5509_REG_VBG_TRIM 0xC3 ++#define RT5509_REG_VTEMP_TRIM 0xC4 ++#define RT5509_REG_TCOEFF 0xC5 ++#define RT5509_REG_SPSCONF 0xC6 ++#define RT5509_REG_SPSTHR 0xC7 ++#define RT5509_REG_VTHERMBATEN 0xC8 ++#define RT5509_REG_DBGADS 0xC9 ++#define RT5509_REG_TESTDAC 0xCA ++#define RT5509_REG_SPKDCS 0xCB ++#define RT5509_REG_MSKFLAG 0xCC ++#define RT5509_REG_DRCMINGAIN 0xCF ++#define RT5509_REG_DRC_SEL 0xD0 ++#define RT5509_REG_DRC_ATTACK 0xD1 ++#define RT5509_REG_DRC_PARAM 0xD2 ++#define RT5509_REG_DRCBQ1 0xD3 /* Limiter1 */ ++#define RT5509_REG_DRCBQ2 0xD4 /* Limiter2 */ ++#define RT5509_REG_DRCBQ3 0xD5 /* High1 */ ++#define RT5509_REG_DRCBQ4 0xD6 /* High2 */ ++#define RT5509_REG_DRCBQ5 0xD7 /* Mid1 */ ++#define RT5509_REG_DRCBQ6 0xD8 /* Mid2 */ ++#define RT5509_REG_DRCBQ7 0xD9 /* Mid3 */ ++#define RT5509_REG_DRCBQ8 0xDA /* Mid4 */ ++#define RT5509_REG_DRCBQ9 0xDB /* Low1 */ ++#define RT5509_REG_DRCBQ10 0xDC /* Low2 */ ++#define RT5509_REG_DRCBQ11 0xDD /* Sub1 */ ++#define RT5509_REG_DRCBQ12 0xDE /* Sub2 */ ++#define RT5509_REG_DRCEN 0xDF ++#define RT5509_REG_MTPFLOW1 0xE1 ++#define RT5509_REG_MTPFLOW2 0xE2 ++#define RT5509_REG_MTPFLOW3 0xE3 ++#define RT5509_REG_MTPFLOW4 0xE4 ++#define RT5509_REG_MTPFLOW5 0xE5 ++#define RT5509_REG_MTPFLOW6 0xE6 ++#define RT5509_REG_MTPFLOW7 0xE7 ++#define RT5509_REG_MTPFLOW8 0xE8 ++#define RT5509_REG_MTPFLOW9 0xE9 ++#define RT5509_REG_MTPFLOWA 0xEA ++#define RT5509_REG_MTPFLOWB 0xEB ++#define RT5509_REG_MTPFLOWC 0xEC ++#define RT5509_REG_MTPFLOWD 0xED ++#define RT5509_REG_MTPFLOWE 0xEE ++#define RT5509_REG_MTPFLOWF 0xEF ++#define RT5509_REG_TESTMODE1 0xF0 ++#define RT5509_REG_RAMIND1 0xF1 ++#define RT5509_REG_RAMIND2 0xF2 ++#define RT5509_REG_SCANMODE 0xF3 ++#define RT5509_REG_CLKEN1 0xF4 ++#define RT5509_REG_CLKEN2 0xF5 ++#define RT5509_REG_PADDRV 0xF6 ++#define RT5509_REG_TESTMODE2 0xF7 ++#define RT5509_REG_SLEWRATE1 0xF8 ++#define RT5509_REG_SLEWRATE2 0xF9 ++#define RT5509_REG_BIASRESISTOR 0xFA ++#define RT5509_REG_SPKDRV 0xFB ++#define RT5509_REG_BLOCKREF1 0xFC ++#define RT5509_REG_BLOCKREF2 0xFD ++#define RT5509_REG_BIASCURRENT 0xFE ++#define RT5509_REG_BIASOPTION 0xFF ++#define RT5509_MAX_REGS 0x100 ++ ++/* RT5509_REG_CHIPREV: 0x00 */ ++#define RT5509_CHIPID_MASK 0xF0 ++#define RT5509_CHIP_ID 0xE0 ++#define RT5509_CHIPREV_MASK 0x0F ++#define RT5509_CHIPREV_SHFT 0 ++ ++/* RT5509_REG_EVENTINFO: 0x01 */ ++#define RT5509_BCKLOCK_STATSHFT 7 ++#define RT5509_PLLLOCK_STATSHFT 6 ++#define RT5509_BATUV_STATSHFT 5 ++#define RT5509_AMPOV_STATSHFT 4 ++#define RT5509_AMPOC_STATSHFT 3 ++#define RT5509_AMPOT_STATSHFT 2 ++#define RT5509_BSTOC_STATSHFT 1 ++#define RT5509_BSTOT_STATSHFT 0 ++ ++/* RT5509_REG_CHIPEN: 0x03 */ ++#define RT5509_TRIWAVE_ENMASK 0x20 ++#define RT5509_SPKAMP_ENMASK 0x08 ++#define RT5509_SPKAMP_ENSHFT 3 ++#define RT5509_SPKMUTE_ENMASK 0x04 ++#define RT5509_SPKPROT_ENMASK 0x02 ++#define RT5509_SPKPROT_ENSHFT 1 ++#define RT5509_CHIPPD_ENMASK 0x01 ++ ++/* RT5509_REG_AUDFMT: 0x04 */ ++enum { ++ RT5509_DSP_MODEA = 0, ++ RT5509_DSP_MODEB, ++}; ++#define RT5509_DSPMODE_MASK 0x10 ++#define RT5509_DSPMODE_SHFT 4 ++enum { ++ RT5509_AUDFMT_I2S = 0, ++ RT5509_AUDFMT_LEFTJ, ++ RT5509_AUDFMT_RIGHTJ, ++}; ++#define RT5509_AUDFMT_MASK 0x0C ++#define RT5509_AUDFMT_SHFT 2 ++enum { ++ RT5509_AUDBIT_24 = 0, ++ RT5509_AUDBIT_20, ++ RT5509_AUDBIT_18, ++ RT5509_AUDBIT_16, ++}; ++#define RT5509_AUDBIT_MASK 0x03 ++#define RT5509_AUDBIT_SHFT 0 ++ ++/* RT5509_REG_AUDSR: 0x05 */ ++enum { ++ RT5509_BCKMODE_32FS = 0, ++ RT5509_BCKMODE_48FS, ++ RT5509_BCKMODE_64FS, ++}; ++#define RT5509_BCKMODE_MASK 0x18 ++#define RT5509_BCKMODE_SHFT 3 ++enum { ++ RT5509_SRMODE_8K = 0, ++ RT5509_SRMODE_12K, ++ RT5509_SRMODE_16K, ++ RT5509_SRMODE_24K, ++ RT5509_SRMODE_32K, ++ RT5509_SRMODE_48K, ++ RT5509_SRMODE_96K, ++ RT5509_SRMODE_192K, ++}; ++#define RT5509_SRMODE_MASK 0x07 ++#define RT5509_SRMODE_SHFT 0 ++ ++/* RT5509_REG_I2SSEL: 0x06 */ ++#define RT5509_I2SLRSEL_SHFT 2 ++#define RT5509_I2SSEL_SHFT 0 ++ ++/* RT5509_REG_FUNCEN: 0x09 */ ++#define RT5509_LMTEN_SHFT 5 ++#define RT5509_ALCEN_SHFT 4 ++#define RT5509_MBDRCEN_SHFT 3 ++#define RT5509_BEWEN_SHFT 2 ++#define RT5509_HPFEN_SHFT 1 ++#define RT5509_BQEN_SHFT 0 ++ ++/* RT5509_REG_CLIP_CTRL : 0x11 */ ++#define RT5509_CLIPEN_SHFT 7 ++ ++/* RT5509_REG_BST_MODE: 0x1E */ ++#define RT5509_BSTMODE_SHFT 0 ++#define RT5509_BSTMODE_MASK 0x03 ++ ++/* RT5509_REG_SWRESET: 0x80 */ ++#define RT5509_SWRST_MASK 0x80 ++ ++/* RT5509_REG_SPKGAIN: 0x81 */ ++#define RT5509_BSTGAIN_SHFT 5 ++#define RT5509_POSTPGAGAIN_SHFT 0 ++ ++/* RT5509_REG_DSPKCONF1: 0x82 */ ++#define RT5509_PREPGAGAIN_SHFT 0 ++ ++/* RT5509_REG_DSPKVMID: 0x86 */ ++#define RT5509_VMID_ENMASK 0x80 ++ ++/* RT5509_REG_DSPKEN1: 0x8A */ ++#define RT5509_BUF_ENMASK 0x80 ++#define RT5509_BIAS_ENMASK 0x40 ++ ++/* RT5509_REG_DSPKCONF5: 0x94 */ ++#define RT5509_VBG_ENMASK 0x40 ++ ++/* RT5509_REG_TDM_CTRL: 0xB4 */ ++#define RT5509_TDM_ENMASK 0x08 ++ ++/* RT5509_REG_CLKEN1: 0xF4 */ ++#define RT5509_CLKEN1_MASK 0xFF ++ ++/* RT5509_REG_CLKEN2: 0xF5 */ ++#define RT5509_CLKEN2_MASK 0x03 ++ ++ ++int rt5509_calib_create(struct rt5509_chip *chip); ++void rt5509_calib_destroy(struct rt5509_chip *chip); ++int rt5509_i2c_probe(struct i2c_client *client, ++ const struct i2c_device_id *id); ++int rt5509_i2c_remove(struct i2c_client *client); ++void rt5509_i2c_shutdown(struct i2c_client *client); ++ ++#endif /* #ifndef __RT5509_H */ +diff --git a/sound/soc/mediatek/mt8365/mt8365-sb35.c b/sound/soc/mediatek/mt8365/mt8365-sb35.c +index 19fd1d1b7339..27acef137e74 100644 +--- a/sound/soc/mediatek/mt8365/mt8365-sb35.c ++++ b/sound/soc/mediatek/mt8365/mt8365-sb35.c +@@ -19,6 +19,7 @@ + #include + #include + #include "mt8365-afe-common.h" ++#include "../common/mtk-soundcard-driver.h" + + #define PREFIX "mediatek," + +@@ -65,6 +66,7 @@ enum { + DAI_LINK_AWB_CAPTURE, + DAI_LINK_VUL_CAPTURE, + /* BE */ ++ DAI_LINK_2ND_I2S_INTF, + DAI_LINK_DMIC, + DAI_LINK_INT_ADDA, + DAI_LINK_NUM +@@ -73,11 +75,13 @@ enum { + static const struct snd_soc_dapm_widget mt8365_sb35_widgets[] = { + SND_SOC_DAPM_MIC("PMIC MIC", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), ++ SND_SOC_DAPM_OUTPUT("HDMI Out"), + }; + + static const struct snd_soc_dapm_route mt8365_sb35_routes[] = { + {"Headphone", NULL, "MT6357 Playback"}, + {"MT6357 Capture", NULL, "PMIC MIC"}, ++ {"HDMI Out", NULL, "2ND I2S Playback"}, + }; + + static int mt8365_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, +@@ -210,6 +214,10 @@ SND_SOC_DAILINK_DEFS(vul, + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + ++SND_SOC_DAILINK_DEFS(i2s3, ++ DAILINK_COMP_ARRAY(COMP_CPU("2ND I2S")), ++ DAILINK_COMP_ARRAY(COMP_DUMMY()), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); + SND_SOC_DAILINK_DEFS(dmic, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), +@@ -232,6 +240,7 @@ static struct snd_soc_dai_link mt8365_sb35_dais[] = { + }, + .dynamic = 1, + .dpcm_playback = 1, ++ .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback1), + }, + [DAI_LINK_DL2_PLAYBACK] = { +@@ -244,6 +253,7 @@ static struct snd_soc_dai_link mt8365_sb35_dais[] = { + }, + .dynamic = 1, + .dpcm_playback = 1, ++ .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(playback2), + }, + [DAI_LINK_AWB_CAPTURE] = { +@@ -256,6 +266,7 @@ static struct snd_soc_dai_link mt8365_sb35_dais[] = { + }, + .dynamic = 1, + .dpcm_capture = 1, ++ .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(awb_capture), + }, + [DAI_LINK_VUL_CAPTURE] = { +@@ -268,9 +279,21 @@ static struct snd_soc_dai_link mt8365_sb35_dais[] = { + }, + .dynamic = 1, + .dpcm_capture = 1, ++ .dpcm_merged_rate = 1, + SND_SOC_DAILINK_REG(vul), + }, + /* Back End DAI links */ ++ [DAI_LINK_2ND_I2S_INTF] = { ++ .name = "2ND I2S BE", ++ .no_pcm = 1, ++ .id = DAI_LINK_2ND_I2S_INTF, ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .dpcm_playback = 1, ++ .dpcm_capture = 1, ++ SND_SOC_DAILINK_REG(i2s3), ++ }, + [DAI_LINK_DMIC] = { + .name = "DMIC BE", + .no_pcm = 1, +@@ -460,6 +483,13 @@ static int mt8365_sb35_dev_probe(struct platform_device *pdev) + struct mt8365_sb35_priv *priv; + int i, ret; + ++ card->dev = dev; ++ ret = set_card_codec_info(card); ++ if (ret) { ++ return dev_err_probe(&pdev->dev, ret, "%s set_card_codec_info failed\n", ++ __func__); ++ } ++ + platform_node = of_parse_phandle(dev->of_node, "mediatek,platform", 0); + if (!platform_node) { + dev_err(dev, "Property 'platform' missing or invalid\n"); +@@ -472,8 +502,6 @@ static int mt8365_sb35_dev_probe(struct platform_device *pdev) + mt8365_sb35_dais[i].platforms->of_node = platform_node; + } + +- card->dev = dev; +- + priv = devm_kzalloc(dev, sizeof(struct mt8365_sb35_priv), + GFP_KERNEL); + if (!priv) { +@@ -494,6 +522,7 @@ static int mt8365_sb35_dev_probe(struct platform_device *pdev) + dev_err(dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + ++ dev_info(dev, "%s done\n", __func__); + return ret; + } + +-- +2.39.2 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-drm-bridge-lt9611-Switch-to-atomic-operations.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-drm-bridge-lt9611-Switch-to-atomic-operations.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-drm-bridge-lt9611-Switch-to-atomic-operations.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-drm-bridge-lt9611-Switch-to-atomic-operations.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,82 @@ +From c28e84fe4e18715e7f82108b1317dd1b6be8fea6 Mon Sep 17 00:00:00 2001 +From: Marek Vasut +Date: Thu, 31 Mar 2022 17:39:22 +0200 +Subject: [PATCH 1/9] drm/bridge: lt9611: Switch to atomic operations + +Use the atomic version of the enable/disable operations to continue the +transition to the atomic API. This will be needed to access the mode +from the atomic state. + +Signed-off-by: Marek Vasut +Cc: Dave Airlie +Cc: John Stultz +Cc: Maxime Ripard +Cc: Sam Ravnborg +Cc: Thomas Zimmermann +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20220331153923.14314-1-marex@denx.de +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 660e05fa4a70..ce196b7ea84d 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -703,7 +703,9 @@ lt9611_connector_mode_valid(struct drm_connector *connector, + } + + /* bridge funcs */ +-static void lt9611_bridge_enable(struct drm_bridge *bridge) ++static void ++lt9611_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + +@@ -724,7 +726,9 @@ static void lt9611_bridge_enable(struct drm_bridge *bridge) + regmap_write(lt9611->regmap, 0x8130, 0xea); + } + +-static void lt9611_bridge_disable(struct drm_bridge *bridge) ++static void ++lt9611_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + int ret; +@@ -900,7 +904,9 @@ static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) + lt9611->sleep = false; + } + +-static void lt9611_bridge_post_disable(struct drm_bridge *bridge) ++static void ++lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + +@@ -965,13 +971,17 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { + .attach = lt9611_bridge_attach, + .detach = lt9611_bridge_detach, + .mode_valid = lt9611_bridge_mode_valid, +- .enable = lt9611_bridge_enable, +- .disable = lt9611_bridge_disable, +- .post_disable = lt9611_bridge_post_disable, + .mode_set = lt9611_bridge_mode_set, + .detect = lt9611_bridge_detect, + .get_edid = lt9611_bridge_get_edid, + .hpd_enable = lt9611_bridge_hpd_enable, ++ ++ .atomic_enable = lt9611_bridge_atomic_enable, ++ .atomic_disable = lt9611_bridge_atomic_disable, ++ .atomic_post_disable = lt9611_bridge_atomic_post_disable, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, + }; + + static int lt9611_parse_dt(struct device *dev, +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Failed-to-start-Weston-system-service.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Failed-to-start-Weston-system-service.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Failed-to-start-Weston-system-service.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Failed-to-start-Weston-system-service.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,32 @@ +From 51c470ba17609e29941d099dac471c4ccf47450b Mon Sep 17 00:00:00 2001 +From: Roy Chen +Date: Mon, 15 May 2023 15:53:38 +0800 +Subject: [PATCH] Failed to start Weston system service + +Signed-off-by: Roy Chen +--- + arch/arm64/boot/dts/mediatek/mt8365-sb35.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +index 8b7442bafa32..44e1c1fd9c5a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +@@ -94,6 +94,14 @@ optee_reserved: optee@43200000 { + no-map; + reg = <0 0x43200000 0 0x00c00000>; + }; ++ ++ /* global autoconfigured region for contiguous allocations */ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x00000000 0x01c00000>; ++ linux,cma-default; ++ }; + }; + + dc5v: dc5v-regulator { +-- +2.39.2 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-incorrect-pinctrl-properties-in-i2c.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-incorrect-pinctrl-properties-in-i2c.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-incorrect-pinctrl-properties-in-i2c.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-incorrect-pinctrl-properties-in-i2c.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,59 @@ +From 6a6ea4b15b0d796ad1962cd0bed63bc6fc2f66d1 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Thu, 18 May 2023 09:33:05 +0800 +Subject: [PATCH 1/1] Fix incorrect pinctrl properties in i2c + +Following pinctrl properties are not supported by genio-350(pinctrl-mt8365.c driver) +(they are supported by genio 500, genio 1200, etc) + +mediatek,pull-up-adv +mediatek,drive-strength-adv + +replace them by 'bias-pull-up' instead. +--- + arch/arm64/boot/dts/mediatek/mt8365-sb35.dts | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +index 44e1c1fd9c5a..f226ec49bc2f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +@@ -584,8 +584,9 @@ i2c0_pins: i2c0 { + pins_i2c { + pinmux = , + ; +- mediatek,pull-up-adv = <3>; +- mediatek,drive-strength-adv = <7>; ++ //mediatek,pull-up-adv = <3>; ++ //mediatek,drive-strength-adv = <7>; ++ bias-pull-up; + }; + }; + +@@ -604,8 +605,9 @@ i2c2_pins: i2c2 { + pins_i2c { + pinmux = , + ; +- mediatek,pull-up-adv = <3>; +- mediatek,drive-strength-adv = <00>; ++ //mediatek,pull-up-adv = <3>; ++ //mediatek,drive-strength-adv = <00>; ++ bias-pull-up; + }; + }; + +@@ -613,8 +615,9 @@ i2c3_pins: i2c3 { + pins_i2c { + pinmux = , + ; +- mediatek,pull-up-adv = <3>; +- mediatek,drive-strength-adv = <00>; ++ //mediatek,pull-up-adv = <3>; ++ //mediatek,drive-strength-adv = <00>; ++ bias-pull-up; + }; + }; + +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-MTK-DSI-malfuctions-with-bridge.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-MTK-DSI-malfuctions-with-bridge.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-MTK-DSI-malfuctions-with-bridge.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-Fix-MTK-DSI-malfuctions-with-bridge.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,263 @@ +From a0c8fa055885cfae5f6e076c5dec9b810e3f3310 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Wed, 17 May 2023 11:34:51 +0800 +Subject: [PATCH 1/1] Fix MTK DSI malfuctions with bridge + +The MTK DSI malfuctions with bridge after following 2 CLs are applied +(The major cause is UPSTREAM: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge) +Rollback them to fix the issue. + +commit 63f572f81597d16a29d841b5cb2be4a204ced159 (UPSTREAM: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge) + +commit 28b879c7611756a5d04384bbbcfcb2b8ecf90419 (BL_INTERNAL: HACK: drm/mediatek: dsi: Manage when no panel is attached) +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 178 ++++++++++++----------------- + 1 file changed, 73 insertions(+), 105 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 455fa95b86db..8a44ac97b179 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -792,39 +792,6 @@ void mtk_dsi_ddp_stop(struct device *dev) + mtk_dsi_poweroff(dsi); + } + +-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) +-{ +- int ret; +- +- ret = drm_simple_encoder_init(drm, &dsi->encoder, +- DRM_MODE_ENCODER_DSI); +- if (ret) { +- DRM_ERROR("Failed to encoder init to drm\n"); +- return ret; +- } +- +- dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); +- +- ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, +- DRM_BRIDGE_ATTACH_NO_CONNECTOR); +- if (ret) +- goto err_cleanup_encoder; +- +- dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); +- if (IS_ERR(dsi->connector)) { +- DRM_ERROR("Unable to create bridge connector\n"); +- ret = PTR_ERR(dsi->connector); +- goto err_cleanup_encoder; +- } +- drm_connector_attach_encoder(dsi->connector, &dsi->encoder); +- +- return 0; +- +-err_cleanup_encoder: +- drm_encoder_cleanup(&dsi->encoder); +- return ret; +-} +- + int mtk_dsi_encoder_index(struct device *dev) + { + struct mtk_dsi *dsi = dev_get_drvdata(dev); +@@ -834,72 +801,18 @@ int mtk_dsi_encoder_index(struct device *dev) + return encoder_index; + } + +-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) +-{ +- int ret; +- struct drm_device *drm = data; +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- if (!dsi->next_bridge) +- return 0; +- +- ret = mtk_dsi_encoder_init(drm, dsi); +- if (ret) +- return ret; +- +- return device_reset_optional(dev); +-} +- +-static void mtk_dsi_unbind(struct device *dev, struct device *master, +- void *data) +-{ +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- if (!dsi->next_bridge) +- return; +- +- drm_encoder_cleanup(&dsi->encoder); +-} +- +-static const struct component_ops mtk_dsi_component_ops = { +- .bind = mtk_dsi_bind, +- .unbind = mtk_dsi_unbind, +-}; +- + static int mtk_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) + { + struct mtk_dsi *dsi = host_to_dsi(host); +- struct device *dev = host->dev; +- int ret; + + dsi->lanes = device->lanes; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; +- dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); +- if (IS_ERR(dsi->next_bridge)) +- return PTR_ERR(dsi->next_bridge); +- +- drm_bridge_add(&dsi->bridge); +- +- ret = component_add(host->dev, &mtk_dsi_component_ops); +- if (ret) { +- DRM_ERROR("failed to add dsi_host component: %d\n", ret); +- drm_bridge_remove(&dsi->bridge); +- return ret; +- } + + return 0; + } + +-static int mtk_dsi_host_detach(struct mipi_dsi_host *host, +- struct mipi_dsi_device *device) +-{ +- struct mtk_dsi *dsi = host_to_dsi(host); +- +- component_del(host->dev, &mtk_dsi_component_ops); +- drm_bridge_remove(&dsi->bridge); +- return 0; +-} +- + static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi) + { + int ret; +@@ -1055,14 +968,73 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, + + static const struct mipi_dsi_host_ops mtk_dsi_ops = { + .attach = mtk_dsi_host_attach, +- .detach = mtk_dsi_host_detach, + .transfer = mtk_dsi_host_transfer, + }; + ++static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ++{ ++ int ret; ++ ++ ret = drm_simple_encoder_init(drm, &dsi->encoder, ++ DRM_MODE_ENCODER_DSI); ++ if (ret) { ++ DRM_ERROR("Failed to encoder init to drm\n"); ++ return ret; ++ } ++ ++ dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); ++ ++ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (ret) ++ goto err_cleanup_encoder; ++ ++ dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); ++ if (IS_ERR(dsi->connector)) { ++ DRM_ERROR("Unable to create bridge connector\n"); ++ ret = PTR_ERR(dsi->connector); ++ goto err_cleanup_encoder; ++ } ++ drm_connector_attach_encoder(dsi->connector, &dsi->encoder); ++ ++ return 0; ++ ++err_cleanup_encoder: ++ drm_encoder_cleanup(&dsi->encoder); ++ return ret; ++} ++ ++static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) ++{ ++ int ret; ++ struct drm_device *drm = data; ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ ret = mtk_dsi_encoder_init(drm, dsi); ++ if (ret) ++ return ret; ++ ++ return device_reset_optional(dev); ++} ++ ++static void mtk_dsi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ drm_encoder_cleanup(&dsi->encoder); ++} ++ ++static const struct component_ops mtk_dsi_component_ops = { ++ .bind = mtk_dsi_bind, ++ .unbind = mtk_dsi_unbind, ++}; ++ + static int mtk_dsi_probe(struct platform_device *pdev) + { + struct mtk_dsi *dsi; + struct device *dev = &pdev->dev; ++ struct drm_panel *panel; + struct resource *regs; + int irq_num; + int ret; +@@ -1079,6 +1051,12 @@ static int mtk_dsi_probe(struct platform_device *pdev) + return ret; + } + ++ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); ++ if (IS_ERR(dsi->next_bridge)) { ++ ret = PTR_ERR(dsi->next_bridge); ++ goto err_unregister_host; ++ } ++ + dsi->driver_data = of_device_get_match_data(dev); + + dsi->poweron_in_hs_mode = 1; +@@ -1147,24 +1125,12 @@ static int mtk_dsi_probe(struct platform_device *pdev) + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + ++ drm_bridge_add(&dsi->bridge); + +- dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); +- if (IS_ERR(dsi->next_bridge) && PTR_ERR(dsi->next_bridge) == -ENODEV) { +- /* if no panel has been connected in the device tree on purpose, +- * add the component directly here with empty ops as the +- * unction doing this will never be called. But first warn +- * about this. +- */ +- dev_warn(dev, "No panel connected in the devicetree, continuing without any panel...\n"); +- dsi->next_bridge = NULL; +- drm_bridge_add(&dsi->bridge); +- +- ret = component_add(&pdev->dev, &mtk_dsi_component_ops); +- if (ret) { +- DRM_ERROR("failed to add dsi_host component: %d\n", ret); +- drm_bridge_remove(&dsi->bridge); +- return ret; +- } ++ ret = component_add(&pdev->dev, &mtk_dsi_component_ops); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add component: %d\n", ret); ++ goto err_unregister_host; + } + + return 0; +@@ -1179,6 +1145,8 @@ static int mtk_dsi_remove(struct platform_device *pdev) + struct mtk_dsi *dsi = platform_get_drvdata(pdev); + + mtk_output_dsi_disable(dsi); ++ drm_bridge_remove(&dsi->bridge); ++ component_del(&pdev->dev, &mtk_dsi_component_ops); + mipi_dsi_host_unregister(&dsi->host); + + return 0; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-gpu-lontium-lt9611-Fix-NULL-pointer-dereference-in-l.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-gpu-lontium-lt9611-Fix-NULL-pointer-dereference-in-l.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-gpu-lontium-lt9611-Fix-NULL-pointer-dereference-in-l.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-gpu-lontium-lt9611-Fix-NULL-pointer-dereference-in-l.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,46 @@ +From a29f7427041a943484f916157c43c46d3bbf25d4 Mon Sep 17 00:00:00 2001 +From: Zeng Jingxiang +Date: Wed, 27 Jul 2022 15:31:19 +0800 +Subject: [PATCH 1/8] gpu: lontium-lt9611: Fix NULL pointer dereference in + lt9611_connector_init() + +[ Upstream commit ef8886f321c5dab8124b9153d25afa2a71d05323 ] + +A NULL check for bridge->encoder shows that it may be NULL, but it +already been dereferenced on all paths leading to the check. +812 if (!bridge->encoder) { + +Dereference the pointer bridge->encoder. +810 drm_connector_attach_encoder(<9611->connector, bridge->encoder); + +Signed-off-by: Zeng Jingxiang +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20220727073119.1578972-1-zengjx95@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 29b1ce2140ab..1dcc28a4d853 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -816,13 +816,14 @@ static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt961 + + drm_connector_helper_add(<9611->connector, + <9611_bridge_connector_helper_funcs); +- drm_connector_attach_encoder(<9611->connector, bridge->encoder); + + if (!bridge->encoder) { + DRM_ERROR("Parent encoder object not found"); + return -ENODEV; + } + ++ drm_connector_attach_encoder(<9611->connector, bridge->encoder); ++ + return 0; + } + +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-lt9611-porting.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-lt9611-porting.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-lt9611-porting.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-lt9611-porting.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,89 @@ +From 94daedcf534be4762f11c8ab921263540884c5f2 Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Wed, 17 May 2023 11:35:51 +0800 +Subject: [PATCH 1/1] lt9611 porting + +--- + arch/arm64/boot/dts/mediatek/mt8365-sb35.dts | 28 +++++++++++++++++++- + drivers/gpu/drm/bridge/lontium-lt9611.c | 19 +++++++++++++ + 2 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +index f226ec49bc2f..e8260faaab55 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8365-sb35.dts +@@ -321,7 +321,7 @@ hdmi-bridge@3b { + compatible = "lontium,lt9611"; + reg = <0x3b>; + pinctrl-0 = <&hdmi_pins>; +- pintctrl-names = "default"; ++ pinctrl-names = "default"; + + reset-gpios = <&pio 20 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&pio 125 IRQ_TYPE_EDGE_FALLING>; +@@ -657,6 +657,32 @@ pin_pwr_en { + pinmux = ; + output-high; + }; ++ ++ pin_lt9611_1v8_en { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_rst { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_3v3_en { ++ pinmux = ; ++ output-low; ++ }; ++ ++ pin_lt9611_intr { ++ pinmux = ; ++ input-enable; ++ bias-pull-up; ++ }; ++ ++ pin_dsi_sel { ++ pinmux = ; ++ output-low; ++ }; + }; + + keypad_pins: keypad-pins { +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 45acff6014e1..7442e14f564f 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -882,6 +882,25 @@ static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + ++ if (of_device_is_compatible(lt9611->next_bridge->of_node, "hdmi-connector")) { ++ struct i2c_adapter *ddc; ++ struct device_node *ddc_node; ++ ++ ddc_node = of_parse_phandle(lt9611->next_bridge->of_node, "ddc-i2c-bus", 0); ++ if (ddc_node) { ++ ddc = of_find_i2c_adapter_by_node(ddc_node); ++ of_node_put(ddc_node); ++ ++ if (ddc) ++ return drm_get_edid(connector, ddc); ++ else ++ dev_err(lt9611->dev, "The ddc i2c adapter found by node is not ready yet!\n"); ++ } else { ++ dev_err(lt9611->dev, "Failed to find ddc-i2c-bus node in %pOF\n", ++ lt9611->next_bridge->of_node); ++ } ++ } ++ + lt9611_power_on(lt9611); + return drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); + } +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-To-fix-rpi_touchscreen_dsi_probe-failed.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-To-fix-rpi_touchscreen_dsi_probe-failed.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-To-fix-rpi_touchscreen_dsi_probe-failed.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0001-To-fix-rpi_touchscreen_dsi_probe-failed.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,28 @@ +From 521dafc9001e1e5ce9824f7678f1b5cbce4311c1 Mon Sep 17 00:00:00 2001 +From: Roy Chen +Date: Thu, 11 May 2023 17:50:14 +0800 +Subject: [PATCH] To fix rpi_touchscreen_dsi_probe failed + +Signed-off-by: Roy Chen +--- + drivers/gpu/drm/panel/panel-rpi-pumpkin-touchscreen.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/panel/panel-rpi-pumpkin-touchscreen.c b/drivers/gpu/drm/panel/panel-rpi-pumpkin-touchscreen.c +index ea6fb96fda9b..e644d1993f7c 100644 +--- a/drivers/gpu/drm/panel/panel-rpi-pumpkin-touchscreen.c ++++ b/drivers/gpu/drm/panel/panel-rpi-pumpkin-touchscreen.c +@@ -527,8 +527,8 @@ static struct i2c_driver rpi_touchscreen_driver = { + + static int __init rpi_touchscreen_init(void) + { +- mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver); +- return i2c_add_driver(&rpi_touchscreen_driver); ++ i2c_add_driver(&rpi_touchscreen_driver); ++ return mipi_dsi_driver_register(&rpi_touchscreen_dsi_driver); + } + module_init(rpi_touchscreen_init); + +-- +2.39.2 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-drm-bridge-lt9611-fix-sleep-mode-setup.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-drm-bridge-lt9611-fix-sleep-mode-setup.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-drm-bridge-lt9611-fix-sleep-mode-setup.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-drm-bridge-lt9611-fix-sleep-mode-setup.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,44 @@ +From 1b5adc8752b0fdce5e41be75c164bcf4168f1e1d Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:46 +0200 +Subject: [PATCH 2/8] drm/bridge: lt9611: fix sleep mode setup + +[ Upstream commit ae2d329f104b75a0a78dcaded29fe6283289cdf9 ] + +On atomic_post_disable the bridge goes to the low power state. However +the code disables too much of the chip, so the HPD event is not being +detected and delivered to the host. Reduce the power saving in order to +get the HPD event. + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-2-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 1dcc28a4d853..5e5641ac5ea3 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -446,12 +446,11 @@ static void lt9611_sleep_setup(struct lt9611 *lt9611) + { 0x8023, 0x01 }, + { 0x8157, 0x03 }, /* set addr pin as output */ + { 0x8149, 0x0b }, +- { 0x8151, 0x30 }, /* disable IRQ */ ++ + { 0x8102, 0x48 }, /* MIPI Rx power down */ + { 0x8123, 0x80 }, + { 0x8130, 0x00 }, +- { 0x8100, 0x01 }, /* bandgap power down */ +- { 0x8101, 0x00 }, /* system clk power down */ ++ { 0x8011, 0x0a }, + }; + + regmap_multi_reg_write(lt9611->regmap, +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-lontium-lt9611-check-a-different-register-bit-for-HD.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-lontium-lt9611-check-a-different-register-bit-for-HD.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-lontium-lt9611-check-a-different-register-bit-for-HD.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0002-lontium-lt9611-check-a-different-register-bit-for-HD.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,46 @@ +From b8e169eb5893f95a6dd83dbcc9b7c3905383a34d Mon Sep 17 00:00:00 2001 +From: Peter Collingbourne +Date: Tue, 16 Nov 2021 18:07:24 -0800 +Subject: [PATCH 2/9] lontium-lt9611: check a different register bit for HDMI + sensing + +It has been observed that with certain monitors such as the HP Z27n, +the register 0x825e reads a value of 0x79 when the HDMI cable is +connected and 0x78 when it is disconnected, i.e. bit 0 appears +to correspond to the HDMI connection status and bit 2 is never +set. Therefore, change the driver to check bit 0 instead of bit 2. + +Signed-off-by: Peter Collingbourne +Link: https://linux-review.googlesource.com/id/I7e76411127e1ce4988a3f6d0c8ba5f1c3d880c23 +Reviewed-by: Vinod Koul +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20211117020724.2647769-1-pcc@google.com +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index ce196b7ea84d..a1604787baaf 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -589,7 +589,7 @@ lt9611_connector_detect(struct drm_connector *connector, bool force) + int connected = 0; + + regmap_read(lt9611->regmap, 0x825e, ®_val); +- connected = (reg_val & BIT(2)); ++ connected = (reg_val & BIT(0)); + + lt9611->status = connected ? connector_status_connected : + connector_status_disconnected; +@@ -943,7 +943,7 @@ static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) + int connected; + + regmap_read(lt9611->regmap, 0x825e, ®_val); +- connected = reg_val & BIT(2); ++ connected = reg_val & BIT(0); + + lt9611->status = connected ? connector_status_connected : + connector_status_disconnected; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-Consolidate-detection-logic.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-Consolidate-detection-logic.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-Consolidate-detection-logic.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-Consolidate-detection-logic.patch 2023-06-06 11:40:50.480906014 +0800 @@ -0,0 +1,75 @@ +From ac5cdca155cacfe0758c13864eb7dfbd580c513d Mon Sep 17 00:00:00 2001 +From: John Stultz +Date: Wed, 11 May 2022 01:26:11 +0000 +Subject: [PATCH 3/9] drm/bridge: lt9611: Consolidate detection logic + +This patch simply consolidates the duplicated detection +functionality in the driver. + +Cc: Yongqin Liu +Cc: Amit Pundir +Cc: Peter Collingbourne +Cc: Vinod Koul +Cc: Bjorn Andersson +Cc: Robert Foss +Cc: kernel-team@android.com +Reviewed-by: Robert Foss +Signed-off-by: John Stultz +Reviewed-by: Robert Foss +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20220511012612.3297577-1-jstultz@google.com +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 22 ++++++++-------------- + 1 file changed, 8 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index a1604787baaf..4c899b234243 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -581,10 +581,8 @@ static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) + } + + /* connector funcs */ +-static enum drm_connector_status +-lt9611_connector_detect(struct drm_connector *connector, bool force) ++static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) + { +- struct lt9611 *lt9611 = connector_to_lt9611(connector); + unsigned int reg_val = 0; + int connected = 0; + +@@ -597,6 +595,12 @@ lt9611_connector_detect(struct drm_connector *connector, bool force) + return lt9611->status; + } + ++static enum drm_connector_status ++lt9611_connector_detect(struct drm_connector *connector, bool force) ++{ ++ return __lt9611_detect(connector_to_lt9611(connector)); ++} ++ + static int lt9611_read_edid(struct lt9611 *lt9611) + { + unsigned int temp; +@@ -938,17 +942,7 @@ static void lt9611_bridge_mode_set(struct drm_bridge *bridge, + + static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) + { +- struct lt9611 *lt9611 = bridge_to_lt9611(bridge); +- unsigned int reg_val = 0; +- int connected; +- +- regmap_read(lt9611->regmap, 0x825e, ®_val); +- connected = reg_val & BIT(0); +- +- lt9611->status = connected ? connector_status_connected : +- connector_status_disconnected; +- +- return lt9611->status; ++ return __lt9611_detect(bridge_to_lt9611(bridge)); + } + + static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-fix-HPD-reenablement.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-fix-HPD-reenablement.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-fix-HPD-reenablement.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0003-drm-bridge-lt9611-fix-HPD-reenablement.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,50 @@ +From 77ba2d294e16007bec7ecbd692664b938fa40fcf Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:47 +0200 +Subject: [PATCH 3/8] drm/bridge: lt9611: fix HPD reenablement + +[ Upstream commit a7790f6bd38f3642b60ae3504a2c749135b89451 ] + +The driver will reset the bridge in the atomic_pre_enable(). However +this will also drop the HPD interrupt state. Instead of resetting the +bridge, properly wake it up. This fixes the HPD interrupt delivery after +the disable/enable cycle. + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-3-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 5e5641ac5ea3..fe660d667daf 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -880,12 +880,18 @@ static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, + static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); ++ static const struct reg_sequence reg_cfg[] = { ++ { 0x8102, 0x12 }, ++ { 0x8123, 0x40 }, ++ { 0x8130, 0xea }, ++ { 0x8011, 0xfa }, ++ }; + + if (!lt9611->sleep) + return; + +- lt9611_reset(lt9611); +- regmap_write(lt9611->regmap, 0x80ee, 0x01); ++ regmap_multi_reg_write(lt9611->regmap, ++ reg_cfg, ARRAY_SIZE(reg_cfg)); + + lt9611->sleep = false; + } +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-fix-polarity-programming.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-fix-polarity-programming.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-fix-polarity-programming.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-fix-polarity-programming.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,66 @@ +From 24e51dea988588bc7af3c5b4b14964ceedc84203 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:48 +0200 +Subject: [PATCH 4/8] drm/bridge: lt9611: fix polarity programming + +[ Upstream commit 0b157efa384ea417304b1da284ee2f603c607fc3 ] + +Fix programming of hsync and vsync polarities + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-4-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index fe660d667daf..4c56407c4cf0 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -205,7 +205,6 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod + + /* stage 2 */ + { 0x834a, 0x40 }, +- { 0x831d, 0x10 }, + + /* MK limit */ + { 0x832d, 0x38 }, +@@ -220,11 +219,19 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod + { 0x8325, 0x00 }, + { 0x832a, 0x01 }, + { 0x834a, 0x10 }, +- { 0x831d, 0x10 }, +- { 0x8326, 0x37 }, + }; ++ u8 pol = 0x10; + +- regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); ++ if (mode->flags & DRM_MODE_FLAG_NHSYNC) ++ pol |= 0x2; ++ if (mode->flags & DRM_MODE_FLAG_NVSYNC) ++ pol |= 0x1; ++ regmap_write(lt9611->regmap, 0x831d, pol); ++ ++ if (mode->hdisplay == 3840) ++ regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2)); ++ else ++ regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + + switch (mode->hdisplay) { + case 640: +@@ -234,7 +241,7 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod + regmap_write(lt9611->regmap, 0x8326, 0x37); + break; + case 3840: +- regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2)); ++ regmap_write(lt9611->regmap, 0x8326, 0x37); + break; + } + +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-Use-both-bits-for-HDMI-sensing.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-Use-both-bits-for-HDMI-sensing.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-Use-both-bits-for-HDMI-sensing.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0004-drm-bridge-lt9611-Use-both-bits-for-HDMI-sensing.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,49 @@ +From 4208aacd561ac8aede65a42b176b646ae356eab9 Mon Sep 17 00:00:00 2001 +From: John Stultz +Date: Wed, 11 May 2022 01:26:12 +0000 +Subject: [PATCH 4/9] drm/bridge: lt9611: Use both bits for HDMI sensing + +In commit 19cf41b64e3b ("lontium-lt9611: check a different +register bit for HDMI sensing"), the bit flag used to detect +HDMI cable connect was switched from BIT(2) to BIT(0) to improve +compatibility with some monitors that didn't seem to set BIT(2). + +However, with that change, I've seen occasional issues where the +detection failed, because BIT(2) was set, but not BIT(0). + +Unfortunately, as I understand it, the bits and their function +was never clearly documented. So lets instead check both +(BIT(2) | BIT(0)) when checking the register. + +Cc: Yongqin Liu +Cc: Amit Pundir +Cc: Peter Collingbourne +Cc: Vinod Koul +Cc: Bjorn Andersson +Cc: Robert Foss +Cc: kernel-team@android.com +Fixes: 19cf41b64e3b ("lontium-lt9611: check a different register bit for HDMI sensing") +Signed-off-by: John Stultz +Reviewed-by: Robert Foss +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20220511012612.3297577-2-jstultz@google.com +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 4c899b234243..b94a8320b08b 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -587,7 +587,7 @@ static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) + int connected = 0; + + regmap_read(lt9611->regmap, 0x825e, ®_val); +- connected = (reg_val & BIT(0)); ++ connected = (reg_val & (BIT(2) | BIT(0))); + + lt9611->status = connected ? connector_status_connected : + connector_status_disconnected; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-fix-programming-of-video-modes.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-fix-programming-of-video-modes.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-fix-programming-of-video-modes.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-fix-programming-of-video-modes.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,36 @@ +From a2c196f05a30761ebf9c46603df27be98747185f Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:49 +0200 +Subject: [PATCH 5/8] drm/bridge: lt9611: fix programming of video modes + +[ Upstream commit ad188aa47edaa033a270e1a3efae43836ff47569 ] + +Program the upper part of the hfront_porch into the proper register. + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-5-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 4c56407c4cf0..4925566dfc54 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -185,7 +185,8 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611, + + regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256)); + +- regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256)); ++ regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256) | ++ ((hfront_porch / 256) << 4)); + regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256)); + } + +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-rework-the-mode_set-function.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-rework-the-mode_set-function.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-rework-the-mode_set-function.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0005-drm-bridge-lt9611-rework-the-mode_set-function.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,118 @@ +From e9d719237c25bc250572c32ff740b4e4c1ce5398 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:52 +0200 +Subject: [PATCH 5/9] drm/bridge: lt9611: rework the mode_set function + +The mode_set callback is deprectated for drm_bridges in favour of using +atomic_enable callback. Move corresponding code into the function +lt9611_bridge_atomic_enable() and turn lt9611_bridge_pre_enable() into +the proper atomic_pre_enable callback. + +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-8-dmitry.baryshkov@linaro.org +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 61 +++++++++++++++---------- + 1 file changed, 36 insertions(+), 25 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index b94a8320b08b..37ad243f06f2 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -712,6 +712,39 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); ++ struct drm_atomic_state *state = old_bridge_state->base.state; ++ struct drm_connector *connector; ++ struct drm_connector_state *conn_state; ++ struct drm_crtc_state *crtc_state; ++ struct drm_display_mode *mode; ++ struct hdmi_avi_infoframe avi_frame; ++ unsigned int postdiv; ++ int ret; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); ++ if (WARN_ON(!connector)) ++ return; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, connector); ++ if (WARN_ON(!conn_state)) ++ return; ++ ++ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); ++ if (WARN_ON(!crtc_state)) ++ return; ++ ++ mode = &crtc_state->adjusted_mode; ++ ++ lt9611_mipi_input_digital(lt9611, mode); ++ lt9611_pll_setup(lt9611, mode, &postdiv); ++ lt9611_mipi_video_setup(lt9611, mode); ++ lt9611_pcr_setup(lt9611, mode, postdiv); ++ ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, ++ connector, ++ mode); ++ if (!ret) ++ lt9611->vic = avi_frame.video_code; + + if (lt9611_power_on(lt9611)) { + dev_err(lt9611->dev, "power on failed\n"); +@@ -889,7 +922,8 @@ static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, + return MODE_OK; + } + +-static void lt9611_bridge_pre_enable(struct drm_bridge *bridge) ++static void lt9611_bridge_atomic_pre_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + static const struct reg_sequence reg_cfg[] = { +@@ -917,29 +951,6 @@ lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge, + lt9611_sleep_setup(lt9611); + } + +-static void lt9611_bridge_mode_set(struct drm_bridge *bridge, +- const struct drm_display_mode *mode, +- const struct drm_display_mode *adj_mode) +-{ +- struct lt9611 *lt9611 = bridge_to_lt9611(bridge); +- struct hdmi_avi_infoframe avi_frame; +- unsigned int postdiv; +- int ret; +- +- lt9611_bridge_pre_enable(bridge); +- +- lt9611_mipi_input_digital(lt9611, mode); +- lt9611_pll_setup(lt9611, mode, &postdiv); +- lt9611_mipi_video_setup(lt9611, mode); +- lt9611_pcr_setup(lt9611, mode, postdiv); +- +- ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, +- <9611->connector, +- mode); +- if (!ret) +- lt9611->vic = avi_frame.video_code; +-} +- + static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) + { + return __lt9611_detect(bridge_to_lt9611(bridge)); +@@ -965,11 +976,11 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = { + .attach = lt9611_bridge_attach, + .detach = lt9611_bridge_detach, + .mode_valid = lt9611_bridge_mode_valid, +- .mode_set = lt9611_bridge_mode_set, + .detect = lt9611_bridge_detect, + .get_edid = lt9611_bridge_get_edid, + .hpd_enable = lt9611_bridge_hpd_enable, + ++ .atomic_pre_enable = lt9611_bridge_atomic_pre_enable, + .atomic_enable = lt9611_bridge_atomic_enable, + .atomic_disable = lt9611_bridge_atomic_disable, + .atomic_post_disable = lt9611_bridge_atomic_post_disable, +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-attach-to-the-next-bridge.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-attach-to-the-next-bridge.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-attach-to-the-next-bridge.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-attach-to-the-next-bridge.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,215 @@ +From 47ad85ea4466fcaefcdb8667f2add832a4dd4a25 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:53 +0200 +Subject: [PATCH 6/9] drm/bridge: lt9611: attach to the next bridge + +The bindings require that there is a next bridge after the lt9611. If +nothing else it can be the hdmi-connector (as used on the RB3 platform, +see sdm845-db845c.dts). + +Bring in the next bridge into the drm bridges chain and attach to it. + +Since lt9611 is not anymore the last bridge in the chain, this also +allows us to drop all the !DRM_BRIDGE_ATTACH_NO_CONNECTOR functionality. + +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-9-dmitry.baryshkov@linaro.org +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 99 ++----------------------- + 1 file changed, 7 insertions(+), 92 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 37ad243f06f2..c454c12aebf8 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -31,7 +32,7 @@ + struct lt9611 { + struct device *dev; + struct drm_bridge bridge; +- struct drm_connector connector; ++ struct drm_bridge *next_bridge; + + struct regmap *regmap; + +@@ -105,11 +106,6 @@ static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge) + return container_of(bridge, struct lt9611, bridge); + } + +-static struct lt9611 *connector_to_lt9611(struct drm_connector *connector) +-{ +- return container_of(connector, struct lt9611, connector); +-} +- + static int lt9611_mipi_input_analog(struct lt9611 *lt9611) + { + const struct reg_sequence reg_cfg[] = { +@@ -580,9 +576,9 @@ static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) + return NULL; + } + +-/* connector funcs */ +-static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) ++static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) + { ++ struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + unsigned int reg_val = 0; + int connected = 0; + +@@ -595,12 +591,6 @@ static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) + return lt9611->status; + } + +-static enum drm_connector_status +-lt9611_connector_detect(struct drm_connector *connector, bool force) +-{ +- return __lt9611_detect(connector_to_lt9611(connector)); +-} +- + static int lt9611_read_edid(struct lt9611 *lt9611) + { + unsigned int temp; +@@ -682,30 +672,6 @@ lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) + return 0; + } + +-static int lt9611_connector_get_modes(struct drm_connector *connector) +-{ +- struct lt9611 *lt9611 = connector_to_lt9611(connector); +- unsigned int count; +- struct edid *edid; +- +- lt9611_power_on(lt9611); +- edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611); +- drm_connector_update_edid_property(connector, edid); +- count = drm_add_edid_modes(connector, edid); +- kfree(edid); +- +- return count; +-} +- +-static enum drm_mode_status +-lt9611_connector_mode_valid(struct drm_connector *connector, +- struct drm_display_mode *mode) +-{ +- struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); +- +- return lt9611_mode ? MODE_OK : MODE_BAD; +-} +- + /* bridge funcs */ + static void + lt9611_bridge_atomic_enable(struct drm_bridge *bridge, +@@ -783,21 +749,6 @@ lt9611_bridge_atomic_disable(struct drm_bridge *bridge, + } + } + +-static struct +-drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = { +- .get_modes = lt9611_connector_get_modes, +- .mode_valid = lt9611_connector_mode_valid, +-}; +- +-static const struct drm_connector_funcs lt9611_bridge_connector_funcs = { +- .fill_modes = drm_helper_probe_single_connector_modes, +- .detect = lt9611_connector_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, +-}; +- + static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, + struct device_node *dsi_node) + { +@@ -846,43 +797,12 @@ static void lt9611_bridge_detach(struct drm_bridge *bridge) + mipi_dsi_device_unregister(lt9611->dsi0); + } + +-static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611) +-{ +- int ret; +- +- ret = drm_connector_init(bridge->dev, <9611->connector, +- <9611_bridge_connector_funcs, +- DRM_MODE_CONNECTOR_HDMIA); +- if (ret) { +- DRM_ERROR("Failed to initialize connector with drm\n"); +- return ret; +- } +- +- drm_connector_helper_add(<9611->connector, +- <9611_bridge_connector_helper_funcs); +- +- if (!bridge->encoder) { +- DRM_ERROR("Parent encoder object not found"); +- return -ENODEV; +- } +- +- drm_connector_attach_encoder(<9611->connector, bridge->encoder); +- +- return 0; +-} +- + static int lt9611_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + int ret; + +- if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { +- ret = lt9611_connector_init(bridge, lt9611); +- if (ret < 0) +- return ret; +- } +- + /* Attach primary DSI */ + lt9611->dsi0 = lt9611_attach_dsi(lt9611, lt9611->dsi0_node); + if (IS_ERR(lt9611->dsi0)) +@@ -897,11 +817,11 @@ static int lt9611_bridge_attach(struct drm_bridge *bridge, + } + } + +- return 0; ++ return drm_bridge_attach(bridge->encoder, lt9611->next_bridge, ++ bridge, flags); + + err_unregister_dsi0: + lt9611_bridge_detach(bridge); +- drm_connector_cleanup(<9611->connector); + mipi_dsi_device_unregister(lt9611->dsi0); + + return ret; +@@ -951,11 +871,6 @@ lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge, + lt9611_sleep_setup(lt9611); + } + +-static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) +-{ +- return __lt9611_detect(bridge_to_lt9611(bridge)); +-} +- + static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) + { +@@ -1002,7 +917,7 @@ static int lt9611_parse_dt(struct device *dev, + + lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode"); + +- return 0; ++ return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611->next_bridge); + } + + static int lt9611_gpio_init(struct lt9611 *lt9611) +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-fix-clock-calculation.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-fix-clock-calculation.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-fix-clock-calculation.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0006-drm-bridge-lt9611-fix-clock-calculation.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,104 @@ +From 75b3c2777dbb71af89c3f96ff8f9c3071d4e0601 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:50 +0200 +Subject: [PATCH 6/8] drm/bridge: lt9611: fix clock calculation + +[ Upstream commit 2576eb26494eb0509dd9ceb0cd27771a7a5e3674 ] + +Instead of having several fixed values for the pcr register, calculate +it before programming. This allows the bridge to support most of the +display modes. + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-6-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 32 +++++++++++-------------- + 1 file changed, 14 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 4925566dfc54..bb13511dd426 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -190,8 +190,9 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611, + regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256)); + } + +-static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) ++static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int postdiv) + { ++ unsigned int pcr_m = mode->clock * 5 * postdiv / 27000; + const struct reg_sequence reg_cfg[] = { + { 0x830b, 0x01 }, + { 0x830c, 0x10 }, +@@ -234,24 +235,14 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod + else + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + +- switch (mode->hdisplay) { +- case 640: +- regmap_write(lt9611->regmap, 0x8326, 0x14); +- break; +- case 1920: +- regmap_write(lt9611->regmap, 0x8326, 0x37); +- break; +- case 3840: +- regmap_write(lt9611->regmap, 0x8326, 0x37); +- break; +- } ++ regmap_write(lt9611->regmap, 0x8326, pcr_m); + + /* pcr rst */ + regmap_write(lt9611->regmap, 0x8011, 0x5a); + regmap_write(lt9611->regmap, 0x8011, 0xfa); + } + +-static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode) ++static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int *postdiv) + { + unsigned int pclk = mode->clock; + const struct reg_sequence reg_cfg[] = { +@@ -269,12 +260,16 @@ static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode + + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); + +- if (pclk > 150000) ++ if (pclk > 150000) { + regmap_write(lt9611->regmap, 0x812d, 0x88); +- else if (pclk > 70000) ++ *postdiv = 1; ++ } else if (pclk > 70000) { + regmap_write(lt9611->regmap, 0x812d, 0x99); +- else ++ *postdiv = 2; ++ } else { + regmap_write(lt9611->regmap, 0x812d, 0xaa); ++ *postdiv = 4; ++ } + + /* + * first divide pclk by 2 first +@@ -917,14 +912,15 @@ static void lt9611_bridge_mode_set(struct drm_bridge *bridge, + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + struct hdmi_avi_infoframe avi_frame; ++ unsigned int postdiv; + int ret; + + lt9611_bridge_pre_enable(bridge); + + lt9611_mipi_input_digital(lt9611, mode); +- lt9611_pll_setup(lt9611, mode); ++ lt9611_pll_setup(lt9611, mode, &postdiv); + lt9611_mipi_video_setup(lt9611, mode); +- lt9611_pcr_setup(lt9611, mode); ++ lt9611_pcr_setup(lt9611, mode, postdiv); + + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, + <9611->connector, +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-pass-a-pointer-to-the-of-node.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-pass-a-pointer-to-the-of-node.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-pass-a-pointer-to-the-of-node.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-pass-a-pointer-to-the-of-node.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,35 @@ +From 15edaafbff754ff94b01dd59d61334a3819f9e14 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:51 +0200 +Subject: [PATCH 7/8] drm/bridge: lt9611: pass a pointer to the of node + +[ Upstream commit b0a7f8736789935f62d6df32d441cdf05a5c05d2 ] + +Pass a pointer to the OF node while registering lt9611 MIPI device. + +Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge") +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-7-dmitry.baryshkov@linaro.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index bb13511dd426..0c6dea9ccb72 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -759,7 +759,7 @@ static const struct drm_connector_funcs lt9611_bridge_connector_funcs = { + static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611, + struct device_node *dsi_node) + { +- const struct mipi_dsi_device_info info = { "lt9611", 0, NULL }; ++ const struct mipi_dsi_device_info info = { "lt9611", 0, lt9611->dev->of_node}; + struct mipi_dsi_device *dsi; + struct mipi_dsi_host *host; + int ret; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-simplify-video-timings-programming.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-simplify-video-timings-programming.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-simplify-video-timings-programming.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0007-drm-bridge-lt9611-simplify-video-timings-programming.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,38 @@ +From f2ab9ec46b29ac39ef373650d9d8f5c8d3eafff1 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:55 +0200 +Subject: [PATCH 7/9] drm/bridge: lt9611: simplify video timings programming + +Inline calculated values to simplify the calculation in +lt9611_mipi_video_setup(). + +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-11-dmitry.baryshkov@linaro.org +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index c454c12aebf8..385a0459a1b2 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -153,12 +153,12 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611, + hactive = mode->hdisplay; + hsync_len = mode->hsync_end - mode->hsync_start; + hfront_porch = mode->hsync_start - mode->hdisplay; +- hsync_porch = hsync_len + mode->htotal - mode->hsync_end; ++ hsync_porch = mode->htotal - mode->hsync_start; + + vactive = mode->vdisplay; + vsync_len = mode->vsync_end - mode->vsync_start; + vfront_porch = mode->vsync_start - mode->vdisplay; +- vsync_porch = vsync_len + mode->vtotal - mode->vsync_end; ++ vsync_porch = mode->vtotal - mode->vsync_start; + + regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256)); + regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256)); +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-Fix-PLL-being-unable-to-lock.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-Fix-PLL-being-unable-to-lock.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-Fix-PLL-being-unable-to-lock.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-Fix-PLL-being-unable-to-lock.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,40 @@ +From 1fc9263ad79593972a132ea4fcc7530e87e8063e Mon Sep 17 00:00:00 2001 +From: Robert Foss +Date: Tue, 13 Dec 2022 16:03:04 +0100 +Subject: [PATCH 8/8] drm/bridge: lt9611: Fix PLL being unable to lock + +commit 2a9df204be0bbb896e087f00b9ee3fc559d5a608 upstream. + +This fixes PLL being unable to lock, and is derived from an equivalent +downstream commit. + +Available LT9611 documentation does not list this register, neither does +LT9611UXC (which is a different chip). + +This commit has been confirmed to fix HDMI output on DragonBoard 845c. + +Suggested-by: Amit Pundir +Reviewed-by: Amit Pundir +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20221213150304.4189760-1-robert.foss@linaro.org +Signed-off-by: Amit Pundir +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 0c6dea9ccb72..660e05fa4a70 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -256,6 +256,7 @@ static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode + { 0x8126, 0x55 }, + { 0x8127, 0x66 }, + { 0x8128, 0x88 }, ++ { 0x812a, 0x20 }, + }; + + regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg)); +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-rework-infoframes-handling.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-rework-infoframes-handling.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-rework-infoframes-handling.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0008-drm-bridge-lt9611-rework-infoframes-handling.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,119 @@ +From 201be375bc67813c285a7c331018ce940ca38d1a Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:56 +0200 +Subject: [PATCH 8/9] drm/bridge: lt9611: rework infoframes handling + +Rework handling infoframes: +- Write full HDMI AVI infoframe instead of just fixing the VIC value +- Also send the HDMI Vendor Specific infoframe, as recommended by the + HDMI spec. + +Reviewed-by: Neil Armstrong +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-12-dmitry.baryshkov@linaro.org +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 57 +++++++++++++++++++------ + 1 file changed, 44 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 385a0459a1b2..56b40a26cfd8 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -57,7 +57,6 @@ struct lt9611 { + enum drm_connector_status status; + + u8 edid_buf[EDID_SEG_SIZE]; +- u32 vic; + }; + + #define LT9611_PAGE_CONTROL 0xff +@@ -351,12 +350,51 @@ static int lt9611_video_check(struct lt9611 *lt9611) + return temp; + } + +-static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) ++static void lt9611_hdmi_set_infoframes(struct lt9611 *lt9611, ++ struct drm_connector *connector, ++ struct drm_display_mode *mode) + { +- regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic); +- regmap_write(lt9611->regmap, 0x8447, lt9611->vic); +- regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */ ++ union hdmi_infoframe infoframe; ++ ssize_t len; ++ u8 iframes = 0x0a; /* UD1 infoframe */ ++ u8 buf[32]; ++ int ret; ++ int i; ++ ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi, ++ connector, ++ mode); ++ if (ret < 0) ++ goto out; ++ ++ len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); ++ if (len < 0) ++ goto out; ++ ++ for (i = 0; i < len; i++) ++ regmap_write(lt9611->regmap, 0x8440 + i, buf[i]); ++ ++ ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi, ++ connector, ++ mode); ++ if (ret < 0) ++ goto out; ++ ++ len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf)); ++ if (len < 0) ++ goto out; + ++ for (i = 0; i < len; i++) ++ regmap_write(lt9611->regmap, 0x8474 + i, buf[i]); ++ ++ iframes |= 0x20; ++ ++out: ++ regmap_write(lt9611->regmap, 0x843d, iframes); /* UD1 infoframe */ ++} ++ ++static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) ++{ + regmap_write(lt9611->regmap, 0x82d6, 0x8c); + regmap_write(lt9611->regmap, 0x82d7, 0x04); + } +@@ -683,9 +721,7 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_display_mode *mode; +- struct hdmi_avi_infoframe avi_frame; + unsigned int postdiv; +- int ret; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (WARN_ON(!connector)) +@@ -706,18 +742,13 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge, + lt9611_mipi_video_setup(lt9611, mode); + lt9611_pcr_setup(lt9611, mode, postdiv); + +- ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, +- connector, +- mode); +- if (!ret) +- lt9611->vic = avi_frame.video_code; +- + if (lt9611_power_on(lt9611)) { + dev_err(lt9611->dev, "power on failed\n"); + return; + } + + lt9611_mipi_input_analog(lt9611); ++ lt9611_hdmi_set_infoframes(lt9611, connector, mode); + lt9611_hdmi_tx_digital(lt9611); + lt9611_hdmi_tx_phy(lt9611); + +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0009-drm-bridge-lt9611-stop-filtering-modes-via-the-table.patch b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0009-drm-bridge-lt9611-stop-filtering-modes-via-the-table.patch --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0009-drm-bridge-lt9611-stop-filtering-modes-via-the-table.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/0009-drm-bridge-lt9611-stop-filtering-modes-via-the-table.patch 2023-06-06 11:40:50.484906104 +0800 @@ -0,0 +1,96 @@ +From ec7cca5d327f279f7d073f51d2513530bc3f086a Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Wed, 18 Jan 2023 10:16:57 +0200 +Subject: [PATCH 9/9] drm/bridge: lt9611: stop filtering modes via the table + +The lt9611 bridge can support different modes, it makes no sense to list +them in the table. Drop the table and check the number of interfaces +using the fixed value. + +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20230118081658.2198520-13-dmitry.baryshkov@linaro.org +--- + drivers/gpu/drm/bridge/lontium-lt9611.c | 49 ++++++------------------- + 1 file changed, 12 insertions(+), 37 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 56b40a26cfd8..45acff6014e1 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -82,24 +82,6 @@ static const struct regmap_config lt9611_regmap_config = { + .num_ranges = ARRAY_SIZE(lt9611_ranges), + }; + +-struct lt9611_mode { +- u16 hdisplay; +- u16 vdisplay; +- u8 vrefresh; +- u8 lanes; +- u8 intfs; +-}; +- +-static struct lt9611_mode lt9611_modes[] = { +- { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */ +- { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */ +- { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */ +- { 1920, 1080, 24, 3, 1 }, +- { 720, 480, 60, 4, 1 }, +- { 720, 576, 50, 2, 1 }, +- { 640, 480, 60, 2, 1 }, +-}; +- + static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge) + { + return container_of(bridge, struct lt9611, bridge); +@@ -599,21 +581,6 @@ static int lt9611_regulator_enable(struct lt9611 *lt9611) + return 0; + } + +-static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) { +- if (lt9611_modes[i].hdisplay == mode->hdisplay && +- lt9611_modes[i].vdisplay == mode->vdisplay && +- lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) { +- return <9611_modes[i]; +- } +- } +- +- return NULL; +-} +- + static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) + { + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); +@@ -862,12 +829,20 @@ static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) + { +- struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode); + struct lt9611 *lt9611 = bridge_to_lt9611(bridge); + +- if (!lt9611_mode) +- return MODE_BAD; +- else if (lt9611_mode->intfs > 1 && !lt9611->dsi1) ++ if (mode->hdisplay > 3840) ++ return MODE_BAD_HVALUE; ++ ++ if (mode->vdisplay > 2160) ++ return MODE_BAD_VVALUE; ++ ++ if (mode->hdisplay == 3840 && ++ mode->vdisplay == 2160 && ++ drm_mode_vrefresh(mode) > 30) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->hdisplay > 2000 && !lt9611->dsi1_node) + return MODE_PANEL; + else + return MODE_OK; +-- +2.25.1 + diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/mt8365-sb35.cfg b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/mt8365-sb35.cfg --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/mt8365-sb35.cfg 2023-06-06 14:42:15.399971764 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk/mt8365-sb35.cfg 2023-06-06 11:40:50.484906104 +0800 @@ -1,5 +1,6 @@ -CONFIG_DRM_PANEL_RPI_PUMPKIN_TOUCHSCREEN=m -CONFIG_DRM_LONTIUM_LT9611=m +CONFIG_DRM_PANEL_RPI_PUMPKIN_TOUCHSCREEN=y +CONFIG_DRM_LONTIUM_LT9611=y +CONFIG_DRM_DISPLAY_CONNECTOR=y # OTG CONFIG_USB_CONN_GPIO=y @@ -8,3 +9,4 @@ # Audio CONFIG_SND_SOC_MT8365_SB35=y +CONFIG_SND_SOC_RT5509=y diff -Naur a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk_5.15.bb b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk_5.15.bb --- a/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk_5.15.bb 2023-06-06 14:42:15.399971764 +0800 +++ b/src/meta-mediatek-bsp/recipes-kernel/linux/linux-mtk_5.15.bb 2023-06-06 11:40:50.484906104 +0800 @@ -9,3 +9,29 @@ SRCBRANCH ?= "mtk-v5.15-dev" SRCREV = "d95de46d89cf798590eedc57973c9b3ed3dd5fdb" +SRC_URI += " \ + file://0001-To-fix-rpi_touchscreen_dsi_probe-failed.patch \ + file://0001-Failed-to-start-Weston-system-service.patch \ + file://0001-Fix-incorrect-pinctrl-properties-in-i2c.patch \ + file://0001-Fix-MTK-DSI-malfuctions-with-bridge.patch \ + file://0001-gpu-lontium-lt9611-Fix-NULL-pointer-dereference-in-l.patch \ + file://0002-drm-bridge-lt9611-fix-sleep-mode-setup.patch \ + file://0003-drm-bridge-lt9611-fix-HPD-reenablement.patch \ + file://0004-drm-bridge-lt9611-fix-polarity-programming.patch \ + file://0005-drm-bridge-lt9611-fix-programming-of-video-modes.patch \ + file://0006-drm-bridge-lt9611-fix-clock-calculation.patch \ + file://0007-drm-bridge-lt9611-pass-a-pointer-to-the-of-node.patch \ + file://0008-drm-bridge-lt9611-Fix-PLL-being-unable-to-lock.patch \ + file://0001-drm-bridge-lt9611-Switch-to-atomic-operations.patch \ + file://0002-lontium-lt9611-check-a-different-register-bit-for-HD.patch \ + file://0003-drm-bridge-lt9611-Consolidate-detection-logic.patch \ + file://0004-drm-bridge-lt9611-Use-both-bits-for-HDMI-sensing.patch \ + file://0005-drm-bridge-lt9611-rework-the-mode_set-function.patch \ + file://0006-drm-bridge-lt9611-attach-to-the-next-bridge.patch \ + file://0007-drm-bridge-lt9611-simplify-video-timings-programming.patch \ + file://0008-drm-bridge-lt9611-rework-infoframes-handling.patch \ + file://0009-drm-bridge-lt9611-stop-filtering-modes-via-the-table.patch \ + file://0001-lt9611-porting.patch \ + file://0001-Audio-RT5509-driver-porting.patch \ + file://0001-Add-stereo-mode-support.patch \ +" diff -Naur a/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck/0001-Open-serial-port-without-tty-line-discipline-involve.patch b/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck/0001-Open-serial-port-without-tty-line-discipline-involve.patch --- a/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck/0001-Open-serial-port-without-tty-line-discipline-involve.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck/0001-Open-serial-port-without-tty-line-discipline-involve.patch 2023-06-06 11:40:50.940916424 +0800 @@ -0,0 +1,27 @@ +From 78328f9e790a3129b9226b7009745d0b42ba5d64 Mon Sep 17 00:00:00 2001 +From: rockefeller +Date: Thu, 9 Apr 2020 09:13:15 +0800 +Subject: [PATCH] Open serial port without tty line discipline involved + +For transferring binary data, tty line discipline would corrupt the data +--- + serialcheck.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/serialcheck.c b/serialcheck.c +index 4f5b747..976d171 100644 +--- a/serialcheck.c ++++ b/serialcheck.c +@@ -521,7 +521,8 @@ int main(int argc, char *argv[]) + sigint_action.sa_flags = 0; + sigaction(SIGINT, &sigint_action, NULL); + +- fd = open(opts.uart_name, open_mode | O_NONBLOCK); ++ printf("Openning %s without tty line discipline\n", opts.uart_name); ++ fd = open(opts.uart_name, open_mode | O_NONBLOCK | O_NOCTTY); + if (fd < 0) + die("Failed to open %s: %m\n", opts.uart_name); + +-- +2.23.0 + diff -Naur a/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck_1.0.0.bb b/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck_1.0.0.bb --- a/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck_1.0.0.bb 2023-06-06 14:42:16.199969606 +0800 +++ b/src/meta-openembedded/meta-oe/recipes-devtools/serialcheck/serialcheck_1.0.0.bb 2023-06-06 11:40:50.940916424 +0800 @@ -7,6 +7,10 @@ git://github.com/nsekhar/serialcheck.git;branch=master;protocol=https \ " +SRC_URI:append = " \ + file://0001-Open-serial-port-without-tty-line-discipline-involve.patch \ +" + SRCREV = "45eb2ffa5378396e85432872833890b0a1cba872" S = "${WORKDIR}/git" diff -Naur a/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test/0001-Open-serial-port-without-tty-line-discipline-involve.patch b/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test/0001-Open-serial-port-without-tty-line-discipline-involve.patch --- a/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test/0001-Open-serial-port-without-tty-line-discipline-involve.patch 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test/0001-Open-serial-port-without-tty-line-discipline-involve.patch 2023-06-06 11:40:50.940916424 +0800 @@ -0,0 +1,27 @@ +From 6bcf77b9e021da24e5ea8251865f8bd02593bacc Mon Sep 17 00:00:00 2001 +From: Rockefeller Lin +Date: Fri, 12 May 2023 10:10:51 +0800 +Subject: [PATCH] Open serial port without tty line discipline involved + +For transferring binary data, tty line discipline would corrupt the data +--- + linux-serial-test.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/linux-serial-test.c b/linux-serial-test.c +index b89c839..8bf0741 100644 +--- a/linux-serial-test.c ++++ b/linux-serial-test.c +@@ -604,7 +604,8 @@ static void setup_serial_port(int baud) + struct serial_rs485 rs485; + int ret; + +- _fd = open(_cl_port, O_RDWR | O_NONBLOCK); ++ printf("Openning %s without tty line discipline\n", _cl_port); ++ _fd = open(_cl_port, O_RDWR | O_NONBLOCK | O_NOCTTY); + + if (_fd < 0) { + ret = -errno; +-- +2.25.1 + diff -Naur a/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test_git.bb b/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test_git.bb --- a/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test_git.bb 1970-01-01 08:00:00.000000000 +0800 +++ b/src/meta-openembedded/meta-oe/recipes-devtools/serialtest/serial-test_git.bb 2023-06-06 11:40:50.940916424 +0800 @@ -0,0 +1,18 @@ +DESCRIPTION = "Serial test application" +HOMEPAGE = "https://github.com/cbrake/linux-serial-test" +SECTION = "utils" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://LICENSES/MIT;md5=544799d0b492f119fa04641d1b8868ed" +SRCREV = "2ee61484167eab846f7b7c565284d7c350d738d3" + +SRC_URI = " \ + git://github.com/cbrake/linux-serial-test.git;branch=master;protocol=https \ +" + +SRC_URI:append = " \ + file://0001-Open-serial-port-without-tty-line-discipline-involve.patch \ +" + +S = "${WORKDIR}/git" + +inherit cmake diff -Naur a/src/meta-rity/meta/conf/local.conf.sample b/src/meta-rity/meta/conf/local.conf.sample --- a/src/meta-rity/meta/conf/local.conf.sample 2023-06-06 14:42:16.371969143 +0800 +++ b/src/meta-rity/meta/conf/local.conf.sample 2023-06-06 11:40:51.064919228 +0800 @@ -19,14 +19,14 @@ # #MACHINE ??= "genio-1200-evk" #MACHINE ??= "genio-350-evk" -MACHINE ??= "genio-700-evk" +#MACHINE ??= "genio-700-evk" #MACHINE ??= "i300a-coral" #MACHINE ??= "i300a-pumpkin" #MACHINE ??= "i300a-sb30" #MACHINE ??= "i300b-pumpkin" #MACHINE ??= "i350-evk" #MACHINE ??= "i350-pumpkin" -#MACHINE ??= "i350-sb35" +MACHINE ??= "i350-sb35" #MACHINE ??= "i500-evb" #MACHINE ??= "i500-pumpkin" #MACHINE ??= "i1200-demo" @@ -42,7 +42,7 @@ # # The default is a downloads directory under TOPDIR which is the build directory. # -#DL_DIR ?= "${TOPDIR}/downloads" +DL_DIR ?= "${TOPDIR}/../downloads" # # Where to place shared-state files @@ -58,7 +58,7 @@ # # The default is a sstate-cache directory under TOPDIR. # -#SSTATE_DIR ?= "${TOPDIR}/sstate-cache" +SSTATE_DIR ?= "${TOPDIR}/../sstate-cache" # # Where to place the build output diff -Naur a/src/meta-rity/meta/recipes-rity/packagegroups/packagegroup-rity-tools.bb b/src/meta-rity/meta/recipes-rity/packagegroups/packagegroup-rity-tools.bb --- a/src/meta-rity/meta/recipes-rity/packagegroups/packagegroup-rity-tools.bb 2023-06-06 14:42:16.375969133 +0800 +++ b/src/meta-rity/meta/recipes-rity/packagegroups/packagegroup-rity-tools.bb 2023-06-06 11:40:51.064919228 +0800 @@ -26,6 +26,7 @@ evtest \ libdrm-tests \ read-edid \ + serial-test \ " RDEPENDS:${PN}-extended = " \ diff -Naur a/src/meta-rity/meta-rity-demo/recipes-demo/images/rity-demo-image.bb b/src/meta-rity/meta-rity-demo/recipes-demo/images/rity-demo-image.bb --- a/src/meta-rity/meta-rity-demo/recipes-demo/images/rity-demo-image.bb 2023-06-06 14:42:16.367969154 +0800 +++ b/src/meta-rity/meta-rity-demo/recipes-demo/images/rity-demo-image.bb 2023-06-06 11:40:51.060919137 +0800 @@ -42,3 +42,5 @@ r2inference \ gstinference \ " + +IMAGE_FEATURES:append = " splash"