diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 711cf3bba6e857..afed5e6876681c 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -343,6 +343,7 @@ properties: - items: - enum: - fairphone,fp5 + - nexcomputer,nexphone - particle,tachyon - qcom,qcm6490-idp - qcom,qcs6490-rb3gen2 diff --git a/Documentation/devicetree/bindings/display/panel/focaltech,ft8722.yaml b/Documentation/devicetree/bindings/display/panel/focaltech,ft8722.yaml new file mode 100644 index 00000000000000..1348ff5f891b46 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/focaltech,ft8722.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/focaltech,ft8722.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Focaltech FT8722 LCD panel controller + +maintainers: + - Luka Panio + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: txd,txdi660jbpv + + reg: + maxItems: 1 + + backlight: true + port: true + reset-gpios: true + + vddio-supply: + description: power IC supply regulator + + vddpos-supply: + description: positive boost supply regulator + + vddneg-supply: + description: negative boost supply regulator + +required: + - compatible + - reg + - port + - vddio-supply + - vddpos-supply + - vddneg-supply + - reset-gpios + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "txd,txdi660jbpv"; + reg = <0>; + vddio-supply = <&vreg_l12c>; + vddpos-supply = <&lab>; + vddneg-supply = <&ibb>; + reset-gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>; + + backlight = <&aw99703_backlight>; + pinctrl-0 = <&sde_dsi_active &sde_te_active_sleep>; + pinctrl-1 = <&sde_dsi_sleep &sde_te_active_sleep>; + pinctrl-names = "default", "sleep"; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/leds/backlight/awinic,aw99703.yaml b/Documentation/devicetree/bindings/leds/backlight/awinic,aw99703.yaml new file mode 100644 index 00000000000000..3871e2a5494c8a --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/awinic,aw99703.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/awinic,aw99703.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Awinic AW99703 3-channel WLED Backlight Driver + +maintainers: + - Luka Panio + +allOf: + - $ref: common.yaml# + +properties: + compatible: + const: awinic,aw99703 + + reg: + maxItems: 1 + + enable-gpios: + description: GPIO to use to enable/disable the backlight (HWEN pin). + maxItems: 1 + +required: + - compatible + - reg + - enable-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + backlight@36 { + compatible = "awinic,aw99703"; + reg = <0x36>; + enable-gpios = <&pm8350c_gpios 7 GPIO_ACTIVE_HIGH>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index c7591b2aec2a74..1dbaab06c8113f 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1134,6 +1134,8 @@ patternProperties: description: New Vision Display (Shenzhen) Co., Ltd. "^nexbox,.*": description: Nexbox + "^nexcomputer,.*": + description: Nex Computer LLC "^nextthing,.*": description: Next Thing Co. "^ni,.*": diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 61618da3f68c9c..ae528b859331cf 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -125,6 +125,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-poplar.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-xiaomi-sagit.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-fairphone-fp5.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-idp.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcm6490-nexcomputer-nexphone.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-particle-tachyon.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-shift-otter.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb diff --git a/arch/arm64/boot/dts/qcom/qcm6490-nexcomputer-nexphone.dts b/arch/arm64/boot/dts/qcom/qcm6490-nexcomputer-nexphone.dts new file mode 100644 index 00000000000000..ef80313b34138f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6490-nexcomputer-nexphone.dts @@ -0,0 +1,911 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2026, Luka Panio + */ + +/dts-v1/; + +#define PM7250B_SID 8 +#define PM7250B_SID1 9 + +#include +#include +#include +#include +#include +#include +#include +#include "kodiak.dtsi" +#include "pm7250b.dtsi" +#include "pm7325.dtsi" +#include "pm8350c.dtsi" /* PM7350C */ +#include "pmk8350.dtsi" /* PMK7325 */ + +/delete-node/ &rmtfs_mem; + +/ { + model = "NexPhone"; + compatible = "nexcomputer,nexphone", "qcom,qcm6490"; + chassis-type = "handset"; + + aliases { + serial1 = &uart7; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer0: framebuffer@a000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0xe1000000 0x0 (2340 * 1080 * 4)>; + width = <1080>; + height = <2340>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + clocks = <&gcc GCC_DISP_HF_AXI_CLK>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&volume_up_default>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume Up"; + gpios = <&pm7325_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + ibb: regulator-ibb { + compatible = "regulator-fixed"; + regulator-name = "ibb"; + + regulator-min-microvolt = <6000000>; + regulator-max-microvolt = <6000000>; + + gpio = <&pm7250b_gpios 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + + regulator-boot-on; + }; + + lab: regulator-lab { + compatible = "regulator-fixed"; + regulator-name = "lab"; + + regulator-min-microvolt = <6000000>; + regulator-max-microvolt = <6000000>; + + gpio = <&pm7250b_gpios 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + + regulator-boot-on; + }; + + pmic-glink { + compatible = "qcom,qcm6490-pmic-glink", "qcom,pmic-glink"; + + #address-cells = <1>; + #size-cells = <0>; + + orientation-gpios = <&tlmm 140 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_dp_qmpphy_out>; + }; + }; + + port@2 { + reg = <2>; + + pmic_glink_sbu: endpoint { + remote-endpoint = <&usb_sbu_mux>; + }; + }; + }; + }; + }; + + reserved-memory { + ramoops_mem: ramoops@a9000000 { + compatible = "ramoops"; + reg = <0x0 0xa9000000 0x0 0x200000>; + console-size = <0x200000>; + mem-type = <2>; + }; + + cont_splash_mem: cont-splash@e1000000 { + reg = <0x0 0xe1000000 0x0 0x2300000>; + no-map; + }; + + rmtfs_mem: memory@f8500000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0xf8500000 0x0 0x600000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = , ; + }; + }; + + usb-sbu-mux { + compatible = "pericom,pi3usb102", "gpio-sbu-mux"; + + enable-gpios = <&tlmm 96 GPIO_ACTIVE_LOW>; + select-gpios = <&tlmm 42 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&usb0_sbu_default>; + pinctrl-names = "default"; + + mode-switch; + orientation-switch; + + port { + usb_sbu_mux: endpoint { + remote-endpoint = <&pmic_glink_sbu>; + }; + }; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vreg_s1b: smps1 { + regulator-name = "vreg_s1b"; + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s7b: smps7 { + regulator-name = "vreg_s7b"; + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b: smps8 { + regulator-name = "vreg_s8b"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b: ldo1 { + regulator-name = "vreg_l1b"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vreg_l2b: ldo2 { + regulator-name = "vreg_l2b"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l3b: ldo3 { + regulator-name = "vreg_l3b"; + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vreg_l6b: ldo6 { + regulator-name = "vreg_l6b"; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l7b: ldo7 { + regulator-name = "vreg_l7b"; + /* Constrained for UFS VCC, at least until UFS driver scales voltage */ + regulator-min-microvolt = <2952000>; + regulator-max-microvolt = <2952000>; + regulator-initial-mode = ; + }; + + vreg_l8b: ldo8 { + regulator-name = "vreg_l8b"; + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vreg_l9b: ldo9 { + regulator-name = "vreg_l9b"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l11b: ldo11 { + regulator-name = "vreg_l11b"; + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12b: ldo12 { + regulator-name = "vreg_l12b"; + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l13b: ldo13 { + regulator-name = "vreg_l13b"; + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l14b: ldo14 { + regulator-name = "vreg_l14b"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l15b: ldo15 { + regulator-name = "vreg_l15b"; + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b: ldo16 { + regulator-name = "vreg_l16b"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l17b: ldo17 { + regulator-name = "vreg_l17b"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l18b: ldo18 { + regulator-name = "vreg_l18b"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l19b: ldo19 { + regulator-name = "vreg_l19b"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vreg_s1c: smps1 { + regulator-name = "vreg_s1c"; + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + regulator-initial-mode = ; + }; + + vreg_s9c: smps9 { + regulator-name = "vreg_s9c"; + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + regulator-initial-mode = ; + }; + + vreg_l1c: ldo1 { + regulator-name = "vreg_l1c"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c: ldo2 { + regulator-name = "vreg_l2c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3c: ldo3 { + regulator-name = "vreg_l3c"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vreg_l4c: ldo4 { + regulator-name = "vreg_l4c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5c: ldo5 { + regulator-name = "vreg_l5c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l6c: ldo6 { + regulator-name = "vreg_l6c"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7c: ldo7 { + regulator-name = "vreg_l7c"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8c: ldo8 { + regulator-name = "vreg_l8c"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c: ldo9 { + regulator-name = "vreg_l9c"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l10c: ldo10 { + regulator-name = "vreg_l10c"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + }; + + vreg_l11c: ldo11 { + regulator-name = "vreg_l11c"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l12c: ldo12 { + regulator-name = "vreg_l12c"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l13c: ldo13 { + regulator-name = "vreg_l13c"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + }; +}; + +&spi13 { + /* 0 - focaltech touchscreen */ +}; + +&tlmm { + gpio-reserved-ranges = <18 2>, /* Fingerprint LDO controls */ + <34 2>, /* Fingerprint GPIO's (interrupt and reset) */ + <56 4>, /* Fingerprint SPI */ + <61 1>, /* Fingerprint ID */ + <48 1>, /* Wireless charger status */ + <49 1>, /* LCD ID? */ + <50 2>; /* GPS secure UART */ + + qup_uart7_sleep_cts: qup-uart7-sleep-cts-state { + pins = "gpio28"; + function = "gpio"; + bias-bus-hold; + }; + + qup_uart7_sleep_rts: qup-uart7-sleep-rts-state { + pins = "gpio29"; + function = "gpio"; + bias-pull-down; + }; + + qup_uart7_sleep_tx: qup-uart7-sleep-tx-state { + pins = "gpio30"; + function = "gpio"; + bias-pull-up; + }; + + qup_uart7_sleep_rx: qup-uart7-sleep-rx-state { + pins = "gpio31"; + function = "gpio"; + bias-pull-up; + }; + + usb0_sbu_default: usb0-sbu-state { + sel-pins { + pins = "gpio42"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + }; + + oe-n-pins { + pins = "gpio96"; + function = "gpio"; + bias-disable; + drive-strength = <8>; + output-high; + }; + }; + + sde_dsi_active: sde-dsi-active-state { + pins = "gpio44"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + sde_dsi_sleep: sde-dsi-sleep-state { + pins = "gpio44"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + sde_te_active_sleep: sde-te-active-state { + pins = "gpio80"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + bluetooth_enable_default: bluetooth-enable-default-state { + pins = "gpio85"; + function = "gpio"; + output-low; + bias-disable; + }; + + sw_ctrl_default: sw-ctrl-default-state { + pins = "gpio86"; + function = "gpio"; + bias-pull-down; + }; +}; + +&gcc { + protected-clocks = , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/a660_zap.mbn"; +}; + +&i2c2 { + status = "okay"; + + aw99703_backlight: backlight@36 { + compatible = "awinic,aw99703"; + reg = <0x36>; + enable-gpios = <&pm8350c_gpios 7 GPIO_ACTIVE_HIGH>; + }; +}; + +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/ipa_fws.mbn"; + + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dp { + status = "okay"; +}; + +&mdss_dp_out { + data-lanes = <0 1>; + remote-endpoint = <&usb_dp_qmpphy_dp_in>; +}; + +&mdss_dsi { + vdda-supply = <&vreg_l6b>; + + status = "okay"; + + panel@0 { + compatible = "txd,txdi660jbpv"; + reg = <0>; + vddio-supply = <&vreg_l12c>; + vddpos-supply = <&lab>; + vddneg-supply = <&ibb>; + reset-gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>; + + backlight = <&aw99703_backlight>; + pinctrl-0 = <&sde_dsi_active &sde_te_active_sleep>; + pinctrl-1 = <&sde_dsi_sleep &sde_te_active_sleep>; + pinctrl-names = "default", "sleep"; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + data-lanes = <0 1 2>; + remote-endpoint = <&panel_in>; +}; + +&mdss_dsi_phy { + vdds-supply = <&vreg_l10c>; + phy-type = ; + + status = "okay"; +}; + +&pm7325_gpios { + volume_up_default: volume-up-default-state { + pins = "gpio6"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = <1>; + bias-pull-up; + input-enable; + }; +}; + +&pmk8350_adc_tm { + status = "okay"; + + xo-therm@0 { + reg = <0>; + io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + quiet-therm@1 { + reg = <1>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + cam-flash-therm@2 { + reg = <2>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + sdm-skin-therm@3 { + reg = <3>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + wide-rfc-therm@4 { + reg = <4>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM4_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + +&pmk8350_rtc { + status = "okay"; +}; + +&pmk8350_vadc { + status = "okay"; + + channel@44 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pmk8350_xo_therm"; + }; + + channel@144 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_quiet_therm"; + }; + + channel@145 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_cam_flash_therm"; + }; + + channel@146 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_sdm_skin_therm"; + }; + + channel@147 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_wide_rfc_therm"; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + + status = "okay"; +}; + +&q6afedai { + dai@104 { + reg = ; + }; +}; + +&qup_spi13_cs { + drive-strength = <6>; + bias-disable; +}; + +&qup_spi13_data_clk { + drive-strength = <6>; + bias-disable; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/adsp.mbn"; + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/cdsp.mbn"; + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/modem.mbn"; + status = "okay"; +}; + +&remoteproc_wpss { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/wpss.mbn"; + status = "okay"; +}; + +&sdc2_clk { + drive-strength = <16>; + bias-disable; +}; + +&sdc2_cmd { + drive-strength = <10>; + bias-pull-up; +}; + +&sdc2_data { + drive-strength = <10>; + bias-pull-up; +}; + +&sdhc_2 { + vmmc-supply = <&vreg_l9c>; + vqmmc-supply = <&vreg_l18b>; + + broken-cd; + + pinctrl-0 = <&sdc2_clk>, <&sdc2_cmd>, <&sdc2_data>; + pinctrl-1 = <&sdc2_clk_sleep>, <&sdc2_cmd_sleep>, <&sdc2_data_sleep>; + + status = "okay"; +}; + +&uart7 { + /delete-property/interrupts; + interrupts-extended = <&intc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 31 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-1 = <&qup_uart7_sleep_cts>, <&qup_uart7_sleep_rts>, <&qup_uart7_sleep_tx>, <&qup_uart7_sleep_rx>; + pinctrl-names = "default", "sleep"; + + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6750-bt"; + + pinctrl-0 = <&bluetooth_enable_default>, <&sw_ctrl_default>; + pinctrl-names = "default"; + + enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_l19b>; + vddaon-supply = <&vreg_s7b>; + vddbtcxmx-supply = <&vreg_s7b>; + vddrfacmn-supply = <&vreg_s7b>; + vddrfa0p8-supply = <&vreg_s7b>; + vddrfa1p7-supply = <&vreg_s1b>; + vddrfa1p2-supply = <&vreg_s8b>; + vddrfa2p2-supply = <&vreg_s1c>; + vddasd-supply = <&vreg_l11c>; + + max-speed = <3200000>; + }; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b>; + vcc-max-microamp = <800000>; + + vccq-supply = <&vreg_l9b>; + vccq-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c>; + vdda-pll-supply = <&vreg_l6b>; + + status = "okay"; +}; + +&usb_1 { + dr_mode = "otg"; + usb-role-switch; + + status = "okay"; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l10c>; + vdda18-supply = <&vreg_l1c>; + vdda33-supply = <&vreg_l2b>; + + qcom,hs-crossover-voltage-microvolt = <28000>; + qcom,hs-output-impedance-micro-ohms = <2600000>; + qcom,hs-rise-fall-time-bp = <5430>; + qcom,hs-disconnect-bp = <1743>; + qcom,hs-amplitude-bp = <2430>; + + qcom,pre-emphasis-amplitude-bp = <20000>; + qcom,pre-emphasis-duration-bp = <20000>; + + qcom,squelch-detector-bp = <(-2090)>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l6b>; + vdda-pll-supply = <&vreg_l1b>; + + status = "okay"; +}; + +&usb_dp_qmpphy_out { + remote-endpoint = <&pmic_glink_ss_in>; +}; + +&usb_dp_qmpphy_usb_ss_in { + remote-endpoint = <&usb_1_dwc3_ss>; +}; + +&venus { + firmware-name = "qcom/qcm6490/nexcomputer/nexphone/venus.mbn"; + + status = "okay"; +}; + +&wifi { + qcom,calibration-variant = "Nexphone"; + + status = "okay"; +}; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 1e361d4836caec..bfd540f6dbeb4f 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -135,6 +135,15 @@ config DRM_PANEL_FEIXIN_K101_IM2BA02 Say Y here if you want to enable support for the Feixin K101 IM2BA02 4-lane 800x1280 MIPI DSI panel. +config DRM_PANEL_FOCALTECH_FT8722 + tristate "Focaltech FT8722 panel driver" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Focaltech FT8722 controller + based LCD panels. + config DRM_PANEL_FEIYANG_FY07024DI26A30D tristate "Feiyang FY07024DI26A30-D MIPI-DSI LCD panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 17b2ad39abe419..85afcfaa34e45f 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_DRM_PANEL_EDP) += panel-edp.o obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o +obj-$(CONFIG_DRM_PANEL_FOCALTECH_FT8722) += panel-focaltech-ft8722.o obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o diff --git a/drivers/gpu/drm/panel/panel-focaltech-ft8722.c b/drivers/gpu/drm/panel/panel-focaltech-ft8722.c new file mode 100644 index 00000000000000..628e1b8d90e48d --- /dev/null +++ b/drivers/gpu/drm/panel/panel-focaltech-ft8722.c @@ -0,0 +1,571 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2026 Luka Panio +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static const char * const regulator_names[] = { + "vddio", + "vddpos", + "vddneg", +}; + +struct focaltech_ft8722 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)]; + struct gpio_desc *reset_gpio; +}; + +static inline +struct focaltech_ft8722 *to_focaltech_ft8722(struct drm_panel *panel) +{ + return container_of(panel, struct focaltech_ft8722, panel); +} + +static void focaltech_ft8722_reset(struct focaltech_ft8722 *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); +} + +static int focaltech_ft8722_on(struct focaltech_ft8722 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0x07, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x87, 0x22, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x87, 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x09, 0x68); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0xb0, 0x00, 0x2c, 0x00, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x4b, 0x00, 0x2c, 0x00, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x4b, 0x00, 0x2c, 0x00, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0xd4, 0x00, 0x2c, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x01, 0x08, 0x00, 0xd1, 0x00, 0xb0, 0x01, + 0x3a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x4b, 0x00, 0x2c, 0x00, 0x14); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, + 0x00, 0x54, 0x00, 0x54, 0x00, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x00, 0x54); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x01, 0x81, 0xff, 0xff, 0x00, 0x85, 0x00, + 0x85, 0x00, 0xc8, 0x00, 0xc8, 0x00, 0xc8, + 0x00, 0xc8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x00, 0xbd, 0x12, 0x75, 0x00, 0xbd, 0x80, + 0xff, 0xff, 0x00, 0x06, 0x40, 0x0a, 0x0d, + 0x0d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x22, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xd1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x0a, 0x03, 0x14, 0x03, 0x14, 0x03, 0x14, + 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x0e, 0x2a, 0x2a, 0x01, 0x42, 0x01, 0x09, + 0x01, 0x09); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x00, 0x00, 0xc2, 0xc6); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x05, 0x05, 0x72, 0x76); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x09, 0x09, 0x63, 0x67); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x09, 0x09, 0x69, 0x6d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x00, 0x00, 0xc2, 0xc6, 0x05, 0x05, 0x72, + 0x76); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x00, 0x00, 0xc2, 0xc6, 0x05, 0x05, 0x72, + 0x76); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xd1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, + 0x0a, 0xec, 0x0f, 0x19, 0x19, 0xd4, 0x0a, + 0xce, 0x0f, 0x19, 0x19, 0xd4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x0f, 0x19); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, + 0x09, 0xf8, 0x09, 0xf7, 0x09, 0xf7, 0x09, + 0xf7, 0x09, 0xf7, 0x09, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x44, 0x44); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x03); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf6); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x78); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x78); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x11); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x8f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x82, 0x01, 0x25, 0x25, 0x00, 0x00, 0x00, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x00, 0x00, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x00, 0x80, 0x00, 0x17, 0x8a, 0x01, 0x00, + 0x00, 0x17, 0x8a, 0x02, 0x01, 0x00, 0x17, + 0x8a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x03, 0x02, 0x00, 0x17, 0x8a, 0x80, 0x08, + 0x03, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xca); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x84, 0x08, 0x03, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x33, 0x33, 0x70, 0x00, 0x70); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, + 0x00, 0x01, 0x00, 0x03, 0xfd, 0x01, 0x01, + 0x00, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x03, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, + 0x00, 0x00, 0x00, 0x0c, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0c, + 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, 0x13, 0x54, 0x05, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, 0x13, 0x54, 0x05, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xd5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x01, 0x01, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcb, + 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, + 0x2c, 0x12, 0x2c, 0x22, 0x2c, 0x0a, 0x2c, + 0x2c, 0x09, 0x08, 0x07, 0x06, 0x2c, 0x2c, + 0x2c, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, + 0x2c, 0x18, 0x16, 0x17, 0x2c, 0x1c, 0x1d, + 0x1e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, + 0x2c, 0x12, 0x2c, 0x23, 0x2c, 0x0e, 0x2c, + 0x2c, 0x06, 0x07, 0x08, 0x09, 0x2c, 0x2c, + 0x2c, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcc, + 0x2c, 0x18, 0x16, 0x17, 0x2c, 0x1c, 0x1d, + 0x1e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, + 0x2c, 0x2c, 0x2c, 0x02, 0x2c, 0x0a, 0x2c, + 0x2c, 0x09, 0x08, 0x07, 0x06, 0x2c, 0x2c, + 0x2c, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, + 0x2c, 0x18, 0x16, 0x17, 0x2c, 0x1c, 0x1d, + 0x1e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, + 0x2c, 0x2c, 0x2c, 0x02, 0x2c, 0x0e, 0x2c, + 0x2c, 0x06, 0x07, 0x08, 0x09, 0x2c, 0x2c, + 0x2c, 0x2c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, + 0x2c, 0x18, 0x16, 0x17, 0x2c, 0x1c, 0x1d, + 0x1e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x86); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, + 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x96); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, + 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa6); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, + 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x76); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, + 0x00, 0x00, 0x00, 0x01, 0x11, 0x11, 0x11, + 0x05); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x82); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa7, 0x10, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x8d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa7, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x8f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa7, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x35, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa4); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x01, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xaa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xad); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xae); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb6); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x01, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc3); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0xff); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x8e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x25); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x97); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x25); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x21); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb6); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, + 0x10, 0x10, 0x0e, 0x0e, 0x10, 0x10, 0x0e, + 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xfa); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x23); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xca); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x82); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x93); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9b); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x49); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9d); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x49); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xbe); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0xf0, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xdc); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x37); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x8a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0xc7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x1f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb7); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x1f); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x99); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x50); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x9e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, + 0xc0, 0x4a, 0x39, 0xc0, 0x4a, 0x0e); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc2); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x42); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x77); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe8); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0x40); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54, 0x5d, 0x65, 0x6c, 0xd6, 0x73, + 0x7b, 0x83, 0x8c, 0xd4, 0x96, 0x9c, 0xa3, + 0xaa, 0x93, 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, + 0xe0, 0xef, 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x30); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54, 0x5d, 0x65, 0x6c, 0xd6, 0x73, + 0x7b, 0x83, 0x8c, 0xd4, 0x96, 0x9c, 0xa3, + 0xaa, 0x93, 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, + 0xe0, 0xef, 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x60); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54, 0x5d, 0x65, 0x6c, 0xd6, 0x73, + 0x7b, 0x83, 0x8c, 0xd4, 0x96, 0x9c, 0xa3, + 0xaa, 0x93, 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, + 0xe0, 0xef, 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54, 0x5d, 0x65, 0x6c, 0xd6, 0x73, + 0x7b, 0x83, 0x8c, 0xd4, 0x96, 0x9c, 0xa3, + 0xaa, 0x93, 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, + 0xe0, 0xef, 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xc0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54, 0x5d, 0x65, 0x6c, 0xd6, 0x73, + 0x7b, 0x83, 0x8c, 0xd4, 0x96, 0x9c, 0xa3, + 0xaa, 0x93, 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, + 0xe0, 0xef, 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xf0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, + 0x00, 0x02, 0x07, 0x0f, 0x36, 0x1a, 0x22, + 0x29, 0x34, 0xba, 0x3d, 0x44, 0x4a, 0x4f, + 0x1b, 0x54); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe2, + 0x5d, 0x65, 0x6c, 0xd6, 0x73, 0x7b, 0x83, + 0x8c, 0xd4, 0x96, 0x9c, 0xa3, 0xaa, 0x93, + 0xb3, 0xbe, 0xcd, 0xd5, 0xf3, 0xe0, 0xef, + 0xf9, 0xff, 0x84); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xe0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcf, 0x34); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x85); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa7, 0x41); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x80); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x22); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x83); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x63); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa1); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xa9); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0xaa, 0x0a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb0); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0x01, 0x01, 0x0c); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xb5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0x08); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1c, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xff, 0xff, 0xff); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 120); + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb7, 0x59, 0x02); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xff, 0xff); + + return dsi_ctx.accum_err; +} + +static int focaltech_ft8722_off(struct focaltech_ft8722 *ctx) +{ + struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_usleep_range(&dsi_ctx, 16000, 17000); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 50); + + return dsi_ctx.accum_err; +} + +static int focaltech_ft8722_prepare(struct drm_panel *panel) +{ + struct focaltech_ft8722 *ctx = to_focaltech_ft8722(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return ret; + + focaltech_ft8722_reset(ctx); + + ret = focaltech_ft8722_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + return ret; + } + + return 0; +} + +static int focaltech_ft8722_unprepare(struct drm_panel *panel) +{ + struct focaltech_ft8722 *ctx = to_focaltech_ft8722(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = focaltech_ft8722_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode focaltech_ft8722_mode = { + .clock = (1080 + 32 + 8 + 32) * (2408 + 30 + 4 + 30) * 120 / 1000, + .hdisplay = 1080, + .hsync_start = 1080 + 32, + .hsync_end = 1080 + 32 + 8, + .htotal = 1080 + 32 + 8 + 32, + .vdisplay = 2408, + .vsync_start = 2408 + 30, + .vsync_end = 2408 + 30 + 4, + .vtotal = 2408 + 30 + 4 + 30, + .width_mm = 68, + .height_mm = 153, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int focaltech_ft8722_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &focaltech_ft8722_mode); +} + +static const struct drm_panel_funcs focaltech_ft8722_panel_funcs = { + .prepare = focaltech_ft8722_prepare, + .unprepare = focaltech_ft8722_unprepare, + .get_modes = focaltech_ft8722_get_modes, +}; + +static int focaltech_ft8722_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct focaltech_ft8722 *ctx; + int ret; + int i; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) + ctx->supplies[i].supply = regulator_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 3; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; + + drm_panel_init(&ctx->panel, dev, &focaltech_ft8722_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&ctx->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&ctx->panel); + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void focaltech_ft8722_remove(struct mipi_dsi_device *dsi) +{ + struct focaltech_ft8722 *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id focaltech_ft8722_of_match[] = { + { .compatible = "txd,txdi660jbpv" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, focaltech_ft8722_of_match); + +static struct mipi_dsi_driver ft8722_driver = { + .probe = focaltech_ft8722_probe, + .remove = focaltech_ft8722_remove, + .driver = { + .name = "panel-focaltech-ft8722", + .of_match_table = focaltech_ft8722_of_match, + }, +}; +module_mipi_dsi_driver(ft8722_driver); + +MODULE_AUTHOR("Luka Pani "); +MODULE_DESCRIPTION("DRM driver for ft8722 panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index a1422ddd1c223a..a017e90114ade5 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -156,6 +156,12 @@ config BACKLIGHT_ATMEL_LCDC If in doubt, it's safe to enable this option; it doesn't kick in unless the board's description says it's wired that way. +config BACKLIGHT_AW99703 + tristate "Awinic AW99703 Backlight" + depends on I2C + help + If you have a Awinic AW99703 say Y to enable the backlight driver. + config BACKLIGHT_AW99706 tristate "Backlight Driver for Awinic AW99706" depends on I2C diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a5d62b01810274..f524b2628b89b0 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_APPLE_DWI) += apple_dwi_bl.o obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o +obj-$(CONFIG_BACKLIGHT_AW99703) += aw99703.o obj-$(CONFIG_BACKLIGHT_AW99706) += aw99706.o obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o diff --git a/drivers/video/backlight/aw99703.c b/drivers/video/backlight/aw99703.c new file mode 100644 index 00000000000000..112b240e97e435 --- /dev/null +++ b/drivers/video/backlight/aw99703.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * aw99703 - Backlight driver for the awinic AW99703 + * + * Copyright (C) 2026 Luka Panio + */ + +#include +#include +#include +#include +#include +#include + +#define AW99703_REG_ID 0x00 +#define AW99703_REG_MODE 0x02 +#define AW99703_REG_LEDCUR 0x03 +#define AW99703_REG_LEDLSB 0x06 +#define AW99703_REG_LEDMSB 0x07 +#define AW99703_REG_FLAGS1 0x0E + +#define AW99703_DEFAULT_BRIGHTNESS 255 + +static const struct regmap_config regmap_config_aw = { + .reg_bits = 8, + .val_bits = 8, +}; + +struct aw99703_data { + struct i2c_client *client; + struct regmap *regmap; + struct backlight_device *bl_dev; + struct gpio_desc *en_gpio; +}; + +static int aw99703_update_brightness(struct backlight_device *bl_dev) +{ + struct aw99703_data *data = bl_get_data(bl_dev); + unsigned int brightness = backlight_get_brightness(bl_dev); + int ret; + + ret = regmap_write(data->regmap, AW99703_REG_LEDLSB, brightness & 0x07); + if (ret) { + dev_err(&data->client->dev, "Failed to write LSB brightness: %d\n", ret); + return ret; + } + + ret = regmap_write(data->regmap, AW99703_REG_LEDMSB, brightness >> 3); + if (ret) { + dev_err(&data->client->dev, "Failed to write MSB brightness: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct backlight_ops aw99703_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = aw99703_update_brightness, +}; + +static int aw99703_probe(struct i2c_client *client) +{ + struct aw99703_data *data; + struct backlight_properties props; + int ret; + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + + if (!data) + return -ENOMEM; + + data->en_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH); + + data->client = client; + + data->regmap = devm_regmap_init_i2c(client, ®map_config_aw); + if (IS_ERR(data->regmap)) { + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), + "Failed to init regmap\n"); + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 255; + props.brightness = 255; + props.scale = BACKLIGHT_SCALE_LINEAR; + + data->bl_dev = devm_backlight_device_register(&client->dev, "aw99703_bl", &client->dev, data, &aw99703_bl_ops, &props); + if (IS_ERR(data->bl_dev)) { + return dev_err_probe(&client->dev, PTR_ERR(data->bl_dev), + "Failed to register backlight device\n"); + } + + data->bl_dev->props.brightness = AW99703_DEFAULT_BRIGHTNESS; + i2c_set_clientdata(client, data); + + ret = aw99703_update_brightness(data->bl_dev); + if (ret) { + return dev_err_probe(&client->dev, ret, + "Failed to set default brightness\n"); + } + + return 0; +} + +static const struct i2c_device_id aw99703_id[] = { + { "aw99703", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, aw99703_id); + +static const struct of_device_id aw99703_of_match[] = { + { .compatible = "awinic,aw99703" }, + {} +}; +MODULE_DEVICE_TABLE(of, aw99703_of_match); + +static struct i2c_driver aw99703_driver = { + .driver = { + .name = "aw99703", + .of_match_table = aw99703_of_match, + }, + .probe = aw99703_probe, + .id_table = aw99703_id, +}; +module_i2c_driver(aw99703_driver); + +MODULE_AUTHOR("Luka Panio "); +MODULE_DESCRIPTION("AW99703 Backlight Driver"); +MODULE_LICENSE("GPL");