diff --git a/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt index 4520b26cdebc..900ee94a1f08 100644 --- a/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt +++ b/Documentation/devicetree/bindings/hwlock/rockchip-hwspinlock.txt @@ -13,7 +13,9 @@ Required properties : - rockchip,hwlock-num-locks :number of hwlocks provided by this device. Optional properties : -- rockchip,hwlock-user-id : Set hwlock user id (4 bit, default is 0x01). +- rockchip,hwlock-user-id : Set hwlock user id (default is 0x01). +- rockchip,hwlock-max-user : Set the maximum hwlock user count supported + by the IP (default is 0x0F). Please look at the generic hwlock binding for usage information for consumers, "Documentation/devicetree/bindings/hwlock/hwlock.txt" diff --git a/arch/arm/boot/dts/rk3506.dtsi b/arch/arm/boot/dts/rk3506.dtsi index 77d574ac9246..a6bf49d75413 100644 --- a/arch/arm/boot/dts/rk3506.dtsi +++ b/arch/arm/boot/dts/rk3506.dtsi @@ -40,7 +40,7 @@ }; can0: can@ff320000 { - compatible = "rockchip,rk3506-canfd", "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3506-can", "rockchip,rk3576-can"; reg = <0xff320000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -53,7 +53,7 @@ }; can1: can@ff330000 { - compatible = "rockchip,rk3506-canfd", "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3506-can", "rockchip,rk3576-can"; reg = <0xff330000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 01bd27dececb..d1c81766d08a 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -304,6 +304,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-vehicle-evb-v21.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-vehicle-evb-v21-mcu.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-evb1-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-evb1-v10-linux.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-rk809-tablet-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576s-tablet-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi index e41db79c3879..d1a94c3c134d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-eink.dtsi @@ -67,12 +67,12 @@ interrupt-parent = <&gpio0>; interrupts = <6 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default", "pmic-power-off"; - pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, <&rk806_dvs2_null>, <&rk806_dvs3_null>; - pinctrl-1 = <&rk806_dvs2_pwrdn>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>; //for rk3576 have ultra sleep circuit design pwrctrl3_output = <0>; + shutown_by_pwrctrln = <2>; /* 2800mv-3500mv */ low_voltage_threshold = <3000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi index 5c08a3329b03..b66f9186ebf8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi @@ -282,62 +282,34 @@ 0322 0024 //Init Default 0326 00E4 - //HSYNC_WIDTH_L - 0385 0038 - //VSYNC_WIDTH_L - 0386 0008 + //HSYNC_WIDTH_L HSYNC=32 + 0385 0020 + //VSYNC_WIDTH_L VSYNC=2 + 0386 0002 //HSYNC_WIDTH_H/VSYNC_WIDTH_H 0387 0000 - //VFP_L + //VFP_L VFP=200 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L - 03A6 0020 - //VRES_L + //VBP_L/VFP_H VBP=8 + 03A6 0080 + //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H 03A9 0002 - //HFP_L + //HFP_L HFP=56 03AA 0038 //HBP_H - 03AC 0002 - //HFP_H/HBP_L - 03AB 0000 - //HRES_L + 03AC 0003 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 + //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 - //HSYNC_WIDTH_L - 0395 0038 - //VSYNC_WIDTH_L - 0396 0008 - //HSYNC_WIDTH_H/VSYNC_WIDTH_H - 0397 0000 - //VFP_L - 03B1 00C8 - //VBP_H - 03B3 0000 - //VFP_H/VBP_L - 03B2 0020 - //VRES_L - 03B4 00D0 - //VRES_H - 03B5 0002 - //HFP_L - 03B6 0038 - //HBP_H - 03B8 0002 - //HFP_H/HBP_L - 03B7 0000 - //HRES_L - 03B9 0080 - //HRES_H - 03BA 0007 - //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03A4 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts index fb838682d3ca..d7b9562bf4b4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20.dts @@ -561,6 +561,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts index 44162ee09a4e..27427e35d9cb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21-mcu.dts @@ -574,6 +574,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts index 9e119c0a1b16..d4b1131656a8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v21.dts @@ -569,6 +569,10 @@ status = "okay"; }; +&usbdp_phy_u3 { + status = "disabled"; +}; + &usb_drd1_dwc3 { snps,dis_u2_susphy_quirk; snps,usb2-lpm-disable; diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index ec54470fd966..60205e003d93 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -5547,7 +5547,7 @@ }; can0: can@2ac00000 { - compatible = "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3576-can"; reg = <0x0 0x2ac00000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -5558,7 +5558,7 @@ }; can1: can@2ac10000 { - compatible = "rockchip,rk3576-canfd"; + compatible = "rockchip,rk3576-can"; reg = <0x0 0x2ac10000 0x0 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi new file mode 100644 index 000000000000..248620c8d8b3 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ +/ { + flash_rgb13h: flash-rgb13h { + status = "okay"; + compatible = "led,rgb13h"; + label = "gpio-flash"; + pinctrl-names = "default"; + pinctrl-0 = <&flash_led_gpios>; + led-max-microamp = <20000>; + flash-max-microamp = <20000>; + flash-max-timeout-us = <1000000>; + enable-gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; + //mode-gpio = <&gpio2 RK_PC3 GPIO_ACTIVE_HIGH>; //EN + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + }; + + vcc_mipipwr: vcc-mipipwr-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&mipicam_pwr>; + regulator-name = "vcc_mipipwr"; + enable-active-high; + regulator-boot-on; + }; +}; + +&csi2_dcphy0 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_gc05a2: endpoint@1 { + reg = <1>; + remote-endpoint = <&gc05a2_out0>; + data-lanes = <1 2 3 4>; + }; + + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidcphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi0_csi2_input>; + }; + }; + }; +}; + +&csi2_dphy0 { + status = "okay"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_gc02m1: endpoint@1 { + reg = <1>; + remote-endpoint = <&gc02m1_out>; + data-lanes = <1>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi1_csi2_input>; + }; + }; + }; +}; + +&csi2_dphy3 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_ov13850: endpoint@1 { + reg = <1>; + remote-endpoint = <&ov13850_out>; + data-lanes = <1 2 3 4>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy3_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi3_csi2_input>; + }; + }; + }; +}; + +&i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c4m3_xfer>; + + gc02m1: gc02m1@37 { + status = "okay"; + compatible = "galaxycore,gc02m1"; + reg = <0x37>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M1>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk1m0_clk1>; + pwdn-gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + //dvdd-supply = <&vcc1v2_dvp>; + dvdd-supply = <&vcc_1v2_cam>; + rockchip,camera-module-index = <2>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "KYT-8789-V10"; + rockchip,camera-module-lens-name = "default"; + port { + gc02m1_out: endpoint { + remote-endpoint = <&mipi_in_gc02m1>; + data-lanes = <1>; + }; + }; + }; +}; + +&i2c5 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m3_xfer>; + + dw9714: dw9714@c { + compatible = "dongwoon,dw9714"; + status = "okay"; + reg = <0x0c>; + rockchip,camera-module-index = <0>; + rockchip,vcm-start-current = <5>; + rockchip,vcm-rated-current = <65>; + rockchip,vcm-step-mode = <5>; + rockchip,camera-module-facing = "back"; + avdd-supply = <&vcc_mipipwr>; + xsd-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + }; + + gc05a2: gc05a2@37 { + compatible = "galaxycore,gc05a2"; + status = "okay"; + reg = <0x37>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M0>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk0m0_clk0>; + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + dvdd-supply = <&vcc_1v2_cam>; + rockchip,camera-module-index = <1>; + rockchip,camera-module-facing = "front"; + rockchip,camera-module-name = "KYT-11210-V2"; + rockchip,camera-module-lens-name = "default"; + port { + gc05a2_out0: endpoint { + remote-endpoint = <&mipi_in_gc05a2>; + data-lanes = <1 2>; + }; + }; + }; + + ov13850: ov13850@10 { + status = "okay"; + compatible = "ovti,ov13850"; + reg = <0x10>; + clocks = <&cru CLK_MIPI_CAMERAOUT_M2>; + clock-names = "xvclk"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_clk2m0_clk2>; + pwdn-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; + dvdd-supply = <&vcc_1v2_cam>; + avdd-supply = <&vcc_mipipwr>; + //dovdd-supply = <&vcc_1v8_cam>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "G1-T-B-s5k"; + rockchip,camera-module-lens-name = "XA-0806B"; + flash-leds = <&flash_rgb13h>; + lens-focus = <&dw9714>; + port { + ov13850_out: endpoint { + remote-endpoint = <&mipi_in_ov13850>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&mipi0_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidcphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi0_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi_in0>; + }; + }; + }; +}; + +&mipi3_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi3_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy3_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi3_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi3_in0>; + }; + }; + }; +}; + + +&mipi1_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi1_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi1_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi1_in0>; + }; + }; + }; +}; + +&pinctrl { + cam { + mipicam_pwr: mipicam-pwr { + rockchip,pins = + /* camera power en */ + <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + flash_led_gpios: flash-led { + rockchip,pins = + /* flash led enable */ + <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&rkcif { + status = "okay"; +}; + +&rkcif_mipi_lvds { + status = "okay"; + + port { + cif_mipi_in0: endpoint { + remote-endpoint = <&mipi0_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds_sditf { + status = "okay"; + + port { + mipi_lvds_sditf: endpoint { + remote-endpoint = <&isp_vir0_in0>; + }; + }; +}; + +&rkcif_mipi_lvds1 { + status = "okay"; + + port { + cif_mipi1_in0: endpoint { + remote-endpoint = <&mipi1_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds1_sditf { + status = "okay"; + + port { + mipi_lvds1_sditf: endpoint { + remote-endpoint = <&isp_vir0_in2>; + }; + }; +}; + +&rkcif_mipi_lvds3 { + status = "okay"; + + port { + cif_mipi3_in0: endpoint { + remote-endpoint = <&mipi3_csi2_output>; + }; + }; +}; + +&rkcif_mipi_lvds3_sditf { + status = "okay"; + + port { + mipi_lvds3_sditf: endpoint { + remote-endpoint = <&isp_vir0_in1>; + }; + }; +}; + +&rkcif_mmu { + status = "okay"; +}; + +&rkisp { + status = "okay"; +}; + +&rkisp_mmu { + status = "okay"; +}; + +&rkisp_vir0 { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + isp_vir0_in0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi_lvds_sditf>; + }; + + isp_vir0_in1: endpoint@1 { + reg = <1>; + remote-endpoint = <&mipi_lvds3_sditf>; + }; + + isp_vir0_in2: endpoint@2 { + reg = <2>; + remote-endpoint = <&mipi_lvds1_sditf>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts new file mode 100644 index 000000000000..ff5ed3797470 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts @@ -0,0 +1,1521 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk3576s.dtsi" +#include "rk3576-android.dtsi" +#include "rk3576s-rk809-tablet-camera.dtsi" + +/ { + model = "Rockchip RK3576S RK809 TABLET V10 Board"; + compatible = "rockchip,rk3576s-rk809-tablet-v10", "rockchip,rk3576s"; + + adc_keys: adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + vol-up-key { + label = "volume up"; + linux,code = ; + press-threshold-microvolt = <1750>; + }; + + vol-down-key { + label = "volume down"; + linux,code = ; + press-threshold-microvolt = <1350000>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0_2ch_1 0 25000 0>; + brightness-levels = < + 0 20 20 21 21 22 22 23 + 23 24 24 25 25 26 26 27 + 27 28 28 29 29 30 30 31 + 31 32 32 33 33 34 34 35 + 35 36 36 37 37 38 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255 + >; + default-brightness-level = <150>; + max-brightness-level = <145>; + }; + + bt-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_b"; + simple-audio-card,bitclock-inversion = <1>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,cpu { + sound-dai = <&sai2>; + }; + simple-audio-card,codec { + sound-dai = <&bt_sco>; + }; + }; + + bt_sco: bt-sco { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <0>; + status = "okay"; + }; + + charge-animation { + compatible = "rockchip,uboot-charge"; + rockchip,uboot-charge-on = <0>; + rockchip,android-charge-on = <1>; + rockchip,uboot-low-power-voltage = <3450>; + rockchip,screen-on-voltage = <3500>; + rockchip,auto-wakeup-interval = <5>; + rockchip,uboot-exit-charge-level = <2>; + rockchip,uboot-exit-charge-voltage = <3500>; + rockchip,uboot-exit-charge-auto = <1>; + status = "okay"; + }; + + charger-manager { + compatible = "rockchip-charger-manager"; + cm-name = "battery"; + cm-poll-mode = <2>; + cm-poll-interval = <1000>; + + cm-chargers = "sc89601-charger";//cx2560x-charger,sc89601-charger + cm-chargers-phandle = <&usbc0>; + cm-fuel-gauge = "battery"; + /* monitored-battery = <&bat>; */ + extcon = <&u2phy0>; + vbus-supply = <&vbus5v0_typec>; + //cm-jeita-temp-charge-table = <0 15 2400000 4350000>, + // <15 45 2400000 4350000>, + // <45 60 2400000 4200000>; + }; + + dp0_sound: dp0-sound { + compatible = "rockchip,hdmi"; + rockchip,mclk-fs = <512>; + rockchip,card-name = "rockchip-dp0"; + rockchip,cpu = <&spdif_tx3>; + rockchip,codec = <&dp0 1>; + rockchip,jack-det; + }; + + rk809-sound { + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "rockchip-rk809"; + hp-det-gpio = <&gpio4 RK_PA4 GPIO_ACTIVE_LOW>; + io-channels = <&saradc 3>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&sai1>; + rockchip,codec = <&rk809_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_det>; + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; + }; + + vcc_sys: vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + }; + + vcc_2v0_pldo_s3: vcc-2v0-pldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v0_pldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + vin-supply = <&vcc_sys>; + }; + + vcc_1v1_nldo_s3: vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sys>; + }; + + vcc_1v8_s0: vcc-1v8-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + + vcc_ufs_s0: vcc-ufs-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_ufs_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + }; + + vcc1v8_ufs_vccq2_s0: vcc1v8-ufs-vccq2-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v8_ufs_vccq2_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + vcc1v2_ufs_vccq_s0: vcc1v2-ufs-vccq-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc1v2_ufs_vccq_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + vin-supply = <&vcc_sys>; + }; + + vdd_cpu_big_s0: vdd-cpu-big-s0 { + compatible = "pwm-regulator"; + pwms = <&pwm1_6ch_0 0 5000 1>; + regulator-name = "vdd_cpu_big_s0"; + regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_npu_s0: vdd-npu-s0 { + compatible = "pwm-regulator"; + pwms = <&pwm1_6ch_2 0 5000 1>; + regulator-name = "vdd_npu_s0"; + //regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + seekwcn_boot:seekwcn_boot { + compatible = "seekwave,sv6160"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>,<&wifi_chip_wake_irq>; + sv6160_path = "/vendor/bin/sv6160.bin"; + sv6160_dram_path = "/vendor/etc/firmware/RAM_RW_KERNEL_DRAM"; + sv6160_iram_path = "/vendor/etc/firmware/ROM_EXEC_KERNEL_IRAM"; + dma_type = <1>;/*1:ADMA,2:SDMA*/ + gpio_host_wake = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>; /* [> CP2AP<] */ + gpio_chip_wake = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; /* AP2CP */ + gpio_chip_en = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; /* CP POWERON */ + status = "okay"; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_power_en>; + + /* + * On the module itself this is one of these (depending + * on the actual card populated): + * - SDIO_RESET_L_WL_REG_ON + * - PDN (power down when low) + */ + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>; + }; + + wireless_bluetooth: wireless-bluetooth { + compatible = "bluetooth-platdata"; + uart_rts_gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "rts_gpio"; + pinctrl-0 = <&uart4m1_rtsn>; + pinctrl-1 = <&uart4_gpios>; + BT,reset_gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; + BT,wake_gpio = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; + BT,wake_host_irq = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + wireless_wlan: wireless-wlan { + compatible = "wlan-platdata"; + wifi_chip_type = "ap6275p"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>; + WIFI,host_wake_irq = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; + WIFI,poweren_gpio = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big_s0>; +}; + +&csu { + status = "okay"; +}; + +&dp { + status = "okay"; +}; + +&dp0 { + status = "okay"; +}; + +&dp0_in_vp0 { + status = "okay"; +}; + +&dsi_in_vp0 { + status = "okay"; +}; + +&dsi { + status = "okay"; + auto-calculation-mode; + //rockchip,lane-rate = <1080>; + + dsi_panel: panel@0 { + compatible = "aoly,sl008pa21y1285-b00", "simple-panel-dsi"; + reg = <0>; + backlight = <&backlight>; + + enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>; + tpreset-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&lcd_enable_gpio>, <&lcd_rst_gpio>; + + prepare-delay-ms = <20>; + reset-delay-ms = <20>; + init-delay-ms = <60>; + enable-delay-ms = <120>; + disable-delay-ms = <20>; + unprepare-delay-ms = <20>; + need-up-reset = <1>; + + width-mm = <137>; + height-mm = <217>; + + dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS)>; + dsi,format = ; + dsi,lanes = <4>; + + panel-init-sequence = [ + 15 00 02 41 5A + 39 00 03 41 5A 03 + 15 00 02 80 70 + 39 00 03 41 5A 2F + 15 00 02 28 00 + 15 78 02 10 00 + 39 00 03 41 5A 08 + 39 00 05 80 82 00 82 00 + 39 00 03 41 5A 09 + 39 00 11 80 1A 01 AB 93 A5 97 59 2A B1 06 00 00 80 BF 85 10 + 39 00 11 90 42 44 84 14 C6 13 99 09 C0 0B 6B 36 07 60 28 00 + 39 00 11 A0 80 90 20 AA 00 04 55 55 05 00 1F 0D 42 00 FE FF + 39 00 11 B0 03 7C F3 00 37 01 37 01 00 00 00 41 25 00 4A 00 + 39 00 11 C0 00 00 00 00 00 00 00 00 10 04 02 00 07 00 08 18 + 39 00 03 D0 00 00 + 39 00 03 41 5A 0A + 39 00 11 80 AF AF D4 30 40 2B 3A 42 4B 59 65 66 73 74 86 80 + 39 00 11 90 6F 71 67 60 56 46 3A 31 20 0E 0A 30 40 2B 3A 42 + 39 00 11 A0 4B 59 65 66 73 74 86 80 6F 71 67 60 56 46 3A 31 + 39 00 04 B0 20 0E 0A + 39 00 03 41 5A 0B + 39 00 11 80 00 00 50 B5 C5 AC 00 00 A0 6A 8B A9 AE 22 02 00 + 39 00 11 90 EF D8 B8 F7 25 70 E0 08 11 02 40 13 4F 4D 3C 35 + 39 00 09 A0 F1 A4 06 FF FF 00 03 00 + 39 00 03 41 5A 0C + 39 00 11 80 FE 68 58 02 BC 37 31 08 00 00 56 01 00 55 61 15 + 39 00 11 90 55 51 15 56 01 00 56 01 00 55 61 15 55 51 15 56 + 39 00 11 A0 B1 84 01 00 00 00 00 00 00 40 94 02 00 00 00 30 + 39 00 11 B0 28 15 80 04 00 18 00 00 00 30 0A 00 00 00 00 00 + 39 00 08 C0 00 01 05 C2 B0 00 00 + 39 00 03 41 5A 0D + 39 00 11 80 08 00 00 28 02 00 04 12 00 08 02 77 02 4A 10 F0 + 39 00 07 90 00 02 58 16 04 A1 + 39 00 03 41 5A 0E + 39 00 11 80 FF 81 68 6C 22 FD 22 00 55 55 55 55 05 5A 5A 80 + 39 00 07 90 01 00 00 60 01 00 + 39 00 03 41 5A 0F + 39 00 11 80 01 39 C1 23 63 04 80 04 06 02 28 84 0B 00 70 03 + 39 00 11 90 19 04 20 00 06 10 00 A0 05 5A 10 00 00 90 94 92 + 39 00 11 A0 1D DC 41 B3 65 C0 4A 0B 5A 71 22 80 19 4A 00 20 + 39 00 11 B0 27 9E 01 C0 19 7A 21 14 00 40 30 E0 00 2D D0 82 + 39 00 11 C0 00 00 60 18 63 D0 A0 0D 9A 21 02 10 62 84 28 03 + 39 00 11 D0 8A 88 88 48 92 09 0F 15 1E E0 31 06 04 02 14 04 + 39 00 11 E0 10 22 22 BD 84 C8 41 24 10 51 2D 3E 64 40 41 00 + 39 00 10 F0 00 27 1A 04 F5 FF FF 3F 00 00 15 40 14 00 00 + 39 00 03 41 5A 10 + 39 00 11 80 00 00 03 E7 8F 0B 00 3C 80 01 6A 0C 18 C4 20 C5 + 39 00 11 90 1C 94 D4 62 CD 3D F8 03 3F F0 03 3F 00 FF FF FF + 39 00 03 A0 81 00 + 39 00 03 41 5A 11 + 39 00 08 80 00 00 00 00 00 00 00 + 39 00 03 41 5A 12 + 39 00 11 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 90 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 2D 23 05 FB 00 2D 23 05 FB 00 + 39 00 03 41 5A 13 + 39 00 11 80 00 08 80 15 00 90 10 18 3E 10 00 D6 03 04 18 00 + 39 00 11 90 70 88 30 90 32 70 3E 97 8B 39 30 C4 09 C4 09 C4 + 39 00 11 A0 89 4F DC 45 80 0A C4 09 C4 09 80 02 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 1B 01 31 75 B9 42 86 CA 31 75 + 39 00 11 C0 B9 42 86 CA 00 00 00 00 0C 60 00 24 18 00 09 06 + 39 00 11 D0 40 82 01 90 60 00 24 D0 01 09 74 40 02 1D 90 40 + 39 00 11 E0 07 24 D0 01 09 1E 46 1E 46 00 00 20 C5 0F 00 C0 + 39 00 0d F0 10 40 26 4E 46 02 C8 20 80 0C 00 00 + 39 00 03 41 5A 14 + 39 00 11 80 01 02 40 2C 99 DF EF F7 9B CF 01 00 00 C0 83 38 + 39 00 11 90 31 9F 1F 10 23 E6 F3 03 B6 C2 7C 4E C0 66 98 CF + 39 00 11 A0 09 D0 0C BF 1F 01 9A E1 F7 23 00 80 07 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 80 84 07 84 + 39 00 11 C0 07 05 00 30 18 0C CF 84 F9 7C 0C C5 00 F4 3C 98 + 39 00 11 D0 CF C7 50 0C 40 CF 82 F9 7C 0C C5 00 F4 1C 98 CF + 39 00 11 E0 C7 50 0C 40 CF 80 F9 7C 0C C5 00 F4 04 98 CF C7 + 39 00 11 F0 50 0C 40 4F 81 F9 7C 0C C5 00 F4 24 98 CF C7 50 + 39 00 03 41 5A 15 + 39 00 11 80 0C 40 40 80 DF 0F 00 00 00 00 00 00 00 00 00 00 + 39 00 11 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 A0 00 00 1C 00 00 00 08 42 60 0E 00 00 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 C0 00 40 00 00 00 00 00 00 00 A0 1F 40 E8 00 20 2C + 39 00 11 D0 8A 34 4D AE 6B 01 81 30 10 85 71 24 A8 6D 5B B3 + 39 00 11 E0 6D 21 C9 24 4D AE 6B 1D 46 41 0C 42 00 28 AB 6D + 39 00 11 F0 5B B3 6D 2D 8A 34 4D AE 6B 01 81 30 10 85 71 24 + 39 00 03 41 5A 16 + 39 00 11 80 A8 6D 5B B3 6D 21 C9 24 4D AE 6B 1D 46 41 0C 42 + 39 00 11 90 00 28 AB 6D 5B B3 6D 01 03 03 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 00 00 00 00 00 00 C0 1F E1 01 + 39 00 11 B0 28 02 00 00 00 00 00 00 00 00 04 00 00 00 00 00 + 39 00 11 C0 00 00 00 00 00 00 02 06 00 00 00 00 00 00 02 00 + 39 00 11 D0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 + 39 00 11 E0 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 + 39 00 11 F0 00 04 00 00 00 00 00 00 00 00 00 20 00 00 00 00 + 39 00 03 41 5A 17 + 39 00 11 80 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 20 + 39 00 11 90 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 + 39 00 11 A0 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 + 39 00 11 B0 40 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 + 39 00 11 C0 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 + 39 00 07 D0 00 01 00 00 00 00 + 39 00 03 41 5A 18 + 39 00 11 80 7F 7F FE FE FE FE FE FE FE FE FE FE D4 7F D4 D4 + 39 00 11 90 D4 D4 D4 D4 D4 D4 D4 D4 AA AA AA AA AA AA AA AA + 39 00 11 A0 AA AA AA AA 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F + 39 00 11 B0 7C 83 79 86 79 86 79 86 79 86 79 86 7A 83 7A 85 + 39 00 11 C0 7A 85 7A 85 7A 85 7A 85 7B 84 7B 84 7B 84 7B 84 + 39 00 11 D0 7B 84 7B 84 7C 83 7C 83 7C 83 7C 83 7C 83 7C 83 + 39 00 11 E0 FE 7F 7F FE FE FE FE FE FE FE FE FE FE D4 7F D4 + 39 00 11 F0 D4 D4 D4 D4 D4 D4 D4 D4 D4 AA AA AA AA AA AA AA + 39 00 03 41 5A 19 + 39 00 11 80 AA AA AA AA AA 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F + 39 00 11 90 7F 7C 83 79 86 79 86 79 86 79 86 79 86 7A 83 7A + 39 00 11 A0 85 7A 85 7A 85 7A 85 7A 85 7B 84 7B 84 7B 84 7B + 39 00 11 B0 84 7B 84 7B 84 7C 83 7C 83 7C 83 7C 83 7C 83 7C + 39 00 11 C0 83 7F 04 FF 1E 00 08 10 18 20 28 30 38 FC 00 04 + 39 00 0c D0 20 00 01 08 40 00 02 10 80 00 FC + 39 00 03 41 5A 1A + 39 00 11 80 F0 D9 C8 BA AF A6 9E 98 92 8D 88 84 00 60 F6 CF + 39 00 11 90 FC 6F F6 EF CF AF 5F 55 00 F8 00 F8 00 F8 AD 8D + 39 00 11 A0 73 60 53 4A 43 7F 78 10 A0 3F 00 00 00 00 00 00 + 39 00 11 B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 39 00 09 C0 00 00 00 00 00 00 00 00 + 39 00 03 41 5A 1C + 39 00 11 80 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 00 40 + 39 00 11 90 48 50 58 00 60 68 70 78 00 80 88 90 98 00 A0 A8 + 39 00 11 A0 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC FE FF + 39 00 11 B0 00 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 00 + 39 00 11 C0 40 48 50 58 00 60 68 70 78 00 80 88 90 98 00 A0 + 39 00 11 D0 A8 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC FE + 39 00 11 E0 FF 00 00 04 08 0C 00 10 14 18 1C 00 20 28 30 38 + 39 00 11 F0 00 40 48 50 58 00 60 68 70 78 00 80 88 90 98 00 + 39 00 03 41 5A 1D + 39 00 11 80 A0 A8 B0 B8 00 C0 C8 D0 D8 00 E0 E8 F0 F8 00 FC + 39 00 05 90 FE FF 00 00 + 39 00 03 41 5A 1F + 39 00 11 80 5A 0F 70 09 28 30 38 40 48 50 58 60 20 30 38 40 + 39 00 11 90 48 50 58 60 20 28 38 40 48 50 58 60 20 28 30 40 + 39 00 11 A0 48 50 58 60 20 28 30 38 48 50 58 60 20 28 30 38 + 39 00 11 B0 40 50 58 60 20 28 30 38 40 48 58 60 20 28 30 38 + 39 00 11 C0 40 48 50 60 20 28 30 38 40 48 50 58 FF 5A 1E 20 + 39 00 0d D0 00 02 20 00 02 20 00 02 20 00 02 FE + 39 00 03 41 5A 20 + 39 00 11 80 44 73 03 00 CA F3 FF 6B 10 08 02 08 03 41 18 30 + 39 00 11 90 18 44 E1 40 E1 20 30 18 C8 21 41 01 39 13 44 42 + 39 00 11 A0 91 50 28 14 0A 85 03 D2 B0 80 36 7F D0 1F 12 E0 + 39 00 11 B0 18 36 1B 11 04 20 02 D0 80 B3 21 38 20 18 88 03 + 39 00 11 C0 82 01 4D 70 40 30 8D 0D A4 A2 00 80 04 38 00 50 + 39 00 11 D0 80 13 E0 00 14 C0 70 40 00 E0 81 00 00 28 0E 06 + 39 00 11 E0 43 55 55 55 55 55 D5 CC CC CC CC CC 4C 08 82 C6 + 39 00 11 F0 E0 01 00 00 00 21 42 88 00 00 00 00 00 00 00 20 + 39 00 03 41 5A 21 + 39 00 11 80 04 41 06 49 90 04 49 00 00 49 00 00 49 00 00 49 + 39 00 11 90 90 04 00 85 11 0C 00 00 40 00 00 00 00 16 00 A5 + 39 00 11 A0 00 08 08 15 10 D1 B6 45 92 8A 20 A2 6D 0B 00 54 + 39 00 11 B0 40 44 DB 16 00 48 92 24 09 E0 0F 80 55 30 01 10 + 39 00 11 C0 01 42 82 11 20 02 10 10 01 08 88 00 04 44 00 02 + 39 00 11 D0 22 00 04 91 80 1F 00 40 40 04 00 00 00 18 10 16 + 39 00 03 E0 10 00 + 39 00 03 41 5A 22 + 39 00 11 80 29 D3 00 55 55 55 55 55 55 55 55 55 55 55 1F 70 + 39 00 04 90 F0 00 00 + 39 00 03 41 5A 23 + 39 00 11 80 09 01 02 05 00 05 04 00 00 00 00 00 00 00 00 00 + 39 00 0a 90 00 FF 1F 20 00 01 00 00 FE + 39 00 03 41 5A 24 + 39 00 11 80 00 03 00 FF FF 66 00 00 00 00 00 00 00 00 24 64 + 39 00 0f 90 5A A5 5A 00 00 00 00 22 22 3A 22 00 00 00 + 39 00 03 41 5A 24 + 15 00 02 90 A5 + 39 00 03 41 5A 2F + 15 00 02 4C 03 + 15 00 02 09 01 + 39 00 03 51 ff 0f + 15 00 02 53 24 + 15 00 02 55 00 + //15 00 02 02 5a + + 05 78 01 11 + 05 0A 01 29 + ]; + + panel-exit-sequence = [ + 13 14 01 28 + 13 78 01 10 + ]; + + disp_timings0: display-timings { + native-mode = <&dsi_timing0>; + dsi_timing0: timing0 { + clock-frequency = <170000000>; + hactive = <1200>; + vactive = <1920>; + + hfront-porch = <48>; + hsync-len = <20>; + hback-porch = <38>; + + vfront-porch = <224>; + vsync-len = <6>; + vback-porch = <32>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + panel_in_dsi: endpoint { + remote-endpoint = <&dsi_out_panel>; + }; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + dsi_out_panel: endpoint { + remote-endpoint = <&panel_in_dsi>; + }; + }; + }; + +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&i2c0 { + pinctrl-0 = <&i2c0m1_xfer>; + clock-frequency = <400000>; + status = "okay"; + + ts@40 { + compatible = "GSL,GSL3673_800X1280"; + reg = <0x40>; + irq_gpio_number = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + rst_gpio_number = <&gpio0 RK_PD0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&touch_gpio>; + rockchip,panel-notifier = <&dsi_panel>; + status = "disabled"; + }; + + focaltech@38 { + compatible = "focaltech,fts"; + reg = <0x38>; + //extcon = <&dsi>; + focaltech,irq-gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + focaltech,reset-gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + focaltech,max-touch-number = <10>; + focaltech,display-coords = <0 0 1200 1920>;//AB:1920 1200, P:1200 1920 + rockchip,panel-notifier = <&dsi_panel>; + status = "okay"; + }; +}; + +&i2c1 { + status = "okay"; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default", "pmic-sleep", + "pmic-power-off", "pmic-reset"; + pinctrl-0 = <&pmic_int>; + pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>; + pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>; + pinctrl-3 = <&soc_slppin_slp>, <&rk817_slppin_slp>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + //clock-output-names = "rk808-clkout1", "rk808-clkout2"; + + /* PWRON_ON_TIME: 0:500mS; 1:100mS */ + pwron-on-time-500ms; + + /* 1: rst regs (default in codes), 0: rst the pmic */ + pmic-reset-func = <1>; + /* not save the PMIC_POWER_EN register in uboot */ + not-save-power-en = <1>; + rockchip,clk-32k-always-on; + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&vcc_sys>; + + pwrkey { + status = "okay"; + }; + + pinctrl_rk8xx: pinctrl_rk8xx { + gpio-controller; + #gpio-cells = <2>; + + rk817_slppin_null: rk817_slppin_null { + pins = "gpio_slp"; + function = "pin_fun0"; + }; + + rk817_slppin_slp: rk817_slppin_slp { + pins = "gpio_slp"; + function = "pin_fun1"; + }; + + rk817_slppin_pwrdn: rk817_slppin_pwrdn { + pins = "gpio_slp"; + function = "pin_fun2"; + }; + + rk817_slppin_rst: rk817_slppin_rst { + pins = "gpio_slp"; + function = "pin_fun3"; + }; + }; + + regulators { + vdd_cpu_lit_s0: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-init-microvolt = <850000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_cpu_lit_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_gpu_s0: DCDC_REG2 { + regulator-boot-on; + regulator-init-microvolt = <750000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd_ddr_s0: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdd_ddr_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vdd_logic_s0: vdd_log_mem_s0: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-init-microvolt = <750000>; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_0v85_s0: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdda_0v85_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vcca_1v8_s0: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca_1v8_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vcca3v3_codec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "vcca3v3_codec"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + + vccio_sd_s0: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc3v3_sd_s0: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_sd_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_otp_s0: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_otp_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v2_cam: LDO_REG8 { + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vcc_1v2_cam"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vdda_1v2_s0: LDO_REG9 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdda_1v2_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1200000>; + }; + }; + + vcc_1v8_s3: DCDC_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_3v3_motor: SWITCH_REG1 { + regulator-name = "vcc_3v3_motor"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_3v3_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + battery { + compatible = "rk817,battery"; + ocv_table = <3400 3671 3686 3712 3738 3756 3773 + 3787 3802 3819 3840 3868 3916 3959 + 3998 4041 4087 4138 4191 4247 4313>; + design_capacity = <5780>; + design_qmax = <6358>; + bat_res = <100>; + sleep_enter_current = <150>; + sleep_exit_current = <180>; + sleep_filter_current = <100>; + power_off_thresd = <3400>; + zero_algorithm_vol = <3950>; + max_soc_offset = <60>; + monitor_sec = <5>; + sample_res = <10>; + virtual_power = <0>; + bat_res_up = <60>; + bat_res_down = <20>; + }; + + rk809_codec: codec { + #sound-dai-cells = <1>; + compatible = "rockchip,rk809-codec", "rockchip,rk817-codec"; + clocks = <&mclkout_sai1>; + clock-names = "mclk"; + assigned-clocks = <&mclkout_sai1>; + assigned-clock-rates = <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&sai1m0_mclk>; + hp-volume = <20>; + spk-volume = <25>; + use-ext-amplifier; + status = "okay"; + }; + }; +}; + +&i2c2 { + status = "okay"; + + icm42607_acc: icm_acc@68 { + status = "disabled"; + compatible = "icm42607_acc"; + reg = <0x68>; + irq-gpio = <&gpio0 RK_PC7 IRQ_TYPE_EDGE_RISING>; + irq_enable = <0>; + poll_delay_ms = <30>; + type = ; + layout = <1>; + }; + + icm42607_gyro: icm_gyro@69 { //real addr 0x68 + status = "disabled"; + compatible = "icm42607_gyro"; + reg = <0x69>; + poll_delay_ms = <30>; + type = ; + layout = <0>; + }; + + sensor@19 { + compatible = "gs_sc7a20"; + reg = <0x19>; + type = ; + irq_enable = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_gpio>; + irq-gpio = <&gpio0 RK_PC7 IRQ_TYPE_LEVEL_LOW>; + poll_delay_ms = <10>; + layout = <7>; //<7>;//<5>; + reprobe_en = <0>; + is_sc7a20e = <0>; + swap_xy = <0>; + revert_x = <1>; + revert_y = <1>; + revert_z = <0>; + status = "disabled"; + }; + + sensorda@27{ + compatible = "gs_da223"; + reg = <0x27>; + type = ; + //irq-gpio = <&gpio0 RK_PC4 IRQ_TYPE_LEVEL_LOW>; + irq_enable = <0>; + poll_delay_ms = <10>; + layout = <6>; + //layout = <5>; + swap_xy = <0>; + revert_x = <0>; + revert_y = <1>; + revert_z = <0>; + status = "okay"; + }; +}; + +&i2c3 { + status = "okay"; + +}; + +&i2c6 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6m3_xfer>; + + sc89601: sc89601@6b { + compatible = "sc,sc89601"; + reg = <0x6b>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&charger_ok>; + interrupt-parent = <&gpio0>; + interrupts = ; /* IRQ_TYPE_LEVEL_LOW>;*/ + charger-phandle = <&usbc0>; + sc,battery-regulation-voltage = <4350000>; /* 4200000,4.2V , 4350000, 4232000*/ + sc,charge-current = <3000000>; /*2040000,* 2.040A, 3000000 */ + sc,termination-current = <180000>; /* 180mA, 180000 */ + sc,precharge-current = <180000>; /* 180mA */ + sc,minimum-sys-voltage = <3400000>; /*3500000, 3.5V */ + sc,boost-voltage = <5000000>; /*5100000, 5.1V */ + sc,boost-max-current = <1500000>; /*1200000, 1200mA */ + + sc,use-stat-pin = <0>; /* enable stat pin */ + sc,boost-freq = <0>; /* 1.5MHz */ + + //monitored-battery = <&bat>; + regulators { + otg-en-pin = <&gpio0 RK_PD3 GPIO_ACTIVE_HIGH>; + vbus5v0_typec: vbus5v0-typec { + regulator-compatible = "otg-vbus"; + regulator-name = "vbus5v0_typec"; + }; + }; + }; + + /* aw35615. aw35615 is compatible with fusb302. */ + usbc0: fusb302@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&usbc0_int>; + vbus-supply = <&vbus5v0_typec>; + wakeup-source; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_role_sw: endpoint@0 { + remote-endpoint = <&usb_drd0_role_switch>; + }; + }; + }; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + op-sink-microwatt = <1000000>; + sink-pdos = + ; + source-pdos = + ; + + altmodes { + #address-cells = <1>; + #size-cells = <0>; + + altmode@0 { + reg = <0>; + svid = <0xff01>; + vdo = <0xffffffff>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_orien_sw: endpoint { + remote-endpoint = <&usbdp_phy_orientation_switch>; + }; + }; + + port@1 { + reg = <1>; + dp_altmode_mux: endpoint { + remote-endpoint = <&usbdp_phy_dp_altmode_mux>; + }; + }; + }; + }; + }; +}; + +&i2c9 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c9m3_xfer>; + + fs15xx_pa_34: pa@34 { + compatible = "foursemi,fs15xx"; + reg = <0x34>; + status = "okay"; + }; + + fs15xx_pa_35: pa@35 { + compatible = "foursemi,fs15xx"; + reg = <0x35>; + status = "okay"; + }; + + fs15xx_pa_36: pa@36 { + compatible = "foursemi,fs15xx"; + reg = <0x36>; + status = "okay"; + }; + + fs15xx_pa_37: pa@37 { + compatible = "foursemi,fs15xx"; + reg = <0x37>; + status = "okay"; + }; +}; + +&iep { + status = "okay"; +}; + +&iep_mmu { + status = "okay"; +}; + +&jpegd { + status = "okay"; +}; + +&jpege { + status = "okay"; +}; + +&jpeg_mmu { + status = "okay"; +}; + +&mipidcphy0 { + status = "okay"; +}; + +&mpp_srv { + status = "okay"; +}; + +&pcie0 { + reset-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>; + rockchip,skip-scan-in-resume; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_poweren_gpio>; + status = "disabled"; +}; + +&pinctrl { + + wifi{ + wifi_power_en: wifi_power_en { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_host_wake_irq: wifi_host_wake_irq { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_chip_wake_irq: wifi_chip_wake_irq { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + charger { + charger_ok: charger_ok { + rockchip,pins = + <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, + <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + headphone { + hp_det: hp-det { + rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + lcd { + lcd_rst_gpio: lcd-rst-gpio { + rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + + lcd_enable_gpio: lcd-enable-gpio { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + /omit-if-no-ref/ + pmic_int: pmic-int { + rockchip,pins = + <0 RK_PA6 0 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + soc_slppin_gpio: soc-slppin-gpio { + rockchip,pins = + <0 RK_PA3 0 &pcfg_output_low>; + }; + + /omit-if-no-ref/ + soc_slppin_slp: soc-slppin-slp { + rockchip,pins = + <0 RK_PA3 9 &pcfg_pull_none>; + }; + }; + + touch { + touch_gpio: touch-gpio { + rockchip,pins = + <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>, + <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sensor { + sensor_gpio: sensor-gpio { + rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usbc0_int: usbc0-int { + rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wireless-bluetooth { + uart4_gpios: uart4-gpios { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-wlan { + wifi_poweren_gpio: wifi-poweren-gpio { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm0_2ch_1 { + status = "okay"; +}; + +&pwm1_6ch_0 { + status = "okay"; +}; + +&pwm1_6ch_2 { + status = "okay"; +}; + +&rga2_core0 { + status = "okay"; +}; + +&rga2_core0_mmu { + status = "okay"; +}; + +&rga2_core1 { + status = "okay"; +}; + +&rga2_core1_mmu { + status = "okay"; +}; + +&rknpu { + rknpu-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknpu_mmu { + status = "okay"; +}; + +&rkvenc_ccu { + status = "okay"; +}; + +&rkvenc0 { + status = "okay"; +}; + +&rkvenc0_mmu { + status = "okay"; +}; + +&rkvenc1 { + status = "okay"; +}; + +&rkvenc1_mmu { + status = "okay"; + +}; + +&rkvdec { + status = "okay"; +}; + +&rkvdec_mmu { + status = "okay"; +}; + +&rockchip_suspend { + status = "okay"; + rockchip,sleep-debug-en = <1>; + + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_ARMOFF_LOGOFF + | RKPM_SLP_PMU_PMUALIVE_32K + | RKPM_SLP_PMU_DIS_OSC + | RKPM_SLP_32K_EXT + ) + >; + rockchip,sleep-io-ret-config = < + (0 + | RKPM_VCCIO3_RET_EN + ) + >; +}; + +&route_dsi { + status = "okay"; + connect = <&vp0_out_dsi>; +}; + +&sai1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&sai1m0_lrck + &sai1m0_sclk + &sai1m0_sdi0 + &sai1m0_sdo0>; +}; + +&saradc { + status = "okay"; + vref-supply = <&vcca_1v8_s0>; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + full-pwr-cycle-in-suspend; + status = "disabled"; +}; + +&sdio { + max-frequency = <150000000>; + no-sd; + no-mmc; + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1m0_bus4 &sdmmc1m0_clk &sdmmc1m0_cmd>; + sd-uhs-sdr104; + status = "okay"; +}; + +&sdmmc { + max-frequency = <200000000>; + no-sdio; + no-mmc; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sd_s0>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spdif_tx3 { + status = "okay"; +}; + +&tsadc { + status = "okay"; +}; + +&uart4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart4m1_xfer &uart4m1_ctsn>; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; + rockchip,typec-vbus-det; +}; + +&u2phy1 { + status = "disabled"; +}; + +&ufs { + vcc-supply = <&vcc_ufs_s0>; + vccq-supply = <&vcc1v2_ufs_vccq_s0>; + vccq2-supply = <&vcc1v8_ufs_vccq2_s0>; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&usbdp_phy { + status = "okay"; + orientation-switch; + svid = <0xff01>; + sbu1-dc-gpios = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>; + sbu2-dc-gpios = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + usbdp_phy_orientation_switch: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_orien_sw>; + }; + + usbdp_phy_dp_altmode_mux: endpoint@1 { + reg = <1>; + remote-endpoint = <&dp_altmode_mux>; + }; + }; +}; + +&usbdp_phy_dp { + status = "okay"; + max-link-rate = <5400>; +}; + +&usbdp_phy_u3 { + status = "okay"; +}; + +&usb_drd0_dwc3 { + status = "okay"; + dr_mode = "otg"; + usb-role-switch; + port { + usb_drd0_role_switch: endpoint { + remote-endpoint = <&usbc0_role_sw>; + }; + }; +}; + +&vdpp { + status = "okay"; +}; + +&vop { + status = "okay"; + vop-supply = <&vdd_logic_s0>; +}; + +&vop_mmu { + status = "okay"; +}; + diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts index e417edfe9a5b..044001ecd81b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v22.dts @@ -562,6 +562,14 @@ phy-supply = <&vcc5v0_host_usb30>; }; +&usbdp_phy0_u3 { + status = "disabled"; +}; + +&usbdp_phy1_u3 { + status = "disabled"; +}; + &vdd_log_s0 { regulator-state-mem { regulator-on-in-suspend; @@ -591,4 +599,3 @@ &vcc5v0_host { status = "disabled"; }; - diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts index 12d8ef5d4d30..c63cc0134a2f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-evb-v23.dts @@ -859,6 +859,14 @@ phy-supply = <&vcc5v0_host_usb30>; }; +&usbdp_phy0_u3 { + status = "disabled"; +}; + +&usbdp_phy1_u3 { + status = "disabled"; +}; + &vdd_log_s0 { regulator-state-mem { regulator-on-in-suspend; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi index 035c1cfb09d3..bf32c5cd090f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim-split.dtsi @@ -499,8 +499,8 @@ 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L VBP=8 - 03A6 0008 + //VBP_L/VFP_H VBP=8 + 03A6 0080 //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H @@ -509,14 +509,14 @@ 03AA 0038 //HBP_H 03AC 0003 - //HFP_H/HBP_L(4bit) HBP=56 - 03AB 0008 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 + 03A4 00C1 //HSYNC_WIDTH_L HSYNC=40 0395 0028 //VSYNC_WIDTH_L VSYNC=20 @@ -527,8 +527,8 @@ 03B1 000F //VBP_H 03B3 0000 - //VFP_H/VBP_L VBP=10 - 03B2 000A + //VBP_L/VFP_H VBP=10 + 03B2 00A0 //VRES_L VRES=0X0438=1080 03B4 0038 //VRES_H @@ -537,14 +537,14 @@ 03B6 008C //HBP_H 03B8 0006 - //HFP_H/HBP_L HBP=100 - 03B7 0004 + //HBP_L/HFP_H HBP=100 + 03B7 0040 //HRES_L HRES=0X0780=1920 03B9 0080 //HRES_H 03BA 0007 //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03B0 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot @@ -740,7 +740,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -1422,7 +1422,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <230400000>; //4128*930@60 + clock-frequency = <230000000>; //3840*720@60 hactive = <3840>; vactive = <720>; hfront-porch = <112>; @@ -1550,7 +1550,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -2101,7 +2101,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <230400000>; //4128*930@60 + clock-frequency = <230000000>; //3840*720@60 hactive = <3840>; vactive = <720>; hfront-porch = <112>; @@ -2230,7 +2230,7 @@ panel-size= <346 194>; panel-timing { - clock-frequency = <115200000>; + clock-frequency = <115000000>; hactive = <1920>; vactive = <720>; hfront-porch = <56>; @@ -2413,8 +2413,7 @@ }; &vop { - assigned-clocks = <&cru PLL_V0PLL>; - assigned-clock-rates = <2304000000>; + status = "okay"; }; &vp0 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi index fbe04680f379..3c3b31b37226 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-mfd-display-maxim.dtsi @@ -499,8 +499,8 @@ 03A5 00C8 //VBP_H 03A7 0000 - //VFP_H/VBP_L VBP=8 - 03A6 0008 + //VBP_L/VFP_H VBP=8 + 03A6 0080 //VRES_L VRES=0X02D0=720 03A8 00D0 //VRES_H @@ -509,42 +509,42 @@ 03AA 0038 //HBP_H 03AC 0003 - //HFP_H/HBP_L(4bit) HBP=56 - 03AB 0008 + //HBP_L/HFP_H(4bit) HBP=56 + 03AB 0080 //HRES_L HRES=0X0780=1920 03AD 0080 //HRES_H 03AE 0007 //Disable FIFO/DESKEW_EN - 03A4 00C0 - //HSYNC_WIDTH_L HSYNC=40 - 0395 0028 - //VSYNC_WIDTH_L VSYNC=20 - 0396 0014 + 03A4 00C1 + //HSYNC_WIDTH_L HSYNC=32 + 0395 0020 + //VSYNC_WIDTH_L VSYNC=2 + 0396 0002 //HSYNC_WIDTH_H/VSYNC_WIDTH_H 0397 0000 - //VFP_L VFP=15 - 03B1 000F + //VFP_L VFP=200 + 03B1 00C8 //VBP_H 03B3 0000 - //VFP_H/VBP_L VBP=10 - 03B2 000A - //VRES_L VRES=0X0438=1080 - 03B4 0038 + //VBP_L/VFP_H VBP=8 + 03B2 0080 + //VRES_L VRES=0X02D0=720 + 03B4 00D0 //VRES_H - 03B5 0004 - //HFP_L HFP=140 - 03B6 008C + 03B5 0002 + //HFP_L HFP=56 + 03B6 0038 //HBP_H - 03B8 0006 - //HFP_H/HBP_L HBP=100 - 03B7 0004 + 03B8 0003 + //HBP_L/HFP_H HBP=56 + 03B7 0080 //HRES_L HRES=0X0780=1920 03B9 0080 //HRES_H 03BA 0007 //Disable FIFO/DESKEW_EN - 03B0 00C0 + 03B0 00C1 //Turn on video pipe 0002 0033 //Enable splitter mode reset one shot @@ -2103,8 +2103,7 @@ }; &vop { - assigned-clocks = <&cru PLL_V0PLL>; - assigned-clock-rates = <1150000000>; + status = "okay"; }; //dp &vp0 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi index 8cfbba940433..603fb80736eb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi @@ -380,7 +380,7 @@ native-mode = <&dsi1_timing0>; dsi1_timing0: timing0 { clock-frequency = <280000000>; - hactive = <1140>; + hactive = <1440>; vactive = <3120>; hfront-porch = <16>; hsync-len = <8>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi index 2a299227d605..3f6f897a012e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s-tablet-rk806-single.dtsi @@ -1071,7 +1071,7 @@ native-mode = <&dsi1_timing0>; dsi1_timing0: timing0 { clock-frequency = <280000000>; - hactive = <1140>; + hactive = <1440>; vactive = <3120>; hfront-porch = <16>; hsync-len = <8>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi index 971f67e0ccab..c177b787c2e9 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb1-v10.dtsi @@ -100,6 +100,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; enable-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi index cf6b5788ea5e..f8603e865191 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dtsi @@ -179,6 +179,7 @@ regulator-init-microvolt = <905000>; regulator-min-microvolt = <810000>; regulator-max-microvolt = <1006000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -192,6 +193,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <800000>; regulator-max-microvolt = <1150000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -205,6 +207,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <800000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -230,6 +233,13 @@ WIFI,host_wake_irq = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>; status = "okay"; }; + + rk96x_wake_aov_irq: rk96x-wake-aov-irq { + compatible = "rockchip,rk96x-wake-aov-irq"; + rk96x-wake-irq-gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>; + wakeup-source; + status = "okay"; + }; }; &acdcdig_dsm { diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts index 503e4ba33b52..53de70d052b1 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb3-v10.dts @@ -166,6 +166,7 @@ regulator-init-microvolt = <905000>; regulator-min-microvolt = <810000>; regulator-max-microvolt = <1006000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -179,6 +180,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; @@ -192,6 +194,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; pwm-supply = <&vccsys_stb>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts index 2dcec24ddb52..be9fb9d30118 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb4-v10.dts @@ -103,6 +103,7 @@ regulator-init-microvolt = <950000>; regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; + regulator-settling-time-up-us = <250>; regulator-always-on; regulator-boot-on; enable-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index 043a37f41ebf..35de85a0ac6b 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -454,18 +454,20 @@ cpu_opp_j_od_1416000000: opp-j-od-1416000000 { opp-supported-hw = <0x04 0xffff>; opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <925000 925000 1100000>; - opp-microvolt-L0 = <9750000 9750000 1100000>; - opp-microvolt-L1 = <950000 950000 1100000>; + opp-microvolt = <950000 950000 1100000>; + opp-microvolt-L0 = <1025000 1025000 1100000>; + opp-microvolt-L1 = <1000000 1000000 1100000>; + opp-microvolt-L2 = <975000 975000 1100000>; clock-latency-ns = <40000>; status = "disabled"; }; cpu_opp_j_od_1512000000: opp-j-od-1512000000 { opp-supported-hw = <0x04 0xffff>; opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <950000 950000 1100000>; - opp-microvolt-L0 = <1000000 1000000 1100000>; - opp-microvolt-L1 = <975000 975000 1100000>; + opp-microvolt = <975000 975000 1100000>; + opp-microvolt-L0 = <1050000 1050000 1100000>; + opp-microvolt-L1 = <1025000 1025000 1100000>; + opp-microvolt-L2 = <1000000 1000000 1100000>; clock-latency-ns = <40000>; status = "disabled"; }; @@ -3256,7 +3258,7 @@ }; can0: can@21d40000 { - compatible = "rockchip,rv1126b-canfd"; + compatible = "rockchip,rv1126b-can"; reg = <0x21d40000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN0>, <&cru HCLK_CAN0>; @@ -3269,7 +3271,7 @@ }; can1: can@21d50000 { - compatible = "rockchip,rv1126b-canfd"; + compatible = "rockchip,rv1126b-can"; reg = <0x21d50000 0x1000>; interrupts = ; clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>; diff --git a/arch/arm64/configs/rk3576_vehicle.config b/arch/arm64/configs/rk3576_vehicle.config index e49df7c51019..8faefdc6eeeb 100644 --- a/arch/arm64/configs/rk3576_vehicle.config +++ b/arch/arm64/configs/rk3576_vehicle.config @@ -106,6 +106,7 @@ CONFIG_VEHICLE_GPIO_MCU_EXPANDER=y # CONFIG_VIDEO_GC4C33 is not set # CONFIG_VIDEO_GC8034 is not set # CONFIG_VIDEO_IMX415 is not set +CONFIG_VIDEO_MAX96756=y CONFIG_VIDEO_MAXIM_SERDES=y # CONFIG_VIDEO_OV02B10 is not set # CONFIG_VIDEO_OV13850 is not set diff --git a/arch/arm64/configs/rockchip_linux_defconfig b/arch/arm64/configs/rockchip_linux_defconfig index 2bdaa128c37b..c26368904f4b 100644 --- a/arch/arm64/configs/rockchip_linux_defconfig +++ b/arch/arm64/configs/rockchip_linux_defconfig @@ -220,7 +220,7 @@ CONFIG_MOTORCOMM_PHY=y CONFIG_ROCKCHIP_FEPHY=y CONFIG_ROCKCHIP_PHY=y CONFIG_RK630_PHY=y -CONFIG_CANFD_RK3576=y +CONFIG_CAN_RK3576=y CONFIG_USB_RTL8150=y CONFIG_USB_RTL8152=y CONFIG_WL_ROCKCHIP=y diff --git a/drivers/clk/rockchip/clk-pvtpll.c b/drivers/clk/rockchip/clk-pvtpll.c index f0353ecaaabf..be1d7b777c1b 100644 --- a/drivers/clk/rockchip/clk-pvtpll.c +++ b/drivers/clk/rockchip/clk-pvtpll.c @@ -173,14 +173,14 @@ static struct pvtpll_table rv1126b_core_pvtpll_table[] = { static struct pvtpll_table rv1126bj_core_pvtpll_table[] = { /* rate_hz, ring_sel, length */ - ROCKCHIP_PVTPLL_VOLT_SEL(1900000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1850000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1800000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1750000000, 0, 30, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1700000000, 0, 30, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1900000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1850000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1800000000, 0, 32, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1750000000, 0, 32, 6), + ROCKCHIP_PVTPLL_VOLT_SEL(1700000000, 0, 32, 6), + ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 32, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 34, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 38, 5), ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 5), ROCKCHIP_PVTPLL_VOLT_SEL(1200000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1008000000, 0, 56, 1), diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index a29212f42f78..1955bd7ed545 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -322,6 +322,7 @@ struct drm_dp_link_train { struct dw_dp_link { u8 dpcd[DP_RECEIVER_CAP_SIZE]; + u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; unsigned char revision; unsigned int max_rate; unsigned int rate; @@ -439,6 +440,14 @@ struct dw_dp_mst_enc { bool active; }; +struct dw_dp_dfp { + int min_tmds_clock; + int max_tmds_clock; + int max_dotclock; + u8 max_bpc; + bool ycbcr_444_to_420; +}; + struct dw_dp { const struct dw_dp_chip_data *chip_data; struct device *dev; @@ -473,12 +482,14 @@ struct dw_dp { struct dw_dp_video video; struct dw_dp_audio *audio; struct dw_dp_compliance compliance; + struct dw_dp_dfp dfp; DECLARE_BITMAP(sdp_reg_bank, SDP_REG_BANK_SIZE); bool split_mode; bool dual_connector_split; bool left_display; + bool branch_ycbcr_444_to_422; struct dw_dp *left; struct dw_dp *right; @@ -1661,6 +1672,35 @@ static int dw_dp_update_hdr_property(struct drm_connector *connector) return ret; } +static void dw_dp_update_dfp(struct dw_dp *dp, struct edid *edid) +{ + struct dw_dp_link *link = &dp->link; + struct dw_dp_dfp *dfp = &dp->dfp; + bool ycbcr_420_passthrough, ycbcr_444_to_420; + + memset(&dp->dfp, 0, sizeof(dp->dfp)); + + dfp->max_bpc = drm_dp_downstream_max_bpc(link->dpcd, link->downstream_ports, edid); + + dfp->max_dotclock = drm_dp_downstream_max_dotclock(link->dpcd, link->downstream_ports); + + dfp->min_tmds_clock = drm_dp_downstream_min_tmds_clock(link->dpcd, link->downstream_ports, + edid); + dfp->max_tmds_clock = drm_dp_downstream_max_tmds_clock(link->dpcd, link->downstream_ports, + edid); + ycbcr_420_passthrough = drm_dp_downstream_420_passthrough(link->dpcd, + link->downstream_ports); + ycbcr_444_to_420 = drm_dp_downstream_444_to_420_conversion(link->dpcd, + link->downstream_ports); + /* Prefer 4:2:0 passthrough over 4:4:4->4:2:0 conversion */ + dfp->ycbcr_444_to_420 = ycbcr_444_to_420 && !ycbcr_420_passthrough; + + dw_dp_dbg(dp, + "dfp max bpc:%d, max dot:%d, min tmds:%d, max tmds:%d, ycbcr 444 to 420:%d\n", + dfp->max_bpc, dfp->max_dotclock, dfp->min_tmds_clock, dfp->max_tmds_clock, + dfp->ycbcr_444_to_420); +} + static int dw_dp_connector_get_modes(struct drm_connector *connector) { struct dw_dp *dp = connector_to_dp(connector); @@ -1689,6 +1729,7 @@ static int dw_dp_connector_get_modes(struct drm_connector *connector) drm_connector_update_edid_property(connector, edid); num_modes = drm_add_edid_modes(connector, edid); dw_dp_update_hdr_property(connector); + dw_dp_update_dfp(dp, edid); kfree(edid); } } @@ -1922,6 +1963,9 @@ static int dw_dp_link_probe(struct dw_dp *dp) } link->sink_support_mst = drm_dp_read_mst_cap(&dp->aux, dp->link.dpcd); + ret = drm_dp_read_downstream_info(&dp->aux, link->dpcd, link->downstream_ports); + if (ret) + return ret; ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, &dpcd); @@ -3016,6 +3060,9 @@ static int dw_dp_video_enable(struct dw_dp *dp, struct dw_dp_video *video, int s FIELD_PREP(HBLANK_INTERVAL_EN, 1) | FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); + if (dp->branch_ycbcr_444_to_422) + drm_dp_dpcd_writeb(&dp->aux, DP_PROTOCOL_CONVERTER_CONTROL_1, + DP_CONVERSION_TO_YCBCR420_ENABLE); /* Video stream enable */ regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL_N(stream_id), VIDEO_STREAM_ENABLE, FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); @@ -3419,6 +3466,39 @@ static ssize_t dw_dp_sim_aux_transfer(struct drm_dp_aux *aux, return dw_dp_aux_transfer(aux, msg); } +static int dw_dp_hdmi_tmds_clock(int clock, int bpc, bool ycbcr420_output) +{ + if (ycbcr420_output) + clock /= 2; + + return DIV_ROUND_CLOSEST(clock * bpc, 8); +} + +static enum drm_mode_status +dw_dp_tmds_clock_valid(struct dw_dp *dp, int bpc, + const struct drm_display_mode *mode, + const struct drm_display_info *info) +{ + int tmds_clock, min_tmds_clock, max_tmds_clock; + bool ycbcr_420_output; + + if (dp->dfp.max_dotclock && mode->clock > dp->dfp.max_dotclock) + return MODE_CLOCK_HIGH; + + ycbcr_420_output = drm_mode_is_420_only(info, mode); + tmds_clock = dw_dp_hdmi_tmds_clock(mode->clock, bpc, ycbcr_420_output); + min_tmds_clock = dp->dfp.min_tmds_clock; + max_tmds_clock = min(dp->dfp.max_tmds_clock, info->max_tmds_clock); + + if (min_tmds_clock && tmds_clock < min_tmds_clock) + return MODE_CLOCK_LOW; + + if (max_tmds_clock && tmds_clock > max_tmds_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static enum drm_mode_status dw_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, @@ -3446,6 +3526,7 @@ dw_dp_bridge_mode_valid(struct drm_bridge *bridge, min_bpp = 24; if (!link->vsc_sdp_extension_for_colorimetry_supported && + !dp->dfp.ycbcr_444_to_420 && drm_mode_is_420_only(info, &m)) return MODE_NO_420; @@ -3455,7 +3536,8 @@ dw_dp_bridge_mode_valid(struct drm_bridge *bridge, if (m.flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; - return MODE_OK; + /* Assume 8bpc for the HDMI/DVI TMDS clock check */ + return dw_dp_tmds_clock_valid(dp, 8, mode, info); } static void _dw_dp_loader_protect(struct dw_dp *dp, bool on) @@ -4799,6 +4881,9 @@ out: } } + if (status == connector_status_disconnected) + memset(&dp->dfp, 0, sizeof(dp->dfp)); + return status; } @@ -4852,6 +4937,7 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, unsigned int i, j = 0; dp->eotf_type = dw_dp_get_eotf(conn_state); + dp->branch_ycbcr_444_to_422 = false; if (dp->split_mode || dp->dual_connector_split) drm_mode_convert_to_origin_mode(&mode); @@ -4895,9 +4981,16 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, fmt->color_format == DRM_COLOR_FORMAT_YCBCR420) continue; - if (drm_mode_is_420_only(di, &mode) && - fmt->color_format != DRM_COLOR_FORMAT_YCBCR420) - continue; + if (drm_mode_is_420_only(di, &mode)) { + if (dp->dfp.ycbcr_444_to_420) { + dp->branch_ycbcr_444_to_422 = true; + if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR444) + continue; + } else { + if (fmt->color_format != DRM_COLOR_FORMAT_YCBCR420) + continue; + } + } if (!dw_dp_bandwidth_ok(dp, &mode, fmt->bpp, link->lanes, link->max_rate)) continue; @@ -4905,6 +4998,12 @@ static u32 *dw_dp_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, if (dw_dp_is_hdr_eotf(dp->eotf_type) && fmt->bpc < 8) continue; + if (dp->dfp.max_bpc && fmt->bpc > dp->dfp.max_bpc) + continue; + + if (dp->dfp.max_tmds_clock && fmt->bpc > 8) + continue; + output_fmts[j++] = fmt->bus_format; } diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 89952e5d743c..b142e1a3ca2c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -241,6 +241,11 @@ static const uint64_t format_modifiers_afbc[] = { AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_SPLIT), + /* SPLIT mandates SPARSE */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID, }; diff --git a/drivers/hwspinlock/rockchip_hwspinlock.c b/drivers/hwspinlock/rockchip_hwspinlock.c index f570ac260de8..615787ccffeb 100644 --- a/drivers/hwspinlock/rockchip_hwspinlock.c +++ b/drivers/hwspinlock/rockchip_hwspinlock.c @@ -14,6 +14,8 @@ struct rockchip_hwspinlock { void __iomem *io_base; + u32 user_id; + u32 user_id_mask; struct hwspinlock_device bank; }; @@ -22,35 +24,35 @@ struct rockchip_hwspinlock { /* Hardware spinlock register offsets */ #define HWSPINLOCK_OFFSET(x) (0x4 * (x)) -#define HWSPINLOCK_ID_MASK 0x0F -#define HWLOCK_DEFAULT_USER 0x01 - -static u32 hwlock_user_id; +#define HWLOCK_DEFAULT_USER 0x01 +#define HWLOCK_DEFAULT_USER_ID_MASK 0x0F static int rockchip_hwspinlock_trylock(struct hwspinlock *lock) { + struct rockchip_hwspinlock *hwlock = dev_get_drvdata(lock->bank->dev); void __iomem *lock_addr = lock->priv; - writel(hwlock_user_id, lock_addr); + writel(hwlock->user_id, lock_addr); /* * Get only first 4 bits and compare to HWSPINLOCK_OWNER_ID, * if equal, we attempt to acquire the lock, otherwise, * someone else has it. */ - return (hwlock_user_id == (readl(lock_addr) & HWSPINLOCK_ID_MASK)); + return (hwlock->user_id == (readl(lock_addr) & hwlock->user_id_mask)); } static void rockchip_hwspinlock_unlock(struct hwspinlock *lock) { + struct rockchip_hwspinlock *hwlock = dev_get_drvdata(lock->bank->dev); void __iomem *lock_addr = lock->priv; - u32 lock_owner = readl(lock_addr) & HWSPINLOCK_ID_MASK; + u32 lock_owner = readl(lock_addr) & hwlock->user_id_mask; - if (lock_owner != hwlock_user_id) { + if (lock_owner != hwlock->user_id) { dev_warn(lock->bank->dev, "WARNING: against user %u release a lock held by %u\n", - hwlock_user_id, lock_owner); + hwlock->user_id, lock_owner); return; } @@ -85,11 +87,18 @@ static int rockchip_hwspinlock_probe(struct platform_device *pdev) if (IS_ERR(hwspin->io_base)) return PTR_ERR(hwspin->io_base); + ret = device_property_read_u32(&pdev->dev, "rockchip,hwlock-max-user", + &hwspin->user_id_mask); + if (ret || !hwspin->user_id_mask) + hwspin->user_id_mask = HWLOCK_DEFAULT_USER_ID_MASK; + ret = device_property_read_u32(&pdev->dev, "rockchip,hwlock-user-id", - &hwlock_user_id); - if (ret || !hwlock_user_id || hwlock_user_id > HWSPINLOCK_ID_MASK) - hwlock_user_id = HWLOCK_DEFAULT_USER; - dev_info(&pdev->dev, "hwlock user id %u, locks %u\n", hwlock_user_id, num_locks); + &hwspin->user_id); + if (ret || !hwspin->user_id || hwspin->user_id > hwspin->user_id_mask) + hwspin->user_id = HWLOCK_DEFAULT_USER; + + dev_info(&pdev->dev, "hwlock user id %u, locks %u, maximum user %u\n", + hwspin->user_id, num_locks, hwspin->user_id_mask); for (idx = 0; idx < num_locks; idx++) { hwlock = &hwspin->bank.lock[idx]; diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 8d6df41dcba3..287dae6f497a 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -94,6 +94,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_icm42600/Kconfig" +source "drivers/iio/imu/inv_icm42607/Kconfig" source "drivers/iio/imu/inv_icm42670/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsr/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index f2cfa8828a07..7745e4218817 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o obj-y += inv_icm42600/ +obj-y += inv_icm42607/ obj-y += inv_icm42670/ obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig new file mode 100644 index 000000000000..8368bf160b69 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +config IIO_INV_ICM42607 + tristate "INV ICM42607 driver for 6-axis IMU MEMS sensors" + depends on I2C + select IIO_BUFFER + select IIO_KFIFO_BUF + select IIO_INV_ICM42607_I2C if (I2C) + help + Say yes here to build support for INV icm42607 sensor. + + To compile this driver as a module, choose M here: the module + will be called inv_icm42607. + +config IIO_INV_ICM42607_I2C + tristate + depends on IIO_INV_ICM42607 + select REGMAP_I2C diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile new file mode 100644 index 000000000000..dfdbf5cb7a07 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +inv-icm42607-y := invimu_core.o invimu_iio.o icm42607.o + +obj-$(CONFIG_IIO_INV_ICM42607) += inv-icm42607.o + +inv-icm42607-i2c-y := invimu_i2c.o +obj-$(CONFIG_IIO_INV_ICM42607_I2C) += inv-icm42607-i2c.o diff --git a/drivers/iio/imu/inv_icm42607/icm42607.c b/drivers/iio/imu/inv_icm42607/icm42607.c new file mode 100644 index 000000000000..a65ca5a7476c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/icm42607.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "icm42607.h" + +static struct imu_reg_value_map icm_acce_only_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x03}, /* Accelerometer only mode */ + {REG_ACCEL_CONFIG0, 0x9},/* 100Hz, 16g range */ +}; + +static struct imu_reg_value_map icm_acce_gyro_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x0f}, /* Both accelerometer and gyroscope on */ + {REG_ACCEL_CONFIG0, 0x9},/* 100Hz, 16g range */ + {REG_GYRO_CONFIG0, 0x9}, /* 100Hz, 2000dps range */ +}; + +static struct imu_reg_value_map icm_powerdown_regs_cfg_map[] = { + {REG_PWR_MGMT_0, 0x00}, +}; + +static int icm42607_regs_cfg_write(struct imu_ctrb *ctrb, + struct imu_reg_value_map *maparrays, int regcnt) +{ + int i, ret; + + if (ctrb == NULL) + return -1; + + if (regcnt <= 0) { + dev_err(ctrb->dev, "reg map len err\n"); + return -1; + } + for (i = 0; i < regcnt; i++) { + ret = regmap_write(ctrb->regmap, maparrays[i].reg, maparrays[i].value); + if (ret) { + dev_err(ctrb->dev, "regmap write err\n"); + return -1; + } + } + return 0; +} + +static int icm42607_read_id(void *ctrbp) +{ + int ret; + unsigned int val = 0; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + + if (ctrb == NULL) + return -1; + + ret = regmap_read(ctrb->regmap, REG_WHO_AM_I, &val); + if (ret) { + dev_err(ctrb->dev, "regmap_read err\n"); + return 0; + } + dev_info(ctrb->dev, "ID = 0x%02x\n", val); + return (int)val; +} + +static int icm42607_mode_set(void *ctrbp, int mode) +{ + int ret = 0; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + + if (ctrb == NULL) + return -1; + + switch (mode) { + case IMU_POWER_MODE_INIT: + break; + case IMU_POWER_MODE_DOWN: + ret = icm42607_regs_cfg_write(ctrb, icm_powerdown_regs_cfg_map, + sizeof(icm_powerdown_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + case IMU_POWER_ACCE_ONLY: + ret = icm42607_regs_cfg_write(ctrb, icm_acce_only_regs_cfg_map, + sizeof(icm_acce_only_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + case IMU_POWER_ACCE_GYRO: + ret = icm42607_regs_cfg_write(ctrb, icm_acce_gyro_regs_cfg_map, + sizeof(icm_acce_gyro_regs_cfg_map) / sizeof(struct imu_reg_value_map)); + break; + default: + ret = -1; + } + dev_info(ctrb->dev, "set power:%d success\n", mode); + return ret; +} + +static int icm42607_mreg_write(struct imu_ctrb *ctrb, u16 addr, u8 data) +{ + int ret; + u8 bank = addr >> 8; + u8 reg = addr & 0xFF; + + ret = regmap_write(ctrb->regmap, REG_BLK_SEL_W, bank); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_MADDR_W, reg); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_M_W, data); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_BLK_SEL_W, 0); + + return ret; +} + +static int icm42607_mreg_read(struct imu_ctrb *ctrb, u16 addr, u8 *data) +{ + int ret; + u8 bank = addr >> 8; + u8 reg = addr & 0xFF; + unsigned int tmp; + + ret = regmap_write(ctrb->regmap, REG_BLK_SEL_R, bank); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_MADDR_R, reg); + usleep_range(10, 11); + ret |= regmap_read(ctrb->regmap, REG_M_R, &tmp); + usleep_range(10, 11); + ret |= regmap_write(ctrb->regmap, REG_BLK_SEL_R, 0); + + if (!ret) + *data = (u8)tmp; + + return ret; +} + +static int icm42607_otp_reload(struct imu_ctrb *ctrb) +{ + int ret; + u8 rb; + + ret = regmap_write(ctrb->regmap, REG_PWR_MGMT_0, BIT_IDLE); + if (ret) + return ret; + usleep_range(20, 21); + + /* OTP_COPY_MODE = 2'b01 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CONFIG_MREG_TOP1, &rb); + if (ret) + return ret; + rb &= ~OTP_COPY_MODE_MASK; + rb |= BIT_OTP_COPY_NORMAL; + ret = icm42607_mreg_write(ctrb, REG_OTP_CONFIG_MREG_TOP1, rb); + if (ret) + return ret; + + /* OTP_PWR_DOWN = 0 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CTRL7_MREG_OTP, &rb); + if (ret) + return ret; + rb &= ~BIT_OTP_PWR_DOWN; + ret = icm42607_mreg_write(ctrb, REG_OTP_CTRL7_MREG_OTP, rb); + if (ret) + return ret; + usleep_range(300, 400); + + /* OTP_RELOAD = 1 */ + ret = icm42607_mreg_read(ctrb, REG_OTP_CTRL7_MREG_OTP, &rb); + if (ret) + return ret; + rb |= BIT_OTP_RELOAD; + ret = icm42607_mreg_write(ctrb, REG_OTP_CTRL7_MREG_OTP, rb); + if (ret) + return ret; + usleep_range(280, 380); + + return 0; +} + +static int icm42607_set_default_register(struct imu_ctrb *ctrb) +{ + int s = 0; + + s |= regmap_write(ctrb->regmap, REG_GYRO_CONFIG0, 0x69); + s |= regmap_write(ctrb->regmap, REG_ACCEL_CONFIG0, 0x69); + s |= regmap_write(ctrb->regmap, REG_APEX_CONFIG0, 0x08); + s |= regmap_write(ctrb->regmap, REG_APEX_CONFIG1, 0x02); + s |= regmap_write(ctrb->regmap, REG_WOM_CONFIG, 0x00); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG1, 0x01); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG2, 0x00); + s |= regmap_write(ctrb->regmap, REG_FIFO_CONFIG3, 0x00); + + s |= icm42607_mreg_write(ctrb, REG_FIFO_CONFIG5_MREG_TOP1, 0x20); + s |= icm42607_mreg_write(ctrb, REG_ST_CONFIG_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE7_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE8_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE9_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_INT_SOURCE10_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG2_MREG_TOP1, 0xA2); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG3_MREG_TOP1, 0x85); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG4_MREG_TOP1, 0x51); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG5_MREG_TOP1, 0x80); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG9_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG10_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG11_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_X_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_Y_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_ACCEL_WOM_Z_THR_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER0_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER1_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER2_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER3_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER4_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER5_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER6_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER7_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_GOS_USER8_MREG_TOP1, 0x00); + s |= icm42607_mreg_write(ctrb, REG_APEX_CONFIG12_MREG_TOP1, 0x00); + + return s ? -EIO : 0; +} + +static int icm42607_chip_init(void *ctrbp) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret; + unsigned int val; + + if (!ctrb) + return -EINVAL; + + ret = icm42607_otp_reload(ctrb); + if (ret) { + dev_err(ctrb->dev, "OTP reload fail(%d)\n", ret); + return ret; + } + + ret = icm42607_set_default_register(ctrb); + if (ret) { + dev_err(ctrb->dev, "set default reg fail(%d)\n", ret); + return ret; + } + + val = BIT_SENSOR_DATA_ENDIAN | BIT_FIFO_COUNT_ENDIAN; + ret = regmap_write(ctrb->regmap, REG_INTF_CONFIG0, val); + if (ret) + return ret; + + val = BIT_CLK_SEL_PLL | BIT_I3C_SDR_EN | BIT_I3C_DDR_EN; + ret = regmap_write(ctrb->regmap, REG_INTF_CONFIG1, val); + if (ret) + return ret; + + return icm42607_mode_set(ctrb, IMU_POWER_MODE_DOWN); +} + +static int icm42607_read_acce_gyro_raw(void *ctrbp, void *rawdatap, uint8_t reg) +{ + int ret = 0; + uint8_t rawarrays[6] = { 0 }; + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + struct imu_3axis_data *rawdata = (struct imu_3axis_data *)rawdatap; + + if (ctrb == NULL || rawdata == NULL) + return -1; + + ret = regmap_bulk_read(ctrb->regmap, reg, rawarrays, sizeof(rawarrays)); + if (!ret) { + rawdata->raw[0] = ((uint16_t)rawarrays[0]) << 8 | rawarrays[1]; + rawdata->raw[1] = ((uint16_t)rawarrays[2]) << 8 | rawarrays[3]; + rawdata->raw[2] = ((uint16_t)rawarrays[4]) << 8 | rawarrays[5]; + } else { + dev_err(ctrb->dev, "regmap_bulk_read err:%d\n", ret); + } + return ret; +} + +static int icm42607_read_acce_raw(void *ctrbp, void *rawdatap) +{ + return icm42607_read_acce_gyro_raw(ctrbp, rawdatap, REG_ACCEL_DATA_X0_UI); +} + +static int icm42607_read_gyro_raw(void *ctrbp, void *rawdatap) +{ + return icm42607_read_acce_gyro_raw(ctrbp, rawdatap, REG_GYRO_DATA_X0_UI); +} + +static int icm42607_read_asix_one(void *ctrbp, int addr, int *datap) +{ + int ret; + struct imu_3axis_data accedata = {0}, gyrodata = {0}; + + ret = icm42607_read_acce_raw(ctrbp, &accedata); + ret = ret || icm42607_read_gyro_raw(ctrbp, &gyrodata); + switch (addr) { + case 0: + (*datap) = accedata.raw[0]; + break; + case 1: + (*datap) = accedata.raw[1]; + break; + case 2: + (*datap) = accedata.raw[2]; + break; + case 3: + (*datap) = gyrodata.raw[0]; + break; + case 4: + (*datap) = gyrodata.raw[1]; + break; + case 5: + (*datap) = gyrodata.raw[2]; + break; + } + return ret; +} + +static int icm42607_set_accel_offset(void *ctrbp, int offset, int axis) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret = 0; + u8 reg_l, reg_h; + u16 val; + + offset = clamp(offset, -2048, 2047); + val = (u16)(offset & 0x0FFF); + + switch (axis) { + case 0: /* X */ + reg_l = REG_GOS_USER5_MREG_TOP1; + reg_h = REG_GOS_USER4_MREG_TOP1; + break; + case 1: /* Y */ + reg_l = REG_GOS_USER6_MREG_TOP1; + reg_h = REG_GOS_USER7_MREG_TOP1; + break; + case 2: /* Z */ + reg_l = REG_GOS_USER8_MREG_TOP1; + reg_h = REG_GOS_USER7_MREG_TOP1; + break; + default: + return -EINVAL; + } + + ret |= icm42607_mreg_write(ctrb, reg_l, val & 0xFF); + ret |= icm42607_mreg_write(ctrb, reg_h, (val >> 8) & 0x0F); + + return ret ? -EIO : 0; +} + +static int icm42607_set_gyro_offset(void *ctrbp, int offset, int axis) +{ + struct imu_ctrb *ctrb = (struct imu_ctrb *)ctrbp; + int ret = 0; + u8 reg_l, reg_h; + u16 val; + + offset = clamp(offset, -2048, 2047); + val = (u16)(offset & 0x0FFF); + + switch (axis) { + case 0: /* X */ + reg_l = REG_GOS_USER0_MREG_TOP1; + reg_h = REG_GOS_USER1_MREG_TOP1; + break; + case 1: /* Y */ + reg_l = REG_GOS_USER2_MREG_TOP1; + reg_h = REG_GOS_USER1_MREG_TOP1; + break; + case 2: /* Z */ + reg_l = REG_GOS_USER3_MREG_TOP1; + reg_h = REG_GOS_USER4_MREG_TOP1; + break; + default: + return -EINVAL; + } + + ret |= icm42607_mreg_write(ctrb, reg_l, val & 0xFF); + ret |= icm42607_mreg_write(ctrb, reg_h, (val >> 8) & 0x0F); + + return ret ? -EIO : 0; +} + +static const struct imu_info icm42607_info = { + .name = "icm42607", + .id = ICM42607_CHIP_ID, + .read_id = icm42607_read_id, + .chip_init = icm42607_chip_init, + .mode_set = icm42607_mode_set, + .read_acce_raw = icm42607_read_acce_raw, + .read_gyro_raw = icm42607_read_gyro_raw, + .read_asix_one = icm42607_read_asix_one, + .set_accel_offset = icm42607_set_accel_offset, + .set_gyro_offset = icm42607_set_gyro_offset, +}; + +struct imu_info *icm42607_chip_probe(struct imu_ctrb *ctrb) +{ + int chip_id = -1; + + chip_id = icm42607_read_id(ctrb); + if (chip_id == icm42607_info.id) { + dev_info(ctrb->dev, "probe sensor: %s, id = 0x%02X\n", + icm42607_info.name, icm42607_info.id); + return (struct imu_info *)&icm42607_info; + } + return NULL; +} diff --git a/drivers/iio/imu/inv_icm42607/icm42607.h b/drivers/iio/imu/inv_icm42607/icm42607.h new file mode 100644 index 000000000000..1d9543a22505 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/icm42607.h @@ -0,0 +1,435 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __ICM42607_H__ +#define __ICM42607_H__ + +#include "imu.h" + +/* Registers and associated bit definitions */ +/* Bank 0 */ +#define REG_MISC_1 0x00 +#define REG_CHIP_CONFIG_REG 0x01 +#define REG_SIGNAL_PATH_RESET 0x02 +#define REG_DRIVE_CONFIG_REG1 0x03 +#define REG_DRIVE_CONFIG_REG2 0x04 +#define REG_DRIVE_CONFIG_REG3 0x05 +#define REG_INT_CONFIG_REG 0x06 +#define REG_ODRGRID0 0x07 +#define REG_ODRGRID1 0x08 +#define REG_TEMP_DATA0_UI 0x09 +#define REG_TEMP_DATA1_UI 0x0a +#define REG_ACCEL_DATA_X0_UI 0x0b +#define REG_ACCEL_DATA_X1_UI 0x0c +#define REG_ACCEL_DATA_Y0_UI 0x0d +#define REG_ACCEL_DATA_Y1_UI 0x0e +#define REG_ACCEL_DATA_Z0_UI 0x0f +#define REG_ACCEL_DATA_Z1_UI 0x10 +#define REG_GYRO_DATA_X0_UI 0x11 +#define REG_GYRO_DATA_X1_UI 0x12 +#define REG_GYRO_DATA_Y0_UI 0x13 +#define REG_GYRO_DATA_Y1_UI 0x14 +#define REG_GYRO_DATA_Z0_UI 0x15 +#define REG_GYRO_DATA_Z1_UI 0x16 +#define REG_TMST_FSYNC1 0x17 +#define REG_TMST_FSYNC2 0x18 +#define REG_ODR_LP_STATUS 0x19 +#define REG_PWR_MGMT_0 0x1f +#define REG_GYRO_CONFIG0 0x20 +#define REG_ACCEL_CONFIG0 0x21 +#define REG_TEMP_CONFIG0 0x22 +#define REG_GYRO_CONFIG1 0x23 +#define REG_ACCEL_CONFIG1 0x24 +#define REG_APEX_CONFIG0 0x25 +#define REG_APEX_CONFIG1 0x26 +#define REG_WOM_CONFIG 0x27 +#define REG_FIFO_CONFIG1 0x28 +#define REG_FIFO_CONFIG2 0x29 +#define REG_FIFO_CONFIG3 0x2a +#define REG_INT_SOURCE0 0x2b +#define REG_INT_SOURCE1 0x2c +#define REG_INT_SOURCE3 0x2d +#define REG_INT_SOURCE4 0x2e +#define REG_FIFO_LOST_PKT0 0x2f +#define REG_FIFO_LOST_PKT1 0x30 +#define REG_APEX_DATA0 0x31 +#define REG_APEX_DATA1 0x32 +#define REG_APEX_DATA2 0x33 +#define REG_APEX_DATA3 0x34 +#define REG_INTF_CONFIG0 0x35 +#define REG_INTF_CONFIG1 0x36 +#define REG_INT_STATUS_DRDY 0x39 +#define REG_INT_STATUS 0x3a +#define REG_INT_STATUS2 0x3b +#define REG_INT_STATUS3 0x3c +#define REG_FIFO_BYTE_COUNT1 0x3d +#define REG_FIFO_BYTE_COUNT2 0x3e +#define REG_FIFO_DATA_REG 0x3f +#define REG_S4S_GYRO_TPH1 0x40 +#define REG_S4S_GYRO_TPH2 0x41 +#define REG_S4S_ACCEL_TPH1 0x42 +#define REG_S4S_ACCEL_TPH2 0x43 +#define REG_S4S_RR 0x44 +#define REG_GYR_BIAS_CFG1 0x46 +#define REG_WHO_AM_I 0x75 +#define REG_S4S_ST 0x76 +#define REG_S4S_ST_CLONE 0x77 +#define REG_S4S_DT 0x78 +#define REG_BLK_SEL_W 0x79 +#define REG_MADDR_W 0x7a +#define REG_M_W 0x7b +#define REG_BLK_SEL_R 0x7c +#define REG_MADDR_R 0x7d +#define REG_M_R 0x7e + +/* MREG_TOP1 */ +#define REG_TMST_CONFIG1_MREG_TOP1 0x00 +#define REG_FIFO_CONFIG5_MREG_TOP1 0x01 +#define REG_FIFO_CONFIG6_MREG_TOP1 0x02 +#define REG_FSYNC_CONFIG_MREG_TOP1 0x03 +#define REG_INT_CONFIG0_MREG_TOP1 0x04 +#define REG_INT_CONFIG1_MREG_TOP1 0x05 +#define REG_AFSR_CONFIG0_MREG_TOP1 0x07 +#define REG_AFSR_CONFIG1_MREG_TOP1 0x08 +#define REG_TBC_RCOSC_MREG_TOP1 0x0d +#define REG_TBC_PLL_MREG_TOP1 0x0e +#define REG_ST_CONFIG_MREG_TOP1 0x13 +#define REG_SELFTEST_MREG_TOP1 0x14 +#define REG_PADS_CONFIG3_MREG_TOP1 0x17 +#define REG_TEMP_CONFIG1_MREG_TOP1 0x1c +#define REG_TEMP_CONFIG3_MREG_TOP1 0x1e +#define REG_S4S_CONFIG1_MREG_TOP1 0x1f +#define REG_S4S_CONFIG2_MREG_TOP1 0x20 +#define REG_S4S_FREQ_RATIO1_MREG_TOP1 0x21 +#define REG_S4S_FREQ_RATIO2_MREG_TOP1 0x22 +#define REG_INTF_CONFIG6_MREG_TOP1 0x23 +#define REG_INTF_CONFIG10_MREG_TOP1 0x25 +#define REG_INTF_CONFIG7_MREG_TOP1 0x28 +#define REG_OTP_CONFIG_MREG_TOP1 0x2b +#define REG_INT_SOURCE6_MREG_TOP1 0x2f +#define REG_INT_SOURCE7_MREG_TOP1 0x30 +#define REG_INT_SOURCE8_MREG_TOP1 0x31 +#define REG_INT_SOURCE9_MREG_TOP1 0x32 +#define REG_INT_SOURCE10_MREG_TOP1 0x33 +#define REG_GYRO_PWR_CFG0_MREG_TOP1 0x38 +#define REG_ACCEL_CP_CFG0_MREG_TOP1 0x39 +#define REG_APEX_CONFIG2_MREG_TOP1 0x44 +#define REG_APEX_CONFIG3_MREG_TOP1 0x45 +#define REG_APEX_CONFIG4_MREG_TOP1 0x46 +#define REG_APEX_CONFIG5_MREG_TOP1 0x47 +#define REG_APEX_CONFIG9_MREG_TOP1 0x48 +#define REG_APEX_CONFIG10_MREG_TOP1 0x49 +#define REG_APEX_CONFIG11_MREG_TOP1 0x4a +#define REG_APEX_CONFIG12_MREG_TOP1 0x67 +#define REG_ACCEL_WOM_X_THR_MREG_TOP1 0x4b +#define REG_ACCEL_WOM_Y_THR_MREG_TOP1 0x4c +#define REG_ACCEL_WOM_Z_THR_MREG_TOP1 0x4d +#define REG_GOS_USER0_MREG_TOP1 0x4e +#define REG_GOS_USER1_MREG_TOP1 0x4f +#define REG_GOS_USER2_MREG_TOP1 0x50 +#define REG_GOS_USER3_MREG_TOP1 0x51 +#define REG_GOS_USER4_MREG_TOP1 0x52 +#define REG_GOS_USER5_MREG_TOP1 0x53 +#define REG_GOS_USER6_MREG_TOP1 0x54 +#define REG_GOS_USER7_MREG_TOP1 0x55 +#define REG_GOS_USER8_MREG_TOP1 0x56 +#define REG_ST_STATUS1_MREG_TOP1 0x63 +#define REG_ST_STATUS2_MREG_TOP1 0x64 + +/* MMEM_TOP */ +#define REG_XG_ST_DATA_MMEM_TOP 0x5000 +#define REG_YG_ST_DATA_MMEM_TOP 0x5001 +#define REG_ZG_ST_DATA_MMEM_TOP 0x5002 +#define REG_XA_ST_DATA_MMEM_TOP 0x5003 +#define REG_YA_ST_DATA_MMEM_TOP 0x5004 +#define REG_ZA_ST_DATA_MMEM_TOP 0x5005 + +/* MREG_OTP */ +#define REG_OTP_CTRL7_MREG_OTP 0x2806 + +/* Bank0 REG_GYRO_CONFIG0/REG_ACCEL_CONFIG0 */ +#define SHIFT_GYRO_FS_SEL 5 +#define SHIFT_ACCEL_FS_SEL 5 +#define SHIFT_ODR_CONF 0 +#define BIT_GYRO_FSR 0x60 +#define BIT_GYRO_ODR 0x0F +#define BIT_ACCEL_FSR 0x60 +#define ACCEL_FS_SEL 3 //(-2G, +2G) +#define GYRO_FS_SEL 3 //00~11:2000dps\1000dps\500dps\250dps +#define BIT_ACCEL_ODR 0x0F +#define BIT_SENSOR_ODR_800HZ 0x06 +#define BIT_SENSOR_ODR_400HZ 0x07 +#define BIT_SENSOR_ODR_200HZ 0x08 +#define BIT_SENSOR_ODR_100HZ 0x09 +#define BIT_SENSOR_ODR_50HZ 0x0A +#define BIT_SENSOR_ODR_25HZ 0x0B +#define BIT_SENSOR_ODR_12HZ 0x0C +#define BIT_SENSOR_ODR_6HZ 0x0D +#define BIT_SENSOR_ODR_3HZ 0x0E + +/* Bank0 REG_GYRO_CONFIG1 */ +#define BIT_GYR_UI_FLT_BW_BYPASS 0x00 +#define BIT_GYR_UI_FLT_BW_180HZ 0x01 +#define BIT_GYR_UI_FLT_BW_121HZ 0x02 +#define BIT_GYR_UI_FLT_BW_73HZ 0x03 +#define BIT_GYR_UI_FLT_BW_53HZ 0x04 +#define BIT_GYR_UI_FLT_BW_34HZ 0x05 +#define BIT_GYR_UI_FLT_BW_25HZ 0x06 +#define BIT_GYR_UI_FLT_BW_16HZ 0x07 +#define BIT_GYR_UI_AVG_IND_2X 0x00 +#define BIT_GYR_UI_AVG_IND_4X 0x10 +#define BIT_GYR_UI_AVG_IND_8X 0x20 +#define BIT_GYR_UI_AVG_IND_16X 0x30 +#define BIT_GYR_UI_AVG_IND_32X 0x40 +#define BIT_GYR_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_ACCEL_CONFIG1 */ +#define BIT_ACC_FILT_BW_IND_BYPASS 0x00 +#define BIT_ACC_FILT_BW_IND_180HZ 0x01 +#define BIT_ACC_FILT_BW_IND_121HZ 0x02 +#define BIT_ACC_FILT_BW_IND_73HZ 0x03 +#define BIT_ACC_FILT_BW_IND_53HZ 0x04 +#define BIT_ACC_FILT_BW_IND_34HZ 0x05 +#define BIT_ACC_FILT_BW_IND_25HZ 0x06 +#define BIT_ACC_FILT_BW_IND_16HZ 0x07 +#define BIT_ACC_UI_AVG_IND_2X 0x00 +#define BIT_ACC_UI_AVG_IND_4X 0x10 +#define BIT_ACC_UI_AVG_IND_8X 0x20 +#define BIT_ACC_UI_AVG_IND_16X 0x30 +#define BIT_ACC_UI_AVG_IND_32X 0x40 +#define BIT_ACC_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_INT_CONFIG_REG */ +#define SHIFT_INT1_MODE 0x02 +#define SHIFT_INT1_DRIVE_CIRCUIT 0x01 +#define SHIFT_INT1_POLARITY 0x00 + +/* Bank0 REG_PWR_MGMT_0 */ +#define BIT_ACCEL_MODE_OFF 0x00 +#define BIT_ACCEL_MODE_LPM 0x02 +#define BIT_ACCEL_MODE_LNM 0x03 +#define BIT_ACCEL_MODE_MASK 0x03 +#define BIT_GYRO_MODE_OFF 0x00 +#define BIT_GYRO_MODE_STBY 0x04 +#define BIT_GYRO_MODE_LPM 0x08 +#define BIT_GYRO_MODE_LNM 0x0c +#define BIT_GYRO_MODE_MASK 0x0c +#define BIT_IDLE 0x10 +#define BIT_ACCEL_LP_CLK_SEL 0x80 + +/* Bank0 REG_SIGNAL_PATH_RESET */ +#define BIT_FIFO_FLUSH 0x04 +#define BIT_SOFT_RESET_CHIP_CONFIG 0x10 + +/* Bank0 REG_INTF_CONFIG0 */ +#define BIT_SIFS_CFG_I2C_ONLY 0x02 +#define BIT_SIFS_CFG_SPI_ONLY 0x03 +#define BIT_SENSOR_DATA_ENDIAN 0x10 +#define BIT_FIFO_COUNT_ENDIAN 0x20 +#define BIT_FIFO_COUNT_FORMAT 0x40 +#define BIT_FIFO_SREG_INVALID_IND_DIS 0x80 + +/* Bank0 REG_INTF_CONFIG1 */ +#define BIT_CLK_SEL_RC 0x00 +#define BIT_CLK_SEL_PLL 0x01 +#define BIT_CLK_SEL_DIS 0x03 +#define BIT_I3C_DDR_EN 0x04 +#define BIT_I3C_SDR_EN 0x08 +#define BIT_GYRO_AFSR_MODE_LFS 0x00 +#define BIT_GYRO_AFSR_MODE_HFS 0x20 +#define BIT_GYRO_AFSR_MODE_DYN 0x40 + +/* Bank0 REG_FIFO_CONFIG1 */ +#define BIT_FIFO_MODE_NO_BYPASS 0x00 +#define BIT_FIFO_MODE_BYPASS 0x01 +#define BIT_FIFO_MODE_STREAM 0x00 +#define BIT_FIFO_MODE_STOPFULL 0x02 + +/* Bank 0 REG_INT_SOURCE0 */ +#define BIT_INT_AGC_RDY_INT1_EN 0x01 +#define BIT_INT_FIFO_FULL_INT1_EN 0x02 +#define BIT_INT_FIFO_THS_INT1_EN 0x04 +#define BIT_INT_DRDY_INT_EN 0x08 +#define BIT_INT_RESET_DONE_INT1_EN 0x10 +#define BIT_INT_PLL_RDY_INT1_EN 0x20 +#define BIT_INT_FSYNC_INT1_EN 0x40 +#define BIT_INT_ST_DONE_INT1_EN 0x80 + +/* Bank 0 REG_INT_SOURCE1 */ +#define BIT_INT_WOM_X_INT1_EN 0x01 +#define BIT_INT_WOM_Y_INT1_EN 0x02 +#define BIT_INT_WOM_Z_INT1_EN 0x04 +#define BIT_INT_WOM_XYZ_INT1_EN (BIT_INT_WOM_X_INT1_EN | \ + BIT_INT_WOM_Y_INT1_EN | BIT_INT_WOM_Z_INT1_EN) +#define BIT_INT_SMD_INT1_EN 0x08 +#define BIT_INT_I3C_PROTCL_ERR_INT1_EN 0x40 + +/* Bank0 REG_INT_STATUS_DRDY */ +#define BIT_INT_STATUS_DRDY 0x01 + +/* Bank0 REG_INT_STATUS */ +#define BIT_INT_STATUS_AGC_RDY 0x01 +#define BIT_INT_STATUS_FIFO_FULL 0x02 +#define BIT_INT_STATUS_FIFO_THS 0x04 +#define BIT_INT_STATUS_RESET_DONE 0x10 +#define BIT_INT_STATUS_PLL_RDY 0x20 +#define BIT_INT_STATUS_FSYNC 0x40 +#define BIT_INT_STATUS_ST_DONE 0x80 + +/* Bank0 REG_INT_STATUS2 */ +#define BIT_INT_STATUS_WOM_Z 0x01 +#define BIT_INT_STATUS_WOM_Y 0x02 +#define BIT_INT_STATUS_WOM_X 0x04 +#define BIT_INT_STATUS_WOM_XYZ (BIT_INT_STATUS_WOM_X | \ + BIT_INT_STATUS_WOM_Y | BIT_INT_STATUS_WOM_Z) +#define BIT_INT_STATUS_SMD 0x08 + +/* Bank 0 REG_INT_STATUS3 */ +#define BIT_INT_STATUS_LOWG_DET 0x02 +#define BIT_INT_STATUS_FF_DET 0x04 +#define BIT_INT_STATUS_TILT_DET 0x08 +#define BIT_INT_STATUS_STEP_CNT_OVFL 0x10 +#define BIT_INT_STATUS_STEP_DET 0x20 + +/* Bank0 REG_WOM_CONFIG */ +#define BIT_WOM_EN_OFF 0x00 +#define BIT_WOM_EN_ON 0x01 +#define BIT_WOM_MODE_INITIAL 0x00 +#define BIT_WOM_MODE_PREV 0x02 +#define BIT_WOM_INT_MODE_OR 0x00 +#define BIT_WOM_INT_MODE_AND 0x04 +#define BIT_WOM_INT_DUR_LEGACY 0x00 +#define BIT_WOM_INT_DUR_2ND 0x08 +#define BIT_WOM_INT_DUR_3RD 0x10 +#define BIT_WOM_INT_DUR_4TH 0x18 + +/* Bank0 REG_APEX_CONFIG0 */ +#define BIT_DMP_SRAM_RESET_APEX 0x01 +#define BIT_DMP_INIT_EN 0x04 +#define BIT_DMP_POWER_SAVE_EN 0x08 + +/* Bank0 REG_APEX_CONFIG1 */ +#define BIT_DMP_ODR_25HZ 0x00 +#define BIT_DMP_ODR_50HZ 0x02 +#define BIT_DMP_ODR_100HZ 0x03 +#define BIT_DMP_PEDO_EN 0x08 +#define BIT_DMP_TILT_EN 0x10 +#define BIT_DMP_FF_EN 0x20 +#define BIT_DMP_SMD_EN 0x40 + +/* REG_OTP_CONFIG_MREG_TOP1 */ +#define BIT_OTP_COPY_NORMAL 0x04 +#define BIT_OTP_COPY_ST_DATA 0x0C +#define OTP_COPY_MODE_MASK 0x0C + +/* REG_INT_SOURCE6_MREG_TOP1 */ +#define BIT_INT_TLT_DET_INT1_EN 0x08 +#define BIT_INT_STEP_CNT_OVFL_INT1_EN 0x10 +#define BIT_INT_STEP_DET_INT1_EN 0x20 +#define BIT_INT_LOWG_INT1_EN 0x40 +#define BIT_INT_FF_INT1_EN 0x80 + +/* REG_TMST_CONFIG1_MREG_TOP1 */ +#define BIT_TMST_EN 0x01 +#define BIT_TMST_FSYNC_EN 0x02 +#define BIT_TMST_DELTA_EN 0x04 +#define BIT_TMST_RESOL 0x08 +#define BIT_TMST_ON_SREG_EN 0x10 +#define BIT_ODR_EN_WITHOUT_SENSOR 0x40 + +/* REG_FIFO_CONFIG5_MREG_TOP1 */ +#define BIT_FIFO_ACCEL_EN 0x01 +#define BIT_FIFO_GYRO_EN 0x02 +#define BIT_FIFO_TMST_FSYNC_EN 0x04 +#define BIT_FIFO_HIRES_EN 0x08 +#define BIT_RESUME_PARTIAL_RD 0x10 +#define BIT_WM_GT_TH 0x20 + +/* REG_SELFTEST_MREG_TOP1 */ +#define BIT_EN_AX_ST 0x01 +#define BIT_EN_AY_ST 0x02 +#define BIT_EN_AZ_ST 0x04 +#define BIT_EN_GX_ST 0x08 +#define BIT_EN_GY_ST 0x10 +#define BIT_EN_GZ_ST 0x20 +#define BIT_ACCEL_ST_EN 0x40 +#define BIT_GYRO_ST_EN 0x80 + +/* REG_ST_CONFIG_MREG_TOP1 */ +#define BIT_PD_ACCEL_CP45_ST_REG 0x80 +#define SHIFT_GYRO_ST_LIM 0 +#define SHIFT_ACCEL_ST_LIM 3 +#define SHIFT_ST_NUM_SAMPLE 6 + +/* REG_ST_STATUS1_MREG_TOP1 */ +#define BIT_DMP_AX_ST_PASS 0x02 +#define BIT_DMP_AY_ST_PASS 0x04 +#define BIT_DMP_AZ_ST_PASS 0x08 +#define BIT_DMP_ACCEL_ST_DONE 0x10 +#define BIT_DMP_ACCEL_ST_PASS 0x20 + +/* REG_ST_STATUS2_MREG_TOP1 */ +#define BIT_DMP_GX_ST_PASS 0x02 +#define BIT_DMP_GY_ST_PASS 0x04 +#define BIT_DMP_GZ_ST_PASS 0x08 +#define BIT_DMP_GYRO_ST_DONE 0x10 +#define BIT_DMP_GYRO_ST_PASS 0x20 +#define BIT_DMP_ST_INCOMPLETE 0x40 + +/* REG_OTP_CTRL7_MREG_OTP */ +#define BIT_OTP_RELOAD 0x08 +#define BIT_OTP_PWR_DOWN 0x02 + + +/* fifo data packet header */ +#define BIT_FIFO_HEAD_MSG 0x80 +#define BIT_FIFO_HEAD_ACCEL 0x40 +#define BIT_FIFO_HEAD_GYRO 0x20 +#define BIT_FIFO_HEAD_20 0x10 +#define BIT_FIFO_HEAD_TMSP_ODR 0x08 +#define BIT_FIFO_HEAD_TMSP_NO_ODR 0x04 +#define BIT_FIFO_HEAD_TMSP_FSYNC 0x0C +#define BIT_FIFO_HEAD_ODR_ACCEL 0x02 +#define BIT_FIFO_HEAD_ODR_GYRO 0x01 + +/* data definitions */ +#define FIFO_PACKET_BYTE_SINGLE 8 +#define FIFO_PACKET_BYTE_6X 16 +#define FIFO_PACKET_BYTE_HIRES 20 +#define FIFO_COUNT_BYTE 2 + +/* sensor startup time */ +#define INV_ICM43600_GYRO_START_TIME 100 +#define INV_ICM43600_ACCEL_START_TIME 100 + +/* sensor stop time */ +#define INV_ICM43600_GYRO_STOP_TIME 20 + +/* M-reg access wait tile */ +#define INV_ICM42607_MCLK_WAIT_US 20 +#define INV_ICM42607_BLK_SEL_WAIT_US 10 +#define INV_ICM42607_MADDR_WAIT_US 10 +#define INV_ICM42607_M_RW_WAIT_US 10 + +/* temperature sensor */ +#define TEMP_SCALE 100 /* scale by 100 */ +#define TEMP_LSB_PER_DEG 2 /* 2LSB=1degC */ +#define TEMP_OFFSET 25 /* 25 degC */ + +/* + * INT configurations + * Polarity: 0 -> Active Low, 1 -> Active High + * Drive circuit: 0 -> Open Drain, 1 -> Push-Pull + * Mode: 0 -> Pulse, 1 -> Latch + */ +#define INT_POLARITY 1 +#define INT_DRIVE_CIRCUIT 1 +#define INT_MODE 0 + +#define ICM42607_CHIP_ID 0x61 + +struct imu_info *icm42607_chip_probe(struct imu_ctrb *ctrb); + +#endif diff --git a/drivers/iio/imu/inv_icm42607/imu.h b/drivers/iio/imu/inv_icm42607/imu.h new file mode 100644 index 000000000000..a209447a22b4 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/imu.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __IMU_H__ +#define __IMU_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum imu_power_mode { + IMU_POWER_MODE_INIT = 0, + IMU_POWER_MODE_DOWN = 1, + IMU_POWER_ACCE_ONLY = 2, + IMU_POWER_ACCE_GYRO = 3, +}; + +enum imu_sensor_id { + IMU_SENSOR_ID_ACCE = 0, + IMU_SENSOR_ID_GYRO, + IMU_SENSOR_ID_MAX +}; + +enum imu_position_id { + IMU_P_D_0 = 0, + IMU_P_D_90 = 1, + IMU_P_D_180 = 2, + IMU_P_D_270 = 3, + IMU_D_MAX +}; + +struct imu_3axis_data { + int16_t raw[3]; + s64 ts; +}; + +struct imu_info { + char name[30]; + int id; + int (*read_id)(void *ctrbp); + int (*mode_set)(void *ctrbp, int mode); + int (*chip_init)(void *ctrbp); + int (*read_acce_raw)(void *ctrbp, void *rawdata); + int (*read_gyro_raw)(void *ctrbp, void *rawdata); + int (*read_asix_one)(void *ctrbp, int addr, int *datap); + int (*set_accel_offset)(void *ctrbp, int offset, int axis); + int (*set_gyro_offset)(void *ctrbp, int offset, int axis); +}; + +struct imu_ctrb { + struct device *dev; + struct regmap *regmap; + struct iio_dev *iio_devs[IMU_SENSOR_ID_MAX]; + struct mutex power_lock; + struct delayed_work pollingwork; + struct imu_info *chipinfo; + int irq; + int mode; + int debugon; + int position; + bool irq_enable; +}; + +struct imu_sensor { + char name[32]; + enum imu_sensor_id id; + struct imu_ctrb *ctrb; + unsigned int odr; + int calibrated; + int32_t offset_x; + int32_t offset_y; + int32_t offset_z; + uint32_t readcnt; + struct imu_3axis_data rawdata; +}; + +struct imu_reg_value_map { + uint8_t reg; + uint8_t value; +}; + +#define IMU_POLLING_TIME_MS (10) +#endif diff --git a/drivers/iio/imu/inv_icm42607/invimu_core.c b/drivers/iio/imu/inv_icm42607/invimu_core.c new file mode 100644 index 000000000000..2020d1bf569c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_core.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "icm42607.h" +#include "invimu_iio.h" +#include "invimu_core.h" +#include "imu.h" + +static ssize_t invimu_debug_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int val = -1; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + if (sscanf(buf, "%d\n", &val) != 1) { + dev_err(ctrb->dev, "debugon para err\n"); + return -1; + } + ctrb->debugon = val; + dev_info(ctrb->dev, "debugon set %d\n", val); + return size; +} + +static IIO_DEVICE_ATTR(in_imu_debug, 0200, NULL, invimu_debug_store, 0); + +static struct attribute *invimu_accel_attributes[] = { + &iio_dev_attr_in_imu_debug.dev_attr.attr, + NULL, +}; + +static const struct attribute_group invimu_accel_attribute_group = { + .attrs = invimu_accel_attributes, +}; + +static const struct iio_info invimu_acc_info = { + .attrs = &invimu_accel_attribute_group, + .read_raw = invimu_read_raw, + .read_avail = invimu_read_avail, + .write_raw = invimu_write_raw, + .write_raw_get_fmt = invimu_write_raw_get_fmt, +}; + +static struct attribute *invimu_anglvel_attributes[] = { + NULL, +}; + +static const struct attribute_group invimu_anglvel_attribute_group = { + .attrs = invimu_anglvel_attributes, +}; + +static const struct iio_info invimu_gryo_info = { + .attrs = &invimu_anglvel_attribute_group, + .read_raw = invimu_read_raw, + .read_avail = invimu_read_avail, + .write_raw = invimu_write_raw, + .write_raw_get_fmt = invimu_write_raw_get_fmt, +}; + +static void invimu_axis_transposition(struct imu_3axis_data *rawdata, int position) +{ + struct imu_3axis_data tempdata; + + memcpy(&tempdata, rawdata, sizeof(struct imu_3axis_data)); + if (position == IMU_P_D_90) { + rawdata->raw[0] = tempdata.raw[1]; + rawdata->raw[1] = 0 - tempdata.raw[0]; + rawdata->raw[2] = tempdata.raw[2]; + } else if (position == IMU_P_D_270) { + rawdata->raw[0] = tempdata.raw[1]; + rawdata->raw[1] = tempdata.raw[0]; + rawdata->raw[2] = tempdata.raw[2]; + } else if (position == IMU_P_D_180) { + rawdata->raw[0] = tempdata.raw[0]; + rawdata->raw[1] = -tempdata.raw[1]; + rawdata->raw[2] = tempdata.raw[2]; + } +} + +static void invimu_axis_print(struct imu_ctrb *ctrb, struct imu_sensor *sensor) +{ + int print_on = 0; + + if (ctrb == NULL || sensor == NULL) + return; + + print_on = (sensor->readcnt != 0) && ((sensor->readcnt % 6000) == 0); + print_on = (print_on) || (ctrb->debugon); + if (print_on) { + if (sensor->id == IMU_SENSOR_ID_ACCE) { + dev_info(ctrb->dev, "acce read cnt=%d, raw=%d,%d,%d\n", sensor->readcnt, + sensor->rawdata.raw[0], + sensor->rawdata.raw[1], + sensor->rawdata.raw[2]); + dev_info(ctrb->dev, "acce calib offset=%d,%d,%d\n", + sensor->offset_x, sensor->offset_y, sensor->offset_z); + } + if (sensor->id == IMU_SENSOR_ID_GYRO) { + dev_info(ctrb->dev, "gyro read cnt=%d, raw=%d,%d,%d\n", sensor->readcnt, + sensor->rawdata.raw[0], + sensor->rawdata.raw[1], + sensor->rawdata.raw[2]); + dev_info(ctrb->dev, "gyro calib offset=%d,%d,%d\n", + sensor->offset_x, sensor->offset_y, sensor->offset_z); + } + } +} + +static int invimu_data_report(struct imu_ctrb *ctrb) +{ + int i, ret = 0; + struct iio_dev *indio_dev; + struct imu_sensor *sensor; + struct imu_3axis_data rawdata; + + if (ctrb == NULL) + return -1; + + for (i = 0; i < IMU_SENSOR_ID_MAX; i++) { + indio_dev = ctrb->iio_devs[i]; + sensor = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) { + memset(&rawdata, 0, sizeof(struct imu_3axis_data)); + sensor->readcnt++; + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + ret = ctrb->chipinfo->read_acce_raw(ctrb, &rawdata); + break; + case IMU_SENSOR_ID_GYRO: + ret = ctrb->chipinfo->read_gyro_raw(ctrb, &rawdata); + break; + default: + continue; + } + invimu_axis_transposition(&rawdata, ctrb->position); + memcpy(&sensor->rawdata, &rawdata, sizeof(struct imu_3axis_data)); + iio_push_to_buffers_with_timestamp(indio_dev, + &rawdata, ktime_get_boottime_ns()); + invimu_axis_print(ctrb, sensor); + //invimu_calibrator_process(ctrb, sensor); + } + } + return ret; +} + +static void invimu_work_handler(struct work_struct *work) +{ + struct imu_ctrb *ctrb; + + ctrb = (struct imu_ctrb *)container_of(work, struct imu_ctrb, pollingwork.work); + invimu_data_report(ctrb); + schedule_delayed_work(&ctrb->pollingwork, msecs_to_jiffies(IMU_POLLING_TIME_MS)); +} + +int invimu_chip_init(struct imu_ctrb *ctrb, bool use_spi) +{ + if (ctrb == NULL) + return -1; + + return ctrb->chipinfo->chip_init(ctrb); +} +EXPORT_SYMBOL_GPL(invimu_chip_init); + +static int invimu_parse_dt_parameters(struct device *dev, struct imu_ctrb *ctrb) +{ + int position = 0; + struct device_node *np = dev->of_node; + + ctrb->position = 0; + if (np != NULL) { + if (of_property_read_s32(np, "position", &position) == 0) { + if (position < IMU_P_D_0 || position >= IMU_D_MAX) + goto HWCIMU_PARSE_DT_ERR; + else + ctrb->position = position; + } else { + goto HWCIMU_PARSE_DT_ERR; + } + } else { + goto HWCIMU_PARSE_DT_ERR; + } + dev_info(ctrb->dev, "imu position sets %d\n", ctrb->position); + return 0; + +HWCIMU_PARSE_DT_ERR: + dev_err(ctrb->dev, "imu position sets default %d\n", ctrb->position); + return -ENODEV; +} + +int invimu_core_probe(struct device *dev, struct regmap *regmap, int irq, bool use_spi) +{ + int i, ret = 0; + struct imu_ctrb *ctrb; + struct imu_info *info = NULL; + + ctrb = devm_kzalloc(dev, sizeof(*ctrb), GFP_KERNEL); + if (!ctrb) + return -ENOMEM; + + dev_set_drvdata(dev, (void *)ctrb); + mutex_init(&ctrb->power_lock); + ctrb->dev = dev; + ctrb->regmap = regmap; + ctrb->irq = irq; + ctrb->debugon = 0; + dev_info(ctrb->dev, "probe start\n"); + + info = icm42607_chip_probe(ctrb); + if (info == NULL) { + dev_err(ctrb->dev, "no chip probed!\n"); + return -ENODEV; + } + ctrb->chipinfo = info; + + ret = invimu_chip_init(ctrb, use_spi); + if (ret) { + dev_err(ctrb->dev, "chip err\n"); + return ret; + } + + for (i = 0; i < IMU_SENSOR_ID_MAX; i++) { + ctrb->iio_devs[i] = invimu_alloc_iiodev(ctrb, + &invimu_acc_info, &invimu_gryo_info, i, ctrb->chipinfo->name); + if (!ctrb->iio_devs[i]) { + dev_err(ctrb->dev, "iio alloc err\n"); + return -ENOMEM; + } + ret = devm_iio_device_register(ctrb->dev, ctrb->iio_devs[i]); + if (ret) { + dev_err(ctrb->dev, "iio register err\n"); + return ret; + } + } + + invimu_parse_dt_parameters(dev, ctrb); + INIT_DELAYED_WORK(&ctrb->pollingwork, invimu_work_handler); + + dev_info(ctrb->dev, "probe end\n"); + return 0; +} +EXPORT_SYMBOL_GPL(invimu_core_probe); + +MODULE_DESCRIPTION("inv imu driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42607/invimu_core.h b/drivers/iio/imu/inv_icm42607/invimu_core.h new file mode 100644 index 000000000000..b5cd6b1a912c --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_core.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ +#ifndef __INVIMU_CORE_H +#define __INVIMU_CORE_H + +int invimu_chip_init(struct imu_ctrb *ctrb, bool use_spi); +int invimu_core_probe(struct device *dev, struct regmap *regmap, int irq, bool use_spi); +#endif diff --git a/drivers/iio/imu/inv_icm42607/invimu_i2c.c b/drivers/iio/imu/inv_icm42607/invimu_i2c.c new file mode 100644 index 000000000000..0a1800cefc98 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_i2c.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imu.h" +#include "invimu_core.h" + +static bool invimu_writeable_reg(struct device *dev, unsigned int reg); +static bool invimu_volatile_reg(struct device *dev, unsigned int reg); + +const struct regmap_config invimu_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = invimu_writeable_reg, + .volatile_reg = invimu_volatile_reg, +}; + +static bool invimu_writeable_reg(struct device *dev, unsigned int reg) +{ + return true; +} + +static bool invimu_volatile_reg(struct device *dev, unsigned int reg) +{ + return true; +} + +static int invimu_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &invimu_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap: %p\n", regmap); + return PTR_ERR(regmap); + } + return invimu_core_probe(&client->dev, regmap, client->irq, false); +} + +static int invimu_suspend(struct device *dev) +{ + dev_info(dev, "inv_imu suspend\n"); + return 0; +} + +static int invimu_resume(struct device *dev) +{ + int ret; + struct imu_ctrb *ctrb = dev_get_drvdata(dev); + + ret = invimu_chip_init(ctrb, false); + dev_info(dev, "inv_imu resume:%d\n", ret); + return ret; +} + +static const struct dev_pm_ops invimu_pm_ops = { + .suspend = invimu_suspend, + .resume = invimu_resume, +}; + +#ifdef CONFIG_OF +static const struct of_device_id invimu_of_match[] = { + { .compatible = "inv,icm42607"}, + { }, +}; +MODULE_DEVICE_TABLE(of, invimu_of_match); +#endif + +static struct i2c_driver invimu_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "invimu_i2c", + .pm = &invimu_pm_ops, + .of_match_table = of_match_ptr(invimu_of_match), + }, + .probe = invimu_i2c_probe, +}; + +static int32_t __init invimu_driver_init(void) +{ + return i2c_add_driver(&invimu_i2c_driver); +} + +static void __exit invimu_driver_exit(void) +{ + i2c_del_driver(&invimu_i2c_driver); +} + +late_initcall(invimu_driver_init); +module_exit(invimu_driver_exit); + +MODULE_DESCRIPTION("INV ICM42607 I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42607/invimu_iio.c b/drivers/iio/imu/inv_icm42607/invimu_iio.c new file mode 100644 index 000000000000..ab5dfeb5526f --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_iio.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icm42607.h" +#include "imu.h" +#include "invimu_iio.h" + +#define INVIMU_CHANNEL(_type, _address, _channel2, _scan_index) \ +{ \ + .type = _type, \ + .address = _address, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _scan_index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const int icm42607_avail_acc_sample_freqs[] = {100}; +static const int icm42607_avail_gyro_sample_freqs[] = {100}; + +int invimu_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ctrb->chipinfo->read_asix_one(ctrb, chan->address, val); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (sensor->id == IMU_SENSOR_ID_ACCE) { + *val = 980665ULL; + *val2 = 100000ULL * 2048;/* scale = 9.8 / 2048 */ + } else if (sensor->id == IMU_SENSOR_ID_GYRO) { + *val = 314159ULL; + *val2 = 1800000ULL * 143;/* scale = pi / (180 * 14.3) */ + } else { + return -EINVAL; + } + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OFFSET: + if (chan->channel2 == IIO_MOD_X) + *val = sensor->offset_x; + else if (chan->channel2 == IIO_MOD_Y) + *val = sensor->offset_y; + else if (chan->channel2 == IIO_MOD_Z) + *val = sensor->offset_z; + else + return -EINVAL; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = sensor->odr; + return IIO_VAL_INT; + default: + return -EINVAL; + } + return IIO_VAL_INT; +} +EXPORT_SYMBOL_GPL(invimu_read_raw); + +int invimu_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT; + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + *vals = icm42607_avail_acc_sample_freqs; + *length = ARRAY_SIZE(icm42607_avail_acc_sample_freqs); + return IIO_AVAIL_LIST; + case IMU_SENSOR_ID_GYRO: + *vals = icm42607_avail_gyro_sample_freqs; + *length = ARRAY_SIZE(icm42607_avail_gyro_sample_freqs); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(invimu_read_avail); + +int invimu_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + break; + case IIO_CHAN_INFO_SAMP_FREQ: + sensor->odr = val; + break; + case IIO_CHAN_INFO_OFFSET: + switch (chan->channel2) { + case IIO_MOD_X: + sensor->offset_x = val; + break; + case IIO_MOD_Y: + sensor->offset_y = val; + break; + case IIO_MOD_Z: + sensor->offset_z = val; + break; + default: + return -EINVAL; + } + + if (sensor->id == IMU_SENSOR_ID_ACCE) + return ctrb->chipinfo->set_accel_offset(ctrb, val, chan->channel2); + else if (sensor->id == IMU_SENSOR_ID_GYRO) + return ctrb->chipinfo->set_gyro_offset(ctrb, val, chan->channel2); + else + return -EINVAL; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_GPL(invimu_write_raw); + +int invimu_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(invimu_write_raw_get_fmt); + +static const struct iio_chan_spec invimu_acc_channels[] = { + INVIMU_CHANNEL(IIO_ACCEL, 0, IIO_MOD_X, 0), + INVIMU_CHANNEL(IIO_ACCEL, 1, IIO_MOD_Y, 1), + INVIMU_CHANNEL(IIO_ACCEL, 2, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec invimu_gyro_channels[] = { + INVIMU_CHANNEL(IIO_ANGL_VEL, 3, IIO_MOD_X, 0), + INVIMU_CHANNEL(IIO_ANGL_VEL, 4, IIO_MOD_Y, 1), + INVIMU_CHANNEL(IIO_ANGL_VEL, 5, IIO_MOD_Z, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static int invimu_buffer_preenable(struct iio_dev *indio_dev) +{ + int mode, ret = 0; + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + mutex_lock(&ctrb->power_lock); + + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_GYRO]) ? + IMU_POWER_ACCE_GYRO : IMU_POWER_ACCE_ONLY; + break; + case IMU_SENSOR_ID_GYRO: + mode = IMU_POWER_ACCE_GYRO; + break; + default: + mode = IMU_POWER_MODE_DOWN; + break; + } + ret = ctrb->chipinfo->mode_set(ctrb, mode); + + if (ret == 0 && (mode == IMU_POWER_ACCE_ONLY || mode == IMU_POWER_ACCE_GYRO)) + schedule_delayed_work(&ctrb->pollingwork, msecs_to_jiffies(IMU_POLLING_TIME_MS)); + + mutex_unlock(&ctrb->power_lock); + return ret; +} + +static int invimu_buffer_postdisable(struct iio_dev *indio_dev) +{ + int ret = 0, mode = 0; + struct imu_sensor *sensor = iio_priv(indio_dev); + struct imu_ctrb *ctrb = sensor->ctrb; + + mutex_lock(&ctrb->power_lock); + + switch (sensor->id) { + case IMU_SENSOR_ID_ACCE: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_GYRO]) ? + IMU_POWER_ACCE_GYRO : IMU_POWER_MODE_DOWN; + break; + case IMU_SENSOR_ID_GYRO: + mode = iio_buffer_enabled(ctrb->iio_devs[IMU_SENSOR_ID_ACCE]) ? + IMU_POWER_ACCE_ONLY : IMU_POWER_MODE_DOWN; + break; + default: + mode = IMU_POWER_MODE_DOWN; + break; + } + ret = ctrb->chipinfo->mode_set(ctrb, mode); + if (ret == 0 && mode == IMU_POWER_MODE_DOWN) + cancel_delayed_work(&ctrb->pollingwork); + + mutex_unlock(&ctrb->power_lock); + return ret; +} + +static const struct iio_buffer_setup_ops invimu_buffer_ops = { + .preenable = invimu_buffer_preenable, + .postdisable = invimu_buffer_postdisable, +}; + +struct iio_dev *invimu_alloc_iiodev(struct imu_ctrb *ctrb, + const struct iio_info *acce_iio_info, const struct iio_info *gyro_iio_info, + enum imu_sensor_id id, char *name) +{ + struct imu_sensor *sensor; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(ctrb->dev, sizeof(*sensor)); + if (!indio_dev) + return NULL; + + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + + devm_iio_kfifo_buffer_setup(ctrb->dev, indio_dev, &invimu_buffer_ops); + + sensor = iio_priv(indio_dev); + sensor->id = id; + sensor->ctrb = ctrb; + + switch (id) { + case IMU_SENSOR_ID_ACCE: + sensor->odr = icm42607_avail_acc_sample_freqs[0]; + indio_dev->info = acce_iio_info; + indio_dev->channels = invimu_acc_channels; + indio_dev->num_channels = ARRAY_SIZE(invimu_acc_channels); + scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", name); + break; + case IMU_SENSOR_ID_GYRO: + sensor->odr = icm42607_avail_gyro_sample_freqs[0]; + indio_dev->info = gyro_iio_info; + indio_dev->channels = invimu_gyro_channels; + indio_dev->num_channels = ARRAY_SIZE(invimu_gyro_channels); + scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", name); + break; + default: + return NULL; + } + + indio_dev->name = sensor->name; + return indio_dev; +} +EXPORT_SYMBOL_GPL(invimu_alloc_iiodev); diff --git a/drivers/iio/imu/inv_icm42607/invimu_iio.h b/drivers/iio/imu/inv_icm42607/invimu_iio.h new file mode 100644 index 000000000000..f4948a201bc1 --- /dev/null +++ b/drivers/iio/imu/inv_icm42607/invimu_iio.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#ifndef __INVIMU_IIO_H +#define __INVIMU_IIO_H + +#include +#include +#include +#include +#include +#include +#include +#include + +int invimu_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask); + +int invimu_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask); + +int invimu_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask); + +int invimu_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long mask); + +struct iio_dev *invimu_alloc_iiodev(struct imu_ctrb *ctrb, + const struct iio_info *acce_iio_info, const struct iio_info *gyro_iio_info, + enum imu_sensor_id id, char *name); + +#endif diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index e5d8fbdcc254..f2fb15eeaf7e 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -32,6 +32,8 @@ config CROS_EC_MKBP_PROXIMITY To compile this driver as a module, choose M here: the module will be called cros_ec_mkbp_proximity. +source "drivers/iio/proximity/nds03/Kconfig" + config ISL29501 tristate "Intersil ISL29501 Time Of Flight sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index cc838bb5408a..ae0028d6729a 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o +obj-$(CONFIG_DTOF_NDS03) += nds03/ obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o diff --git a/drivers/iio/proximity/nds03/Kconfig b/drivers/iio/proximity/nds03/Kconfig new file mode 100644 index 000000000000..da8d3c8c258c --- /dev/null +++ b/drivers/iio/proximity/nds03/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config DTOF_NDS03 + tristate "NDS03 I2C DEVICE" + depends on I2C && SYSFS + help + Using I2C diff --git a/drivers/iio/proximity/nds03/Makefile b/drivers/iio/proximity/nds03/Makefile new file mode 100644 index 000000000000..5f23d3d56d41 --- /dev/null +++ b/drivers/iio/proximity/nds03/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the nds03 drivers. +# + +obj-$(CONFIG_DTOF_NDS03) += nds03.o +nds03-y += nds03_module.o nds03_platform.o nds03_module_i2c.o nds03_iio.o \ + nds03_dev.o nds03_data.o \ + nds03_comm.o nds03_calib.o diff --git a/drivers/iio/proximity/nds03/nds03.h b/drivers/iio/proximity/nds03/nds03.h new file mode 100644 index 000000000000..ef789ed72047 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03.h @@ -0,0 +1,104 @@ +/*! + @file nds03.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_H +#define __NDS03_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* nds03 sdk */ +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" +#include "nds03_def.h" + +#define TOF_NDS03_DRV_NAME "tof_nds03" +#define DRIVER_VERSION "1.0.4" +#define TOF_NDS03_MAJOR 255 +#define MAX_POS_BITS 32 + +/*! use debug */ +extern int nds03_enable_debug; + +#define nds03_dbgmsg(str, ...) \ + do { \ + if (nds03_enable_debug > 0) \ + printk("%s: " str, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + + +#define nds03_info(str, ...) \ + pr_info("%s: " str , __FUNCTION__, ##__VA_ARGS__) + +#define nds03_errmsg(str, ...) \ + pr_err("%s: " str, __FUNCTION__, ##__VA_ARGS__) + +#define nds03_warnmsg(str, ...) \ + pr_warn("%s: " str,__FUNCTION__, ##__VA_ARGS__) + +struct nds03_context { + + /*!< multiple device id 0 based*/ + int id; + + /*!< misc device name */ + char name[64]; + + struct i2c_client * client; + + /*!< nds03 device info */ + NDS03_Dev_t g_nds03_device; + + /*!< main dev mutex/lock */ + struct mutex work_mutex; + + // /*!< work for pseudo irq polling check */ + struct delayed_work dwork; + struct work_struct irq_work; + // /*!< input device used for sending event */ + struct input_dev *idev; + + /*!< intr gpio number */ + int irq; + + bool remove_flag; + /// /* user control configuration parameter */ + /*!< measure mode irq or poll*/ + atomic_t meas_mode; + /*!< rescheduled time use in poll mode */ + atomic_t poll_delay_ms; + /*!< use ctrl measure state */ + atomic_t is_meas; + /*!< calibtion result of the deivce */ + int calib_result; + /*!< open input file descriptor count*/ + int fd_open_count; + struct iio_dev *indio_dev; + struct nds03_iio_dev *iio; +}; + +int nds03_common_probe(struct nds03_context * ctx); +int nds03_common_remove(struct nds03_context * ctx); +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open); +int nds03_sensor_init(struct nds03_context *ctx); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_calib.c b/drivers/iio/proximity/nds03/nds03_calib.c new file mode 100644 index 000000000000..ea47934653af --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.c @@ -0,0 +1,275 @@ +/** + * @file nds03_calib.c + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" + +/** + * @brief NDS03 Get Offset Calib Depth MM + * 获取offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + + return ret; +} + +/** + * @brief NDS03 Set Offset Calib Depth MM + * 设置offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (calib_depth_mm == 0) + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, &calib_depth_mm)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Offset Calibration Check + * Offset 标定检查 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +static NDS03_Error NDS03_OffsetCalibrationCheck(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ref_histo_max, depth[2]; + uint8_t depth_flag; + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DEPTH_FLAG, &depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 1)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[0] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 2)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[1] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + if (ret == NDS03_ERROR_NONE && ((depth[0] + NDS03_OFFSET_DEPTH_ERROR_TH < depth[1]) || + (depth[0] > depth[1] + NDS03_OFFSET_DEPTH_ERROR_TH) || + depth[0] == NDS03_DEPTH_INVALID_VALUE || depth[1] == NDS03_DEPTH_INVALID_VALUE)) { + ret = NDS03_ERROR_OFFSET_ERROR; + NX_PRINTF("depth[0]:%d depth[1]:%d\r\n", depth[0], depth[1]); + } + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 不可以指定标定距离,使用默认距离,如果没有修改,那值默认是500mm + * + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient_bg:%d\r\n", ambient_bg); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 可以指定标定距离 + * + * @param pNxDevice 设备模组 + * @param calib_depth_mm 标定距离 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH){ + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d \r\n", ambient_bg); + return ret; + } + CHECK_RET(NDS03_SetOffsetCalibDepthMM(pNxDevice, calib_depth_mm)); + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Read Xtalk Data + * 读取NDS03串扰数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +static NDS03_Error NDS03_ReadXtalkData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr; + uint16_t rbuf[240]; + uint8_t *rbuf_ptr = (uint8_t *)rbuf; + uint32_t size = 240 * 2; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, 0xEC, &addr)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, rbuf_ptr, + ((size-rsize)>_size) ? _size:(size-rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf_ptr += _size; + addr += _size; + rsize += _size; + } + for (int i = 80; i < 240; i++) { + if (rbuf[i] > 10000) + return -14; + } + + return ret; +} + +/** + * @brief NDS03 Xtalk Calibration + * NDS03串扰/盖板标定 + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: xtalk标定失败 + */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE, calib_state = NDS03_ERROR_NONE; + uint16_t ambient_bg,ref_histo_max; + uint8_t cnt = 2; + int8_t check_xtalk_state = 0; + + NX_PRINTF("%s Start!\r\n", __func__); + do { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d\r\n", ambient_bg); + return ret; + } + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_XTALK_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_XTALK_CALIB, 5000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + if (pNxDevice->chip_info.fw_version == 0x10203) { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + check_xtalk_state = NDS03_ReadXtalkData(pNxDevice); + } + + } while (cnt-- && check_xtalk_state != 0); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&calib_state)); + ret = check_xtalk_state ? check_xtalk_state : (ret | calib_state) & + (NDS03_CALIB_ERROR_XTALK_OVERFLOW | NDS03_CALIB_ERROR_XTALK_EXCESSIVE); + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Get Xtalk Value + * 获取标定串扰值 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_XTALK, xtalk_value)); + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_calib.h b/drivers/iio/proximity/nds03/nds03_calib.h new file mode 100644 index 000000000000..453047f36124 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.h @@ -0,0 +1,42 @@ +/** + * @file nds03_calib.h + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ + +#ifndef __NDS03_CALIB_H__ +#define __NDS03_CALIB_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Calibration_Group NDS03 Calibration Functions + * @brief NDS03 Calibration Functions + * @{ + */ + +/** 获取offset标定距离 */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm); +/** 设置offset标定距离 */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** Offset标定函数(无标定距离设置) */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice); +/** Offset标定函数(有标定距离设置) */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** XTalk标定 */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice); +/** 获取标定串扰值 */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value); + +/** @} NDS03_Calibration_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_comm.c b/drivers/iio/proximity/nds03/nds03_comm.c new file mode 100644 index 000000000000..1b94a4d77c19 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.c @@ -0,0 +1,385 @@ +/** + * @file nds03_comm.c + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM != PLATFORM_LINUX_DRIVER +#include +#include +#else +#include +#endif +#include "nds03_dev.h" +#include "nds03_comm.h" +#include "nds03_def.h" +#include "nds03_platform.h" + +/** + * @brief NDS03 Delay 1ms + * @param ms 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms) +{ + return nds03_delay_1ms(&pNxDevice->platform, ms); +} + +/** + * @brief NDS03 Delay 10us + * @param us 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us) +{ + return nds03_delay_10us(&pNxDevice->platform, us); +} + +/** + * @brief NDS03 Get System Clk Ms +* @param pNxDevice 模组设备 + * @param time_ms 获取时间(ms) + * @return void + */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_get_system_clk_ms(&pNxDevice->platform, time_ms); + + return ret; +} + +/** + * @brief NDS03 Set XShut Pin Level + * 设置xshut引脚的电平 + * @param pNxDevice 模组设备 + * @param level xshut引脚电平,0为低电平,1为高电平 + * @return void + */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level) +{ + return nds03_set_xshut_pin_level(&pNxDevice->platform, level); +} + +/** + * @brief 获取当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 获取的频率 + * @return + */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq) +{ + return nds03_i2c_get_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 设置当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 设置的频率 + * @return + */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq) +{ + return nds03_i2c_set_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 半字,即2个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_HalfWordDataFmtChange(uint16_t *buf, uint16_t buf_num) +{ + uint16_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + } +} + +/** + * @brief 1字,即4个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_WordDataFmtChange(uint32_t *buf, uint16_t buf_num) +{ + uint32_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + *pu8buf++ = (tmp >> 16); + *pu8buf++ = (tmp >> 24); + } +} + +/** + * @brief Write n Words to NDS03 + * 对NDS03的寄存器写N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 存放寄存器值的指针 + * @param len: 写数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + + return ret; +} + +/** + * @brief Read n Words from NDS03 + * 对NDS03的寄存器读N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 存放寄存器值的指针 + * @param len: 读数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + + return ret; +} + +/** + * @brief Write 1 Byte to NDS03 + * 对NDS03的寄存器写1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, &wdata, 1); + + return ret; +} + +/** + * @brief Read 1 Byte from NDS03 + * 对NDS03的寄存器读1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, rdata, 1); + + return ret; +} + +/** + * @brief Write N bytes By Half-Word to NDS03 + * 对NDS03的寄存器写N个字节,使用半字写的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0) { + NDS03_HalfWordDataFmtChange(wdata, size / 2); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_HalfWordDataFmtChange(wdata, size / 2); + } + + return ret; +} + +/** + * @brief Read N Bytes By Half-World from NDS03 + * 对NDS03的寄存器读N个字节,使用半字读的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_HalfWordDataFmtChange(rdata, size / 2); + } + + return ret; +} + +/** + * @brief Write 2 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 2 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8); + } + + return ret; +} + +/** + * @brief Write N Bytes By Word to NDS03 + * 对NDS03的寄存器写N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, + uint32_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0) { + NDS03_WordDataFmtChange(wdata, size / 4); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_WordDataFmtChange(wdata, size / 4); + } + + return ret; +} + +/** + * @brief Read N Bytes By Word from NDS03 + * 对NDS03的寄存器读N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_WordDataFmtChange(rdata, size / 4); + } + + return ret; +} + +/** + * @brief Write 4 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + tmp[2] = (wdata >> 16) & 0xFF; + tmp[3] = (wdata >> 24) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 4 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint32_t)tmp[0] | ((uint32_t)tmp[1] << 8) | + ((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[3] << 24); + } + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_comm.h b/drivers/iio/proximity/nds03/nds03_comm.h new file mode 100644 index 000000000000..43630b61e436 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.h @@ -0,0 +1,71 @@ +/** + * @file nds03_comm.h + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ +#ifndef __NDS03_COMM_H__ +#define __NDS03_COMM_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Communication_Group NDS03 Communication Functions + * @brief NDS03 Communication Functions + * @{ + */ + +/** 延时时间(ms) */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms); + +/** 延时时间(10us) */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us); + +/** 设置xshut引脚的电平 */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level); + +/** NDS03设置i2c频率 */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq); +/** NDS03获取i2c频率 */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq); +/** 对NDS03寄存器写N个字节 */ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节 */ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata); +/** 对NDS03寄存器写N个字节,使用半字方式 */ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用半字方式 */ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata); +/** 对NDS03寄存器写N个字节,使用字方式 */ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用字方式 */ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata); +/** 获取系统时钟时间(ms) */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms); + +/** @} NDS03_Communication_Group */ + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_data.c b/drivers/iio/proximity/nds03/nds03_data.c new file mode 100644 index 000000000000..dbc2f1824d3c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.c @@ -0,0 +1,238 @@ + +/** + * @file nds03_data.c + * @author tongsheng.tang + * @brief NDS03 get depth data functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_def.h" +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" + +/** + * @brief NDS03 Get Ranging Data Ready + * 检测NDS03测距是否完成 + * @param pNxDevice 模组设备 + * @return int8_t + * @retval 函数执行结果 + * - 0:未完成 + * 1: 完成 + * - ::NDS03_ERROR_I2C:IIC通讯错误/数据异常 + */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf_valid_flag = 0x00; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &buf_valid_flag)); + + if (buf_valid_flag == NDS03_DEPTH_DATA_FLAG) + return 1; + + return ret; +} + +/** + * @brief NDS03 Start Single Measurement + * 发送开始单次测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + + return ret; +} + +/** + * @brief NDS03 Start Continuous Measurement + * 发送开始连续测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag == 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_DAT_REQ, NDS03_DEPTH_CONTINUOUS_FLAG)); + pNxDevice->config.continuous_flag = 1; + } + + return ret; +} + +/** + * @brief NDS03 Stop Continuous Measurement + * 发送结束连续测量信号,用于连续模式 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag != 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DATA_REQ_IDLE)); + /* 等待测量完成 */ + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_CONTINUOUS_FLAG, 200)); + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + pNxDevice->config.continuous_flag = 0; + } + + return ret; +} + +/** + * @brief NDS03 Clear Data Valid Flag + * 清除NDS03测量数据的有效位,取完一次数 + * 据做的操作,通知NDS03数据已读取 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + + return ret; +} + +/** + * @brief NDS03 Read Ranging Data + * 读取NDS03寄存器获取测量数据,数据更新于一次测距完成后 + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + +#if NDS03_TARGET_MAX_NUM == 1 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 2 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 2 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 3 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 3 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM >= 4 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 4 * sizeof(pNxDevice->ranging_data[0]))); +#endif + + return ret; +} + +/** + * @brief NDS03 Get Continuous Ranging Data + * 连续模式下,从NDS03中获取一次深度数据, + * 需要与NDS03_StartContinuousMeasurement函数搭配 + * @param pNxDevice 模组设备 + * @param pData 获取到的深度和幅度数据 + * @return int32_t + */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t data_cnt; + uint32_t retry_cnt = 20000; + + /* 等待测量完成 */ + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &data_cnt)); + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + } while (data_cnt == pNxDevice->data_cnt && --retry_cnt); + pNxDevice->data_cnt = data_cnt; + if (retry_cnt != 0) { + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + } else { + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Get Single Ranging Data + * NDS03中获取一次深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t timeout_ms = pNxDevice->config.range_frame_time_us / 1000; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + /* 等待测量完成 */ + timeout_ms = (timeout_ms < 200) ? 200 : timeout_ms; + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_DATA_FLAG, timeout_ms)); + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + +/** + * @brief NDS03 Get Interrupt Ranging Data + * NDS03中获取一次中断深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_data.h b/drivers/iio/proximity/nds03/nds03_data.h new file mode 100644 index 000000000000..4475e4c4dbd3 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.h @@ -0,0 +1,46 @@ +/** + * @file nds03_data.h + * @author tongsheng.tang + * @brief NDS03 communication and data handling functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DATA_H__ +#define __NDS03_DATA_H__ + +#include "nds03_def.h" +/** @defgroup NDS03_Data_Group NDS03 Data Functions + * @brief NDS03 Data Functions + * @{ + */ + +/** 检测NDS03测距是否完成 */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice); +/** 发送开始单次测量信号 */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送开始连续测量信号 */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送结束连续测量信号 */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 清除数据有效位 */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice); +/** 读取深度和幅度值 */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice); +/** 获取连续测量深度和幅度值 */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次测量深度和幅度值 */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次中断数据 */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice); + +/** @} NDS03_Data_Group */ + +#endif // __NDS03_DATA_H__ diff --git a/drivers/iio/proximity/nds03/nds03_def.h b/drivers/iio/proximity/nds03/nds03_def.h new file mode 100644 index 000000000000..047c75ba7929 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_def.h @@ -0,0 +1,308 @@ +/** + * @file nds03_def.h + * @author tongsheng.tang + * @brief NDS03's Macro definition and data structure + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DEF_H__ +#define __NDS03_DEF_H__ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#else +#include +#endif +#include "nds03_platform.h" + +#ifndef DEBUG_INFO +#define DEBUG_INFO 0 /** 调试信息打印开关 */ +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include +#define NX_PRINTF(fmt, ...) do { if (DEBUG_INFO) printf(fmt, ##__VA_ARGS__); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#define NX_PRINTF(fmt, args...) do { if (DEBUG_INFO) printk(fmt, ##args); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_C51 +#define NX_PRINTF(fmt, ...) + +#else +#define NX_PRINTF(fmt, ...) +#endif + +/** @defgroup NDS03_Global_Define_Group NDS03 Defines + * @brief NDS03 Defines + * @{ + */ + +/** @defgroup NDS03_Reg_Group NDS03 Register Defines + * @brief NDS03 Register Defines + * @{ + */ +#define NDS03_REG_DEV_ADDR (0x1E) /** 模组的设备地址 */ + +#define NDS03_REG_STATE (0x20) /** 模组运行状态寄存器 */ +#define NDS03_REG_DATA_CNT (0x21) /** 模组测距次数计数值 */ +#define NDS03_REG_FW_VER (0x24) /** 模组固件版本号寄存器 */ + +#define NDS03_REG_RANGE_STATE (0x28) /** 测距状态码 */ +#define NDS03_REG_CALIB_STATE (0x29) /** 标定状态码 */ +#define NDS03_REG_THERM (0x2A) /** 温度值 */ +#define NDS03_REG_AMBIENT (0x2C) /** 环境光值 */ + +#define NDS03_REG_DEPTH (0x30) /** 深度值 */ +#define NDS03_REG_CONFI (0x32) /** 置信度 */ +#define NDS03_REG_COUNT (0x34) /** 计数值 */ +#define NDS03_REG_CRATE (0x36) /** 计数率 */ +#define NDS03_REG_DEPTH2 (0x38) /** 深度值 */ +#define NDS03_REG_CONFI2 (0x3A) /** 置信度 */ +#define NDS03_REG_COUNT2 (0x3C) /** 计数值 */ +#define NDS03_REG_CRATE2 (0x3E) /** 计数率 */ +#define NDS03_REG_DEPTH3 (0x40) /** 深度值 */ +#define NDS03_REG_CONFI3 (0x42) /** 置信度 */ +#define NDS03_REG_COUNT3 (0x44) /** 计数值 */ +#define NDS03_REG_CRATE3 (0x46) /** 计数率 */ +#define NDS03_REG_DEPTH4 (0x48) /** 深度值 */ +#define NDS03_REG_CONFI4 (0x4A) /** 置信度 */ +#define NDS03_REG_COUNT4 (0x4C) /** 计数值 */ +#define NDS03_REG_CRATE4 (0x4E) /** 计数率 */ + +#define NDS03_REG_DAT_REQ (0x50) /** 获取深度请求寄存器 */ +#define NDS03_REG_DAT_VAL (0x51) /** 获取数据命令有效寄存器 */ +#define NDS03_REG_CMD_REQ (0x52) /** 命令请求寄存器 */ +#define NDS03_REG_CMD_VAL (0x53) /** 命令完成寄存器 */ +#define NDS03_REG_CMD_ENA (0x54) /** 命令使能寄存器 */ +#define NDS03_REG_CFG_ENA (0x55) /** 配置使能,该值为0xA5才能访问其他寄存器 */ +#define NDS03_REG_REF_HISTO_MAX (0x56) /** 参考直方图最大值 */ + +#define NDS03_REG_DEPTH_FLAG (0x64) /** 测距结果标志位 */ +#define NDS03_REG_SLEEP_TIME (0x66) /** 睡眠时间(ms) */ +#define NDS03_REG_PULSE_NUM (0x6C) /** 发光次数 */ + +#define NDS03_REG_DEPTH_TH_L (0x70) /** 深度低阈值 */ +#define NDS03_REG_DEPTH_TH_H (0x72) /** 深度高阈值 */ +#define NDS03_REG_GPIO1_FUNC (0x74) /** 中断功能/方式 */ +#define NDS03_REG_SLEEP_MODE (0x75) /** 睡眠方式 */ +#define NDS03_REG_CONFI_TH (0x76) /** 置信度阈值 */ +#define NDS03_REG_TARGET_NUM (0x77) /** 目标个数 */ +#define NDS03_REG_INV_TIME (0x7C) /** 测量间隔时间 */ +#define NDS03_REG_OFFSET_MM (0x90) /** offset 标定位置 */ + +#define NDS03_REG_XTALK_TH (0xB0) /** 串扰阈值 */ +#define NDS03_REG_XTALK (0xB2) /** 串扰值 */ + +#define NDS03_REG_DATA_SIZE (0x5C) /** 数据大小 */ +#define NDS03_REG_CACHE_SIZE (0x5D) /** 缓存大小 */ +#define NDS03_REG_CACHE_ADDR (0x5E) /** 缓存地址 */ +#define NDS03_REG_CACHE_DATA (0xC0) /** 缓存数据 */ + +/** @} NDS03_Reg_Group */ + +/** @defgroup NDS03_State_Group NDS03 Data Request Index + * @brief NDS03 State (NDS03_REG_STATE) + * @{ + */ + +#define NDS03_STATE_IDLE 0x00 /** 空闲状态 */ +#define NDS03_STATE_SOFT_READY 0xA5 /** 软件就绪状态 */ +#define NDS03_STATE_GOT_DEPTH 0xA6 /** 已获取深度状态 */ + +/** @} NDS03_State_Group */ + +/** @defgroup NDS03_Data_Val_Req_Idx_Group NDS03 Data Request Index + * @brief NDS03 Data Request Mask (NDS03_REG_DAT_VAL_REQ) + * @{ + */ +/** DATA REQ */ +#define NDS03_DATA_REQ_IDLE 0x00 /** 无效数据命令标志位 */ +#define NDS03_DEPTH_DATA_FLAG 0x10 /** 获取深度数据标志 */ +#define NDS03_DEPTH_CONTINUOUS_FLAG 0x13 /** 连续获取深度数据标志 */ +#define NDS03_USER_DATA_FLAG 0x50 /** 读用户数据标志位 */ +#define NDS03_GET_MODEL_FLAG 0x51 /** 获取模组型号标志位 */ +#define NDS03_CMD_READ_HGM_DATA 0xC0 /** 读直方图数据标志位 */ +#define NDS03_CMD_READ_HGM_DATA_ENA 0x05 /** 读直方图数据使能标志位 */ + +/** DATA VAL */ +#define NDS03_DATA_VAL_IDLE 0x00 /** 无效数据标志位 */ + +/** CMD REQ */ +#define NDS03_CMD_OFFSET_CALIB 0x20 /** offset标定命令 */ +#define NDS03_CMD_XTALK_CALIB 0x24 /** xtalk标定 */ +#define NDS03_CMD_WRITE_USER_DATA 0x50 /** 写用户数据区域标志位 */ + + +/** CMD VAL */ +#define NDS03_CMD_VAL_IDLE 0x00 /** 无效命令标志位 */ + +/** CMD ENA */ +#define NDS03_CMD_WRITE_USER_DATA_ENA 0xAA /** 用户数据使能标志位 */ +#define NDS03_CMD_ENA_ENABLE 0xA5 /** 配置开启标志位 */ +#define NDS03_CMD_ENA_DISABLE 0x00 /** 配置关闭标志位 */ + +/** @} NDS03_Data_Val_Req_Idx_Group */ + +/** @defgroup NDS03_Sleep_Group NDS03 Sleep Group + * @brief NDS03 Sleep (NDS03_REG_SLEEP_MODE) + * @{ + */ + +#define NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP 0xA5 /* 手动进入软件睡眠标志位,超时唤醒 */ +#define NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP 0xA4 /* 手动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_MANUAL_WEAK_UP 0xA3 /* 测量结束自动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_TIME_OUT_WEAK_UP 0xA2 /* 测量结束自动进入软件睡眠标志位,超时唤醒 */ + +/** @} NDS03_Sleep_Group */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef int8_t NDS03_Error; + +/** @defgroup NDS03_Error_Group NDS03 Error Group + * @brief NDS03 Error Group (NDS03_REG_ERROR_FLAG) + * @{ + */ +#define NDS03_ERROR_NONE 0 /** 成功 */ +#define NDS03_ERROR_API -1 /** api接口注册失败 */ +#define NDS03_ERROR_TIMEOUT -2 /** 超时错误 */ +#define NDS03_ERROR_I2C -3 /** IIC通讯错误 */ +#define NDS03_ERROR_BOOT -4 /** 模组启动错误 */ +#define NDS03_ERROR_CALIB -5 /** 标定失败错误 */ +#define NDS03_ERROR_INIT -6 /** 初始化失败 */ +#define NDS03_ERROR_RANGING -7 /** 测距出错 */ +#define NDS03_ERROR_UPGRADE_VER -8 /** 升级版本不对 */ +#define NDS03_ERROR_UPGRADE -9 /** 升级失败 */ +#define NDS03_ERROR_AMBIENT_HIGH -10 /** 标定时环境光强过大 */ +#define NDS03_ERROR_NO_NDS03 -11 /** 不是NDS03模组 */ +#define NDS03_ERROR_VCSEL_ERROR -12 /** VCSEL不亮 */ +#define NDS03_ERROR_OFFSET_ERROR -13 /** OFFSET 标定失败 */ + +/** @} NDS03_Error_Group */ + +/** @defgroup NDS03_Calib_State_Group NDS03 Calib State Group + * @brief NDS03 Calib State Group (NDS03_REG_CALIB_STATE) + * @{ + */ +#define NDS03_CALIB_ERROR_NONE 0x00 /** 成功 */ +#define NDS03_CALIB_ERROR_XTALK_OVERFLOW 0x02 /** 串扰溢出 */ +#define NDS03_CALIB_ERROR_XTALK_EXCESSIVE 0x10 /** 串扰过大 */ +#define NDS03_CALIB_ERROR_OFFSET 0x20 /** offset标定后测距误差过大 */ +/** @} NDS03_Calib_State_Group */ + +/** @defgroup NDS03_GPIO1_Func_Group NDS03 GPIO1 Functions Define + * @brief NDS03 GPIO1 Functions Define Group (NDS03_REG_GPIO1_FUNC) + * @{ + */ + +/** REG_GPIO1_SETTING Mask */ +#define NDS03_GPIO1_FUNCTIONALITY_MASK 0x07 /** GPIO1功能配置掩码 */ +#define NDS03_GPIO1_POLARITY_MASK 0x08 /** 极性配置掩码 */ + +/** GPIO1 Functionality */ +typedef uint8_t NDS03_Gpio1Func_t; +#define NDS03_GPIO1_FUNCTIONALITY_OFF ((NDS03_Gpio1Func_t)0x00) /** 无触发中断 */ +#define NDS03_GPIO1_THRESHOLD_LOW ((NDS03_Gpio1Func_t)0x01) /** 低深度触发中断 (value < NDS03_REG_DEPTH_TH_L) */ +#define NDS03_GPIO1_THRESHOLD_HIGH ((NDS03_Gpio1Func_t)0x02) /** 高深度触发中断 (value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_THRESHOLD_DOMAIN_OUT ((NDS03_Gpio1Func_t)0x03) /** 低深度或高深度触发中断 (value < NDS03_REG_DEPTH_TH_L 或 value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_NEW_MEASURE_READY ((NDS03_Gpio1Func_t)0x04) /** 新深度数据就绪中断 */ + +/** GPIO1 polarity */ +typedef uint8_t NDS03_Gpio1Polar_t; +#define NDS03_GPIO1_POLARITY_LOW ((NDS03_Gpio1Polar_t)0x00) /** 负极性, 低电平有效 */ +#define NDS03_GPIO1_POLARITY_HIGH ((NDS03_Gpio1Polar_t)0x01) /** 正极性, 高电平有效 */ + +/** @} NDS03_GPIO1_Func_Group */ + +#define NDS03_TARGET_MAX_NUM 4 +#define NDS03_AMBIENT_TH 1000 /** 标定时环境光强阈值 */ +#define NDS03_OFFSET_DEPTH_ERROR_TH 10 /** OFFSET 标定深度误差阈值 */ +#define NDS03_OFFSET_REF_MAX_COUNT_TH 500 /** OFFSET 标定深度误差阈值 */ +#define NDS03_DEPTH_INVALID_VALUE 65300 /** 深度无效值 */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef enum{ + NDS03_DISABLE = 0, ///< 关闭状态 + NDS03_ENABLE = 1 ///< 使能状态 +} NDS03_Status_e; + +/** + * @struct NDS03_RangingData_t + * + * @brief NDS03测量结果结构体 \n + * 定义存储NDS03的深度、置信度信息 + */ +typedef struct{ + uint16_t depth; ///< 测量距离 + uint16_t confi; ///< 测量置信度 + uint16_t count; ///< 计数值 + uint16_t crate; ///< 计数率 +} NDS03_RangingData_t; + + +/** + * @struct NDS03_ChipInfo_t + * + * @brief NDS03模组生产信息\n + */ +typedef struct { + uint32_t fw_version; ///< NDS03固件版本 +} NDS03_ChipInfo_t; + +/** + * @struct NDS03_DevConfig_t + * + * @brief NDS03模组配置数据\n + */ +typedef struct { + uint32_t range_frame_time_us; //< 模组取图帧间隔时间配置 + uint8_t continuous_flag; ///< 连续模式标志位 + uint8_t target_num; ///< 目标个数 +} NDS03_DevConfig_t; + +/** + * @struct NDS03_Dev_t + * + * @brief 设备类型结构体\n + */ +typedef struct { + uint8_t dev_pwr_state; ///< 设备的当前状态, 就绪模式或者休眠模式 + NDS03_DevConfig_t config; ///< 模组配置信息 + NDS03_ChipInfo_t chip_info; ///< 模组设备信息 + uint8_t data_cnt; ///< 数据获取次数 + NDS03_RangingData_t ranging_data[NDS03_TARGET_MAX_NUM]; ///< 测距数据结果 + NDS03_Platform_t platform; +} NDS03_Dev_t; + +#define NDS03_DEFAULT_SLAVE_ADDR 0x5C + +#if NDS03_PLATFORM == PLATFORM_C51 +#define CHECK_RET(func) \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) \ + return ret; +#else +#define CHECK_RET(func) do { \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) { \ + NX_PRINTF("%s I2c Error, ret: %d\r\n", #func, ret); \ + return ret; \ + } \ +} while (0) +#endif + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_dev.c b/drivers/iio/proximity/nds03/nds03_dev.c new file mode 100644 index 000000000000..09cd9a5f2d53 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.c @@ -0,0 +1,743 @@ +/** + * @file nds03_dev.c + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ + +#include "nds03_dev.h" +#include "nds03_def.h" +#include "nds03_comm.h" + +/** SDK主版本 */ +static uint8_t sdk_version_major = 2; +/** SDK次版本 */ +static uint8_t sdk_version_minor = 0; +/** SDK小版本 */ +static uint8_t sdk_version_patch = 3; + +/** + * @brief NDS03 Get SDK Version + * 获取当前SDK的软件版本号 + * @return uint32_t + * @retval 软件版本号 + */ +uint32_t NDS03_GetSdkVersion(void) +{ + return ((uint32_t)sdk_version_major << 16) + + ((uint32_t)sdk_version_minor << 8) + (uint32_t)sdk_version_patch; +} + +/** + * @brief NDS03 Get Firmware Version + * 获取NDS03模组固件版本号 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_FW_VER, &pNxDevice->chip_info.fw_version)); + return ret; +} + +/** + * @brief NDS03 Get Therm + * 获取NDS03的温度 + * @param pNxDevice + * @param therm 温度,单位为0.1度 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_THERM, (uint16_t*)therm)); + return ret; +} + +/** + * @brief NDS03 Set Pulse Num + * 设置发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} +/** + * @brief NDS03 Get Pulse Num + * 获取发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + + return ret; +} + +/** + * @brief NDS03 Set Frame Time + * 设置测量帧间隔时间(us) + * @param pNxDevice + * @param inv_time 测量帧间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_INV_TIME, frame_time_us)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + + return ret; +} +/** + * @brief NDS03 Get Frame Time + * 获取帧测量间隔时间(us) + * @param pNxDevice + * @param inv_time 测量间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + *frame_time_us = pNxDevice->config.range_frame_time_us; + + return ret; +} + +/** + * @brief NDS03 Set Confidence threshold + * 配置置信度阈值 + * @param pNxDevice + * @param confi_th + * @return NDS03_Error + */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Confidence threshold + * 获取置信度阈值 + * @param pNxDevice + * @param confi_th 置信度阈值 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + + return ret; +} + +/** + * @brief NDS03 Set Target Num + * 配置目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + num = (num > NDS03_TARGET_MAX_NUM) ? NDS03_TARGET_MAX_NUM : num; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + pNxDevice->config.target_num = num; + + return ret; +} + +/** + * @brief NDS03 Get Target Num + * 获取目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + pNxDevice->config.target_num = *num; + + return ret; +} + +/** + * @brief NDS03 Set Gpio1 Configuration + * 设置中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param functionality: 中断功能设置 + * NDS03_GPIO1_FUNCTIONALITY_OFF: 无功能(默认) + * NDS03_GPIO1_THRESHOLD_LOW:比较功能,当深度小于低阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_HIGH:比较功能,当深度大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_DOMAIN_OUT:比较功能,当深度小于低阈值或者大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_NEW_MEASURE_READY:深度数据有效功能,当深度数据有效时,GPIO输出有效电平 + * @param polarity: INT引脚有效电平 + * NDS03_GPIO1_POLARITY_LOW:低电平有效 + * NDS03_GPIO1_POLARITY_HIGH:高电平有效 + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + /** 设置中断功能 */ + rbuf = rbuf & (~NDS03_GPIO1_FUNCTIONALITY_MASK); + rbuf = rbuf | (functionality & NDS03_GPIO1_FUNCTIONALITY_MASK); + /** 设置中断引脚极性 */ + if (polarity == NDS03_GPIO1_POLARITY_HIGH) + rbuf = rbuf | NDS03_GPIO1_POLARITY_MASK; + else + rbuf = rbuf & (~NDS03_GPIO1_POLARITY_MASK); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_GPIO1_FUNC, rbuf)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Gpio1 Config + * 获取中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param functionality: 获取到的中断功能变量指针 + * @param polarity: 获取到的中断引脚极性变量指针 + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + // Polarity + *polarity = ((rbuf & NDS03_GPIO1_POLARITY_MASK) == NDS03_GPIO1_POLARITY_MASK) ? + NDS03_GPIO1_POLARITY_HIGH : NDS03_GPIO1_POLARITY_LOW; + // Functionality + *functionality = rbuf & NDS03_GPIO1_FUNCTIONALITY_MASK; + + return ret; +} + +/** + * @brief NDS03 Set Depth Threshold + * 设置深度阈值 + * 该功能仅用于GPIO功能为 + * NDS03_GPIO1_THRESHOLD_LOW + * 或NDS03_GPIO1_THRESHOLD_HIGH + * 或NDS03_GPIO1_THRESHOLD_DOMAIN_OUT + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Depth Threshold + * 获取深度阈值 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + + return ret; +} + +/** + * @brief NDS03 Waitfor Data Val + * 等待数据完成 + * @param pNxDevice 模组设备 + * @param flag 读命令标志位 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t dat_valid_flag = 0x00; + int32_t retry_cnt; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &dat_valid_flag)); + if (dat_valid_flag == flag) + break; + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("data_valid_flag: %d\r\n", dat_valid_flag); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Waitfor Cmd Val + * 等待命令完成 + * @param pNxDevice 模组设备 + * @param cmd 命令 + * @param timeout_ms 超时时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t retry_cnt; + uint8_t val; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CMD_VAL, &val)); + if (val == cmd) + break; + + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("Timeout!!, val: 0x%02x\r\n", val); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Read Hgm Data + * 读取NDS03直方图数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr = 0xe000; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, + NDS03_REG_CACHE_DATA, rbuf, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 读取NDS03中用户数据区域,支持任意地址循环读取,比如从0xFFF0开始读取32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_USER_DATA_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_USER_DATA_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + rbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 写入NDS03中用户数据区域, 支持任意地址循环写入,比如从0xFFF0开始写入32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param wbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + // NX_PRINTF("%s Start\r\n", __func__); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + wbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DATA_SIZE, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, + NDS03_CMD_WRITE_USER_DATA_ENA)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, + NDS03_CMD_WRITE_USER_DATA)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_WRITE_USER_DATA, 500)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_VAL_IDLE)); + wbuf += _size; + addr += _size; + rsize += _size; + } + // NX_PRINTF("%s End\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03软件休眠,定时自动唤醒 + * + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03软件休眠,需要手动唤醒 + * + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_SLEEP_MODE, NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03 Sleep + * NDS03进入休眠 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 0)); + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从软件睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t freq; + + CHECK_RET(NDS03_GetI2cFreq(pNxDevice,&freq)); + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,1000)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, 0)); + + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,freq)); + + return ret; +} + +/** + * @brief NDS03 Software Sleep + * 软件睡眠 + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + * @deprecated 在以后的版本会弃用,请使用NDS03_SoftSleepWithAutoWakeup() + */ +static __maybe_unused NDS03_Error NDS03_SoftSleep(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE); + ret |= NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms); + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP); + + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 1)); + return ret; +} + +/** + * @brief 判断是否为NDS03 + * + * @param pNxDevice + * @return NDS03_Error + * @arg 0: 是NDS03 + * @arg NDS03_ERROR_NO_NDS03: 不是NDS03 + * @arg others: 不确定是否为该模组,需要进一步排查,可能是I2C通信异常。 + * 如果排除I2C通信异常,则认为不是NDS03,可能是其他设备。 + */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf[4] = {0}; + + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 10)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_GET_MODEL_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_GET_MODEL_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, buf, sizeof(buf))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + if ((buf[0] != 0x31) || (buf[1] != 0x53) || (buf[2] != 0x30) || (buf[3] != 0x33)) + ret = NDS03_ERROR_NO_NDS03; + + return ret; +} + +/** + * @brief NDS03 Set Device Address + * 设置模组设备地址 + * @param pNxDevice 模组设备 + * @param dev_addr + * @return NDS03_Error + */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEV_ADDR, dev_addr)); + pNxDevice->platform.i2c_dev_addr = dev_addr; + + return ret; +} + +/** + * @brief NDS03 InitDevice + * 初始化设备 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + // NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &pNxDevice->data_cnt)); + CHECK_RET(NDS03_GetFrameTime(pNxDevice, &pNxDevice->config.range_frame_time_us)); + pNxDevice->config.continuous_flag = 0; + + // NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Wait for Device Boot Up + * 等待NDS03模组启动 + * @param pNxDevice 模组设备 + * @return NDS03_ERROR_NONE:成功 + * NDS03_ERROR_BOOT:启动失败--请检测模组是否焊接好,还有i2c地址与读写函数是否错误。 + * NDS03_ERROR_FW:固件不兼容--请与FAE联系,是否模组的固件与SDK不兼容。 + */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t try_times = 200; + uint8_t slave_addr = pNxDevice->platform.i2c_dev_addr; + + NDS03_SetXShutPinLevel(pNxDevice, 0); + CHECK_RET(NDS03_Delay10us(pNxDevice, 20)); + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 2)); + ret = NDS03_SetXShutPinLevel(pNxDevice, 1); + pNxDevice->platform.i2c_dev_addr = (ret == NDS03_ERROR_NONE) ? + NDS03_DEFAULT_SLAVE_ADDR : pNxDevice->platform.i2c_dev_addr; + + pNxDevice->data_cnt = 0; + pNxDevice->config.continuous_flag = 0; + + do { + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_STATE, &pNxDevice->dev_pwr_state)); + } while ((pNxDevice->dev_pwr_state != NDS03_STATE_SOFT_READY) && + (pNxDevice->dev_pwr_state != NDS03_STATE_GOT_DEPTH) && --try_times); + + if (0 == try_times) { + NX_PRINTF("state: 0x%02x\r\n", pNxDevice->dev_pwr_state); + NX_PRINTF("NDS03 boot error\r\n"); + return NDS03_ERROR_BOOT; + } + + if (slave_addr != pNxDevice->platform.i2c_dev_addr) + CHECK_RET(NDS03_SetDevAddr(pNxDevice, slave_addr)); + + return ret; +} + +/** + * @brief NDS03 Dirty Warning + * 脏污预警 + * @param pNxDevice 模组设备 + * @param flag 脏污预警标志位 1:脏污预警,0:正常 + * @param time_th 近距离时间阈值,单位ms + * @return NDS03_ERROR_NONE:成功 + */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t depth_low_th = 30; + static int32_t depth_low_count = 0, depth_low_time_sta = 0, depth_low_time_end = 0; + + if (time_th == 0) + time_th = 10 * 1000; + + if (pNxDevice->ranging_data[0].depth < depth_low_th) { + depth_low_count ++; + if (depth_low_count == 1) + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_sta); + + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_end); + if (depth_low_time_end < depth_low_time_sta) { + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + } else { + depth_low_count = 0; + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + + if (depth_low_count > 10 && pNxDevice->ranging_data[1].depth != NDS03_DEPTH_INVALID_VALUE) + *flag = 1; + + if ((depth_low_time_end - depth_low_time_sta) > time_th) + *flag = 1; + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_dev.h b/drivers/iio/proximity/nds03/nds03_dev.h new file mode 100644 index 000000000000..99780128875c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.h @@ -0,0 +1,94 @@ +/** + * @file nds03_dev.h + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_DEV_H__ +#define __NDS03_DEV_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Dev_Group NDS03 Device Functions + * @brief NDS03 Device Functions + * @{ + */ + +/** 获取SDK版本号 */ +uint32_t NDS03_GetSdkVersion(void); +/** 获取NDS03模组固件版本号 */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice); +/** 获取温度 */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm); +/** 设置发光次数 */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num); +/** 获取发光次数 */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num); +/** 设置测量间隔时间 */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us); +/** 获取测量间隔时间 */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us); +/** 设置置信度阈值 */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th); +/** 获取置信度阈值 */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th); +/** 设置目标个数 */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num); +/** 获取目标个数 */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num); +/** 设置中断引脚功能 */ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity); +/** 获取中断引脚功能 */ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity); +/** 设置深度阈值 */ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high); +/** 获取深度阈值 */ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high); +/** 等待获取数据结束 */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms); +/** 等待命令结束 */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms); +/** 从NDS03中读取直方图数据 */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice,uint8_t *rbuf, uint32_t size); +/** 从NDS03中读取用户数据 */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, uint16_t addr, uint8_t *rbuf, uint32_t size); +/** 从NDS03中写入用户数据 */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size); +/** NDS03进入软件睡眠,手动唤醒 */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入软件睡眠,自动唤醒 */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms); +/** NDS03从软件睡眠中唤醒 */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入睡眠 */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice); +/** NDS03从睡眠中唤醒 */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice); +/** 判断是否为NDS03设备,返回值为0表示是NDS03设备 */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice); +/** 设置模组设备地址 */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr); +/** 初始化设备 */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice); +/** 等待设备启动 */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice); +/** 脏污预警 */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th); + +/** @} NDS03_Dev_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_iio.c b/drivers/iio/proximity/nds03/nds03_iio.c new file mode 100644 index 000000000000..a683cc292616 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include "nds03_iio.h" +#include "nds03.h" + +#define NDS03_DISTANCE_CHANNEL { \ + .type = IIO_DISTANCE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),\ + .scan_index = NDS03_IIO_CHAN_DISTANCE, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const int nds03_scales[] = { 1 }; + +static const struct iio_chan_spec nds03_channels[] = { + NDS03_DISTANCE_CHANNEL, + IIO_CHAN_SOFT_TIMESTAMP(NDS03_IIO_CHAN_TIMESTAMP), +}; + +static int nds03_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT; + *vals = nds03_scales; + *length = ARRAY_SIZE(nds03_scales); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +/* === read_raw === */ +static int nds03_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->scan_index == NDS03_IIO_CHAN_DISTANCE) { + *val = iio->ctx->g_nds03_device.ranging_data[0].depth; + return IIO_VAL_INT; + } + break; + case IIO_CHAN_INFO_SCALE: + *val = nds03_scales[0]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + *val = iio->enabled; + return IIO_VAL_INT; + + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int nds03_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_RAW: + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + /* NOTE: Default to 1 */ + return 0; + case IIO_CHAN_INFO_ENABLE: + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_info nds03_iio_info = { + .read_raw = nds03_read_raw, + .write_raw = nds03_write_raw, + .read_avail= nds03_read_avail, +}; + +/* === buffer setup === */ +static void nds03_enable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, enable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + int ret; + + mutex_lock(&ctx->work_mutex); + if (iio->enabled) + goto out; + + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + ret = nds03_sensor_init(ctx); + if(ret != 0) { + dev_err(&ctx->client->dev, "nds03 sensor init failed %d\n", ret); + goto out; + } + ret = NDS03_StartContinuousMeasurement(dev); + if (ret) { + dev_err(&ctx->client->dev, "StartContinuous fail %d\n", ret); + goto out; + } + iio->enabled = true; + dev_info(&ctx->client->dev, "NDS03 sensor started\n"); + goto out; + +out: + mutex_unlock(&ctx->work_mutex); +} + +static void nds03_disable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, disable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + if (!iio->enabled) + goto out; + + atomic_set(&ctx->is_meas, 0); + NDS03_StopContinuousMeasurement(dev); + iio->enabled = false; + dev_info(&ctx->client->dev, "NDS03 sensor stopped\n"); +out: + mutex_unlock(&ctx->work_mutex); +} + +static int nds03_buffer_preenable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->enable_work); + return 0; +} + +static int nds03_buffer_predisable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->disable_work); + return 0; +} + +static const struct iio_buffer_setup_ops nds03_buffer_setup_ops = { + .preenable = nds03_buffer_preenable, + .predisable = nds03_buffer_predisable, +}; + +int nds03_iio_init(struct nds03_context *ctx) +{ + struct device *dev = &ctx->client->dev; + struct nds03_iio_dev *iio; + int ret; + + iio = devm_kzalloc(dev, sizeof(*iio), GFP_KERNEL); + if (!iio) { + nds03_errmsg("devm_kzalloc error\n"); + return -ENOMEM; + } + + iio->indio_dev = devm_iio_device_alloc(dev, 0); + if (!iio->indio_dev) { + nds03_errmsg("devm_iio_device_alloc error\n"); + return -ENOMEM; + } + + iio->ctx = ctx; + iio->enabled = false; + INIT_WORK(&iio->enable_work, nds03_enable_work); + INIT_WORK(&iio->disable_work, nds03_disable_work); + + iio->indio_dev->name = "nds03"; + iio->indio_dev->channels = nds03_channels; + iio->indio_dev->num_channels = ARRAY_SIZE(nds03_channels); + iio->indio_dev->info = &nds03_iio_info; + iio->indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + iio_device_set_drvdata(iio->indio_dev, iio); + + /* kfifo buffer + setup_ops */ + ret = devm_iio_kfifo_buffer_setup(dev, iio->indio_dev, &nds03_buffer_setup_ops); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, iio->indio_dev); + if (ret) + return ret; + + ctx->iio = iio; + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_iio_init); + +void nds03_iio_remove(struct nds03_context *ctx) +{ + return; +} +EXPORT_SYMBOL_GPL(nds03_iio_remove); + +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm) +{ + struct nds03_iio_dev *iio = ctx->iio; + struct nds03_scan scan; + + if (!iio || !iio->enabled) + return; + + scan.distance = distance_mm; + if (iio_buffer_enabled(iio->indio_dev)) + iio_push_to_buffers_with_timestamp(iio->indio_dev, &scan, + ktime_get_boottime_ns()); +} +EXPORT_SYMBOL_GPL(nds03_iio_push_data); diff --git a/drivers/iio/proximity/nds03/nds03_iio.h b/drivers/iio/proximity/nds03/nds03_iio.h new file mode 100644 index 000000000000..9f17533d68a2 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NDS03_IIO_H +#define __NDS03_IIO_H + +#include +#include +#include + +struct nds03_iio_dev { + struct iio_dev *indio_dev; + struct nds03_context *ctx; + bool enabled; + struct work_struct enable_work; + struct work_struct disable_work; +}; + +enum nds03_iio_chan { + NDS03_IIO_CHAN_DISTANCE, + NDS03_IIO_CHAN_TIMESTAMP, +}; + +struct nds03_scan { + __le16 distance; + s64 ts; +}; + +int nds03_iio_init(struct nds03_context *ctx); +void nds03_iio_remove(struct nds03_context *ctx); +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_module.c b/drivers/iio/proximity/nds03/nds03_module.c new file mode 100644 index 000000000000..4025ca087922 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module.c @@ -0,0 +1,674 @@ + +/*! + @file nds03_module.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_iio.h" + +/* Set default value to 1 to allow to see module insertion debug messages */ +int nds03_enable_debug = 0; + +static inline NDS03_Platform_t *to_nds03_platform(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device.platform; +} +static inline NDS03_Dev_t * to_nds03_dev(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device; +} + +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open) +{ + int8_t retval = 0; + + if (is_open) { + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_NEW_MEASURE_READY, NDS03_GPIO1_POLARITY_LOW); + /* 连续模式开启测量 */ + retval |= NDS03_StartContinuousMeasurement(pNxDevice); + } else { + /* 连续模式关闭测量 */ + retval |= NDS03_StopContinuousMeasurement(pNxDevice); + /* 关闭测距中断 */ + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_FUNCTIONALITY_OFF, NDS03_GPIO1_POLARITY_LOW); + } + return retval; +} +EXPORT_SYMBOL_GPL(nds03_interrupt_config); + +int nds03_sensor_init(struct nds03_context *ctx) +{ + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + /* 函数指针结构体 */ + + if (NDS03_ERROR_NONE != nds03_platform_init(pdev, ctx->client)) { + nds03_errmsg("nds03_platform init error\n"); + return -1; + } + /* 循环等待设备启动, 若模组或者IIC读写函数有问题则会报错 */ + if (NDS03_ERROR_NONE != NDS03_WaitDeviceBootUp(pNxDevice)) { + nds03_errmsg("NDS03_WaitDeviceBootUp error\r\n"); + return -1; + } + /** 判断是否为NDS03设备 */ + if (NDS03_ERROR_NONE != NDS03_IsNDS03(pNxDevice)) { + nds03_errmsg("The device is not NDS03, please change the device!\n"); + return -2; + } + /* 初始化模组设备 */ + if (NDS03_ERROR_NONE != NDS03_InitDevice(pNxDevice)) { + nds03_errmsg("NDS03_InitDevice error!!\r\n"); + return -3; + } + if (atomic_read(&ctx->meas_mode) == 0) + nds03_interrupt_config(pNxDevice, 1); + else + nds03_interrupt_config(pNxDevice, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_sensor_init); + +static void printf_ranging_data(NDS03_Dev_t *pNxDevice) +{ + nds03_info("ranging data start:\r\n"); + + nds03_info("dist start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].depth, pNxDevice->ranging_data[1].depth, + pNxDevice->ranging_data[2].depth, pNxDevice->ranging_data[3].depth); + nds03_info("dist end\r\n"); + + nds03_info("confi start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].confi, pNxDevice->ranging_data[1].confi, + pNxDevice->ranging_data[2].confi, pNxDevice->ranging_data[3].confi); + nds03_info("confi end\r\n"); + + nds03_info("count start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].count, pNxDevice->ranging_data[1].count, + pNxDevice->ranging_data[2].count, pNxDevice->ranging_data[3].count); + nds03_info("count end\r\n"); + + nds03_info("crate start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].crate, pNxDevice->ranging_data[1].crate, + pNxDevice->ranging_data[2].crate, pNxDevice->ranging_data[3].crate); + nds03_info("crate end\r\n"); + + nds03_info("ranging data end\r\n"); +} + +static int32_t nds03_make_measure(struct nds03_context *ctx) +{ + int32_t ret = 0; + NDS03_Dev_t *pNxDevice = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + /* 获取测量数据 */ + if (atomic_read(&ctx->meas_mode)) + ret = NDS03_GetSingleRangingData(pNxDevice); + else + ret = NDS03_GetInterruptRangingData(pNxDevice); + + if (ret >= 0 && nds03_enable_debug) + printf_ranging_data(pNxDevice); + + mutex_unlock(&ctx->work_mutex); + + return ret; +} + +static int __ctrl_tof_start(struct nds03_context * ctx) +{ + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + + return 0; +} + +static int __ctrl_tof_stop(struct nds03_context * ctx) +{ + atomic_set(&ctx->is_meas, 0); + return 0; +} + +static int __ctrl_tof_reset(struct nds03_context * ctx) +{ + int ret = 0; + + __ctrl_tof_stop(ctx); + mutex_lock(&ctx->work_mutex); + ret = nds03_sensor_init(ctx); + if (ret != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + return ret; +} + +static int32_t tof_offset_calib(struct nds03_context *ctx, uint16_t calib_dist) +{ + int32_t i, cnt = 20; + int32_t depth_sum, depth_aver; + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + /* 将设备处于500mm处 */ + NDS03_StopContinuousMeasurement(pNxDevice); + msleep(100); + /* 串扰标定 */ + ctx->calib_result = NDS03_XtalkCalibration(pNxDevice); + if (NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Xtalk calib error: %d\n", ctx->calib_result); + return -1; + } + /* Offset标定 */ + ctx->calib_result = NDS03_OffsetCalibrationAtDepth(pNxDevice, calib_dist); + if(NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Offset calib error: %d\n", ctx->calib_result); + return -1; + } + /* 获取平均值 */ + NDS03_GetSingleRangingData(pNxDevice); + NDS03_GetSingleRangingData(pNxDevice); + depth_sum = 0; + for (i = 0; i < cnt; i++) { + if (NDS03_ERROR_NONE != NDS03_GetSingleRangingData(pNxDevice)) { + nds03_info("NDS03_GetSingleRangingData error!!\r\n"); + return -1; + } + depth_sum = depth_sum + (int32_t)(uint32_t)pNxDevice->ranging_data[0].depth; + } + depth_aver = depth_sum / cnt; + if (depth_aver < (calib_dist - 20) || depth_aver > (calib_dist + 20)) { + ctx->calib_result = NDS03_ERROR_RANGING; + nds03_info("NDS03 calibration fail!!\r\n"); + return -1; + } + nds03_info("NDS03 calibration success\r\n"); + return 0; +} + +static void report_meas_event(struct nds03_context * ctx) +{ + int retval = 0; + + retval = nds03_make_measure(ctx); + if (retval < 0) + return; + + uint16_t distance = ctx->g_nds03_device.ranging_data[0].depth; + nds03_iio_push_data(ctx, distance); +} + +static irqreturn_t tof_irq_handler_i2c(int vec, void *info) +{ + struct nds03_context *ctx = (struct nds03_context *)info; + bool is_meas = atomic_read(&ctx->is_meas); + + if (ctx->irq == vec && is_meas) + schedule_work(&ctx->irq_work); + + return IRQ_HANDLED; +} + +static void nds03_work_handler(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, dwork.work); + + if (atomic_read(&ctx->meas_mode) && atomic_read(&ctx->is_meas)) { + nds03_make_measure(ctx); + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + report_meas_event(ctx); + } +} + +static void nds03_measure_irq_work(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, irq_work); + + report_meas_event(ctx); +} + +static ssize_t nds03_show_is_meas(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + return snprintf(buf, 10, "%d\n", atomic_read(&ctx->is_meas)); +} + +static ssize_t nds03_store_is_meas(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = count; + + switch (buf[0]) { + case '0': + __ctrl_tof_stop(ctx); + break; + case '1': + __ctrl_tof_start(ctx); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + return ret ; +} + +static DEVICE_ATTR(is_meas, 0660, nds03_show_is_meas, nds03_store_is_meas); + +static ssize_t nds03_show_poll_delay_ms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + uint32_t poll_ms; + struct nds03_context *ctx = dev_get_drvdata(dev); + + poll_ms = atomic_read(&ctx->poll_delay_ms); + return snprintf(buf, 10, "%d\n", poll_ms); +} + +static ssize_t nds03_store_poll_delay_ms(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long delay_ms; + + ret = kstrtoul(buf, 10, &delay_ms); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + goto store_err; + } + atomic_set(&ctx->poll_delay_ms, delay_ms); + nds03_dbgmsg("Poll delay %lu ms\n", delay_ms); +store_err: + return ret < 0 ? -EINVAL : count; +} + +static DEVICE_ATTR(meas_delay_ms, 0660, nds03_show_poll_delay_ms, nds03_store_poll_delay_ms); + +static ssize_t nds03_show_meas_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",atomic_read(&ctx->meas_mode)); +} + +static ssize_t nds03_store_meas_mode(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + int ret = count; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + if(ctx->irq < 0){ + nds03_warnmsg("No support Interrupt\n"); + ret = -EINVAL; + } else { + atomic_set(&ctx->meas_mode, 0); + nds03_interrupt_config(pNxDevice, 1); + nds03_dbgmsg("Enter Interrupt Mode\n"); + } + break; + case '1': + atomic_set(&ctx->meas_mode, 1); + nds03_interrupt_config(pNxDevice, 0); + nds03_dbgmsg("Enter Poll Mode\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret ; +} +static DEVICE_ATTR(meas_mode, 0660, nds03_show_meas_mode, nds03_store_meas_mode); + +static ssize_t nds03_store_tof_reset(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = 0; + + if(buf[0] == '1') + ret = __ctrl_tof_reset(ctx); + + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_reset, 0660, NULL, nds03_store_tof_reset); + +static ssize_t nds03_show_tof_calib(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",ctx->calib_result); +} + +static ssize_t nds03_store_tof_calib(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long calib_dis; + + mutex_lock(&ctx->work_mutex); + ret = kstrtoul(buf, 10, &calib_dis); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + ret = -EPERM; + goto store_err; + } + nds03_info("offset calib distance: %ld mm\n", calib_dis); + ret = tof_offset_calib(ctx, calib_dis); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + +store_err: + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_calib, 0660, nds03_show_tof_calib, nds03_store_tof_calib); + +static ssize_t nds03_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 10, "%d\n", nds03_enable_debug); +} + +static ssize_t nds03_store_enable_debug(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int32_t ret = 0; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + nds03_enable_debug = 0; + nds03_info("close nds03 debug\n"); + break; + case '1': + nds03_enable_debug = 1; + nds03_info("open nds03 debug\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(enable_debug, 0660, nds03_show_enable_debug, nds03_store_enable_debug); + +static ssize_t nds03_store_tof_pulsenum(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + unsigned long pulsenum; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + ret = kstrtoul(buf, 10, &pulsenum); + if (ret < 0) { + nds03_errmsg("Invalid input ctx\n"); + return -EPERM; + } + mutex_lock(&ctx->work_mutex); + ret = NDS03_SetPulseNum(pdev, pulsenum); + mutex_unlock(&ctx->work_mutex); + nds03_info("set tof pulsenum: %ld, ret: %d\n", pulsenum, ret); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_pulsenum, 0660, NULL, nds03_store_tof_pulsenum); + +static ssize_t nds03_show_tof_xtalk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, count; + uint16_t xtalk_value; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + mutex_lock(&ctx->work_mutex); + ret = NDS03_GetXTalkValue(pdev, &xtalk_value); + if (ret < 0) + nds03_errmsg("get tof xtalk_value error\n"); + mutex_unlock(&ctx->work_mutex); + count = snprintf(buf, 10, "%d\n",xtalk_value); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_xtalk, 0660, nds03_show_tof_xtalk, NULL); + +static ssize_t nds03_store_xtalk_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int32_t ret = 0; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + if (sysfs_streq(buf, "1") || sysfs_streq(buf, "on") || + sysfs_streq(buf, "start")) { + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_XtalkCalibration(pdev); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if(ret < 0) { + nds03_errmsg("NDS03_XtalkCalibration error, ret = %d\n", ret); + return -EIO; + } + return count; + } else { + return -EINVAL; + } +} + +static DEVICE_ATTR(xtalk_calibration, 0660, NULL, nds03_store_xtalk_calibration); + +static ssize_t nds03_store_offset_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + int32_t calib_depth_mm_tmp = 0; + + ret = kstrtoint(buf, 10, &calib_depth_mm_tmp); + if (ret) + return -EINVAL; + + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_OffsetCalibrationAtDepth(pdev, calib_depth_mm_tmp); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if (ret < 0) { + nds03_errmsg("NDS03_OffsetCalibrationAtDepth error, ret = %d\n", ret); + return -EIO; + } + + return count; +} + +static DEVICE_ATTR(offset_calibration, 0660, NULL, nds03_store_offset_calibration); + +static struct attribute *nds03_attributes[] = { + &dev_attr_is_meas.attr, + &dev_attr_meas_delay_ms.attr, + &dev_attr_meas_mode.attr, + &dev_attr_enable_debug.attr, + &dev_attr_tof_reset.attr, + &dev_attr_tof_calib.attr, + &dev_attr_tof_pulsenum.attr, + &dev_attr_tof_xtalk.attr, + &dev_attr_xtalk_calibration.attr, + &dev_attr_offset_calibration.attr, + NULL +}; + +static const struct attribute_group nds03_sysfs_groups = { + .attrs = nds03_attributes, +}; + +static void nds03_parse_device_tree(struct nds03_context *ctx) +{ + int32_t ret; + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + + /* Initialize xshut gpio */ + pdev->xshut_gpio = devm_gpiod_get_optional(&ctx->client->dev, "xshut", GPIOD_OUT_HIGH); + if (IS_ERR(pdev->xshut_gpio)) { + ret = PTR_ERR(pdev->xshut_gpio); + nds03_warnmsg( "no xshut pin available, error = %d\n", ret); + return; + } else { + nds03_dbgmsg("get xshut pin success\n"); + } + + /* Initialize irq gpio*/ + atomic_set(&ctx->meas_mode, 1); //Default to polling mode + ctx->irq = -1; + pdev->intr_gpio = devm_gpiod_get_optional(&ctx->client->dev, "intr", GPIOD_IN); + if (IS_ERR(pdev->intr_gpio)) { + ret = PTR_ERR(pdev->intr_gpio); + nds03_warnmsg( "no intr pin available, error = %d\n", ret); + return; + } + nds03_dbgmsg("get intr pin success\n"); + ctx->irq = ctx->client->irq; + if (ctx->irq) { + unsigned long default_trigger = irqd_get_trigger_type(irq_get_irq_data(ctx->irq)); + ret = devm_request_threaded_irq(&ctx->client->dev, + ctx->irq, NULL, + tof_irq_handler_i2c, + default_trigger|IRQF_ONESHOT, + "nds03_interrupt", + (void *)ctx); + if (ret) { + nds03_errmsg("fail to req threaded irq rc=%d\n", ret); + } else { + nds03_info( + "request irq success, irq mode use, irq num: %d, type: %lu", + ctx->irq, default_trigger); + atomic_set(&ctx->meas_mode, 0); //Configure in interrupt mode + } + } else { + void *poll_interval_dt = NULL; + uint32_t delay_ms; + nds03_info("no irq number specified, polling mode is used\n"); + poll_interval_dt = (void *)of_get_property(ctx->client->dev.of_node, + "nds03_poll_interval", + NULL); + delay_ms = poll_interval_dt ? be32_to_cpup(poll_interval_dt) : 0; + + nds03_dbgmsg("poll delay ms:%d\n", delay_ms); + + atomic_set(&ctx->poll_delay_ms, delay_ms); + } +} + +int nds03_common_probe(struct nds03_context * ctx) +{ + int ret = 0; + u32 i2c_freq = 0; + // struct input_dev *input; + + /* Initialize mutex */ + mutex_init(&ctx->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&ctx->dwork, nds03_work_handler); + + INIT_WORK(&ctx->irq_work, nds03_measure_irq_work); + + atomic_set(&ctx->is_meas, 0); + + /* Parse the device tree for NDS03 sensor configuration. */ + nds03_parse_device_tree(ctx); + of_property_read_u32(ctx->client->adapter->dev.of_node, "clock-frequency", &i2c_freq); + pr_info("I2C bus number is %d, bus speed: %u Hz\n", ctx->client->adapter->nr, i2c_freq); + + ret = nds03_iio_init(ctx); + if (ret) { + nds03_errmsg("IIO init failed: %d\n", ret); + goto err_iio; + } + ctx->fd_open_count = 0; + + nds03_dbgmsg("create sysfs group successfully\n"); + + /* Initialize nds03 sensor */ + ret = nds03_sensor_init(ctx); + if (ret != 0 ) { + nds03_errmsg("Failed to init nds03 sensor error:%d\n", ret); + goto err_iio; + } + nds03_dbgmsg("init nds03 sensor successfully\n"); + + ret = sysfs_create_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + if (ret) { + nds03_errmsg("Failed to create sysfs group error:%d\n", ret); + goto exit_err; + } + ctx->remove_flag = false; + nds03_dbgmsg("register chardev successfully\n"); + + nds03_info("nds03 module registered successfully\n"); + nds03_info( "NDS03 Driver version: %s \n", DRIVER_VERSION); + return 0; + +err_iio: + nds03_iio_remove(ctx); + +exit_err: + return ret; +} +EXPORT_SYMBOL_GPL(nds03_common_probe); + +int nds03_common_remove(struct nds03_context * ctx) +{ + nds03_dbgmsg("Enter %s \n", __FUNCTION__); + cancel_delayed_work(&ctx->dwork); + ctx->remove_flag = true; + sysfs_remove_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + nds03_iio_remove(ctx); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_common_remove); diff --git a/drivers/iio/proximity/nds03/nds03_module_i2c.c b/drivers/iio/proximity/nds03/nds03_module_i2c.c new file mode 100644 index 000000000000..7ec4288479ca --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module_i2c.c @@ -0,0 +1,99 @@ +/*! + @file nds03_module_i2c.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_platform.h" + +struct nds03_context *nds03_context_obj = NULL; + +// int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct device *dev = &client->dev; + struct nds03_context * ctx = NULL; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if(IS_ERR(ctx)) { + nds03_errmsg("nds03_data memory allocation failed\n"); + ret = -ENOMEM; + goto module_reg_err; + } + + nds03_context_obj = ctx; + ctx->client = client; + + ret = nds03_common_probe(ctx); + if(ret != 0) { + nds03_errmsg("Failed to register nds03 module: %d\n", ret); + goto module_reg_err; + } + i2c_set_clientdata(client, ctx); + return 0; + +module_reg_err: + return ret; +} + +static void nds03_i2c_remove(struct i2c_client *client) +{ + struct nds03_context * ctx = i2c_get_clientdata(client); + nds03_common_remove(ctx); + // return 0; +} + +static const struct i2c_device_id tof_nds03_id[] = { + {TOF_NDS03_DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tof_nds03_id); + +static const struct of_device_id tof_nds03_dt_match[] = { + { .compatible = "nx,"TOF_NDS03_DRV_NAME, }, + { } +}; +MODULE_DEVICE_TABLE(of, tof_nds03_dt_match); + +static struct i2c_driver tof_nds03_driver = { + .driver = { + .name = TOF_NDS03_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tof_nds03_dt_match, + }, + .probe = nds03_i2c_probe, + .remove = nds03_i2c_remove, + .id_table = tof_nds03_id, + +}; + +static int __init tof_nds03_init_i2c(void) +{ + int ret = 0; + + nds03_dbgmsg("Enter\n"); + ret = i2c_add_driver(&tof_nds03_driver); + if (ret) + nds03_errmsg("%d erro ret:%d\n", __LINE__, ret); + return ret; +} + +static void __exit tof_nds03_exit_i2c(void ) +{ + nds03_dbgmsg("Exit\n"); + i2c_del_driver(&tof_nds03_driver); +} + +module_init(tof_nds03_init_i2c); +module_exit(tof_nds03_exit_i2c); + +MODULE_DESCRIPTION("Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/iio/proximity/nds03/nds03_platform.c b/drivers/iio/proximity/nds03/nds03_platform.c new file mode 100644 index 000000000000..e3552fe7e7e0 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.c @@ -0,0 +1,117 @@ +/*! + @file nds03_platform.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03_platform.h" + +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void * client) +{ + pdev->client = (struct i2c_client *)client; + pdev->i2c_dev_addr = 0X5C; + + return 0; +} + +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void * param) +{ + return 0; +} + +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len) +{ + int8_t ret; + struct i2c_msg i2c_message[2]; + uint8_t i2c_buf[256]; + + i2c_buf[0] = i2c_raddr; + i2c_message[0].addr = pDev->i2c_dev_addr; + i2c_message[0].buf = i2c_buf; + i2c_message[0].len = 1; + i2c_message[0].flags = 0 ; //| I2C_M_STOP;//I2C_M_STOP; + + i2c_message[1].addr = pDev->i2c_dev_addr; + i2c_message[1].buf = i2c_rdata; + i2c_message[1].len = len; + i2c_message[1].flags = I2C_M_RD; + ret = i2c_transfer(pDev->client->adapter, i2c_message, 2); + if (ret != 2) { + pr_err("NDS03: i2c read error, i2c_raddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_raddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len) +{ + int32_t ret; + struct i2c_msg i2c_message; + //For user implement + uint8_t i2c_buf[256]; + + memcpy(&i2c_buf[1], i2c_wdata, len); + i2c_buf[0] = i2c_waddr; + + i2c_message.addr = pDev->i2c_dev_addr; + i2c_message.buf = i2c_buf; + i2c_message.len = len + 1; + i2c_message.flags = 0; + ret = i2c_transfer(pDev->client->adapter, &i2c_message, 1); + if (ret != 1) { + pr_err("NDS03: i2c write error, i2c_waddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_waddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us) +{ + wait_10us *= 10; + if (wait_10us < 10) + udelay(wait_10us); + else if (wait_10us < 20000) + usleep_range(wait_10us, wait_10us + 1); + else + msleep(wait_10us / 1000); + return 0; +} + +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms) +{ + nds03_delay_10us(pDev, wait_ms * 100); + return 0; +} + +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level) +{ + if (pDev->xshut_gpio == NULL) { + pr_err("xshut_gpiod is not init , not setting xshut\n"); + return -1; + } + gpiod_set_value(pDev->xshut_gpio, level); + // pr_info("xshut set to %d\n", level); + return 0; +} + +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency) +{ + return 0; +} + +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency) +{ + return 0; +} + +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms) +{ + return 0; +} diff --git a/drivers/iio/proximity/nds03/nds03_platform.h b/drivers/iio/proximity/nds03/nds03_platform.h new file mode 100644 index 000000000000..56d68d1ff057 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.h @@ -0,0 +1,137 @@ +/*! + @file nds03_platform.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_PLATFORM__H__ +#define __NDS03_PLATFORM__H__ + +#include "nds03_stdint.h" +#include +#include +#include +#include +/** + * @struct NDS03_Platform_t + * + * @brief NDS03平台相关定义 \n + * 定义i2c地址等,注意必须定义i2c地址 + */ +typedef struct{ + //文件描述符 + int fd; + /** 用户不可更改以下变量 @{ */ + uint8_t i2c_dev_addr; // i2c设备地址 + /** @} */ + /** 用户可根据需要添加变量 */ + struct i2c_client *client; + ////// /* nds03 device io */ + struct gpio_desc *intr_gpio; + /*!< xsdn reset (low active) gpio number to device */ + struct gpio_desc *xshut_gpio; + +} NDS03_Platform_t; + +/** + * @brief NDS03平台初始化 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void *); + +/** + * @brief NDS03平台释放 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void *); + +/** + * @brief I2C读一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_raddr 读寄存器地址 + * @param i2c_rdata 读数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len); + +/** + * @brief I2C写一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_waddr 写寄存器地址 + * @param i2c_wdata 写数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len); + +/** + * @brief 延时wait_ms毫秒 + * + * @param pDev 平台设备指针 + * @param wait_ms 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms); + +/** + * @brief 延时10*wait_10us微秒 + * + * @param pDev 平台设备指针 + * @param wait_10us 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us); + +/** + * @brief 设置nds03 xshut引脚电平 + * + * @param pDev 平台设备指针 + * @param level 引脚电平,0为低电平,1为高电平 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level); + +/*! + @brief NDS03获取当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency); + +/*! + @brief NDS03设置当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency); +/*! + @brief 获取当前系统时间,单位ms + @param pDev + @param time_ms + @return int8_t + */ +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms); + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_stdint.h b/drivers/iio/proximity/nds03/nds03_stdint.h new file mode 100644 index 000000000000..c4657b0e98cd --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_stdint.h @@ -0,0 +1,95 @@ + +/** + * @file nds03_stdint.h + * @author tongsheng.tang + * @brief NDS03 platform-specific integer type definitions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_STDINT_H__ +#define __NDS03_STDINT_H__ + +#define PLATFORM_C51 0 +#define PLATFORM_NOT_C51 1 +#define PLATFORM_LINUX_DRIVER 2 +#ifndef NDS03_PLATFORM +#define NDS03_PLATFORM PLATFORM_LINUX_DRIVER +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include + +#elif NDS03_PLATFORM == PLATFORM_C51 + /* exact-width signed integer types */ + typedef signed char int8_t; + typedef signed int int16_t; + typedef signed long int32_t; + + /* exact-width unsigned integer types */ + typedef unsigned char uint8_t; + typedef unsigned int uint16_t; + typedef unsigned long uint32_t; + + #define __func__ __FILE__ + + /* minimum values of exact-width signed integer types */ + #define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ + + /* maximum values of exact-width signed integer types */ + #define INT32_MAX 2147483647 + + /* maximum values of exact-width unsigned integer types */ + #define UINT32_MAX 4294967295u + + /* 7.18.2.2 */ + + /* minimum values of minimum-width signed integer types */ + #define INT_LEAST32_MIN (~0x7fffffff) + + /* maximum values of minimum-width signed integer types */ + #define INT_LEAST32_MAX 2147483647 + + /* maximum values of minimum-width unsigned integer types */ + #define UINT_LEAST32_MAX 4294967295u + + /* 7.18.2.3 */ + + /* minimum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MIN (~0x7fffffff) + + /* maximum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MAX 2147483647 + + /* maximum values of fastest minimum-width unsigned integer types */ + #define UINT_FAST32_MAX 4294967295u +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER + /* exact-width signed integer types */ +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +/* exact-width unsigned integer types */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define __func__ __FILE__ + +/* minimum values of exact-width signed integer types */ +#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ +/* maximum values of exact-width signed integer types */ +#define INT32_MAX 2147483647 + +/* maximum values of exact-width unsigned integer types */ +#define UINT32_MAX 4294967295u +#endif + +#endif /** __NDS03_STDINT_H__ */ + diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c index 4dd6963d82a5..3455e35d421d 100644 --- a/drivers/mailbox/rockchip-mailbox.c +++ b/drivers/mailbox/rockchip-mailbox.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define MAILBOX_A2B_INTEN 0x00 @@ -28,11 +29,16 @@ #define MAILBOX_V2_A2B_STATUS MAILBOX_A2B_STATUS #define MAILBOX_V2_A2B_CMD 0x08 #define MAILBOX_V2_A2B_DAT 0x0c +#define MAILBOX_V2_A2B_LOCK 0x20 #define MAILBOX_V2_B2A_INTEN 0x10 #define MAILBOX_V2_B2A_STATUS 0x14 #define MAILBOX_V2_B2A_CMD 0x18 #define MAILBOX_V2_B2A_DAT 0x1c +#define MAILBOX_V2_B2A_LOCK 0x30 + +#define MAILBOX_V2_VERSION 0x40 +#define MAILBOX_V2_VERSION_MASK GENMASK(31, 16) #define MAILBOX_V2_TRIGGER_SHIFT 8 #define MAILBOX_V2_TRIGGER_MASK BIT(8) @@ -45,6 +51,11 @@ #define MAILBOX_V2_STATUS_RX_DONE BIT(1) #define MAILBOX_V2_STATUS_MASK GENMASK(1, 0) +#define MAILBOX_VERSION_1_0_0 0x100U +#define MAILBOX_VERSION_2_0_0 0x200U +#define MAILBOX_VERSION_2_1_0 0x210U +#define MAILBOX_VERSION_2_2_0 0x220U + #define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */ #define BIT_WRITEABLE_SHIFT 16 @@ -53,14 +64,17 @@ struct rockchip_mbox_reg { u32 tx_sts; u32 tx_cmd; u32 tx_dat; + u32 tx_lock; u32 rx_int; u32 rx_sts; u32 rx_cmd; u32 rx_dat; + u32 rx_lock; }; struct rockchip_mbox_data { int num_chans; + u32 version; struct rockchip_mbox_reg reg_a2b; struct rockchip_mbox_reg reg_b2a; const struct mbox_chan_ops *ops; @@ -78,6 +92,7 @@ struct rockchip_mbox { void __iomem *mbox_base; spinlock_t cfg_lock; /* Serialise access to the register */ unsigned char trigger_method; /* 0 = write cmd, 1 = write cmd first, then write data */ + u32 version; struct rockchip_mbox_msg *msg; const struct rockchip_mbox_reg *reg; @@ -181,17 +196,27 @@ static irqreturn_t rockchip_mbox_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static bool rockchip_mbox_v2_is_busy(struct rockchip_mbox *mb) +{ + u32 status; + + if (mb->version < MAILBOX_VERSION_2_2_0) + status = readl_relaxed(mb->mbox_base + mb->reg->tx_sts) & MAILBOX_V2_STATUS_TX_DONE; + else + status = readl_relaxed(mb->mbox_base + mb->reg->tx_lock); + + return !!status; +} + static int rockchip_mbox_v2_send_data(struct mbox_chan *chan, void *data) { struct rockchip_mbox *mb = dev_get_drvdata(chan->mbox->dev); struct rockchip_mbox_msg *msg = data; - u32 status; if (!msg) return -EINVAL; - status = readl_relaxed(mb->mbox_base + mb->reg->tx_sts); - if (status & MAILBOX_V2_STATUS_TX_DONE) { + if (rockchip_mbox_v2_is_busy(mb)) { dev_err(mb->mbox.dev, "The mailbox is busy\n"); return -EBUSY; } @@ -325,20 +350,26 @@ EXPORT_SYMBOL_GPL(rockchip_mbox_read_msg); static const struct rockchip_mbox_data rk3368_drv_data = { .num_chans = 4, + .version = MAILBOX_VERSION_1_0_0, .ops = &rockchip_mbox_chan_ops, .irq_func = rockchip_mbox_irq, }; static const struct rockchip_mbox_data rk3576_drv_data = { .num_chans = 1, + .version = MAILBOX_VERSION_2_0_0, .reg_a2b = { MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS, MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT, + MAILBOX_V2_A2B_LOCK, MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS, - MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT }, + MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT, + MAILBOX_V2_B2A_LOCK }, .reg_b2a = { MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS, MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT, + MAILBOX_V2_B2A_LOCK, MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS, - MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT }, + MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT, + MAILBOX_V2_A2B_LOCK }, .ops = &rockchip_mbox_v2_chan_ops, .irq_func = rockchip_mbox_v2_irq, }; @@ -350,6 +381,69 @@ static const struct of_device_id rockchip_mbox_of_match[] = { }; MODULE_DEVICE_TABLE(of, rockchip_mbox_of_match); +static void rockchip_mbox_get_properties(struct rockchip_mbox *mb, + const struct rockchip_mbox_data *drv_data) +{ + struct device *dev = mb->mbox.dev; + u32 txpoll_period; + int ret; + + if (device_property_present(dev, "rockchip,tx-direction-b2a")) + mb->reg = &drv_data->reg_b2a; + else + mb->reg = &drv_data->reg_a2b; + + /* + * rockchip,txdone-ack: the mailbox client uses its own ACK to check + * TX_DONE, and call mbox_client_txdone() API to schedule tx_tick. + * rockchip,txdone-irq: the feature only support from RK3506, the ISR + * function call mbox_chan_txdone() API to schedule tx_tick. + * txdone_poll is default for all the platform, it cooperates with + * "rockchip,txpoll-period-ms" or "rockchip,txpoll-period-us" + * periodically call last_tx_done() to check TX_DONE by the hrtimer + * in mailbox framework. + */ + if (device_property_present(dev, "rockchip,txdone-ack")) { + mb->mbox.txdone_irq = false; + mb->mbox.txdone_poll = false; + } else if (device_property_present(dev, "rockchip,txdone-irq")) { + mb->mbox.txdone_irq = true; + } else { + mb->mbox.txdone_poll = true; + if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-us", + &txpoll_period); + if (!ret) { + mb->mbox.txpoll_period = txpoll_period; + } else { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-ms", + &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + mb->mbox.txpoll_period *= 1000U; /* Convert to us */ + } + } else { + ret = device_property_read_u32(dev, + "rockchip,txpoll-period-ms", + &txpoll_period); + mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; + } + } + + if (device_property_present(dev, "rockchip,enable-cmd-trigger")) + mb->trigger_method = 0; + else + mb->trigger_method = 1; + + if (drv_data->version != MAILBOX_VERSION_1_0_0) + mb->version = FIELD_GET(MAILBOX_V2_VERSION_MASK, + readl_relaxed(mb->mbox_base + MAILBOX_V2_VERSION)); + + if (!mb->version) + mb->version = drv_data->version; +} + static int rockchip_mbox_probe(struct platform_device *pdev) { struct rockchip_mbox *mb; @@ -357,7 +451,6 @@ static int rockchip_mbox_probe(struct platform_device *pdev) const struct rockchip_mbox_data *drv_data; struct resource *res; int ret, irq, i; - u32 txpoll_period; if (!pdev->dev.of_node) return -ENODEV; @@ -391,54 +484,6 @@ static int rockchip_mbox_probe(struct platform_device *pdev) mb->mbox.ops = drv_data->ops; spin_lock_init(&mb->cfg_lock); - if (device_property_present(&pdev->dev, "rockchip,tx-direction-b2a")) - mb->reg = &drv_data->reg_b2a; - else - mb->reg = &drv_data->reg_a2b; - - /* - * rockchip,txdone-ack: the mailbox client uses its own ACK to check - * TX_DONE, and call mbox_client_txdone() API to schedule tx_tick. - * rockchip,txdone-irq: the feature only support from RK3506, the ISR - * function call mbox_chan_txdone() API to schedule tx_tick. - * txdone_poll is default for all the platform, it cooperates with - * "rockchip,txpoll-period-ms" or "rockchip,txpoll-period-us" - * periodically call last_tx_done() to check TX_DONE by the hrtimer - * in mailbox framework. - */ - if (device_property_present(&pdev->dev, "rockchip,txdone-ack")) { - mb->mbox.txdone_irq = false; - mb->mbox.txdone_poll = false; - } else if (device_property_present(&pdev->dev, "rockchip,txdone-irq")) { - mb->mbox.txdone_irq = true; - } else { - mb->mbox.txdone_poll = true; - if (IS_REACHABLE(CONFIG_MAILBOX_POLL_PERIOD_US)) { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-us", - &txpoll_period); - if (!ret) { - mb->mbox.txpoll_period = txpoll_period; - } else { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-ms", - &txpoll_period); - mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; - mb->mbox.txpoll_period *= 1000U; /* Convert to us */ - } - } else { - ret = device_property_read_u32(&pdev->dev, - "rockchip,txpoll-period-ms", - &txpoll_period); - mb->mbox.txpoll_period = !ret ? txpoll_period : MAILBOX_POLLING_MS; - } - } - - if (device_property_present(&pdev->dev, "rockchip,enable-cmd-trigger")) - mb->trigger_method = 0; - else - mb->trigger_method = 1; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -447,6 +492,8 @@ static int rockchip_mbox_probe(struct platform_device *pdev) if (IS_ERR(mb->mbox_base)) return PTR_ERR(mb->mbox_base); + rockchip_mbox_get_properties(mb, drv_data); + mb->pclk = devm_clk_get(&pdev->dev, "pclk_mailbox"); if (IS_ERR(mb->pclk)) { ret = PTR_ERR(mb->pclk); @@ -503,6 +550,13 @@ static int rockchip_mbox_probe(struct platform_device *pdev) enable_irq_wake(mb->chans[i].irq); } + dev_info(&pdev->dev, "version: 0x%04x, tx_dir: %s, tx_done: %s, poll_period: %u, fast_mode: %s\n", + mb->version, + mb->reg == &drv_data->reg_b2a ? "B2A" : "A2B", + mb->mbox.txdone_irq ? "irq" : mb->mbox.txdone_poll ? "poll" : "ack", + mb->mbox.txpoll_period, + str_yes_no(!mb->trigger_method)); + return 0; disable_clk: diff --git a/drivers/media/i2c/it6616.c b/drivers/media/i2c/it6616.c index 295b7930e6a2..42fdcad6cd0f 100644 --- a/drivers/media/i2c/it6616.c +++ b/drivers/media/i2c/it6616.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +266,7 @@ enum av_mute_state { }; enum { - AUDIO_OFF = 0x00, + AUDIO_OFF_MODE = 0x00, AUDIO_I2S = 0x01, AUDIO_SPDIF = 0x02, }; @@ -2659,7 +2660,7 @@ static void it6616_hdmi_tx_audio_output_enable(struct it6616 *it6616, u8 output_ it6616_hdmi_chgbank(hdmi, 1); switch (output_interface) { - case AUDIO_OFF: + case AUDIO_OFF_MODE: dev_info(dev, "audio off"); it6616_hdmi_write(hdmi, 0xC7, 0x7F); // SPDIF/I2S tri-state on break; @@ -2685,7 +2686,7 @@ static void it6616_hdmi_audio_mute_clear(struct it6616 *it6616) static void it6616_hdmi_rx_audio_process(struct it6616 *it6616) { - it6616_hdmi_tx_audio_output_enable(it6616, AUDIO_OFF); + it6616_hdmi_tx_audio_output_enable(it6616, AUDIO_OFF_MODE); it6616_hdmi_rx_reset_audio_logic(it6616); it6616_hdmi_tx_audio_setup(it6616); it6616_hdmi_audio_mute_clear(it6616); @@ -3052,6 +3053,7 @@ static int it6616_initial(struct it6616 *it6616) /* get device id */ if (it6616_get_chip_id(it6616)) { dev_err(dev, "can not find it6616"); + mutex_unlock(&it6616->confctl_mutex); return -ENODEV; } @@ -3277,7 +3279,7 @@ static ssize_t mipi_reg_store(struct device *dev, if (ret) { dev_info(dev, "addr= %2.2X\n", addr); dev_info(dev, "val = %2.2X\n", val); - if (((addr <= 0xFF) && (addr >= 0x00)) && ((val <= 0xFF) && (val >= 0x00))) + if (addr <= 0xFF && val <= 0xFF) regmap_write(mipi, addr, val); } else { dev_info(dev, "it6616_fwrite_mipi_reg , error[%s]\n", buf); @@ -3409,7 +3411,7 @@ static int it6616_get_detected_timings(struct v4l2_subdev *sd, bt->il_vsync = bt->vsync + 1; } - v4l2_dbg(1, debug, sd, "act:%dx%d, total:%dx%d, pixclk:%d, fps:%d\n", + v4l2_dbg(1, debug, sd, "act:%dx%d, total:%dx%d, pixclk:%llu, fps:%d\n", bt->width, bt->height, htotal, vtotal, bt->pixelclock, fps); v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d\n", bt->hfrontporch, bt->hsync, bt->hbackporch, @@ -3871,6 +3873,9 @@ static long it6616_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !it6616->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -3932,6 +3937,20 @@ static long it6616_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = it6616_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = it6616_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); @@ -4257,8 +4276,10 @@ static int it6616_probe(struct i2c_client *client, it6616->edid_i2c = i2c_new_dummy_device(client->adapter, I2C_ADR_EDID >> 1); - if (!it6616->edid_i2c) + if (!it6616->edid_i2c) { + err = -EIO; goto unregister_mipi_i2c; + } it6616->hdmi_regmap = devm_regmap_init_i2c(client, &it6616_hdmi_regmap_config); diff --git a/drivers/media/i2c/lt6911c.c b/drivers/media/i2c/lt6911c.c index 6b2f33a14fc6..621d62a407a8 100644 --- a/drivers/media/i2c/lt6911c.c +++ b/drivers/media/i2c/lt6911c.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -973,6 +974,9 @@ static long lt6911c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<6911c->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911c->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1051,6 +1055,20 @@ static long lt6911c_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911c_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt6911uxc.c b/drivers/media/i2c/lt6911uxc.c index 0dd879dae31c..c2ba244c42ed 100644 --- a/drivers/media/i2c/lt6911uxc.c +++ b/drivers/media/i2c/lt6911uxc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1028,6 +1029,9 @@ static long lt6911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) capture_info->mode = 0; } break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911uxc->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1122,6 +1126,20 @@ static long lt6911uxc_compat_ioctl32(struct v4l2_subdev *sd, } kfree(capture_info); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911uxc_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt6911uxe.c b/drivers/media/i2c/lt6911uxe.c index 64cf63cc3e08..05bf585cc75f 100644 --- a/drivers/media/i2c/lt6911uxe.c +++ b/drivers/media/i2c/lt6911uxe.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) @@ -1532,6 +1532,9 @@ static long lt6911uxe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) capture_info->multi_dev = lt6911uxe->multi_dev_info; } break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt6911uxe->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1647,6 +1650,20 @@ static long lt6911uxe_compat_ioctl32(struct v4l2_subdev *sd, } kfree(capture_info); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt6911uxe_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt7911d.c b/drivers/media/i2c/lt7911d.c index 830282be4e1b..5ddac0f5370b 100644 --- a/drivers/media/i2c/lt7911d.c +++ b/drivers/media/i2c/lt7911d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -900,6 +901,9 @@ static long lt7911d_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt7911d->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -940,6 +944,20 @@ static long lt7911d_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = lt7911d_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = lt7911d_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); diff --git a/drivers/media/i2c/lt7911uxc.c b/drivers/media/i2c/lt7911uxc.c index a894436bae27..eb92fbe5ff6f 100644 --- a/drivers/media/i2c/lt7911uxc.c +++ b/drivers/media/i2c/lt7911uxc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x07) @@ -1193,6 +1193,9 @@ static long lt7911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<7911uxc->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt7911uxc->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1292,6 +1295,20 @@ static long lt7911uxc_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt7911uxc_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/lt8668sx.c b/drivers/media/i2c/lt8668sx.c index 6dedf8d00995..ea4b043e634c 100644 --- a/drivers/media/i2c/lt8668sx.c +++ b/drivers/media/i2c/lt8668sx.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00) @@ -1181,6 +1181,9 @@ static long lt8668sx_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) dev_dbg(<8668sx->i2c_client->dev, "sensor get dphy param\n"); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !lt8668sx->nosignal; + break; default: ret = -ENOIOCTLCMD; break; @@ -1280,6 +1283,20 @@ static long lt8668sx_compat_ioctl32(struct v4l2_subdev *sd, } kfree(dphy_param); break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = lt8668sx_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index ab354f8d015e..b57dbc8e326a 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -78,6 +78,8 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = { regmap_reg_range(HDMI_RX_PDEC_ACR_CTS, HDMI_RX_PDEC_ACR_N), regmap_reg_range(HDMI_RX_PDEC_AVI_HB, HDMI_RX_PDEC_AVI_PB), regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_AIF_PB0), + regmap_reg_range(HDMI_RX_PDEC_GMD_HB0, HDMI_RX_PDEC_GMD_PB0), + regmap_reg_range(HDMI_RX_PDEC_DRM_HB, HDMI_RX_PDEC_DRM_PAYLOAD6), regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG), regmap_reg_range(HDMI_RX_SCDC_REGS0, HDMI_RX_SCDC_REGS2), regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA0), diff --git a/drivers/media/i2c/rk628/rk628.h b/drivers/media/i2c/rk628/rk628.h index f8312b71a132..51adbde3854b 100644 --- a/drivers/media/i2c/rk628/rk628.h +++ b/drivers/media/i2c/rk628/rk628.h @@ -314,6 +314,8 @@ struct rk628 { struct gpio_desc *hdmirx_det_gpio; bool last_mipi_status; bool is_suspend; + bool is_10bit; + bool enable_csi1; }; #define rk628_dbg(rk628, format, ...) \ diff --git a/drivers/media/i2c/rk628/rk628_csi.h b/drivers/media/i2c/rk628/rk628_csi.h index 62438abaff38..28a3f7d34c41 100644 --- a/drivers/media/i2c/rk628/rk628_csi.h +++ b/drivers/media/i2c/rk628/rk628_csi.h @@ -115,4 +115,18 @@ #define CSI_SKIP_FRAME_NORMAL 1 +enum csi_pixfmt { + CSI_RAW8 = 0, + CSI_RAW10, + CSI_PIXEL10, + CSI_PIXEL128, + CSI_RAW12, + CSI_PIXEL12, +}; + +enum csi_datatype { + YUV422_8BIT = 0x1e, + YUV422_10BIT = 0x1f, +}; + #endif diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index f699966f89cb..ba610f6f6405 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -133,6 +133,7 @@ struct rk628_csi { bool is_streaming; bool csi_ints_en; bool dual_mipi_use; + bool hdr_support; enum user_color_range user_color_range; }; @@ -151,8 +152,10 @@ struct rk628_edid { }; static const s64 link_freq_menu_items[] = { - RK628_CSI_LINK_FREQ_LOW, - RK628_CSI_LINK_FREQ_HIGH, + RK628_CSI_LINK_FREQ_350M, + RK628_CSI_LINK_FREQ_450M, + RK628_CSI_LINK_FREQ_650M, + RK628_CSI_LINK_FREQ_750M, RK628_CSI_LINK_FREQ_925M, }; @@ -240,6 +243,41 @@ static u8 rk628f_edid_init_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, }; +static u8 rk628f_hdr_edid_init_data[] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x24, 0xD0, 0x8F, 0x62, 0x01, 0x00, 0x00, 0x00, + 0x2D, 0x21, 0x01, 0x03, 0x80, 0x78, 0x44, 0x78, + 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, + 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x01, 0x01, 0x81, 0x00, 0x95, 0x00, 0xA9, 0xC0, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xE8, + 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, + 0x8A, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x49, + 0x46, 0x50, 0x20, 0x44, 0x69, 0x73, 0x70, 0x6C, + 0x61, 0x79, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, + 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA8, + + 0x02, 0x03, 0x40, 0xF2, 0x4D, 0x01, 0x03, 0x12, + 0x13, 0x84, 0x22, 0x1F, 0x90, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, + 0x00, 0x00, 0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, + 0x18, 0x44, 0x20, 0x00, 0x60, 0x03, 0x02, 0x01, + 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0x80, 0x00, + 0xE3, 0x05, 0xE3, 0x01, 0xE4, 0x0F, 0x00, 0x18, + 0x00, 0xE2, 0x00, 0xCB, 0xE3, 0x06, 0x0D, 0x01, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, + 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, + 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +}; static struct rk628_edid edid_data[] = { { @@ -250,6 +288,10 @@ static struct rk628_edid edid_data[] = { .version = 2, .data = rk628f_edid_init_data, }, + { + .version = 3, + .data = rk628f_hdr_edid_init_data, + }, }; static const unsigned int rk628_csi_extcon_cable[] = { @@ -444,11 +486,19 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, struct rk628_csi *csi = to_csi(sd); struct v4l2_bt_timings *bt = &timings->bt; int ret; + u32 val, eotf; + csi->rk628->is_10bit = false; ret = rk628_hdmirx_get_timings(csi->rk628, timings); if (ret) return ret; + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_DRM_HB, &val); + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_DRM_PAYLOAD0, &val); + eotf = (val >> 8) & 0xff; + if (eotf == 0x02 && csi->rk628->color_format == BUS_FMT_YUV422) + csi->rk628->is_10bit = true; + v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n", bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch, bt->vsync, bt->vbackporch, bt->interlaced); @@ -466,6 +516,13 @@ static int rk628_csi_get_detected_timings(struct v4l2_subdev *sd, csi->rk628->dual_mipi = false; } + if (csi->plat_data->tx_mode == CSI_MODE) { + if (csi->rk628->is_10bit) + csi->mbus_fmt_code = MEDIA_BUS_FMT_YUYV10_2X10; + else + csi->mbus_fmt_code = MEDIA_BUS_FMT_UYVY8_2X8; + } + return ret; } @@ -729,12 +786,12 @@ static void rk628_csi_soft_reset(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL0_IMD, 0x1); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_SYS_CTRL0_IMD, 0x1); rk628_mipi_txdata_reset(sd); rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL0_IMD, 0x0); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_SYS_CTRL0_IMD, 0x0); } @@ -757,13 +814,14 @@ static void enable_csitx(struct v4l2_subdev *sd) csi->rk628->dual_mipi ? GRF_DPHY_CH1_EN(1) : 0); rk628_i2c_update_bits(csi->rk628, GRF_POST_PROC_CON, SW_SPLIT_EN, csi->rk628->dual_mipi ? SW_SPLIT_EN : 0); + csi->rk628->enable_csi1 = csi->rk628->dual_mipi; rk628_csi_set_csi(sd); rk628_csi_soft_reset(sd); usleep_range(5000, 5500); //disabled csi state ints rk628_i2c_write(csi->rk628, CSITX_INTR_EN_IMD, 0x0fff0000); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_INTR_EN_IMD, 0x0fff0000); rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, @@ -772,7 +830,7 @@ static void enable_csitx(struct v4l2_subdev *sd) DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, @@ -787,7 +845,7 @@ static void enable_csitx(struct v4l2_subdev *sd) BYPASS_SELECT_MASK, BYPASS_SELECT(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_CLR_IMD, 0xffffffff); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); } @@ -900,7 +958,7 @@ static void rk628_csi_disable_stream(struct v4l2_subdev *sd) csi->continues_clk ? CONT_MODE_CLK_CLR(1) : CONT_MODE_CLK_CLR(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(0) | CSITX_EN(0)); @@ -1020,21 +1078,37 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) struct rk628_csi *csi = to_csi(sd); u8 video_fmt; u8 lanes = csi->csi_lanes_in_use; - u8 lane_num; - u32 wc_usrdef, val; + u8 lane_num, yc_swap; + u32 wc_usrdef, val, data_type, pixfmt; int avi_rdy; lane_num = lanes - 1; csi->rk628->dphy_lane_en = (1 << (lanes + 1)) - 1; - wc_usrdef = csi->timings.bt.width * 2; - if (csi->rk628->dual_mipi) + + if (csi->rk628->dual_mipi && !csi->rk628->is_10bit) wc_usrdef = csi->timings.bt.width; + else if (csi->rk628->dual_mipi && csi->rk628->is_10bit) + wc_usrdef = div_u64(csi->timings.bt.width * 10, 8); + else if (!csi->rk628->dual_mipi && csi->rk628->is_10bit) + wc_usrdef = div_u64(csi->timings.bt.width * 2 * 10, 8); + else + wc_usrdef = csi->timings.bt.width * 2; + + if (csi->rk628->is_10bit) { + pixfmt = CSI_RAW10; + data_type = YUV422_10BIT; + yc_swap = 1; + } else { + pixfmt = CSI_RAW8; + data_type = YUV422_8BIT; + yc_swap = 0; + } v4l2_info(sd, "%s mipi mode, word count user define: %d\n", csi->rk628->dual_mipi ? "dual" : "single", wc_usrdef); rk628_csi_disable_stream(sd); usleep_range(5000, 5500); rk628_csi0_cru_reset(sd); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_csi1_cru_reset(sd); rk628_post_process_setup(sd); @@ -1069,6 +1143,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) BYPASS_SELECT(1)); } else { rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, + VOP_YU_SWAP_MASK | VOP_UV_SWAP_MASK | VOP_YUV422_EN_MASK | VOP_YUV422_MODE_MASK | @@ -1076,6 +1151,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) LANE_NUM_MASK | DPHY_EN_MASK | CSITX_EN_MASK, + VOP_YU_SWAP(yc_swap) | VOP_UV_SWAP(0) | VOP_YUV422_EN(1) | VOP_YUV422_MODE(2) | @@ -1109,8 +1185,8 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX_VOP_PATH_CTRL, VOP_WC_USERDEFINE(wc_usrdef) | - VOP_DT_USERDEFINE(YUV422_8BIT) | - VOP_PIXEL_FORMAT(0) | + VOP_DT_USERDEFINE(data_type) | + VOP_PIXEL_FORMAT(pixfmt) | VOP_WC_USERDEFINE_EN(1) | VOP_DT_USERDEFINE_EN(1) | VOP_PATH_EN(1)); @@ -1123,8 +1199,9 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); v4l2_dbg(1, debug, sd, "%s csi config done\n", __func__); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, + VOP_YU_SWAP_MASK | VOP_UV_SWAP_MASK | VOP_YUV422_EN_MASK | VOP_YUV422_MODE_MASK | @@ -1132,6 +1209,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) LANE_NUM_MASK | DPHY_EN_MASK | CSITX_EN_MASK, + VOP_YU_SWAP(yc_swap) | VOP_UV_SWAP(0) | VOP_YUV422_EN(1) | VOP_YUV422_MODE(2) | @@ -1163,8 +1241,8 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_i2c_write(csi->rk628, CSITX1_VOP_PATH_CTRL, VOP_WC_USERDEFINE(wc_usrdef) | - VOP_DT_USERDEFINE(YUV422_8BIT) | - VOP_PIXEL_FORMAT(0) | + VOP_DT_USERDEFINE(data_type) | + VOP_PIXEL_FORMAT(pixfmt) | VOP_WC_USERDEFINE_EN(1) | VOP_DT_USERDEFINE_EN(1) | VOP_PATH_EN(1)); @@ -1473,6 +1551,10 @@ static void rk628_csi_initial(struct v4l2_subdev *sd) def_edid.edid = edid_init_data; csi->edid_version = 1; } + if (csi->hdr_support && csi->rk628->version >= RK628F_VERSION) { + def_edid.edid = rk628f_hdr_edid_init_data; + csi->edid_version = 3; + } rk628_csi_s_edid(sd, &def_edid); } @@ -1568,7 +1650,7 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) rk628_csi_clear_csi_interrupts(sd); //disabled csi state ints rk628_i2c_write(csi->rk628, CSITX_INTR_EN_IMD, 0x0fff0000); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_INTR_EN_IMD, 0x0fff0000); //enable csi error ints @@ -1578,7 +1660,8 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, CSI_INT_EN(3) | CSI_INT_WRITE_EN(3)); rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_EN_IMD, 0x0fff0fff); - rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0fff); + if (csi->rk628->enable_csi1) + rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0fff); } else { rk628_i2c_update_bits(csi->rk628, GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, @@ -1592,7 +1675,8 @@ static void rk628_csi_enable_csi_interrupts(struct v4l2_subdev *sd, bool en) GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, CSI_INT_EN(0) | CSI_INT_WRITE_EN(3)); rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_EN_IMD, 0x0fff0000); - rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0000); + if (csi->rk628->enable_csi1) + rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_EN_IMD, 0x0fff0000); } else { rk628_i2c_update_bits(csi->rk628, GRF_INTR0_EN, CSI_INT_EN_MASK | CSI_INT_WRITE_EN_MASK, @@ -1638,7 +1722,7 @@ static void rk628_csi_clear_csi_interrupts(struct v4l2_subdev *sd) //clr int status rk628_i2c_write(csi->rk628, CSITX_ERR_INTR_CLR_IMD, 0xffffffff); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_ERR_INTR_CLR_IMD, 0xffffffff); if (csi->rk628->version >= RK628F_VERSION) @@ -1670,11 +1754,11 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_hdmirx_vid_enable(sd, false); rk628_csi_enable_csi_interrupts(sd, false); rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(0)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(0)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); usleep_range(5000, 5500); @@ -1687,7 +1771,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); @@ -1695,7 +1779,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) for (i = 0; i < 3; i++) { rk628_i2c_read(csi->rk628, CSITX_CSITX_EN, &val); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_read(csi->rk628, CSITX1_CSITX_EN, &val_csi1); v4l2_dbg(1, debug, sd, "%s, csi0_status: 0x%x, csi1_status: 0x%x, i=%d\n", __func__, val, val_csi1, i); @@ -1707,7 +1791,7 @@ static void rk628_csi_error_process(struct v4l2_subdev *sd) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, CSITX_EN_MASK, CSITX_EN(1)); rk628_i2c_write(csi->rk628, @@ -1862,7 +1946,7 @@ static int rk628_csi_isr(struct v4l2_subdev *sd, u32 status, bool *handled) v4l2_dbg(1, debug, sd, "%s: int0 status: 0x%x\n", __func__, int0_status); rk628_i2c_read(csi->rk628, CSITX_ERR_INTR_RAW_STATUS_IMD, &csi0_raw_ints); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_i2c_read(csi->rk628, CSITX1_ERR_INTR_RAW_STATUS_IMD, &csi1_raw_ints); rk628_csi_clear_csi_interrupts(sd); @@ -2141,7 +2225,7 @@ static int rk628_csi_enum_frame_interval(struct v4l2_subdev *sd, static u32 rk628_csi_get_lane_rate_mbps(struct rk628_csi *csi) { u32 lane_rate; - u32 max_lane_rate = 1300; + u32 max_lane_rate = 1800; u8 bpp, lanes; u64 pixelclock = csi->timings.bt.pixelclock; @@ -2152,23 +2236,48 @@ static u32 rk628_csi_get_lane_rate_mbps(struct rk628_csi *csi) lane_rate = div_u64(lane_rate, lanes); if (csi->rk628->dual_mipi) lane_rate /= 2; + if (csi->rk628->is_10bit) + lane_rate = div_u64(lane_rate * 5, 4); - if (lane_rate > 1300) + if (lane_rate > 1500) lane_rate = max_lane_rate; - else if (lane_rate > 700 && lane_rate <= 1300) + else if (lane_rate > 1300 && lane_rate <= 1500) + lane_rate = 1500; + else if (lane_rate > 900 && lane_rate <= 1300) lane_rate = 1300; + else if (lane_rate > 700 && lane_rate <= 900) + lane_rate = 900; else lane_rate = 700; return lane_rate; } +static int rk628_find_best_link_freq(u32 rate) +{ + u32 dist; + int cur_best_fit = 0; + u32 cur_best_fit_dist = -1; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + dist = abs(div_u64(link_freq_menu_items[i] * 2, 1000000) - rate); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + cur_best_fit = i; + } + } + + return cur_best_fit; +} + static int rk628_csi_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct rk628_csi *csi = to_csi(sd); u32 rate; + int index; if (!tx_5v_power_present(sd) || csi->nosignal) { v4l2_info(sd, "%s hdmirx no signal\n", __func__); @@ -2195,13 +2304,8 @@ static int rk628_csi_get_fmt(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s mipi bitrate:%u mbps\n", __func__, rate); - if (rate > 1300) - __v4l2_ctrl_s_ctrl(csi->link_freq, 2); - else if (rate <= 1300 && rate > 700) - __v4l2_ctrl_s_ctrl(csi->link_freq, 1); - else - __v4l2_ctrl_s_ctrl(csi->link_freq, 0); - + index = rk628_find_best_link_freq(rate); + __v4l2_ctrl_s_ctrl(csi->link_freq, index); __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, RK628_CSI_PIXEL_RATE_HIGH); mutex_unlock(&csi->confctl_mutex); @@ -2256,11 +2360,15 @@ static int rk628_csi_set_fmt(struct v4l2_subdev *sd, switch (code) { case MEDIA_BUS_FMT_UYVY8_2X8: - if (csi->plat_data->bus_fmt == MEDIA_BUS_FMT_UYVY8_2X8) + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_2X8) break; return -EINVAL; case MEDIA_BUS_FMT_RGB888_1X24: - if (csi->plat_data->bus_fmt == MEDIA_BUS_FMT_RGB888_1X24) + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24) + break; + return -EINVAL; + case MEDIA_BUS_FMT_YUYV10_2X10: + if (csi->mbus_fmt_code == MEDIA_BUS_FMT_YUYV10_2X10) break; return -EINVAL; default: @@ -2447,7 +2555,8 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | CONT_MODE_CLK_SET(1) | NON_CONTINUOUS_MODE(0)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && + csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_SYS_CTRL3_IMD, CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | @@ -2457,7 +2566,8 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | CONT_MODE_CLK_SET(0) | NON_CONTINUOUS_MODE(1)); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && + csi->rk628->enable_csi1) rk628_i2c_update_bits(csi->rk628, CSITX1_SYS_CTRL3_IMD, CONT_MODE_CLK_CLR_MASK | CONT_MODE_CLK_SET_MASK | NON_CONTINUOUS_MODE_MASK, CONT_MODE_CLK_CLR(0) | @@ -2467,7 +2577,7 @@ static void rk628_csi_reset_streaming(struct v4l2_subdev *sd, int on) rk628_i2c_update_bits(csi->rk628, CSITX_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { rk628_i2c_update_bits(csi->rk628, CSITX1_CSITX_EN, DPHY_EN_MASK | CSITX_EN_MASK, DPHY_EN(1) | CSITX_EN(1)); rk628_i2c_write(csi->rk628, CSITX1_CONFIG_DONE, CONFIG_DONE_IMD); @@ -2521,6 +2631,8 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_capture_info *capture_info; u32 stream = 0; int edid_version, i; + struct hdr_metadata_infoframe hdmi_metadata; + u8 input_color_space; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2619,6 +2731,18 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } v4l2_info(sd, "the edid version is not supported: %d\n", edid_version); return -EINVAL; + case RK_HDMIRX_CMD_GET_HDR_METADATA: + rk628_hdmirx_get_hdr_matedata(csi->rk628, &hdmi_metadata); + memcpy(arg, &hdmi_metadata, sizeof(hdmi_metadata)); + break; + case RK_HDMIRX_CMD_GET_OUTPUT_COLOR_RANGE: + *(int *)arg = HDMIRX_FULL_RANGE; + break; + case RK_HDMIRX_CMD_GET_OUTPUT_COLOR_SPACE: + input_color_space = rk628_csc_color_space_convert(csi->rk628->color_space, + csi->rk628->color_format); + *(int *)arg = rk628_get_output_color_space(csi->rk628, input_color_space); + break; default: ret = -ENOIOCTLCMD; break; @@ -2637,7 +2761,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) csi->lane_mbps = rk628_csi_get_lane_rate_mbps(csi); bus_width = csi->lane_mbps << 8; bus_width |= COMBTXPHY_MODULEA_EN; - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) bus_width |= COMBTXPHY_MODULEB_EN; v4l2_info(sd, "%s mipi bitrate:%llu mbps\n", __func__, csi->lane_mbps); @@ -2648,7 +2772,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) rk628_txphy_set_mode(csi->rk628, PHY_MODE_VIDEO_MIPI); rk628_mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps, 0); - if (csi->rk628->version >= RK628F_VERSION) + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) rk628_mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps, 1); rk628_txphy_power_on(csi->rk628); @@ -2660,7 +2784,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) 0, 1000); if (ret < 0) dev_err(csi->rk628->dev, "csi0 phy is not locked\n"); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { ret = regmap_read_poll_timeout(csi->rk628->regmap[RK628_DEV_CSI1], CSITX1_CSITX_STATUS1, val, val & DPHY_PLL_LOCK, @@ -2677,7 +2801,7 @@ static int mipi_dphy_power_on(struct rk628_csi *csi) if (ret < 0) dev_err(csi->rk628->dev, "csi0 lane module is not in stop state, val: 0x%x\n", val); - if (csi->rk628->version >= RK628F_VERSION) { + if (csi->rk628->version >= RK628F_VERSION && csi->rk628->enable_csi1) { ret = regmap_read_poll_timeout(csi->rk628->regmap[RK628_DEV_CSI1], CSITX1_CSITX_STATUS1, val, (val & mask) == mask, @@ -3223,6 +3347,9 @@ static int rk628_csi_probe_of(struct rk628_csi *csi) if (of_property_read_bool(dev->of_node, "cec-enable")) csi->cec_enable = true; + if (of_property_read_bool(dev->of_node, "hdr-support")) + csi->hdr_support = true; + if (of_property_read_bool(dev->of_node, "i2s-enable-default")) i2s_enable_default = true; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 9c48ab6257fd..291b63b79f10 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1572,6 +1572,38 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata) +{ + u32 val; + int i; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_HB, &val); + if (!val) + return -EINVAL; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD0, &val); + hdmi_metadata->eotf = (val >> 8) & 0xff; + hdmi_metadata->metadata_type = (val >> 16) & 0xff; + for (i = 0; i < 3; i++) { + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD1 + i * 4, &val); + hdmi_metadata->display_primaries[i].x = val & 0xffff; + hdmi_metadata->display_primaries[i].y = (val >> 16) & 0xffff; + } + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD4, &val); + hdmi_metadata->white_point.x = val & 0xffff; + hdmi_metadata->white_point.y = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD5, &val); + hdmi_metadata->max_display_mastering_luminance = val & 0xffff; + hdmi_metadata->min_display_mastering_luminance = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD6, &val); + hdmi_metadata->max_cll = val & 0xffff; + hdmi_metadata->max_fall = (val >> 16) & 0xffff; + + return 0; +} +EXPORT_SYMBOL(rk628_hdmirx_get_hdr_matedata); + struct rk628_timings { int vic; int hactive; @@ -1721,6 +1753,7 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, hfp = hfp * 2 * 8 / 10; hbp = hbp * 2 * 8 / 10; hs = hs * 2 * 8 / 10; + rk628->is_10bit = true; } else { htotal *= 2; hact *= 2; @@ -1898,9 +1931,9 @@ u8 rk628_hdmirx_get_range(struct rk628 *rk628) if (dvi) color_range = HDMIRX_FULL_RANGE; if (color_range == HDMIRX_DEFAULT_RANGE) - vic ? - (color_range = HDMIRX_FULL_RANGE) : - (color_range = HDMIRX_LIMIT_RANGE); + ((vic >= 2) && (vic <= 127)) ? + (color_range = HDMIRX_LIMIT_RANGE) : + (color_range = HDMIRX_FULL_RANGE); } return color_range; @@ -2205,6 +2238,7 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) bool plugin; u32 val, htot, vtot, fps, format; u8 fmt, range, space; + struct hdr_metadata_infoframe hdmi_metadata; plugin = rk628_hdmirx_tx_5v_power_detect(rk628->hdmirx_det_gpio); seq_printf(s, "status: %s\n", plugin ? "plugin" : "plugout"); @@ -2265,6 +2299,41 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) else seq_puts(s, "Unknown\n"); + seq_puts(s, "EOTF: "); + if (!rk628_hdmirx_get_hdr_matedata(rk628, &hdmi_metadata)) { + switch (hdmi_metadata.eotf & 0x7) { + case HDMI_EOTF_TRADITIONAL_GAMMA_SDR: + seq_puts(s, "SDR"); + break; + case HDMI_EOTF_TRADITIONAL_GAMMA_HDR: + seq_puts(s, "HDR"); + break; + case HDMI_EOTF_SMPTE_ST2084: + seq_puts(s, "ST2084"); + break; + case HDMI_EOTF_BT_2100_HLG: + seq_puts(s, "HLG"); + break; + default: + seq_puts(s, "Not Defined\n"); + return 0; + } + seq_printf(s, "\nx0: %d", hdmi_metadata.display_primaries[0].x); + seq_printf(s, "\t\t\t\ty0: %d\n", hdmi_metadata.display_primaries[0].y); + seq_printf(s, "x1: %d", hdmi_metadata.display_primaries[1].x); + seq_printf(s, "\t\t\t\ty1: %d\n", hdmi_metadata.display_primaries[1].y); + seq_printf(s, "x2: %d", hdmi_metadata.display_primaries[2].x); + seq_printf(s, "\t\t\t\ty2: %d\n", hdmi_metadata.display_primaries[2].y); + seq_printf(s, "white x: %d", hdmi_metadata.white_point.x); + seq_printf(s, "\t\t\twhite y: %d\n", hdmi_metadata.white_point.y); + seq_printf(s, "max lum: %d", hdmi_metadata.max_display_mastering_luminance); + seq_printf(s, "\t\t\tmin lum: %d\n", hdmi_metadata.min_display_mastering_luminance); + seq_printf(s, "max cll: %d", hdmi_metadata.max_cll); + seq_printf(s, "\t\t\tmax fall: %d\n", hdmi_metadata.max_fall); + } else { + seq_puts(s, "Off\n"); + } + return 0; } diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 99090e1841ff..ea0e091e82b0 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -8,6 +8,8 @@ #ifndef __RK628_HDMIRX_H #define __RK628_HDMIRX_H +#include +#include #include #include #include @@ -280,6 +282,16 @@ #define HDMI_RX_PDEC_AIF_CTRL (HDMI_RX_BASE + 0x03c0) #define FC_LFE_EXCHG(x) UPDATE(x, 18, 18) #define HDMI_RX_PDEC_AIF_PB0 (HDMI_RX_BASE + 0x03c8) +#define HDMI_RX_PDEC_GMD_HB0 (HDMI_RX_BASE + 0x03d0) +#define HDMI_RX_PDEC_GMD_PB0 (HDMI_RX_BASE + 0x03d4) +#define HDMI_RX_PDEC_DRM_HB (HDMI_RX_BASE + 0x04c0) +#define HDMI_RX_PDEC_DRM_PAYLOAD0 (HDMI_RX_BASE + 0x04c4) +#define HDMI_RX_PDEC_DRM_PAYLOAD1 (HDMI_RX_BASE + 0x04c8) +#define HDMI_RX_PDEC_DRM_PAYLOAD2 (HDMI_RX_BASE + 0x04cc) +#define HDMI_RX_PDEC_DRM_PAYLOAD3 (HDMI_RX_BASE + 0x04d0) +#define HDMI_RX_PDEC_DRM_PAYLOAD4 (HDMI_RX_BASE + 0x04d4) +#define HDMI_RX_PDEC_DRM_PAYLOAD5 (HDMI_RX_BASE + 0x04d8) +#define HDMI_RX_PDEC_DRM_PAYLOAD6 (HDMI_RX_BASE + 0x04dc) #define HDMI_RX_HDMI20_CONTROL (HDMI_RX_BASE + 0x0800) #define PVO1UNMUTE(x) UPDATE(x, 29, 29) @@ -448,6 +460,10 @@ #define RK628_CSI_LINK_FREQ_LOW 350000000 #define RK628_CSI_LINK_FREQ_HIGH 650000000 +#define RK628_CSI_LINK_FREQ_350M 350000000 +#define RK628_CSI_LINK_FREQ_450M 450000000 +#define RK628_CSI_LINK_FREQ_650M 650000000 +#define RK628_CSI_LINK_FREQ_750M 750000000 #define RK628_CSI_LINK_FREQ_925M 925000000 #define RK628_CSI_PIXEL_RATE_LOW 400000000 #define RK628_CSI_PIXEL_RATE_HIGH 600000000 @@ -459,7 +475,6 @@ #define CSITX_ERR_RETRY_TIMES 3 #define USE_4_LANES 4 -#define YUV422_8BIT 0x1e #define SCDC_CED_ERR_CNT 0xfff @@ -545,6 +560,8 @@ int rk628_hdmirx_get_timings(struct rk628 *rk628, u8 rk628_hdmirx_get_range(struct rk628 *rk628); u8 rk628_hdmirx_get_color_space(struct rk628 *rk628); int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); bool rk628_hdmirx_is_locked(struct rk628 *rk628); diff --git a/drivers/media/i2c/rk628/rk628_post_process.c b/drivers/media/i2c/rk628/rk628_post_process.c index 05db9ee6f6fc..ffafabf01bc1 100644 --- a/drivers/media/i2c/rk628/rk628_post_process.c +++ b/drivers/media/i2c/rk628/rk628_post_process.c @@ -1603,7 +1603,7 @@ static int rockchip_calc_post_csc(struct rk628 *rk628, struct post_csc_coef *csc return ret; } -static u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) +u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) { switch (in_color_space) { case HDMIRX_XVYCC601: @@ -1628,8 +1628,9 @@ static u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format) return OPTM_CS_E_UNKNOWN; } } +EXPORT_SYMBOL(rk628_csc_color_space_convert); -static u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space) +u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space) { switch (input_color_space) { case OPTM_CS_E_XV_YCC_601: @@ -1646,6 +1647,7 @@ static u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space return OPTM_CS_E_XV_YCC_709; } } +EXPORT_SYMBOL(rk628_get_output_color_space); static void rk628_post_process_csc(struct rk628 *rk628, bool is_input_full_range, bool is_output_full_range) diff --git a/drivers/media/i2c/rk628/rk628_post_process.h b/drivers/media/i2c/rk628/rk628_post_process.h index a9ccbcb49929..4503910b872c 100644 --- a/drivers/media/i2c/rk628/rk628_post_process.h +++ b/drivers/media/i2c/rk628/rk628_post_process.h @@ -7,6 +7,8 @@ #ifndef POST_PROCESS_H #define POST_PROCESS_H +u8 rk628_csc_color_space_convert(u8 in_color_space, u8 format); +u8 rk628_get_output_color_space(struct rk628 *rk628, u8 input_color_space); void rk628_post_process_csc_en(struct rk628 *rk628, bool input_full_range, bool output_full_range); void rk628_post_process_csc_dis(struct rk628 *rk628); void rk628_post_process_pattern_node(struct rk628 *rk628); diff --git a/drivers/media/i2c/sc850sl.c b/drivers/media/i2c/sc850sl.c index 2abad1b2d37b..0c7ed5411091 100644 --- a/drivers/media/i2c/sc850sl.c +++ b/drivers/media/i2c/sc850sl.c @@ -1479,7 +1479,6 @@ static int __sc850sl_stop_stream(struct sc850sl *sc850sl) sc850sl->has_init_exp = false; if (sc850sl->is_thunderboot) { sc850sl->is_first_streamoff = true; - pm_runtime_put(&sc850sl->client->dev); } return sc850sl_write_reg(sc850sl->client, SC850SL_REG_CTRL_MODE, SC850SL_REG_VALUE_08BIT, SC850SL_MODE_SW_STANDBY); diff --git a/drivers/media/i2c/tc35874x.c b/drivers/media/i2c/tc35874x.c index 2c9bbd63e4e1..0470684ca8a4 100644 --- a/drivers/media/i2c/tc35874x.c +++ b/drivers/media/i2c/tc35874x.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1946,6 +1947,9 @@ static long tc35874x_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RKMODULE_GET_HDMI_MODE: *(int *)arg = RKMODULE_HDMIIN_MODE; break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = !no_signal(sd); + break; default: ret = -ENOIOCTLCMD; break; @@ -2001,6 +2005,20 @@ static long tc35874x_compat_ioctl32(struct v4l2_subdev *sd, return ret; } + ret = tc35874x_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } ret = tc35874x_ioctl(sd, cmd, seq); if (!ret) { ret = copy_to_user(up, seq, sizeof(*seq)); diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 4693ab164847..1fa10183ed62 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -5041,10 +5041,25 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, channel->crop_st_y << 16 | (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } + val = channel->virtual_width; if (dev->chip_id >= CHIP_RV1103B_CIF && dev->sditf[0] && dev->sditf[0]->hdr_wrap_line) val |= dev->sditf[0]->hdr_wrap_line << 20; + if (dev->chip_id >= CHIP_RK3562_CIF) + val |= BIT(31); rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), val); if (stream->lack_buf_cnt == 2) @@ -5172,18 +5187,7 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, } else { atomic_inc(&stream->cifdev->id_use_cnt); } - if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && - index < capture_info->multi_dev.dev_num - 1)) { - if (mode == RKCIF_STREAM_MODE_CAPTURE) - rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - else if (mode == RKCIF_STREAM_MODE_TOISP || - mode == RKCIF_STREAM_MODE_TOISP_RDBK) - rkcif_assign_new_buffer_pingpong_toisp(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - } + dev->intr_mask = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_INTEN); return 0; } @@ -5306,10 +5310,24 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, channel->crop_st_y << 16 | (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } + val = channel->virtual_width; if (dev->sditf[0] && dev->sditf[0]->hdr_wrap_line) val |= dev->sditf[0]->hdr_wrap_line << 20; + val |= BIT(31); rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), val); if (stream->lack_buf_cnt == 2) @@ -5387,18 +5405,7 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream, } else { atomic_inc(&stream->cifdev->id_use_cnt); } - if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && - index < capture_info->multi_dev.dev_num - 1)) { - if (mode == RKCIF_STREAM_MODE_CAPTURE) - rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - else if (mode == RKCIF_STREAM_MODE_TOISP || - mode == RKCIF_STREAM_MODE_TOISP_RDBK) - rkcif_assign_new_buffer_pingpong_toisp(stream, - RKCIF_YUV_ADDR_STATE_INIT, - channel->id); - } + dev->intr_mask = rkcif_read_register(dev, CIF_REG_MIPI_LVDS_INTEN); return 0; } @@ -5640,7 +5647,12 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) } } else { - if (atomic_read(&cif_dev->pipe.stream_cnt) == 1) { + if (stream->cifdev->chip_id >= CHIP_RV1126B_CIF) { + val = rkcif_read_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id)); + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); + rkcif_write_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id), val); + } + if (atomic_read(&stream->cifdev->id_use_cnt) == 0) { val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val & (~ENABLE_CAPTURE)); @@ -7897,6 +7909,7 @@ static int rkcif_stream_start(struct rkcif_stream *stream, unsigned int mode) if (dma_state) return 0; + atomic_inc(&stream->cifdev->id_use_cnt); mbus_flags = mbus->bus.parallel.flags; if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { bt1120_edge_mode = (dev->chip_id < CHIP_RK3588_CIF ? @@ -8264,6 +8277,7 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int if (dma_state) return 0; + atomic_inc(&stream->cifdev->id_use_cnt); mbus_flags = mbus->bus.parallel.flags; if ((mbus_flags & CIF_DVP_PCLK_DUAL_EDGE) == CIF_DVP_PCLK_DUAL_EDGE) { bt1120_edge_mode = BT1120_CLOCK_DOUBLE_EDGES_RV1126B; @@ -8306,7 +8320,6 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int } } - val = stream->pixm.plane_fmt[0].bytesperline; if (stream->crop_enable) { dev->channels[stream->id].crop_en = 1; dev->channels[stream->id].crop_st_x = stream->crop[CROP_SRC_ACT].left; @@ -8321,10 +8334,6 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int dev->channels[stream->id].crop_en = 0; } - if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) - val = (val + 23) / 24 * 24; - - rkcif_write_register(dev, get_dvp_reg_index_of_vlw(stream->id), val); rkcif_write_register(dev, CIF_REG_DVP_SET_SIZE_ID0 + stream->id, dev->channels[stream->id].width | (dev->channels[stream->id].height << 16)); @@ -8351,6 +8360,11 @@ static int rkcif_stream_start_rv1126b(struct rkcif_stream *stream, unsigned int stream->id); } + val = stream->pixm.plane_fmt[0].bytesperline; + if (dev->chip_id > CHIP_RK3562_CIF && stream->sw_dbg_en) + val = (val + 23) / 24 * 24; + rkcif_write_register(dev, get_dvp_reg_index_of_vlw(stream->id), val | BIT(31)); + dev->workmode = RKCIF_WORKMODE_PINGPONG; href_pol = (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) ? HSY_HIGH_ACTIVE : HSY_LOW_ACTIVE; @@ -12122,7 +12136,6 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) active_buf->dbufs.sequence = stream->sequence; active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = rkcif_time_get_ns(stream->cifdev); - stream->last_frame_idx = stream->frame_idx; if (stream->cifdev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(stream, &active_buf->dbufs); if (stream->cifdev->is_support_tools && stream->tools_vdev) @@ -12139,9 +12152,12 @@ static void rkcif_deal_readout_time(struct rkcif_stream *stream) struct rkcif_device *cif_dev = stream->cifdev; struct rkcif_stream *detect_stream = &cif_dev->stream[0]; unsigned long flags; + u64 cur_time = 0; spin_lock_irqsave(&stream->fps_lock, flags); - stream->readout.fe_timestamp = rkcif_time_get_ns(cif_dev); + cur_time = rkcif_time_get_ns(cif_dev); + stream->readout.rate_time = cur_time - stream->readout.fe_timestamp; + stream->readout.fe_timestamp = cur_time; if (cif_dev->inf_id == RKCIF_DVP) { spin_unlock_irqrestore(&stream->fps_lock, flags); @@ -12241,7 +12257,8 @@ static void rkcif_update_stream_interlace(struct rkcif_device *cif_dev, } } } - rkcif_deal_readout_time(stream); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) + rkcif_deal_readout_time(stream); stream->last_fe_interlaced_phase = fe_interlaced_phase; } @@ -12273,7 +12290,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, spin_unlock_irqrestore(&stream->fps_lock, flags); } - rkcif_deal_readout_time(stream); + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) + rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, @@ -12281,7 +12299,6 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, mipi_id); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) return; - stream->last_frame_idx = stream->frame_idx; } else { ret = rkcif_update_new_buffer_wake_up_mode(stream); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) @@ -12318,7 +12335,7 @@ static void rkcif_update_stream_toisp(struct rkcif_device *cif_dev, stream->fps_stats.frm1_timestamp = rkcif_time_get_ns(cif_dev); spin_unlock(&stream->fps_lock); - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) rkcif_deal_readout_time(stream); if (!stream->is_line_wake_up) @@ -12355,7 +12372,7 @@ static void rkcif_update_stream_rockit(struct rkcif_device *cif_dev, spin_unlock_irqrestore(&stream->fps_lock, flags); } - if (cif_dev->inf_id == RKCIF_MIPI_LVDS) + if (!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) rkcif_deal_readout_time(stream); rkcif_assign_new_buffer_pingpong_rockit(stream, @@ -13347,7 +13364,7 @@ void rkcif_enable_dma_capture(struct rkcif_stream *stream, bool is_only_enable) else if (cif_dev->chip_id < CHIP_RK3576_CIF) rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(28) << stream->id); else - rkcif_write_register_or(cif_dev, CIF_REG_DVP_VIR_LINE_WIDTH, BIT(31)); + rkcif_write_register_or(cif_dev, get_dvp_reg_index_of_vlw(stream->id), BIT(31)); } if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY) { @@ -13442,16 +13459,22 @@ static int rkcif_stop_dma_capture(struct rkcif_stream *stream) } rkcif_write_register(cif_dev, get_reg_index_of_lvds_id_ctrl0(stream->id), val); } else { - val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); - if (cif_dev->chip_id == CHIP_RK3588_CIF) - val &= ~DVP_DMA_EN; - else if (cif_dev->chip_id == CHIP_RV1106_CIF) - val &= ~(DVP_SW_DMA_EN(stream->id)); - if (stream->is_stop_capture) { - val &= ~ENABLE_CAPTURE; - stream->is_stop_capture = false; + if (stream->cifdev->chip_id >= CHIP_RV1126B_CIF) { + val = rkcif_read_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id)); + val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); + rkcif_write_register(cif_dev, get_dvp_reg_index_of_id_ctrl0(stream->id), val); + } else { + val = rkcif_read_register(cif_dev, CIF_REG_DVP_CTRL); + if (cif_dev->chip_id == CHIP_RK3588_CIF) + val &= ~DVP_DMA_EN; + else if (cif_dev->chip_id == CHIP_RV1106_CIF) + val &= ~(DVP_SW_DMA_EN(stream->id)); + if (stream->is_stop_capture) { + val &= ~ENABLE_CAPTURE; + stream->is_stop_capture = false; + } + rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); } - rkcif_write_register(cif_dev, CIF_REG_DVP_CTRL, val); } stream->to_stop_dma = 0; v4l2_dbg(4, rkcif_debug, &cif_dev->v4l2_dev, @@ -13913,7 +13936,6 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, int src_id = 0; int i = 0; u32 val = 0; - u64 cur_time = 0; int on = 0; unsigned long flags; struct v4l2_subdev *sd = NULL; @@ -13946,12 +13968,6 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, stream->stopping = false; wake_up(&stream->wq_stopped); } - if (!(stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE)) { - cur_time = rkcif_time_get_ns(stream->cifdev); - stream->readout.total_time = cur_time - stream->readout.fe_timestamp; - stream->readout.readout_time = cur_time - stream->readout.fs_timestamp; - stream->readout.fe_timestamp = cur_time; - } spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); if (stream->is_wait_stop_complete) { @@ -14026,6 +14042,9 @@ static void rkcif_toisp_check_stop_status(struct sditf_priv *priv, if (priv->mode.rdbk_mode == RKISP_VICAP_ONLINE_UNITE || priv->mode.rdbk_mode == RKISP_VICAP_ONLINE_MULTI) priv->is_toisp_off = true; + + rkcif_deal_readout_time(stream); + switch (ch) { case RKCIF_TOISP_CH0: if (priv->cif_dev->chip_id < CHIP_RK3576_CIF) @@ -14250,6 +14269,7 @@ static void rkcif_deal_sof(struct rkcif_device *cif_dev) detect_stream->fs_cnt_in_single_frame++; if ((!cif_dev->sditf[0] || cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) && + cif_dev->inf_id == RKCIF_MIPI_LVDS && detect_stream->fs_cnt_in_single_frame > 1 && cif_dev->chip_id < CHIP_RK3588_CIF) return; @@ -15496,6 +15516,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) stream->dma_en); rkcif_update_stream_rockit(cif_dev, stream, mipi_id); } + stream->last_frame_idx = stream->frame_idx; spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); if (stream->is_single_cap && !stream->cur_skip_frame) { stream->is_single_cap = false; @@ -15751,7 +15772,7 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) cif_dev->sditf[0]->mode.rdbk_mode >= RKISP_VICAP_RDBK_AIQ) stream->buf_wake_up_cnt++; - if (stream->stopping) { + if (stream->stopping && (!stream->dma_en)) { rkcif_stream_stop(stream); stream->stopping = false; wake_up(&stream->wq_stopped); @@ -15816,6 +15837,23 @@ void rkcif_irq_pingpong_v1(struct rkcif_device *cif_dev) spin_unlock_irqrestore(&stream->fps_lock, flags); } stream->is_in_vblank = false; + spin_lock_irqsave(&stream->vbq_lock, flags); + if (stream->stopping && stream->dma_en) { + if (stream->dma_en & RKCIF_DMAEN_BY_VICAP) + stream->to_stop_dma = RKCIF_DMAEN_BY_VICAP; + else if (stream->dma_en & RKCIF_DMAEN_BY_ISP) + stream->to_stop_dma = RKCIF_DMAEN_BY_ISP; + stream->is_stop_capture = true; + } + if (stream->to_stop_dma) { + ret = rkcif_stop_dma_capture(stream); + if (!ret) { + stream->is_finish_stop_dma = true; + if (stream->is_wait_stop_complete) + stream->is_pause_stream = true; + } + } + spin_unlock_irqrestore(&stream->vbq_lock, flags); } } diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 1a54a894203b..b105dab45c39 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -364,6 +364,7 @@ struct rkcif_fps_stats { * @readout_time: one frame of readout time * @early_time: early time of buf send to user * @total_time: totaltime of readout time in hdr + * @rate_time: single frame interval */ struct rkcif_readout_stats { u64 fs_timestamp; @@ -372,6 +373,7 @@ struct rkcif_readout_stats { u64 readout_time; u64 early_time; u64 total_time; + u64 rate_time; }; /* struct rkcif_irq_stats - take notes on irq number diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index 6122ab4ff2c8..ce08b5abdcc2 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -604,7 +604,7 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) timestamp1 = stream->fps_stats.frm1_timestamp; spin_unlock_irqrestore(&stream->fps_lock, flags); if (dev->sditf[0] && dev->sditf[0]->mode.rdbk_mode < RKISP_VICAP_RDBK_AIQ) - fps = dev->stream[0].readout.total_time; + fps = dev->stream[0].readout.rate_time; else fps = timestamp0 > timestamp1 ? timestamp0 - timestamp1 : timestamp1 - timestamp0; @@ -638,8 +638,9 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) } time_val = div_u64_rem(fps, 1000, &remainder); seq_printf(f, "\trate:%u.%u ms\n", time_val, remainder); - fps = div_u64(1000000, fps); - seq_printf(f, "\tfps:%llu\n", fps); + fps = div_u64(1000000000, fps); + time_val = div_u64_rem(fps, 1000, &remainder); + seq_printf(f, "\tfps:%u.%u \n", time_val, remainder); seq_puts(f, "\tirq statistics:\n"); seq_printf(f, "\t\t\ttotal:%llu\n", dev->irq_stats.frm_end_cnt[0] + diff --git a/drivers/mfd/rk806-core.c b/drivers/mfd/rk806-core.c index d6b1af88289e..884d7913d4b9 100644 --- a/drivers/mfd/rk806-core.c +++ b/drivers/mfd/rk806-core.c @@ -789,6 +789,18 @@ static int rk806_parse_dt(struct rk806 *rk806) if (device_property_read_bool(dev, "vdc-wakeup-enable")) pdata->vdc_wakeup_enable = 1; + ret = device_property_read_u32(dev, + "shutown_by_pwrctrln", + &pdata->shutown_by_pwrctrln); + if (ret < 0) { + dev_info(dev, "shutown_by_pwrctrln missing!\n"); + pdata->shutown_by_pwrctrln = 1; + } + if ((pdata->shutown_by_pwrctrln < 1) || (pdata->shutown_by_pwrctrln > 3)) { + dev_err(dev, "shutown_by_pwrctrln out [1 3]!\n"); + pdata->shutown_by_pwrctrln = 1; + } + pdata->shutdown_sequence = devm_kzalloc(dev, RK806_ID_END * sizeof(int), GFP_KERNEL); diff --git a/drivers/net/can/rockchip/Kconfig b/drivers/net/can/rockchip/Kconfig index 7ca3ab4351d5..1f04b52423c5 100644 --- a/drivers/net/can/rockchip/Kconfig +++ b/drivers/net/can/rockchip/Kconfig @@ -26,11 +26,11 @@ config CAN_RK3562 To compile this driver as a module, choose M here: the module will be called rk3562_can. -config CANFD_RK3576 - tristate "RK3576 CANFD controller" +config CAN_RK3576 + tristate "RK3576 CAN controller" depends on ARCH_ROCKCHIP help - Say Y here if you want to use CANFD controller found on RK3576 SoCs. + Say Y here if you want to use CAN controller found on RK3576 SoCs. To compile this driver as a module, choose M here: the module will - be called rk3576_canfd. + be called rk3576_can. diff --git a/drivers/net/can/rockchip/Makefile b/drivers/net/can/rockchip/Makefile index 4c037c281ddb..c50caa6163db 100644 --- a/drivers/net/can/rockchip/Makefile +++ b/drivers/net/can/rockchip/Makefile @@ -1,9 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the rockchip can and canfd controller driver. -# obj-$(CONFIG_CAN_ROCKCHIP) += rockchip_can.o obj-$(CONFIG_CANFD_ROCKCHIP) += rockchip_canfd.o obj-$(CONFIG_CAN_RK3562) += rk3562_can.o -obj-$(CONFIG_CANFD_RK3576) += rk3576_canfd.o +obj-$(CONFIG_CAN_RK3576) += rk3576_can.o diff --git a/drivers/net/can/rockchip/rk3576_canfd.c b/drivers/net/can/rockchip/rk3576_can.c similarity index 55% rename from drivers/net/can/rockchip/rk3576_canfd.c rename to drivers/net/can/rockchip/rk3576_can.c index 2c0d7f056721..cfa8740d72c8 100644 --- a/drivers/net/can/rockchip/rk3576_canfd.c +++ b/drivers/net/can/rockchip/rk3576_can.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2023 Rockchip Electronics Co., Ltd. - * Rk3576 CANFD driver + * Rk3576 CAN driver */ #include @@ -30,119 +30,118 @@ #include /* registers definition */ -enum rk3576_canfd_reg { - CANFD_MODE = 0x00, - CANFD_CMD = 0x04, - CANFD_STATE = 0x08, - CANFD_INT = 0x0c, - CANFD_INT_MASK = 0x10, - CANFD_NBTP = 0x100, - CANFD_DBTP = 0x104, - CANFD_TDCR = 0x108, - CANFD_BRS_CFG = 0x10c, - CANFD_DMA_CTRL = 0x11c, - CANFD_TXFIC = 0x200, - CANFD_TXID = 0x204, - CANFD_TXDAT0 = 0x208, - CANFD_TXDAT1 = 0x20c, - CANFD_TXDAT2 = 0x210, - CANFD_TXDAT3 = 0x214, - CANFD_TXDAT4 = 0x218, - CANFD_TXDAT5 = 0x21c, - CANFD_TXDAT6 = 0x220, - CANFD_TXDAT7 = 0x224, - CANFD_TXDAT8 = 0x228, - CANFD_TXDAT9 = 0x22c, - CANFD_TXDAT10 = 0x230, - CANFD_TXDAT11 = 0x234, - CANFD_TXDAT12 = 0x238, - CANFD_TXDAT13 = 0x23c, - CANFD_TXDAT14 = 0x240, - CANFD_TXDAT15 = 0x244, - CANFD_BUF1_TXFIC = 0x280, - CANFD_BUF1_TXID = 0x284, - CANFD_BUF1_TXDAT0 = 0x288, - CANFD_BUF1_TXDAT1 = 0x28c, - CANFD_BUF1_TXDAT2 = 0x290, - CANFD_BUF1_TXDAT3 = 0x294, - CANFD_BUF1_TXDAT4 = 0x298, - CANFD_BUF1_TXDAT5 = 0x29c, - CANFD_BUF1_TXDAT6 = 0x2a0, - CANFD_BUF1_TXDAT7 = 0x2a4, - CANFD_BUF1_TXDAT8 = 0x2a8, - CANFD_BUF1_TXDAT9 = 0x2ac, - CANFD_BUF1_TXDAT10 = 0x2b0, - CANFD_BUF1_TXDAT11 = 0x2b4, - CANFD_BUF1_TXDAT12 = 0x2b8, - CANFD_BUF1_TXDAT13 = 0x2bc, - CANFD_BUF1_TXDAT14 = 0x2c0, - CANFD_BUF1_TXDAT15 = 0x2c4, - CANFD_RXFIC = 0x300, - CANFD_RXID = 0x304, - CANFD_RXTS = 0x308, - CANFD_RXDAT0 = 0x30c, - CANFD_RXDAT1 = 0x310, - CANFD_RXDAT2 = 0x314, - CANFD_RXDAT3 = 0x318, - CANFD_RXDAT4 = 0x31c, - CANFD_RXDAT5 = 0x320, - CANFD_RXDAT6 = 0x324, - CANFD_RXDAT7 = 0x328, - CANFD_RXDAT8 = 0x32c, - CANFD_RXDAT9 = 0x330, - CANFD_RXDAT10 = 0x334, - CANFD_RXDAT11 = 0x338, - CANFD_RXDAT12 = 0x33c, - CANFD_RXDAT13 = 0x340, - CANFD_RXDAT14 = 0x344, - CANFD_RXDAT15 = 0x348, - CANFD_RXFRD = 0x400, - CANFD_STR_CTL = 0x600, - CANFD_STR_STATE = 0x604, - CANFD_STR_TIMEOUT = 0x608, - CANFD_STR_WTM = 0x60c, - CANFD_EXTM_START_ADDR = 0x610, - CANFD_EXTM_SIZE = 0x614, - CANFD_EXTM_WADDR = 0x618, - CANFD_EXTM_RADDR = 0x61c, - CANFD_EXTM_AHB_TXTHR = 0x620, - CANFD_EXTM_LEFT_CNT = 0x624, - CANFD_ATF0 = 0x700, - CANFD_ATF1 = 0x704, - CANFD_ATF2 = 0x708, - CANFD_ATF3 = 0x70c, - CANFD_ATF4 = 0x710, - CANFD_ATFM0 = 0x714, - CANFD_ATFM1 = 0x718, - CANFD_ATFM2 = 0x71c, - CANFD_ATFM3 = 0x720, - CANFD_ATFM4 = 0x724, - CANFD_ATF_DLC = 0x728, - CANFD_ATF_CTL = 0x72c, - CANFD_SPACE_CTRL = 0x800, - CANFD_AUTO_RETX_CFG = 0x808, - CANFD_AUTO_RETX_STATE0 = 0x80c, - CANFD_AUTO_RETX_STATE1 = 0x810, - CANFD_OLF_CFG = 0x814, - CANFD_RXINT_CTRL = 0x818, - CANFD_RXINT_TIMEOUT = 0x81c, - CANFD_OTHER_CFG = 0x820, - CANFD_WAVE_FILTER_CFG = 0x824, - CANFD_RBC_CFG = 0x828, - CANFD_TXCRC_CFG = 0x82c, - CANFD_BUSOFFRCY_CFG = 0x830, - CANFD_BUSOFF_RCY_THR = 0x834, - CANFD_ERROR_CODE = 0x900, - CANFD_ERROR_MASK = 0x904, - CANFD_RXERRORCNT = 0x910, - CANFD_TXERRORCNT = 0x914, - CANFD_RX_RXSRAM_RDATA = 0xc00, - CANFD_RTL_VERSION = 0xf0c, +enum rk3576_can_reg { + CAN_MODE = 0x00, + CAN_CMD = 0x04, + CAN_STATE = 0x08, + CAN_INT = 0x0c, + CAN_INT_MASK = 0x10, + CAN_NBTP = 0x100, + CAN_DBTP = 0x104, + CAN_TDCR = 0x108, + CAN_DMA_CTRL = 0x11c, + CAN_TXFIC = 0x200, + CAN_TXID = 0x204, + CAN_TXDAT0 = 0x208, + CAN_TXDAT1 = 0x20c, + CAN_TXDAT2 = 0x210, + CAN_TXDAT3 = 0x214, + CAN_TXDAT4 = 0x218, + CAN_TXDAT5 = 0x21c, + CAN_TXDAT6 = 0x220, + CAN_TXDAT7 = 0x224, + CAN_TXDAT8 = 0x228, + CAN_TXDAT9 = 0x22c, + CAN_TXDAT10 = 0x230, + CAN_TXDAT11 = 0x234, + CAN_TXDAT12 = 0x238, + CAN_TXDAT13 = 0x23c, + CAN_TXDAT14 = 0x240, + CAN_TXDAT15 = 0x244, + CAN_BUF1_TXFIC = 0x280, + CAN_BUF1_TXID = 0x284, + CAN_BUF1_TXDAT0 = 0x288, + CAN_BUF1_TXDAT1 = 0x28c, + CAN_BUF1_TXDAT2 = 0x290, + CAN_BUF1_TXDAT3 = 0x294, + CAN_BUF1_TXDAT4 = 0x298, + CAN_BUF1_TXDAT5 = 0x29c, + CAN_BUF1_TXDAT6 = 0x2a0, + CAN_BUF1_TXDAT7 = 0x2a4, + CAN_BUF1_TXDAT8 = 0x2a8, + CAN_BUF1_TXDAT9 = 0x2ac, + CAN_BUF1_TXDAT10 = 0x2b0, + CAN_BUF1_TXDAT11 = 0x2b4, + CAN_BUF1_TXDAT12 = 0x2b8, + CAN_BUF1_TXDAT13 = 0x2bc, + CAN_BUF1_TXDAT14 = 0x2c0, + CAN_BUF1_TXDAT15 = 0x2c4, + CAN_RXFIC = 0x300, + CAN_RXID = 0x304, + CAN_RXTS = 0x308, + CAN_RXDAT0 = 0x30c, + CAN_RXDAT1 = 0x310, + CAN_RXDAT2 = 0x314, + CAN_RXDAT3 = 0x318, + CAN_RXDAT4 = 0x31c, + CAN_RXDAT5 = 0x320, + CAN_RXDAT6 = 0x324, + CAN_RXDAT7 = 0x328, + CAN_RXDAT8 = 0x32c, + CAN_RXDAT9 = 0x330, + CAN_RXDAT10 = 0x334, + CAN_RXDAT11 = 0x338, + CAN_RXDAT12 = 0x33c, + CAN_RXDAT13 = 0x340, + CAN_RXDAT14 = 0x344, + CAN_RXDAT15 = 0x348, + CAN_RXFRD = 0x400, + CAN_STR_CTL = 0x600, + CAN_STR_STATE = 0x604, + CAN_STR_TIMEOUT = 0x608, + CAN_STR_WTM = 0x60c, + CAN_EXTM_START_ADDR = 0x610, + CAN_EXTM_SIZE = 0x614, + CAN_EXTM_WADDR = 0x618, + CAN_EXTM_RADDR = 0x61c, + CAN_EXTM_AHB_TXTHR = 0x620, + CAN_EXTM_LEFT_CNT = 0x624, + CAN_ATF0 = 0x700, + CAN_ATF1 = 0x704, + CAN_ATF2 = 0x708, + CAN_ATF3 = 0x70c, + CAN_ATF4 = 0x710, + CAN_ATFM0 = 0x714, + CAN_ATFM1 = 0x718, + CAN_ATFM2 = 0x71c, + CAN_ATFM3 = 0x720, + CAN_ATFM4 = 0x724, + CAN_ATF_DLC = 0x728, + CAN_ATF_CTL = 0x72c, + CAN_SPACE_CTRL = 0x800, + CAN_AUTO_RETX_CFG = 0x808, + CAN_AUTO_RETX_STATE0 = 0x80c, + CAN_AUTO_RETX_STATE1 = 0x810, + CAN_OLF_CFG = 0x814, + CAN_RXINT_CTRL = 0x818, + CAN_RXINT_TIMEOUT = 0x81c, + CAN_OTHER_CFG = 0x820, + CAN_WAVE_FILTER_CFG = 0x824, + CAN_RBC_CFG = 0x828, + CAN_TXCRC_CFG = 0x82c, + CAN_BUSOFFRCY_CFG = 0x830, + CAN_BUSOFF_RCY_THR = 0x834, + CAN_ERROR_CODE = 0x900, + CAN_ERROR_MASK = 0x904, + CAN_RXERRORCNT = 0x910, + CAN_TXERRORCNT = 0x914, + CAN_RX_RXSRAM_RDATA = 0xc00, + CAN_RTL_VERSION = 0xf0c, }; enum { - ROCKCHIP_RK3576_CANFD = 0, - ROCKCHIP_RV1126B_CANFD, + ROCKCHIP_RK3576_CAN = 0, + ROCKCHIP_RV1126B_CAN, }; #define DATE_LENGTH_12_BYTE (0x9) @@ -153,9 +152,9 @@ enum { #define DATE_LENGTH_48_BYTE (0xe) #define DATE_LENGTH_64_BYTE (0xf) -#define CANFD_TX0_REQ BIT(0) -#define CANFD_TX1_REQ BIT(1) -#define CANFD_TX_REQ_FULL ((CANFD_TX0_REQ) | (CANFD_TX1_REQ)) +#define CAN_TX0_REQ BIT(0) +#define CAN_TX1_REQ BIT(1) +#define CAN_TX_REQ_FULL ((CAN_TX0_REQ) | (CAN_TX1_REQ)) #define MODE_PASS_ERR BIT(10) #define MODE_DIS_PEE BIT(9) @@ -185,13 +184,13 @@ enum { #define PASSIVE_ERR_INT BIT(4) #define TX_LOSTARB_INT BIT(5) #define BUS_ERR_INT BIT(6) -#define RX_STR_FULL_INT BIT(7) +#define RX_STR_FULL_INT BIT(7) #define RX_STR_OV_INT BIT(8) #define BUS_OFF_INT BIT(9) #define BUS_OFF_RECOVERY_INT BIT(10) #define WAKEUP_INT BIT(11) #define AUTO_RETX_FAIL_INT BIT(12) -#define MFI_INT BIT(13) +#define MFI_INT BIT(13) #define MFI_TIMEOUT BIT(14) #define RX_STR_TIMEOUT_INT BIT(15) #define BUSINT_INT BIT(16) @@ -228,9 +227,6 @@ enum { #define RECEIVE_STUFF_COUNT BIT(10) #define RECEIVE_DATA BIT(9) #define RECEIVE_DLC BIT(8) -#define RECEIVE_BRS_ESI BIT(7) -#define RECEIVE_RES BIT(6) -#define RECEIVE_FDF BIT(5) #define RECEIVE_ID2_RTR BIT(4) #define RECEIVE_SOF_IDE BIT(3) #define RECEIVE_BUS_IDLE BIT(2) @@ -249,9 +245,6 @@ enum { #define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT) /* Data Bit Timing & Prescaler Register (DBTP) */ -#define DBTP_BRS_TSEG1_SHIFT 24 -#define DBTP_BRS_TSEG1_MASK (0xff << DBTP_BRS_TSEG1_SHIFT) -#define DBTP_BRS_MODE BIT(23) #define DBTP_MODE_3_SAMPLES BIT(21) #define DBTP_DSJW_SHIFT 17 #define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) @@ -269,17 +262,10 @@ enum { #define RX_DMA_ENABLE BIT(9) -#define TX_FD_ENABLE BIT(5) -#define TX_FD_BRS_ENABLE BIT(4) - #define TX_FORMAT_SHIFT 7 #define TX_FORMAT_MASK (0x1 << TX_FORMAT_SHIFT) #define TX_RTR_SHIFT 6 #define TX_RTR_MASK (0x1 << TX_RTR_SHIFT) -#define TX_FDF_SHIFT 5 -#define TX_FDF_MASK (0x1 << TX_FDF_SHIFT) -#define TX_BRS_SHIFT 4 -#define TX_BRS_MASK (0x1 << TX_BRS_SHIFT) #define TX_DLC_SHIFT 0 #define TX_DLC_MASK (0xF << TX_DLC_SHIFT) @@ -287,10 +273,6 @@ enum { #define RX_FORMAT_MASK (0x1 << RX_FORMAT_SHIFT) #define RX_RTR_SHIFT 22 #define RX_RTR_MASK (0x1 << RX_RTR_SHIFT) -#define RX_FDF_SHIFT 21 -#define RX_FDF_MASK (0x1 << RX_FDF_SHIFT) -#define RX_BRS_SHIFT 20 -#define RX_BRS_MASK (0x1 << RX_BRS_SHIFT) #define RX_DLC_SHIFT 24 #define RX_DLC_MASK (0xF << RX_DLC_SHIFT) #define RX_ISM_LEN_SHIFT 8 @@ -318,7 +300,6 @@ enum { #define EXTTM_LEFT_CNT_MASK (0x3fffff << EXTTM_LEFT_CNT_SHIFT) #define ISM_WATERMASK_CAN 0x6c /* word */ -#define ISM_WATERMASK_CANFD 0x6c /* word */ #define ESM_WATERMASK (0x50 << 8) /* word */ #define BUSOFF_RCY_MODE_EN BIT(8) @@ -348,29 +329,29 @@ enum { #define SRAM_MAX_DEPTH 256 /* word */ #define EXT_MEM_SIZE 0x2000 /* 8KByte */ -#define CANFD_FILTER_MASK 0x1fffffff +#define CAN_FILTER_MASK 0x1fffffff -#define CANFD_FIFO_CNT_MASK 0xff +#define CAN_FIFO_CNT_MASK 0xff #define CANBUSOFF_RCY_SLOW 200 /* ms */ #define CANBUSOFF_RCY_FAST 30 /* ms */ -#define DRV_NAME "rk3576_canfd" +#define DRV_NAME "rk3576_can" -enum rk3576_canfd_atf_mode { - CANFD_ATF_MASK_MODE = 0, - CANFD_ATF_LIST_MODE, +enum rk3576_can_atf_mode { + CAN_ATF_MASK_MODE = 0, + CAN_ATF_LIST_MODE, }; -enum rk3576_canfd_storage_mode { - CANFD_DATA_FLEXIBLE = 0, - CANFD_DATA_CAN_FIXED, - CANFD_DATA_CANFD_FIXED, +enum rk3576_can_storage_mode { + CAN_DATA_FLEXIBLE = 0, + CAN_DATA_CAN_DATE_4_FIXED, + CAN_DATA_CAN_DATA_18_FIXED, }; -/* rk3576_canfd private data structure */ +/* rk3576_can private data structure */ -struct rk3576_canfd { +struct rk3576_can { struct can_priv can; struct device *dev; struct napi_struct napi; @@ -395,19 +376,19 @@ struct rk3576_canfd { dma_addr_t rx_dma_dst_addr; }; -static inline u32 rk3576_canfd_read(const struct rk3576_canfd *priv, - enum rk3576_canfd_reg reg) +static inline u32 rk3576_can_read(const struct rk3576_can *priv, + enum rk3576_can_reg reg) { return readl(priv->base + reg); } -static inline void rk3576_canfd_write(const struct rk3576_canfd *priv, - enum rk3576_canfd_reg reg, u32 val) +static inline void rk3576_can_write(const struct rk3576_can *priv, + enum rk3576_can_reg reg, u32 val) { writel(val, priv->base + reg); } -static const struct can_bittiming_const rk3576_canfd_bittiming_const = { +static const struct can_bittiming_const rk3576_can_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 128, @@ -419,7 +400,7 @@ static const struct can_bittiming_const rk3576_canfd_bittiming_const = { .brp_inc = 2, }; -static const struct can_bittiming_const rk3576_canfd_data_bittiming_const = { +static const struct can_bittiming_const rk3576_can_data_bittiming_const = { .name = DRV_NAME, .tseg1_min = 1, .tseg1_max = 32, @@ -433,40 +414,39 @@ static const struct can_bittiming_const rk3576_canfd_data_bittiming_const = { static int set_reset_mode(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); reset_control_assert(rcan->reset); udelay(2); reset_control_deassert(rcan->reset); - rk3576_canfd_write(rcan, CANFD_MODE, 0); + rk3576_can_write(rcan, CAN_MODE, 0); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE)); + rk3576_can_read(rcan, CAN_MODE)); return 0; } static int set_normal_mode(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 val; - val = rk3576_canfd_read(rcan, CANFD_MODE); + val = rk3576_can_read(rcan, CAN_MODE); val |= WORK_MODE; - rk3576_canfd_write(rcan, CANFD_MODE, val); + rk3576_can_write(rcan, CAN_MODE, val); netdev_dbg(ndev, "%s MODE=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE)); + rk3576_can_read(rcan, CAN_MODE)); return 0; } /* bittiming is called in reset_mode only */ -static int rk3576_canfd_set_bittiming(struct net_device *ndev) +static int rk3576_can_set_bittiming(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); const struct can_bittiming *bt = &rcan->can.bittiming; - const struct can_bittiming *dbt = &rcan->can.data_bittiming; u16 brp, sjw, tseg1, tseg2; u32 reg_btp; @@ -481,58 +461,19 @@ static int rk3576_canfd_set_bittiming(struct net_device *ndev) if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) reg_btp |= NBTP_MODE_3_SAMPLES; - rk3576_canfd_write(rcan, CANFD_NBTP, reg_btp); - - if (rcan->can.ctrlmode & CAN_CTRLMODE_FD) { - reg_btp = 0; - brp = (dbt->brp >> 1) - 1; - sjw = dbt->sjw - 1; - tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; - tseg2 = dbt->phase_seg2 - 1; - if (sjw < 2) - sjw = 2; - - if (dbt->bitrate > 2200000) { - u32 tdco; - - /* Equation based on Bosch's ROCKCHIP_CANFD User Manual's - * Transmitter Delay Compensation Section - */ - tdco = ((1 + 1 + tseg1) * (brp + 1)) - 2; - /* Max valid TDCO value is 63 */ - if (tdco > 63) - tdco = 63; - rk3576_canfd_write(rcan, CANFD_TDCR, - (tdco << TDCR_TDCO_SHIFT) | - TDCR_TDC_ENABLE); - } else { - rk3576_canfd_write(rcan, CANFD_TDCR, 0); - } - - reg_btp |= (brp << DBTP_DBRP_SHIFT) | - (sjw << DBTP_DSJW_SHIFT) | - (tseg1 << DBTP_DTSEG1_SHIFT) | - (tseg2 << DBTP_DTSEG2_SHIFT) | - DBTP_BRS_MODE | - ((tseg1 / 2) << DBTP_BRS_TSEG1_SHIFT); - - if (rcan->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) - reg_btp |= DBTP_MODE_3_SAMPLES; - - rk3576_canfd_write(rcan, CANFD_DBTP, reg_btp); - } + rk3576_can_write(rcan, CAN_NBTP, reg_btp); netdev_dbg(ndev, "%s NBTP=0x%08x, DBTP=0x%08x, TDCR=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_NBTP), - rk3576_canfd_read(rcan, CANFD_DBTP), - rk3576_canfd_read(rcan, CANFD_TDCR)); + rk3576_can_read(rcan, CAN_NBTP), + rk3576_can_read(rcan, CAN_DBTP), + rk3576_can_read(rcan, CAN_TDCR)); return 0; } -static int rk3576_canfd_get_berr_counter(const struct net_device *ndev, - struct can_berr_counter *bec) +static int rk3576_can_get_berr_counter(const struct net_device *ndev, + struct can_berr_counter *bec) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int err; err = pm_runtime_get_sync(rcan->dev); @@ -542,159 +483,157 @@ static int rk3576_canfd_get_berr_counter(const struct net_device *ndev, return err; } - bec->rxerr = rk3576_canfd_read(rcan, CANFD_RXERRORCNT); - bec->txerr = rk3576_canfd_read(rcan, CANFD_TXERRORCNT); + bec->rxerr = rk3576_can_read(rcan, CAN_RXERRORCNT); + bec->txerr = rk3576_can_read(rcan, CAN_TXERRORCNT); pm_runtime_put(rcan->dev); netdev_dbg(ndev, "%s RX_ERR_CNT=0x%08x, TX_ERR_CNT=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_RXERRORCNT), - rk3576_canfd_read(rcan, CANFD_TXERRORCNT)); + rk3576_can_read(rcan, CAN_RXERRORCNT), + rk3576_can_read(rcan, CAN_TXERRORCNT)); return 0; } -static int rk3576_canfd_atf_config(const struct net_device *ndev, int mode) +static int rk3576_can_atf_config(const struct net_device *ndev, int mode) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 id[10] = {0}; u32 dlc = 0, dlc_over = 0; switch (mode) { - case CANFD_ATF_MASK_MODE: - rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); - rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); - rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); - rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); - rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); - rk3576_canfd_write(rcan, CANFD_ATFM0, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM1, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM2, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM3, 0x7fff); - rk3576_canfd_write(rcan, CANFD_ATFM4, 0x7fff); + case CAN_ATF_MASK_MODE: + rk3576_can_write(rcan, CAN_ATF0, id[0]); + rk3576_can_write(rcan, CAN_ATF1, id[1]); + rk3576_can_write(rcan, CAN_ATF2, id[2]); + rk3576_can_write(rcan, CAN_ATF3, id[3]); + rk3576_can_write(rcan, CAN_ATF4, id[4]); + rk3576_can_write(rcan, CAN_ATFM0, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM1, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM2, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM3, 0x7fff); + rk3576_can_write(rcan, CAN_ATFM4, 0x7fff); break; - case CANFD_ATF_LIST_MODE: - rk3576_canfd_write(rcan, CANFD_ATF0, id[0]); - rk3576_canfd_write(rcan, CANFD_ATF1, id[1]); - rk3576_canfd_write(rcan, CANFD_ATF2, id[2]); - rk3576_canfd_write(rcan, CANFD_ATF3, id[3]); - rk3576_canfd_write(rcan, CANFD_ATF4, id[4]); - rk3576_canfd_write(rcan, CANFD_ATFM0, id[5] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM1, id[6] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM2, id[7] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM3, id[8] | (1 << 31)); - rk3576_canfd_write(rcan, CANFD_ATFM4, id[9] | (1 << 31)); + case CAN_ATF_LIST_MODE: + rk3576_can_write(rcan, CAN_ATF0, id[0]); + rk3576_can_write(rcan, CAN_ATF1, id[1]); + rk3576_can_write(rcan, CAN_ATF2, id[2]); + rk3576_can_write(rcan, CAN_ATF3, id[3]); + rk3576_can_write(rcan, CAN_ATF4, id[4]); + rk3576_can_write(rcan, CAN_ATFM0, id[5] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM1, id[6] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM2, id[7] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM3, id[8] | (1 << 31)); + rk3576_can_write(rcan, CAN_ATFM4, id[9] | (1 << 31)); break; default: - rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0xffff); + rk3576_can_write(rcan, CAN_ATF_CTL, 0xffff); return -EINVAL; } if (dlc) { if (dlc_over) - rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4)); + rk3576_can_write(rcan, CAN_ATF_DLC, dlc | (1 << 4)); else - rk3576_canfd_write(rcan, CANFD_ATF_DLC, dlc | (1 << 4) | (1 << 5)); + rk3576_can_write(rcan, CAN_ATF_DLC, dlc | (1 << 4) | (1 << 5)); } - rk3576_canfd_write(rcan, CANFD_ATF_CTL, 0); + rk3576_can_write(rcan, CAN_ATF_CTL, 0); return 0; } -static int rk3576_canfd_start(struct net_device *ndev) +static int rk3576_can_start(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); u32 val, ism = 0, water = 0; /* we need to enter the reset mode */ set_reset_mode(ndev); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); - rk3576_canfd_atf_config(ndev, CANFD_ATF_MASK_MODE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); + rk3576_can_atf_config(ndev, CAN_ATF_MASK_MODE); /* set mode */ - val = rk3576_canfd_read(rcan, CANFD_MODE); + val = rk3576_can_read(rcan, CAN_MODE); if (rcan->rx_max_data > 4) { - ism = CANFD_DATA_CANFD_FIXED; - water = ISM_WATERMASK_CANFD; + ism = CAN_DATA_CAN_DATA_18_FIXED; + water = ISM_WATERMASK_CAN; } else { - ism = CANFD_DATA_CAN_FIXED; + ism = CAN_DATA_CAN_DATE_4_FIXED; water = ISM_WATERMASK_CAN; } /* internal sram mode */ - rk3576_canfd_write(rcan, CANFD_STR_CTL, - (ism << ISM_SEL_SHIFT) | STORAGE_TIMEOUT_MODE); - rk3576_canfd_write(rcan, CANFD_STR_WTM, water); + rk3576_can_write(rcan, CAN_STR_CTL, + (ism << ISM_SEL_SHIFT) | STORAGE_TIMEOUT_MODE); + rk3576_can_write(rcan, CAN_STR_WTM, water); /* Loopback Mode */ if (rcan->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { val |= MODE_LBACK; - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + rk3576_can_write(rcan, CAN_ERROR_MASK, ACK_ERROR_MASK); } else if (rcan->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { val |= MODE_SILENT; - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, ACK_ERROR_MASK); + rk3576_can_write(rcan, CAN_ERROR_MASK, ACK_ERROR_MASK); } else { - rk3576_canfd_write(rcan, CANFD_ERROR_MASK, 0); + rk3576_can_write(rcan, CAN_ERROR_MASK, 0); } if (rcan->auto_retx_cnt) - rk3576_canfd_write(rcan, CANFD_AUTO_RETX_CFG, - AUTO_RETX_EN | RETX_LIMIT_EN | - (rcan->auto_retx_cnt << RETX_TIME_LIMIT_SHIFT)); + rk3576_can_write(rcan, CAN_AUTO_RETX_CFG, + AUTO_RETX_EN | RETX_LIMIT_EN | + (rcan->auto_retx_cnt << RETX_TIME_LIMIT_SHIFT)); else - rk3576_canfd_write(rcan, CANFD_AUTO_RETX_CFG, AUTO_RETX_EN); + rk3576_can_write(rcan, CAN_AUTO_RETX_CFG, AUTO_RETX_EN); - rk3576_canfd_write(rcan, CANFD_MODE, val); + rk3576_can_write(rcan, CAN_MODE, val); if (rcan->use_dma) - rk3576_canfd_write(rcan, CANFD_DMA_CTRL, RX_DMA_ENABLE | rcan->dma_thr); + rk3576_can_write(rcan, CAN_DMA_CTRL, RX_DMA_ENABLE | rcan->dma_thr); - rk3576_canfd_write(rcan, CANFD_BRS_CFG, 0x7); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_FAST); + rk3576_can_write(rcan, CAN_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_FAST); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_FAST); - rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_FAST); - - rk3576_canfd_set_bittiming(ndev); + rk3576_can_set_bittiming(ndev); set_normal_mode(ndev); rcan->can.state = CAN_STATE_ERROR_ACTIVE; netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE), - rk3576_canfd_read(rcan, CANFD_INT_MASK)); + rk3576_can_read(rcan, CAN_MODE), + rk3576_can_read(rcan, CAN_INT_MASK)); return 0; } -static int rk3576_canfd_stop(struct net_device *ndev) +static int rk3576_can_stop(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); rcan->can.state = CAN_STATE_STOPPED; /* we need to enter reset mode */ set_reset_mode(ndev); /* disable all interrupts */ - rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffffffff); + rk3576_can_write(rcan, CAN_INT_MASK, 0xffffffff); netdev_dbg(ndev, "%s MODE=0x%08x, INT_MASK=0x%08x\n", __func__, - rk3576_canfd_read(rcan, CANFD_MODE), - rk3576_canfd_read(rcan, CANFD_INT_MASK)); + rk3576_can_read(rcan, CAN_MODE), + rk3576_can_read(rcan, CAN_INT_MASK)); return 0; } -static int rk3576_canfd_set_mode(struct net_device *ndev, - enum can_mode mode) +static int rk3576_can_set_mode(struct net_device *ndev, + enum can_mode mode) { int err; switch (mode) { case CAN_MODE_START: - err = rk3576_canfd_start(ndev); + err = rk3576_can_start(ndev); if (err) { - netdev_err(ndev, "starting CANFD controller failed!\n"); + netdev_err(ndev, "starting CAN controller failed!\n"); return err; } if (netif_queue_stopped(ndev)) @@ -708,19 +647,19 @@ static int rk3576_canfd_set_mode(struct net_device *ndev, return 0; } -/* transmit a CANFD message +/* transmit a CAN message * message layout in the sk_buff should be like this: * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 * [ can_id ] [flags] [len] [can data (up to 8 bytes] */ -static netdev_tx_t rk3576_canfd_start_xmit(struct sk_buff *skb, - struct net_device *ndev) +static netdev_tx_t rk3576_can_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); - struct canfd_frame *cf = (struct canfd_frame *)skb->data; + struct rk3576_can *rcan = netdev_priv(ndev); + struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc; - u32 cmd = CANFD_TX0_REQ; - u32 tx_fifo = CANFD_TXFIC, tx_id = CANFD_TXID, tx_data = CANFD_TXDAT0; + u32 cmd = CAN_TX0_REQ; + u32 tx_fifo = CAN_TXFIC, tx_id = CAN_TXID, tx_data = CAN_TXDAT0; int i; if (can_dropped_invalid_skb(ndev, skb)) @@ -728,125 +667,110 @@ static netdev_tx_t rk3576_canfd_start_xmit(struct sk_buff *skb, netif_stop_queue(ndev); - if (rk3576_canfd_read(rcan, CANFD_CMD) & CANFD_TX0_REQ) { - cmd = CANFD_TX1_REQ; - if (rcan->mode == ROCKCHIP_RV1126B_CANFD) { - tx_fifo = CANFD_BUF1_TXFIC; - tx_id = CANFD_BUF1_TXID; - tx_data = CANFD_BUF1_TXDAT0; + if (rk3576_can_read(rcan, CAN_CMD) & CAN_TX0_REQ) { + cmd = CAN_TX1_REQ; + if (rcan->mode == ROCKCHIP_RV1126B_CAN) { + tx_fifo = CAN_BUF1_TXFIC; + tx_id = CAN_BUF1_TXID; + tx_data = CAN_BUF1_TXDAT0; } } /* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { - /* Extended CANFD ID format */ + /* Extended CAN ID format */ id = cf->can_id & CAN_EFF_MASK; - dlc = can_fd_len2dlc(cf->len) & TX_DLC_MASK; + dlc = cf->can_dlc & TX_DLC_MASK; dlc |= TX_FORMAT_MASK; /* Extended frames remote TX request */ if (cf->can_id & CAN_RTR_FLAG) dlc |= TX_RTR_MASK; } else { - /* Standard CANFD ID format */ + /* Standard CAN ID format */ id = cf->can_id & CAN_SFF_MASK; - dlc = can_fd_len2dlc(cf->len) & TX_DLC_MASK; + dlc = cf->can_dlc & TX_DLC_MASK; /* Standard frames remote TX request */ if (cf->can_id & CAN_RTR_FLAG) dlc |= TX_RTR_MASK; } - if ((rcan->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { - dlc |= TX_FD_ENABLE; - if (cf->flags & CANFD_BRS) - dlc |= TX_FD_BRS_ENABLE; - } + rk3576_can_write(rcan, tx_id, id); + rk3576_can_write(rcan, tx_fifo, dlc); - rk3576_canfd_write(rcan, tx_id, id); - rk3576_canfd_write(rcan, tx_fifo, dlc); - - for (i = 0; i < cf->len; i += 4) - rk3576_canfd_write(rcan, tx_data + i, - *(u32 *)(cf->data + i)); + for (i = 0; i < can_cc_dlc2len(cf->can_dlc & TX_DLC_MASK); i += 4) + rk3576_can_write(rcan, tx_data + i, + *(u32 *)(cf->data + i)); can_put_echo_skb(skb, ndev, 0, 0); - rk3576_canfd_write(rcan, CANFD_CMD, cmd); + rk3576_can_write(rcan, CAN_CMD, cmd); return NETDEV_TX_OK; } -static int rk3576_canfd_rx(struct net_device *ndev, u32 addr) +static int rk3576_can_rx(struct net_device *ndev, u32 addr) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; - struct canfd_frame *cf; + struct can_frame *cf; struct sk_buff *skb; - u32 id_rk3576_canfd, dlc; + u32 id_rk3576_can, dlc; int i = 0; u32 __maybe_unused ts, ret; u32 data[16] = {0}; if (rcan->use_dma) { dlc = readl(rcan->rxbuf + addr * rcan->rx_max_data); - id_rk3576_canfd = readl(rcan->rxbuf + 1 + addr * rcan->rx_max_data); + id_rk3576_can = readl(rcan->rxbuf + 1 + addr * rcan->rx_max_data); for (i = 0; i < (rcan->rx_max_data - 2); i++) data[i] = readl(rcan->rxbuf + 2 + i + addr * rcan->rx_max_data); } else { - dlc = rk3576_canfd_read(rcan, addr); - id_rk3576_canfd = rk3576_canfd_read(rcan, addr); + dlc = rk3576_can_read(rcan, addr); + id_rk3576_can = rk3576_can_read(rcan, addr); for (i = 0; i < (rcan->rx_max_data - 2); i++) - data[i] = rk3576_canfd_read(rcan, addr); + data[i] = rk3576_can_read(rcan, addr); } - /* create zero'ed CANFD frame buffer */ - if (dlc & RX_FDF_MASK) - skb = alloc_canfd_skb(ndev, &cf); - else - skb = alloc_can_skb(ndev, (struct can_frame **)&cf); + /* create zero'ed CAN frame buffer */ + skb = alloc_can_skb(ndev, (struct can_frame **)&cf); if (!skb) { stats->rx_dropped++; return 1; } - /* Change CANFD data length format to SocketCAN data format */ - if (dlc & RX_FDF_MASK) - cf->len = can_fd_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); - else - cf->len = can_cc_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); + /* Change CAN data length format to SocketCAN data format */ + cf->can_dlc = can_cc_dlc2len((dlc & RX_DLC_MASK) >> RX_DLC_SHIFT); - /* Change CANFD ID format to SocketCAN ID format */ + /* Change CAN ID format to SocketCAN ID format */ if (dlc & RX_FORMAT_MASK) { /* The received frame is an Extended format frame */ - cf->can_id = id_rk3576_canfd; + cf->can_id = id_rk3576_can; cf->can_id |= CAN_EFF_FLAG; if (dlc & RX_RTR_MASK) cf->can_id |= CAN_RTR_FLAG; } else { /* The received frame is a standard format frame */ - cf->can_id = id_rk3576_canfd; + cf->can_id = id_rk3576_can; if (dlc & RX_RTR_MASK) cf->can_id |= CAN_RTR_FLAG; } - if (dlc & RX_BRS_MASK) - cf->flags |= CANFD_BRS; - if (!(cf->can_id & CAN_RTR_FLAG)) { - /* Change CANFD data format to SocketCAN data format */ - for (i = 0; i < cf->len; i += 4) + /* Change CAN data format to SocketCAN data format */ + for (i = 0; i < cf->can_dlc; i += 4) *(u32 *)(cf->data + i) = data[i / 4]; } stats->rx_packets++; - stats->rx_bytes += cf->len; + stats->rx_bytes += cf->can_dlc; netif_rx(skb); return 1; } -/* rk3576_canfd_rx_poll - Poll routine for rx packets (NAPI) +/* rk3576_can_rx_poll - Poll routine for rx packets (NAPI) * @napi: napi structure pointer * @quota: Max number of rx packets to be processed. * @@ -855,57 +779,57 @@ static int rk3576_canfd_rx(struct net_device *ndev, u32 addr) * * Return: number of packets received */ -static int rk3576_canfd_rx_poll(struct napi_struct *napi, int quota) +static int rk3576_can_rx_poll(struct napi_struct *napi, int quota) { struct net_device *ndev = napi->dev; - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int work_done = 0, cnt = 0; if (rcan->use_dma) { while (work_done < rcan->quota) - work_done += rk3576_canfd_rx(ndev, work_done); + work_done += rk3576_can_rx(ndev, work_done); if (work_done <= rcan->rx_fifo_depth) { napi_complete_done(napi, work_done); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); } } else { - quota = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = (rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift; quota = quota / rcan->rx_max_data; - cnt = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & INTM_CNT_MASK) >> INTM_CNT_SHIFT; + cnt = (rk3576_can_read(rcan, CAN_STR_STATE) & INTM_CNT_MASK) >> INTM_CNT_SHIFT; if (quota != cnt) - quota = ((rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = ((rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift) / rcan->rx_max_data; while (work_done < quota) - work_done += rk3576_canfd_rx(ndev, CANFD_RXFRD); + work_done += rk3576_can_rx(ndev, CAN_RXFRD); if (work_done <= rcan->rx_fifo_depth) { napi_complete_done(napi, work_done); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); } } return work_done; } -static void rk3576_canfd_rx_dma_callback(void *data) +static void rk3576_can_rx_dma_callback(void *data) { - struct rk3576_canfd *rcan = data; + struct rk3576_can *rcan = data; napi_schedule(&rcan->napi); } -static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) +static int rk3576_can_rx_dma(struct rk3576_can *rcan) { struct dma_async_tx_descriptor *rxdesc = NULL; int quota = 0; - quota = (rk3576_canfd_read(rcan, CANFD_STR_STATE) & rcan->rx_fifo_mask) >> + quota = (rk3576_can_read(rcan, CAN_STR_STATE) & rcan->rx_fifo_mask) >> rcan->rx_fifo_shift; rcan->quota = DIV_ROUND_UP(quota, rcan->rx_max_data); if (rcan->quota == 0) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); return 1; } @@ -914,7 +838,7 @@ static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) if (!rxdesc) return -EBUSY; - rxdesc->callback = rk3576_canfd_rx_dma_callback; + rxdesc->callback = rk3576_can_rx_dma_callback; rxdesc->callback_param = rcan; dmaengine_submit(rxdesc); @@ -922,9 +846,9 @@ static int rk3576_canfd_rx_dma(struct rk3576_canfd *rcan) return 1; } -static int rk3576_canfd_err(struct net_device *ndev, u32 isr) +static int rk3576_can_err(struct net_device *ndev, u32 isr) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; @@ -933,9 +857,9 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) skb = alloc_can_err_skb(ndev, &cf); - rxerr = rk3576_canfd_read(rcan, CANFD_RXERRORCNT); - txerr = rk3576_canfd_read(rcan, CANFD_TXERRORCNT); - sta_reg = rk3576_canfd_read(rcan, CANFD_STATE); + rxerr = rk3576_can_read(rcan, CAN_RXERRORCNT); + txerr = rk3576_can_read(rcan, CAN_TXERRORCNT); + sta_reg = rk3576_can_read(rcan, CAN_STATE); if (skb) { cf->data[6] = txerr; @@ -972,14 +896,14 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) } if (isr & BUSOFF_RCY_INT) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, 0xffff); - rk3576_canfd_write(rcan, CANFD_INT, isr); + rk3576_can_write(rcan, CAN_INT_MASK, 0xffff); + rk3576_can_write(rcan, CAN_INT, isr); napi_schedule(&rcan->napi); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, BUSOFF_RCY_TIME_CLR); - rk3576_canfd_write(rcan, CANFD_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_SLOW); - rk3576_canfd_write(rcan, CANFD_BUSOFFRCY_CFG, - BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_SLOW); - rk3576_canfd_write(rcan, CANFD_INT_MASK, INT_ENABLE); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, BUSOFF_RCY_TIME_CLR); + rk3576_can_write(rcan, CAN_BUSOFF_RCY_THR, BUSOFF_RCY_TIME_SLOW); + rk3576_can_write(rcan, CAN_BUSOFFRCY_CFG, + BUSOFF_RCY_MODE_EN | BUSOFF_RCY_CNT_SLOW); + rk3576_can_write(rcan, CAN_INT_MASK, INT_ENABLE); netif_stop_queue(ndev); can_free_echo_skb(ndev, 0, NULL); netif_start_queue(ndev); @@ -991,29 +915,29 @@ static int rk3576_canfd_err(struct net_device *ndev, u32 isr) return 0; } -static irqreturn_t rk3576_canfd_interrupt(int irq, void *dev_id) +static irqreturn_t rk3576_can_interrupt(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; u32 err_int = ERR_WARN_INT | RX_BUF_OV_INT | PASSIVE_ERR_INT | BUS_ERR_INT | BUS_OFF_INT | BUSOFF_RCY_INT | BUS_OFF_RECOVERY_INT | RX_STR_FULL_INT; u32 isr; - isr = rk3576_canfd_read(rcan, CANFD_INT); + isr = rk3576_can_read(rcan, CAN_INT); if ((isr & RX_STR_TIMEOUT_INT) || (isr & ISM_WTM_INT) || (isr & RX_STR_FULL_INT)) { - rk3576_canfd_write(rcan, CANFD_INT_MASK, - ISM_WTM_INT | RX_STR_TIMEOUT_INT | - RX_FINISH_INT); + rk3576_can_write(rcan, CAN_INT_MASK, + ISM_WTM_INT | RX_STR_TIMEOUT_INT | + RX_FINISH_INT); if (rcan->use_dma) - rk3576_canfd_rx_dma(rcan); + rk3576_can_rx_dma(rcan); else napi_schedule(&rcan->napi); } if (isr & TX_FINISH_INT) { - rk3576_canfd_write(rcan, CANFD_CMD, 0); + rk3576_can_write(rcan, CAN_CMD, 0); stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL); stats->tx_packets++; netif_wake_queue(ndev); @@ -1021,17 +945,17 @@ static irqreturn_t rk3576_canfd_interrupt(int irq, void *dev_id) if (isr & err_int) { /* error interrupt */ - if (rk3576_canfd_err(ndev, isr)) + if (rk3576_can_err(ndev, isr)) netdev_err(ndev, "can't allocate buffer - clearing pending interrupts\n"); } - rk3576_canfd_write(rcan, CANFD_INT, isr); + rk3576_can_write(rcan, CAN_INT, isr); return IRQ_HANDLED; } -static int rk3576_canfd_open(struct net_device *ndev) +static int rk3576_can_open(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int err; /* common open */ @@ -1046,9 +970,9 @@ static int rk3576_canfd_open(struct net_device *ndev) goto exit; } - err = rk3576_canfd_start(ndev); + err = rk3576_can_start(ndev); if (err) { - netdev_err(ndev, "could not start CANFD peripheral\n"); + netdev_err(ndev, "could not start CAN peripheral\n"); goto exit_can_start; } @@ -1065,13 +989,13 @@ exit: return err; } -static int rk3576_canfd_close(struct net_device *ndev) +static int rk3576_can_close(struct net_device *ndev) { - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); netif_stop_queue(ndev); napi_disable(&rcan->napi); - rk3576_canfd_stop(ndev); + rk3576_can_stop(ndev); close_candev(ndev); pm_runtime_put(rcan->dev); @@ -1079,41 +1003,41 @@ static int rk3576_canfd_close(struct net_device *ndev) return 0; } -static const struct net_device_ops rk3576_canfd_netdev_ops = { - .ndo_open = rk3576_canfd_open, - .ndo_stop = rk3576_canfd_close, - .ndo_start_xmit = rk3576_canfd_start_xmit, +static const struct net_device_ops rk3576_can_netdev_ops = { + .ndo_open = rk3576_can_open, + .ndo_stop = rk3576_can_close, + .ndo_start_xmit = rk3576_can_start_xmit, .ndo_change_mtu = can_change_mtu, }; /** - * rk3576_canfd_suspend - Suspend method for the driver + * rk3576_can_suspend - Suspend method for the driver * @dev: Address of the device structure * * Put the driver into low power mode. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_suspend(struct device *dev) +static int __maybe_unused rk3576_can_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); if (netif_running(ndev)) { netif_stop_queue(ndev); netif_device_detach(ndev); - rk3576_canfd_stop(ndev); + rk3576_can_stop(ndev); } return pm_runtime_force_suspend(dev); } /** - * rk3576_canfd_resume - Resume from suspend + * rk3576_can_resume - Resume from suspend * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_resume(struct device *dev) +static int __maybe_unused rk3576_can_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); int ret; @@ -1125,9 +1049,9 @@ static int __maybe_unused rk3576_canfd_resume(struct device *dev) } if (netif_running(ndev)) { - ret = rk3576_canfd_start(ndev); + ret = rk3576_can_start(ndev); if (ret) { - dev_err(dev, "rk3576_canfd_chip_start failed on resume\n"); + dev_err(dev, "rk3576_can_chip_start failed on resume\n"); return ret; } @@ -1139,16 +1063,16 @@ static int __maybe_unused rk3576_canfd_resume(struct device *dev) } /** - * rk3576_canfd_runtime_suspend - Runtime suspend method for the driver + * rk3576_can_runtime_suspend - Runtime suspend method for the driver * @dev: Address of the device structure * * Put the driver into low power mode. * Return: 0 always */ -static int __maybe_unused rk3576_canfd_runtime_suspend(struct device *dev) +static int __maybe_unused rk3576_can_runtime_suspend(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); clk_bulk_disable_unprepare(rcan->num_clks, rcan->clks); @@ -1156,16 +1080,16 @@ static int __maybe_unused rk3576_canfd_runtime_suspend(struct device *dev) } /** - * rk3576_canfd_runtime_resume - Runtime resume from suspend + * rk3576_can_runtime_resume - Runtime resume from suspend * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error */ -static int __maybe_unused rk3576_canfd_runtime_resume(struct device *dev) +static int __maybe_unused rk3576_can_runtime_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); int ret; ret = clk_bulk_prepare_enable(rcan->num_clks, rcan->clks); @@ -1177,26 +1101,26 @@ static int __maybe_unused rk3576_canfd_runtime_resume(struct device *dev) return 0; } -static const struct dev_pm_ops rk3576_canfd_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rk3576_canfd_suspend, rk3576_canfd_resume) - SET_RUNTIME_PM_OPS(rk3576_canfd_runtime_suspend, - rk3576_canfd_runtime_resume, NULL) +static const struct dev_pm_ops rk3576_can_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rk3576_can_suspend, rk3576_can_resume) + SET_RUNTIME_PM_OPS(rk3576_can_runtime_suspend, + rk3576_can_runtime_resume, NULL) }; -static const struct of_device_id rk3576_canfd_of_match[] = { +static const struct of_device_id rk3576_can_of_match[] = { { - .compatible = "rockchip,rk3576-canfd", - .data = (void *)ROCKCHIP_RK3576_CANFD + .compatible = "rockchip,rk3576-can", + .data = (void *)ROCKCHIP_RK3576_CAN }, { - .compatible = "rockchip,rv1126b-canfd", - .data = (void *)ROCKCHIP_RV1126B_CANFD + .compatible = "rockchip,rv1126b-can", + .data = (void *)ROCKCHIP_RV1126B_CAN }, {}, }; -MODULE_DEVICE_TABLE(of, rk3576_canfd_of_match); +MODULE_DEVICE_TABLE(of, rk3576_can_of_match); -static void rk3576_canfd_dma_init(struct rk3576_canfd *rcan) +static void rk3576_can_dma_init(struct rk3576_can *rcan) { struct dma_slave_config rxconf = { .direction = DMA_DEV_TO_MEM, @@ -1221,10 +1145,10 @@ static void rk3576_canfd_dma_init(struct rk3576_canfd *rcan) dmaengine_slave_config(rcan->rxchan, &rxconf); } -static int rk3576_canfd_probe(struct platform_device *pdev) +static int rk3576_can_probe(struct platform_device *pdev) { struct net_device *ndev; - struct rk3576_canfd *rcan; + struct rk3576_can *rcan; struct resource *res; void __iomem *addr; int err, irq; @@ -1241,9 +1165,9 @@ static int rk3576_canfd_probe(struct platform_device *pdev) if (IS_ERR(addr)) return -EBUSY; - ndev = alloc_candev(sizeof(struct rk3576_canfd), 1); + ndev = alloc_candev(sizeof(struct rk3576_can), 1); if (!ndev) { - dev_err(&pdev->dev, "could not allocate memory for CANFD device\n"); + dev_err(&pdev->dev, "could not allocate memory for CAN device\n"); return -ENOMEM; } rcan = netdev_priv(ndev); @@ -1251,7 +1175,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->reset = devm_reset_control_array_get(&pdev->dev, false, false); if (IS_ERR(rcan->reset)) { if (PTR_ERR(rcan->reset) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get canfd reset lines\n"); + dev_err(&pdev->dev, "failed to get can reset lines\n"); err = PTR_ERR(rcan->reset); goto err_free; } @@ -1268,17 +1192,14 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->dev = &pdev->dev; rcan->can.state = CAN_STATE_STOPPED; - rcan->can.bittiming_const = &rk3576_canfd_bittiming_const; - rcan->can.data_bittiming_const = &rk3576_canfd_data_bittiming_const; - rcan->can.do_set_mode = rk3576_canfd_set_mode; - rcan->can.do_get_berr_counter = rk3576_canfd_get_berr_counter; - rcan->can.do_set_bittiming = rk3576_canfd_set_bittiming; - rcan->can.do_set_data_bittiming = rk3576_canfd_set_bittiming; - rcan->can.ctrlmode = CAN_CTRLMODE_FD; - /* IFI CANFD can do both Bosch FD and ISO FD */ + rcan->can.bittiming_const = &rk3576_can_bittiming_const; + rcan->can.data_bittiming_const = &rk3576_can_data_bittiming_const; + rcan->can.do_set_mode = rk3576_can_set_mode; + rcan->can.do_get_berr_counter = rk3576_can_get_berr_counter; + rcan->can.do_set_bittiming = rk3576_can_set_bittiming; + rcan->can.do_set_data_bittiming = rk3576_can_set_bittiming; rcan->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | - CAN_CTRLMODE_LISTENONLY | - CAN_CTRLMODE_FD; + CAN_CTRLMODE_LISTENONLY; rcan->rx_fifo_shift = INTM_LEFT_CNT_SHIFT; rcan->rx_fifo_mask = INTM_LEFT_CNT_MASK; @@ -1308,14 +1229,14 @@ static int rk3576_canfd_probe(struct platform_device *pdev) rcan->rxchan = NULL; rcan->use_dma = 0; } else { - rcan->rx_dma_src_addr = res->start + CANFD_RXFRD; + rcan->rx_dma_src_addr = res->start + CAN_RXFRD; rcan->dma_size = rcan->rx_max_data * 4; rcan->use_dma = 1; } if (rcan->use_dma) - rk3576_canfd_dma_init(rcan); + rk3576_can_dma_init(rcan); - ndev->netdev_ops = &rk3576_canfd_netdev_ops; + ndev->netdev_ops = &rk3576_can_netdev_ops; ndev->irq = irq; ndev->flags |= IFF_ECHO; @@ -1329,7 +1250,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) __func__, err); goto err_pmdisable; } - netif_napi_add(ndev, &rcan->napi, rk3576_canfd_rx_poll); + netif_napi_add(ndev, &rcan->napi, rk3576_can_rx_poll); err = register_candev(ndev); if (err) { dev_err(&pdev->dev, "registering %s failed (err=%d)\n", @@ -1338,7 +1259,7 @@ static int rk3576_canfd_probe(struct platform_device *pdev) } /* register interrupt handler */ - err = devm_request_irq(&pdev->dev, irq, rk3576_canfd_interrupt, + err = devm_request_irq(&pdev->dev, irq, rk3576_can_interrupt, 0, ndev->name, ndev); if (err) { dev_err(&pdev->dev, "request_irq err: %d\n", err); @@ -1368,10 +1289,10 @@ err_free: return err; } -static int rk3576_canfd_remove(struct platform_device *pdev) +static int rk3576_can_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - struct rk3576_canfd *rcan = netdev_priv(ndev); + struct rk3576_can *rcan = netdev_priv(ndev); if (rcan->rxbuf) { dma_free_coherent(rcan->dev, rcan->dma_size * rcan->rx_fifo_depth, rcan->rxbuf, @@ -1390,17 +1311,17 @@ static int rk3576_canfd_remove(struct platform_device *pdev) return 0; } -static struct platform_driver rk3576_canfd_driver = { +static struct platform_driver rk3576_can_driver = { .driver = { .name = DRV_NAME, - .pm = &rk3576_canfd_dev_pm_ops, - .of_match_table = rk3576_canfd_of_match, + .pm = &rk3576_can_dev_pm_ops, + .of_match_table = rk3576_can_of_match, }, - .probe = rk3576_canfd_probe, - .remove = rk3576_canfd_remove, + .probe = rk3576_can_probe, + .remove = rk3576_can_remove, }; -module_platform_driver(rk3576_canfd_driver); +module_platform_driver(rk3576_can_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Elaine Zhang "); -MODULE_DESCRIPTION("RK3576 CANFD Drivers"); +MODULE_DESCRIPTION("RK3576 CAN Drivers"); diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 2933c6fdfb46..57965475cd05 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -59,6 +59,7 @@ struct rockchip_p3phy_priv { struct clk_bulk_data *clks; int num_clks; bool is_bifurcation; + bool is_initialized; }; struct rockchip_p3phy_ops { @@ -215,6 +216,9 @@ static int rockchip_p3phy_init(struct phy *phy) return ret; } + if (priv->is_initialized) + return 0; + reset_control_assert(priv->p30phy); udelay(1); @@ -233,6 +237,7 @@ static int rockchip_p3phy_exit(struct phy *phy) clk_bulk_disable_unprepare(priv->num_clks, priv->clks); reset_control_assert(priv->p30phy); + priv->is_initialized = false; return 0; } @@ -283,33 +288,38 @@ static int rockchip_p3phy_probe(struct platform_device *pdev) if (IS_ERR(priv->pipe_grf)) dev_info(dev, "failed to find rockchip,pipe_grf regmap\n"); - /* Configuring grf with clk enabled. */ - ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); - if (ret) { - pr_err("failed to enable PCIe bulk clks %d\n", ret); - return ret; - } + priv->is_initialized = device_property_read_bool(dev, "rockchip,skip-init"); ret = device_property_read_u32(dev, "rockchip,pcie30-phymode", &val); if (!ret) { priv->pcie30_phymode = val; if (priv->pcie30_phymode > 4) priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; - regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, - (0x7<<16) | priv->pcie30_phymode); } else { priv->pcie30_phymode = PHY_MODE_PCIE_AGGREGATION; } - /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ - if (!IS_ERR(priv->pipe_grf)) { - reg = priv->pcie30_phymode & 3; - if (reg) - regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, - (reg << 16) | reg); - }; + if (!priv->is_initialized) { + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) { + pr_err("failed to enable PCIe bulk clks %d\n", ret); + return ret; + } - clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + if (priv->pcie30_phymode != PHY_MODE_PCIE_AGGREGATION) + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + (0x7 << 16) | priv->pcie30_phymode); + + /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ + if (!IS_ERR(priv->pipe_grf)) { + reg = priv->pcie30_phymode & 3; + if (reg) + regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, + (reg << 16) | reg); + }; + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + } priv->phy = devm_phy_create(dev, NULL, &rockchip_p3phy_ops); if (IS_ERR(priv->phy)) { diff --git a/drivers/power/supply/sc89601_charger.c b/drivers/power/supply/sc89601_charger.c index c5d680c29cfb..a404aa57711f 100644 --- a/drivers/power/supply/sc89601_charger.c +++ b/drivers/power/supply/sc89601_charger.c @@ -106,7 +106,7 @@ static const struct regmap_access_table sc89601_writeable_regs = { static const struct regmap_range sc89601_volatile_reg_ranges[] = { regmap_reg_range(0x00, 0x00), regmap_reg_range(0x02, 0x02), - regmap_reg_range(0x09, 0x09), + regmap_reg_range(0x08, 0x09), regmap_reg_range(0x0b, 0x0b), regmap_reg_range(0x0c, 0x0c), regmap_reg_range(0x0d, 0x14), diff --git a/drivers/regulator/rk806-regulator.c b/drivers/regulator/rk806-regulator.c index 3eba9d6e7957..3d9b5084fd82 100644 --- a/drivers/regulator/rk806-regulator.c +++ b/drivers/regulator/rk806-regulator.c @@ -1252,9 +1252,19 @@ static void rk806_regulator_shutdown(struct platform_device *pdev) if (system_state == SYSTEM_POWER_OFF) { rk806_shutdown_requence_config(rk806); - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN); - rk806_field_write(rk806, PWRCTRL1_POL, POL_HIGH); - rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_POWOFF_FUN); + if (rk806->pdata->shutown_by_pwrctrln == 2) { + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL2_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_POWOFF_FUN); + } else if (rk806->pdata->shutown_by_pwrctrln == 3) { + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL3_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_POWOFF_FUN); + } else { + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN); + rk806_field_write(rk806, PWRCTRL1_POL, POL_HIGH); + rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_POWOFF_FUN); + } } } diff --git a/drivers/rtc/rtc-rk630.c b/drivers/rtc/rtc-rk630.c index c931301a588d..827b19453261 100644 --- a/drivers/rtc/rtc-rk630.c +++ b/drivers/rtc/rtc-rk630.c @@ -619,7 +619,7 @@ static int rk630_rtc_probe(struct platform_device *pdev) return ret; } - return rtc_register_device(rk630_rtc->rtc); + return devm_rtc_register_device(rk630_rtc->rtc); } static struct platform_driver rk630_rtc_driver = { diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 500503c6338b..7dc9ad405dc5 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -1010,12 +1010,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) if (sfc->max_dll_cells > SFC_DLL_CTRL0_DLL_MAX_VER5) sfc->max_dll_cells = SFC_DLL_CTRL0_DLL_MAX_VER5; - ret = rockchip_sfc_get_gpio_descs(master, sfc); - if (ret) { - dev_err(&pdev->dev, "Failed to get gpio_descs\n"); - return ret; - } - ret = clk_prepare_enable(sfc->hclk); if (ret) { dev_err(&pdev->dev, "Failed to enable ahb clk\n"); @@ -1063,6 +1057,12 @@ static int rockchip_sfc_probe(struct platform_device *pdev) dev_err(dev, "Wait for SFC idle timeout!\n"); } + ret = rockchip_sfc_get_gpio_descs(master, sfc); + if (ret) { + dev_err(&pdev->dev, "Failed to get gpio_descs\n"); + goto err_irq; + } + ret = rockchip_sfc_init(sfc); if (ret) goto err_irq; diff --git a/include/linux/mfd/rk806.h b/include/linux/mfd/rk806.h index 2e3f75da6572..2f26475cf690 100644 --- a/include/linux/mfd/rk806.h +++ b/include/linux/mfd/rk806.h @@ -505,6 +505,7 @@ struct rk806_platform_data { int hotdie_temperture_threshold; int vdc_wakeup_enable; + int shutown_by_pwrctrln; int *shutdown_sequence; int *vb_shutdown_sequence; int *dvs_control_suspend; diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index 0c35e857c5cb..abc6ec7c5452 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -7,6 +7,7 @@ #ifndef _UAPI_RK_HDMIRX_CONFIG_H #define _UAPI_RK_HDMIRX_CONFIG_H +#include #include #include @@ -119,6 +120,15 @@ enum user_color_range { #define RK_HDMIRX_CMD_SET_EDID_VERSION \ _IOW('V', BASE_VIDIOC_PRIVATE + 17, int) +#define RK_HDMIRX_CMD_GET_HDR_METADATA \ + _IOR('V', BASE_VIDIOC_PRIVATE + 18, struct hdr_metadata_infoframe) + +#define RK_HDMIRX_CMD_GET_OUTPUT_COLOR_RANGE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 19, int) + +#define RK_HDMIRX_CMD_GET_OUTPUT_COLOR_SPACE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 20, int) + /* Private v4l2 event */ #define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ (V4L2_EVENT_PRIVATE_START + 1)