mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
Merge commit 'fbdb94a0c7bddcf16d5e01588e5d0aed65ae43f2'
* commit 'fbdb94a0c7bddcf16d5e01588e5d0aed65ae43f2': (40 commits) hwspinlock: rockchip: Add maximum user count config dt-bindings: hwlock: rockchip: Add the maximum user count property mailbox: rockchip: add get properties helper mailbox: rockchip: add version and lock register support arm64: dts: rockchip: rv1126b-evb: Add the regulator-settling-time-up-us configuration power: supply: sc89601_charger: fix the abnormal display of the charging icon arm64: dts: rockchip: add Tablet Board devicetree for RK3576S-RK809 arm64: dts: rockchip: rv1126b: Fix compatible for can node arm64: dts: rockchip: rk3576: Fix compatible for can node ARM: dts: rockchip: rk3506: Fix compatible for can node arm64: configs: rockchip_linux_defconfig enable CONFIG_CAN_RK3576 net: can: rockchip: rename rk3576_canfd.c to rk3576_can.c drm/rockchip: dw-dp: support more feature active protocol converter adapters media: rockchip: vicap force update buffer addr when init stream media: rockchip: vicap change stop dma to fs for dvp media: rockchip: vicap fixes error of stop stream with dvp media: rockchip: vicap fixes error info of fps with toisp mode iio: imu: add inv icm42607 support arm64: dts: rockchip: rv1126b-evb2: Add the rk96x_wake_aov_irq driver's dts. spi: rockchip-sfc: Wait for thunder boot DMA status change before rockchip_sfc_get_gpio_descs ... Change-Id: I21a5ce10a4a9f5c23e607ac2b2ee51c80659aa88
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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 = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -561,6 +561,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbdp_phy_u3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&usb_drd1_dwc3 {
|
||||
snps,dis_u2_susphy_quirk;
|
||||
snps,usb2-lpm-disable;
|
||||
|
||||
@@ -574,6 +574,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbdp_phy_u3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&usb_drd1_dwc3 {
|
||||
snps,dis_u2_susphy_quirk;
|
||||
snps,usb2-lpm-disable;
|
||||
|
||||
@@ -569,6 +569,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usbdp_phy_u3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&usb_drd1_dwc3 {
|
||||
snps,dis_u2_susphy_quirk;
|
||||
snps,usb2-lpm-disable;
|
||||
|
||||
@@ -5547,7 +5547,7 @@
|
||||
};
|
||||
|
||||
can0: can@2ac00000 {
|
||||
compatible = "rockchip,rk3576-canfd";
|
||||
compatible = "rockchip,rk3576-can";
|
||||
reg = <0x0 0x2ac00000 0x0 0x1000>;
|
||||
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>;
|
||||
|
||||
434
arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi
Normal file
434
arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-camera.dtsi
Normal file
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
1521
arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts
Normal file
1521
arch/arm64/boot/dts/rockchip/rk3576s-rk809-tablet-v10.dts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 = <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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 = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru CLK_CAN1>, <&cru HCLK_CAN1>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
18
drivers/iio/imu/inv_icm42607/Kconfig
Normal file
18
drivers/iio/imu/inv_icm42607/Kconfig
Normal file
@@ -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
|
||||
7
drivers/iio/imu/inv_icm42607/Makefile
Normal file
7
drivers/iio/imu/inv_icm42607/Makefile
Normal file
@@ -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
|
||||
416
drivers/iio/imu/inv_icm42607/icm42607.c
Normal file
416
drivers/iio/imu/inv_icm42607/icm42607.c
Normal file
@@ -0,0 +1,416 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#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;
|
||||
}
|
||||
435
drivers/iio/imu/inv_icm42607/icm42607.h
Normal file
435
drivers/iio/imu/inv_icm42607/icm42607.h
Normal file
@@ -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
|
||||
91
drivers/iio/imu/inv_icm42607/imu.h
Normal file
91
drivers/iio/imu/inv_icm42607/imu.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __IMU_H__
|
||||
#define __IMU_H__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
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
|
||||
270
drivers/iio/imu/inv_icm42607/invimu_core.c
Normal file
270
drivers/iio/imu/inv_icm42607/invimu_core.c
Normal file
@@ -0,0 +1,270 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#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");
|
||||
10
drivers/iio/imu/inv_icm42607/invimu_core.h
Normal file
10
drivers/iio/imu/inv_icm42607/invimu_core.h
Normal file
@@ -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
|
||||
109
drivers/iio/imu/inv_icm42607/invimu_i2c.c
Normal file
109
drivers/iio/imu/inv_icm42607/invimu_i2c.c
Normal file
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#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");
|
||||
295
drivers/iio/imu/inv_icm42607/invimu_iio.c
Normal file
295
drivers/iio/imu/inv_icm42607/invimu_iio.c
Normal file
@@ -0,0 +1,295 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#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);
|
||||
34
drivers/iio/imu/inv_icm42607/invimu_iio.h
Normal file
34
drivers/iio/imu/inv_icm42607/invimu_iio.h
Normal file
@@ -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 <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
7
drivers/iio/proximity/nds03/Kconfig
Normal file
7
drivers/iio/proximity/nds03/Kconfig
Normal file
@@ -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
|
||||
9
drivers/iio/proximity/nds03/Makefile
Normal file
9
drivers/iio/proximity/nds03/Makefile
Normal file
@@ -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
|
||||
104
drivers/iio/proximity/nds03/nds03.h
Normal file
104
drivers/iio/proximity/nds03/nds03.h
Normal file
@@ -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 <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/* 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
|
||||
275
drivers/iio/proximity/nds03/nds03_calib.c
Normal file
275
drivers/iio/proximity/nds03/nds03_calib.c
Normal file
@@ -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;
|
||||
}
|
||||
42
drivers/iio/proximity/nds03/nds03_calib.h
Normal file
42
drivers/iio/proximity/nds03/nds03_calib.h
Normal file
@@ -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
|
||||
|
||||
385
drivers/iio/proximity/nds03/nds03_comm.c
Normal file
385
drivers/iio/proximity/nds03/nds03_comm.c
Normal file
@@ -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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <linux/types.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
71
drivers/iio/proximity/nds03/nds03_comm.h
Normal file
71
drivers/iio/proximity/nds03/nds03_comm.h
Normal file
@@ -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
|
||||
238
drivers/iio/proximity/nds03/nds03_data.c
Normal file
238
drivers/iio/proximity/nds03/nds03_data.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
46
drivers/iio/proximity/nds03/nds03_data.h
Normal file
46
drivers/iio/proximity/nds03/nds03_data.h
Normal file
@@ -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__
|
||||
308
drivers/iio/proximity/nds03/nds03_def.h
Normal file
308
drivers/iio/proximity/nds03/nds03_def.h
Normal file
@@ -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 <linux/kernel.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "nds03_platform.h"
|
||||
|
||||
#ifndef DEBUG_INFO
|
||||
#define DEBUG_INFO 0 /** 调试信息打印开关 */
|
||||
#endif
|
||||
|
||||
#if NDS03_PLATFORM == PLATFORM_NOT_C51
|
||||
#include <stdio.h>
|
||||
#define NX_PRINTF(fmt, ...) do { if (DEBUG_INFO) printf(fmt, ##__VA_ARGS__); } while(0)
|
||||
|
||||
#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER
|
||||
#include <linux/kernel.h>
|
||||
#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
|
||||
743
drivers/iio/proximity/nds03/nds03_dev.c
Normal file
743
drivers/iio/proximity/nds03/nds03_dev.c
Normal file
@@ -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;
|
||||
}
|
||||
94
drivers/iio/proximity/nds03/nds03_dev.h
Normal file
94
drivers/iio/proximity/nds03/nds03_dev.h
Normal file
@@ -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
|
||||
|
||||
235
drivers/iio/proximity/nds03/nds03_iio.c
Normal file
235
drivers/iio/proximity/nds03/nds03_iio.c
Normal file
@@ -0,0 +1,235 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/module.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/ktime.h>
|
||||
#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);
|
||||
31
drivers/iio/proximity/nds03/nds03_iio.h
Normal file
31
drivers/iio/proximity/nds03/nds03_iio.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __NDS03_IIO_H
|
||||
#define __NDS03_IIO_H
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
|
||||
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
|
||||
674
drivers/iio/proximity/nds03/nds03_module.c
Normal file
674
drivers/iio/proximity/nds03/nds03_module.c
Normal file
@@ -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);
|
||||
99
drivers/iio/proximity/nds03/nds03_module_i2c.c
Normal file
99
drivers/iio/proximity/nds03/nds03_module_i2c.c
Normal file
@@ -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);
|
||||
117
drivers/iio/proximity/nds03/nds03_platform.c
Normal file
117
drivers/iio/proximity/nds03/nds03_platform.c
Normal file
@@ -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;
|
||||
}
|
||||
137
drivers/iio/proximity/nds03/nds03_platform.h
Normal file
137
drivers/iio/proximity/nds03/nds03_platform.h
Normal file
@@ -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 <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
/**
|
||||
* @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
|
||||
|
||||
95
drivers/iio/proximity/nds03/nds03_stdint.h
Normal file
95
drivers/iio/proximity/nds03/nds03_stdint.h
Normal file
@@ -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 <stdint.h>
|
||||
|
||||
#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__ */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <soc/rockchip/rockchip-mailbox.h>
|
||||
|
||||
#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:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_class.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_class.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -41,7 +42,6 @@
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -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));
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -44,7 +45,6 @@
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
@@ -33,7 +34,6 @@
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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, ...) \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef __RK628_HDMIRX_H
|
||||
#define __RK628_HDMIRX_H
|
||||
|
||||
#include <drm/drm_mode.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/cec-notifier.h>
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk_hdmirx_config.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] +
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#ifndef _UAPI_RK_HDMIRX_CONFIG_H
|
||||
#define _UAPI_RK_HDMIRX_CONFIG_H
|
||||
|
||||
#include <drm/drm_mode.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/v4l2-controls.h>
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user