From 29c6af6ff33467d4cf90463ca1b5e545fae51581 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Wed, 13 May 2026 18:03:44 +0530 Subject: [PATCH 1/8] dt-bindings: arm: qcom: Add SM6350 OnePlus Nord N10 5G Add a compatible for OnePlus Nord N10 5G (billie) Signed-off-by: Saalim Quadri --- Documentation/devicetree/bindings/arm/qcom.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index d84bd3bca20105..14da4651f32b78 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -955,6 +955,7 @@ properties: - items: - enum: + - oneplus,billie - sony,pdx213 - const: qcom,sm6350 From 5328fc6b2b875221c33e58db2a55d295dd7f8847 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Sun, 17 May 2026 01:42:56 +0530 Subject: [PATCH 2/8] arm64: dts: qcom: sm6350: Add device tree for OnePlus Nord N10 5G Add initial device tree support for OnePlus Nord N10. The device successfully boots to framebuffer console. The initial bring-up work was done by Henri Dellal. This version was rewritten and independently implemented with incremental testing during bring-up. Co-developed-by: Anri Dellal Signed-off-by: Saalim Quadri --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../dts/qcom/sm6350-oneplus-nord-billie.dts | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 6f34d5ed331c4c..4a1dc58c2fcb81 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -274,6 +274,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm6115p-lenovo-j606f.dtb dtb-$(CONFIG_ARCH_QCOM) += sm6125-sony-xperia-seine-pdx201.dtb dtb-$(CONFIG_ARCH_QCOM) += sm6125-xiaomi-ginkgo.dtb dtb-$(CONFIG_ARCH_QCOM) += sm6125-xiaomi-laurel-sprout.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm6350-oneplus-nord-billie.dtb dtb-$(CONFIG_ARCH_QCOM) += sm6350-sony-xperia-lena-pdx213.dtb dtb-$(CONFIG_ARCH_QCOM) += sm6375-sony-xperia-murray-pdx225.dtb dtb-$(CONFIG_ARCH_QCOM) += sm7125-xiaomi-curtana.dtb diff --git a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts new file mode 100644 index 00000000000000..362cf8e7133b78 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2026, Saalim Quadri + * Copyright (c) 2025, Henri Dellal + */ + +/dts-v1/; + +#include "sm6350.dtsi" + +/ { + model = "Oneplus Nord N10 5G"; + compatible = "oneplus,billie", "qcom,sm6350"; + chassis-type = "handset"; + + /* required for bootloader to select correct board */ + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <0x1000b 0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "framebuffer0"; + + framebuffer0: framebuffer@a0000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0xa0000000 0x0 (1080 * 2400 * 4)>; + width = <1080>; + height = <2400>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + }; + }; + + reserved-memory { + bootloader-log@9fff7000 { + reg = <0x0 0x9fff7000 0x0 0x8000>; + no-map; + }; + + ramoops@cbe00000 { + compatible = "ramoops"; + reg = <0x0 0xcbe00000 0x0 0x400000>; + record-size = <0x40000>; + console-size = <0x40000>; + ftrace-size = <0x40000>; + pmsg-size = <0x200000>; + ecc-size = <0x0>; + }; + + param@cc200000 { + reg = <0x0 0xcc200000 0x0 0x100000>; + no-map; + }; + + mtp@cc300000 { + reg = <0x0 0xcc300000 0x0 0xb00000>; + no-map; + }; + }; +}; + +&dispcc { + status = "disabled"; +}; + +&sdhc_2 { + status = "okay"; + + cd-gpios = <&tlmm 94 GPIO_ACTIVE_HIGH>; +}; + +&tlmm { + gpio-reserved-ranges = <13 4>, <56 2>; +}; + +&ufs_mem_hc { + status = "okay"; +}; + +&ufs_mem_phy { + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + maximum-speed = "super-speed"; + dr_mode = "otg"; +}; + +&usb_1_hsphy { + status = "okay"; +}; + +&usb_1_qmpphy { + status = "okay"; +}; \ No newline at end of file From 3af63fc99c4712b9a310ad5dd0864a9739536528 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Sun, 17 May 2026 00:28:18 +0530 Subject: [PATCH 3/8] arm64: dts: qcom: sm6350-billie: Include pm6350 and configure buttons Include pm6350 to inherit its GPIO and button configuration, and configure "resin" to serve as volume up, and gpio2 as volume down. Signed-off-by: Saalim Quadri --- .../dts/qcom/sm6350-oneplus-nord-billie.dts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts index 362cf8e7133b78..8dc94f0b357374 100644 --- a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts +++ b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts @@ -6,7 +6,9 @@ /dts-v1/; +#include #include "sm6350.dtsi" +#include "pm6350.dtsi" / { model = "Oneplus Nord N10 5G"; @@ -34,6 +36,20 @@ }; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_down_default>; + + key-volume-down { + label = "Volume Down"; + linux,code = ; + gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + wakeup-source; + }; + }; + reserved-memory { bootloader-log@9fff7000 { reg = <0x0 0x9fff7000 0x0 0x8000>; @@ -66,6 +82,21 @@ status = "disabled"; }; +&pm6350_gpios { + key_vol_down_default: vol-down-default-state { + pins = "gpio2"; + function = PMIC_GPIO_FUNC_NORMAL; + input-enable; + bias-pull-up; + power-source = <0>; + }; +}; + +&pm6350_resin { + linux,code = ; + status = "okay"; +}; + &sdhc_2 { status = "okay"; From 6a929705e18e42e36061385a94e9036b11494a5f Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Sun, 17 May 2026 00:34:24 +0530 Subject: [PATCH 4/8] arm64: dts: qcom: sm6350-billie: Define pm6350 and pm6150l regulators This regulator configuration was adopted from downstream, and is identical to the sm7225 FairPhone 4 and Sony Xperia 10 III. Signed-off-by: Saalim Quadri --- .../dts/qcom/sm6350-oneplus-nord-billie.dts | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts index 8dc94f0b357374..d11e4217aee2eb 100644 --- a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts +++ b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include #include "sm6350.dtsi" #include "pm6350.dtsi" @@ -78,6 +79,259 @@ }; }; +&apps_rsc { + regulators-0 { + compatible = "qcom,pm6350-rpmh-regulators"; + qcom,pmic-id = "a"; + + vreg_s1a: smps1 { + regulator-name = "vreg_s1a"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + }; + + vreg_s2a: smps2 { + regulator-name = "vreg_s2a"; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <2048000>; + }; + + vreg_l2a: ldo2 { + regulator-name = "vreg_l2a"; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3a: ldo3 { + regulator-name = "vreg_l3a"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l4a: ldo4 { + regulator-name = "vreg_l4a"; + regulator-min-microvolt = <352000>; + regulator-max-microvolt = <801000>; + regulator-initial-mode = ; + }; + + vreg_l5a: ldo5 { + regulator-name = "vreg_l5a"; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l6a: ldo6 { + regulator-name = "vreg_l6a"; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7a: ldo7 { + regulator-name = "vreg_l7a"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l8a: ldo8 { + regulator-name = "vreg_l8a"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l9a: ldo9 { + regulator-name = "vreg_l9a"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3401000>; + regulator-initial-mode = ; + }; + + vreg_l11a: ldo11 { + regulator-name = "vreg_l11a"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12a: ldo12 { + regulator-name = "vreg_l12a"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l13a: ldo13 { + regulator-name = "vreg_l13a"; + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <650000>; + regulator-initial-mode = ; + }; + + vreg_l14a: ldo14 { + regulator-name = "vreg_l14a"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l15a: ldo15 { + regulator-name = "vreg_l15a"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1305000>; + regulator-initial-mode = ; + }; + + vreg_l16a: ldo16 { + regulator-name = "vreg_l16a"; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <921000>; + regulator-initial-mode = ; + }; + + vreg_l18a: ldo18 { + regulator-name = "vreg_l18a"; + regulator-min-microvolt = <788000>; + regulator-max-microvolt = <1049000>; + regulator-initial-mode = ; + }; + + vreg_l19a: ldo19 { + regulator-name = "vreg_l19a"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1305000>; + regulator-initial-mode = ; + }; + + vreg_l20a: ldo20 { + regulator-name = "vreg_l20a"; + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <801000>; + regulator-initial-mode = ; + }; + + vreg_l21a: ldo21 { + regulator-name = "vreg_l21a"; + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <825000>; + regulator-initial-mode = ; + }; + + vreg_l22a: ldo22 { + regulator-name = "vreg_l22a"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1305000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm6150l-rpmh-regulators"; + qcom,pmic-id = "e"; + + vreg_s8e: smps8 { + regulator-name = "vreg_s8e"; + regulator-min-microvolt = <313000>; + regulator-max-microvolt = <1395000>; + }; + + vreg_l1e: ldo1 { + regulator-name = "vreg_l1e"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2e: ldo2 { + regulator-name = "vreg_l2e"; + regulator-min-microvolt = <1170000>; + regulator-max-microvolt = <1305000>; + regulator-initial-mode = ; + }; + + vreg_l3e: ldo3 { + regulator-name = "vreg_l3e"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1299000>; + regulator-initial-mode = ; + }; + + vreg_l4e: ldo4 { + regulator-name = "vreg_l4e"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5e: ldo5 { + regulator-name = "vreg_l5e"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + vreg_l6e: ldo6 { + regulator-name = "vreg_l6e"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7e: ldo7 { + regulator-name = "vreg_l7e"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8e: ldo8 { + regulator-name = "vreg_l8e"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9e: ldo9 { + regulator-name = "vreg_l9e"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l10e: ldo10 { + regulator-name = "vreg_l10e"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3401000>; + regulator-initial-mode = ; + }; + + vreg_l11e: ldo11 { + regulator-name = "vreg_l11e"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3401000>; + regulator-initial-mode = ; + }; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <5492000>; + regulator-initial-mode = ; + regulator-allow-bypass; + }; + }; +}; + &dispcc { status = "disabled"; }; From 645437d285439c1da25556c86c3ee070f3344176 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 30 Oct 2022 08:32:30 +0100 Subject: [PATCH 5/8] arm64: dts: qcom: sm6350-billie: Enable QUP and GPI DMA Enable QUP and GPI DMA hardware to be able to add functioning I2C nodes later. Signed-off-by: Marijn Suijten Signed-off-by: Saalim Quadri --- .../boot/dts/qcom/sm6350-oneplus-nord-billie.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts index d11e4217aee2eb..ab07c619cf1d59 100644 --- a/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts +++ b/arch/arm64/boot/dts/qcom/sm6350-oneplus-nord-billie.dts @@ -336,6 +336,14 @@ status = "disabled"; }; +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + &pm6350_gpios { key_vol_down_default: vol-down-default-state { pins = "gpio2"; @@ -351,6 +359,14 @@ status = "okay"; }; +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + &sdhc_2 { status = "okay"; From edd7484be77a1432e66ddd591cf93d5222ddc22a Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Sun, 17 May 2026 01:59:50 +0530 Subject: [PATCH 6/8] dt-bindings: display: panel: Add Himax HX83112F Add device tree bindings for Himax HX83112F-based DSI display panels, such as the Tianma FHD panel used in the OnePlus Nord N10 5G. Signed-off-by: Saalim Quadri --- .../display/panel/himax,hx83112f.yaml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/himax,hx83112f.yaml diff --git a/Documentation/devicetree/bindings/display/panel/himax,hx83112f.yaml b/Documentation/devicetree/bindings/display/panel/himax,hx83112f.yaml new file mode 100644 index 00000000000000..5071ce60fd5a92 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/himax,hx83112f.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/himax,hx83112f.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Himax HX83112F-based DSI display panels + +maintainers: + - Saalim Quadri + +description: + The Himax HX83112F is a generic DSI Panel IC used to control + LCD panels. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + contains: + const: tianma,hx83112f-fhd + + reg: + maxItems: 1 + + vddio-supply: + description: I/O voltage rail + + vsn-supply: + description: Positive source voltage rail + + vsp-supply: + description: Negative source voltage rail + +required: + - compatible + - reg + - reset-gpios + - vddio-supply + - vsn-supply + - vsp-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "tianma,hx83112f-fhd"; + reg = <0>; + + reset-gpios = <&tlmm 75 GPIO_ACTIVE_LOW>; + + vddio-supply = <&vreg_l8c>; + vsn-supply = <&pm6150l_lcdb_ncp>; + vsp-supply = <&pm6150l_lcdb_ldo>; + + port { + panel_in_0: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + +... From 43c29569a42e45a2f4e75f1b56d7ca4722f622cd Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Sun, 17 May 2026 02:13:55 +0530 Subject: [PATCH 7/8] drm/panel: Add panel driver for OnePlus Nord N10 Signed-off-by: Saalim Quadri --- MAINTAINERS | 6 + drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-himax-hx83112f.c | 276 +++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-himax-hx83112f.c diff --git a/MAINTAINERS b/MAINTAINERS index e0876732376362..a39d15e5523368 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7872,6 +7872,12 @@ S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/tiny/gm12u320.c +DRM DRIVER FOR TIANMA HIMAX83112F LCD panels +M: Saalim Quadri +S: Maintained +F: Documentation/devicetree/bindings/display/panel/himax,hx83112f.yaml +F: drivers/gpu/drm/panel/panel-himax-hx83112f.c + DRM DRIVER FOR HIMAX HX8394 MIPI-DSI LCD panels M: Ondrej Jirman M: Javier Martinez Canillas diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 9d40012517af65..89047c606794d5 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -203,6 +203,16 @@ config DRM_PANEL_HIMAX_HX83112B Say Y here if you want to enable support for Himax HX83112B-based display panels, such as the one found in the Fairphone 3 smartphone. +config DRM_PANEL_HIMAX_HX83112F + tristate "Himax HX83112F-based DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + select DRM_KMS_HELPER + help + Say Y here if you want to enable support for Himax HX83112F-based + display panels, such as the one found in the OnePlus Nord N10 smartphone. + config DRM_PANEL_HIMAX_HX8394 tristate "HIMAX HX8394 MIPI-DSI LCD panels" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 9787de6ef7e9c5..3eabdc9323f1d0 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX8279) += panel-himax-hx8279.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o +obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112F) += panel-himax-hx83112f.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112f.c b/drivers/gpu/drm/panel/panel-himax-hx83112f.c new file mode 100644 index 00000000000000..258eb90d5c45de --- /dev/null +++ b/drivers/gpu/drm/panel/panel-himax-hx83112f.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2026 Saalim Quadri + */ + +#include +#include +#include +#include +#include + +#include