diff options
38 files changed, 3047 insertions, 156 deletions
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml new file mode 100644 index 000000000000..f84ccd4d5d91 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ox05b.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OX05B1S Camera Sensor + +maintainers: + - Abhishek Sharma <abhishek.sharma@ti.com> + +description: |- + Omnivision OX05B1S is an RGBIR camera sensor with an active array size of + 2592x1944. It is programmable through the I2C interface. The i2c client + address is fixed at 0x36 as per the sensor datasheet. Every alternate frame, + the sensor changes the exposure/gain registers to stream an - + A. IR-dominant frame on CSI-2 virtual channel 0 + B. RGB-dominant frame on CSI-2 virtual channel 1 + + Both streams are captured at a resolution 2592x1944, 30 fps each + (60 fps total). The sensor also supports a few v4l2 controls like + exposure and gain controls. + +properties: + compatible: + enum: + - ovti,ox05b + + reg: + description: I2C address + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: inck + + pwdn-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the PWDN pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + }; + }; + }; + }; + +... diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index c979fb22bf0e..e00f4078a533 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -184,6 +184,7 @@ CONFIG_BT_MRVL_SDIO=m CONFIG_BT_QCOMSMD=m CONFIG_CFG80211=m CONFIG_MAC80211=m +CONFIG_IWLWIFI=m CONFIG_RFKILL=y CONFIG_RFKILL_INPUT=y CONFIG_RFKILL_GPIO=y diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 888ff46cef7b..2709426aea5f 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -47,6 +47,7 @@ k3-am62a7-sk-ub954-evm-ov2312-dtbs := k3-am62a7-sk.dtb \ k3-am62a7-sk-ub954-evm.dtbo \ k3-fpdlink-ov2312-0-0.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-imx219.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-ox05b1s.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-e3-max-opp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-ethernet-dc01.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-fusion-imx390.dtb @@ -103,6 +104,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-rpi-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-rpi-hdr-ehrpwm.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board-infotainment.dtbo # Boards with J721s2 SoC dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb @@ -111,6 +113,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-bb-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-fpdlink-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-som-ddr-mem-carveout.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-fusion.dtbo @@ -123,14 +126,18 @@ dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-dsi-rpi-7inch-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-fpdlink-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-v3link-fusion.dtbo # Boards with J784s4 SoC dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-ddr-mem-carveout.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-rpi-cam-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion-auxport.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-csi2-ov5640.dtbo @@ -157,7 +164,11 @@ dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-imx390-rcm-0-0.dtbo \ k3-fpdlink-imx390-rcm-1-0.dtbo \ k3-fpdlink-imx390-rcm-1-1.dtbo \ k3-fpdlink-imx390-rcm-1-2.dtbo \ - k3-fpdlink-imx390-rcm-1-3.dtbo + k3-fpdlink-imx390-rcm-1-3.dtbo \ + k3-fpdlink-imx390-rcm-2-0.dtbo \ + k3-fpdlink-imx390-rcm-2-1.dtbo \ + k3-fpdlink-imx390-rcm-2-2.dtbo \ + k3-fpdlink-imx390-rcm-2-3.dtbo dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \ k3-fpdlink-ov2312-0-1.dtbo \ k3-fpdlink-ov2312-0-2.dtbo \ @@ -179,7 +190,12 @@ DTC_FLAGS_k3-am62p5-sk += -@ DTC_FLAGS_k3-am62x-sk-csi2-v3link-fusion += -@ DTC_FLAGS_k3-am654-base-board += -@ DTC_FLAGS_k3-am68-sk-base-board += -@ +DTC_FLAGS_k3-am68-sk-fpdlink-fusion += -@ +DTC_FLAGS_k3-am68-sk-v3link-fusion += -@ DTC_FLAGS_k3-am69-sk += -@ +DTC_FLAGS_k3-am69-sk-csi2-v3link-fusion += -@ +DTC_FLAGS_k3-am69-sk-fpdlink-fusion += -@ +DTC_FLAGS_k3-am69-sk-fpdlink-fusion-auxport += -@ DTC_FLAGS_k3-j7200-common-proc-board += -@ DTC_FLAGS_k3-j721e-beagleboneai64 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ @@ -189,5 +205,7 @@ DTC_FLAGS_k3-j721e-sk-fusion += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ DTC_FLAGS_k3-j721s2-evm-fusion += -@ DTC_FLAGS_k3-j722s-evm += -@ +DTC_FLAGS_k3-j722s-evm-fpdlink-fusion += -@ +DTC_FLAGS_k3-j722s-evm-v3link-fusion += -@ DTC_FLAGS_k3-j784s4-evm += -@ DTC_FLAGS_k3-am642-evm += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso new file mode 100644 index 000000000000..e82589579013 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OX05B1S Camera Module + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&{/} { + clk_ox05b1s_fixed: ox05b1s-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <480000000>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; + }; +}; + +&csi0_port0 { + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index ecf1a50f197c..2bf45e8dfde3 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -1093,6 +1093,8 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x00 0x30000000 0x80000>; + assigned-clocks = <&k3_clks 81 0>; + assigned-clock-parents = <&k3_clks 81 2>; icssg0_mem: memories@0 { reg = <0x0 0x2000>, @@ -1118,7 +1120,7 @@ clocks = <&k3_clks 81 0>, /* icssg0_core_clk */ <&k3_clks 81 20>; /* icssg0_iclk */ assigned-clocks = <&icssg0_coreclk_mux>; - assigned-clock-parents = <&k3_clks 81 20>; + assigned-clock-parents = <&k3_clks 81 0>; }; icssg0_iepclk_mux: iepclk-mux@30 { @@ -1263,6 +1265,8 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x00 0x30080000 0x80000>; + assigned-clocks = <&k3_clks 82 0>; + assigned-clock-parents = <&k3_clks 82 2>; icssg1_mem: memories@0 { reg = <0x0 0x2000>, @@ -1288,7 +1292,7 @@ clocks = <&k3_clks 82 0>, /* icssg1_core_clk */ <&k3_clks 82 20>; /* icssg1_iclk */ assigned-clocks = <&icssg1_coreclk_mux>; - assigned-clock-parents = <&k3_clks 82 20>; + assigned-clock-parents = <&k3_clks 82 0>; }; icssg1_iepclk_mux: iepclk-mux@30 { diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso new file mode 100644 index 000000000000..04ae5d0fa1a5 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> +#include "k3-pinctrl.h" + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp3 { + p01-hog { + /* CSI_MUX_SEL_2 */ + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI_MUX_SEL_2"; + }; +}; + +&main_i2c1 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-switch@70 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + /* CAM0 I2C */ + cam0_i2c: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + cam1_i2c: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +};
\ No newline at end of file diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso new file mode 100644 index 000000000000..988b6a6994d8 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp2 { + p01-hog { + /* P01 - CSI_MUX_SEL_2 */ + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI_MUX_SEL_2"; + }; +}; + +&pca9543 { + #address-cells = <1>; + #size-cells = <0>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + port@0 { + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; +}; }; + +&cdns_csi2rx1 { + ports { + port@0 { + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy_rx0 { + status = "okay"; +}; + +&dphy_rx1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso new file mode 100644 index 000000000000..e3cc0bc36703 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on AM69 SK CSI2 Aux Port + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +&{/} { + clk_fusion1_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&pca9543 { + #address-cells = <1>; + #size-cells = <0>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion1_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x6a 0x6b 0x6c 0x6d 0x6e 0x6f>; + + ds90ub960_2_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX*/ + port@4 { + reg = <4>; + ds90ub960_2_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy2>; + }; + }; + }; + + ds90ub960_2_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + port@0 { + status = "okay"; + + csi2_phy2: endpoint { + remote-endpoint = <&ds90ub960_2_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy_rx2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso new file mode 100644 index 000000000000..3fc888a0d2fd --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x64>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso new file mode 100644 index 000000000000..dc4d4ef71964 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x65>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso new file mode 100644 index 000000000000..486b1fabe018 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x66>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso new file mode 100644 index 000000000000..6b47107efba8 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x67>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso new file mode 100644 index 000000000000..65a7e54f0884 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Infotainment Expansion Board for j721e-evm + * User Guide: <https://www.ti.com/lit/ug/spruit0a/spruit0a.pdf> + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> + +#include "k3-pinctrl.h" + +&{/} { + hdmi-connector { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + ddc-i2c-bus = <&main_i2c1>; + digital; + /* P12 - HDMI_HPD */ + hpd-gpios = <&exp6 10 GPIO_ACTIVE_HIGH>; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + dvi-bridge { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tfp410"; + /* P10 - HDMI_PDn */ + powerdown-gpios = <&exp6 8 GPIO_ACTIVE_LOW>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint { + remote-endpoint = <&dpi_out0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint { + remote-endpoint = + <&hdmi_connector_in>; + }; + }; + }; +}; + +&main_pmx0 { + main_i2c1_exp6_pins_default: main-i2c1-exp6-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x264, PIN_INPUT, 7) /* (T29) MMC2_DAT2.GPIO1_24 */ + >; + }; + + dss_vout0_pins_default: dss-vout0-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x58, PIN_OUTPUT, 10) /* (AE22) PRG1_PRU1_GPO0.VOUT0_DATA0 */ + J721E_IOPAD(0x5c, PIN_OUTPUT, 10) /* (AG23) PRG1_PRU1_GPO1.VOUT0_DATA1 */ + J721E_IOPAD(0x60, PIN_OUTPUT, 10) /* (AF23) PRG1_PRU1_GPO2.VOUT0_DATA2 */ + J721E_IOPAD(0x64, PIN_OUTPUT, 10) /* (AD23) PRG1_PRU1_GPO3.VOUT0_DATA3 */ + J721E_IOPAD(0x68, PIN_OUTPUT, 10) /* (AH24) PRG1_PRU1_GPO4.VOUT0_DATA4 */ + J721E_IOPAD(0x6c, PIN_OUTPUT, 10) /* (AG21) PRG1_PRU1_GPO5.VOUT0_DATA5 */ + J721E_IOPAD(0x70, PIN_OUTPUT, 10) /* (AE23) PRG1_PRU1_GPO6.VOUT0_DATA6 */ + J721E_IOPAD(0x74, PIN_OUTPUT, 10) /* (AC21) PRG1_PRU1_GPO7.VOUT0_DATA7 */ + J721E_IOPAD(0x78, PIN_OUTPUT, 10) /* (Y23) PRG1_PRU1_GPO8.VOUT0_DATA8 */ + J721E_IOPAD(0x7c, PIN_OUTPUT, 10) /* (AF21) PRG1_PRU1_GPO9.VOUT0_DATA9 */ + J721E_IOPAD(0x80, PIN_OUTPUT, 10) /* (AB23) PRG1_PRU1_GPO10.VOUT0_DATA10 */ + J721E_IOPAD(0x84, PIN_OUTPUT, 10) /* (AJ25) PRG1_PRU1_GPO11.VOUT0_DATA11 */ + J721E_IOPAD(0x88, PIN_OUTPUT, 10) /* (AH25) PRG1_PRU1_GPO12.VOUT0_DATA12 */ + J721E_IOPAD(0x8c, PIN_OUTPUT, 10) /* (AG25) PRG1_PRU1_GPO13.VOUT0_DATA13 */ + J721E_IOPAD(0x90, PIN_OUTPUT, 10) /* (AH26) PRG1_PRU1_GPO14.VOUT0_DATA14 */ + J721E_IOPAD(0x94, PIN_OUTPUT, 10) /* (AJ27) PRG1_PRU1_GPO15.VOUT0_DATA15 */ + J721E_IOPAD(0x30, PIN_OUTPUT, 10) /* (AF24) PRG1_PRU0_GPO11.VOUT0_DATA16 */ + J721E_IOPAD(0x34, PIN_OUTPUT, 10) /* (AJ24) PRG1_PRU0_GPO12.VOUT0_DATA17 */ + J721E_IOPAD(0x38, PIN_OUTPUT, 10) /* (AG24) PRG1_PRU0_GPO13.VOUT0_DATA18 */ + J721E_IOPAD(0x3c, PIN_OUTPUT, 10) /* (AD24) PRG1_PRU0_GPO14.VOUT0_DATA19 */ + J721E_IOPAD(0x40, PIN_OUTPUT, 10) /* (AC24) PRG1_PRU0_GPO15.VOUT0_DATA20 */ + J721E_IOPAD(0x44, PIN_OUTPUT, 10) /* (AE24) PRG1_PRU0_GPO16.VOUT0_DATA21 */ + J721E_IOPAD(0x24, PIN_OUTPUT, 10) /* (AJ20) PRG1_PRU0_GPO8.VOUT0_DATA22 */ + J721E_IOPAD(0x28, PIN_OUTPUT, 10) /* (AG20) PRG1_PRU0_GPO9.VOUT0_DATA23 */ + J721E_IOPAD(0x9c, PIN_OUTPUT, 10) /* (AC22) PRG1_PRU1_GPO17.VOUT0_DE */ + J721E_IOPAD(0x98, PIN_OUTPUT, 10) /* (AJ26) PRG1_PRU1_GPO16.VOUT0_HSYNC */ + J721E_IOPAD(0xa4, PIN_OUTPUT, 10) /* (AH22) PRG1_PRU1_GPO19.VOUT0_PCLK */ + J721E_IOPAD(0xa0, PIN_OUTPUT, 10) /* (AJ22) PRG1_PRU1_GPO18.VOUT0_VSYNC */ + >; + }; +}; + +&exp1 { + p14-hog { + /* P14 - VINOUT_MUX_SEL0 */ + gpio-hog; + gpios = <12 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "VINOUT_MUX_SEL0"; + }; + + p15-hog { + /* P15 - VINOUT_MUX_SEL1 */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "VINOUT_MUX_SEL1"; + }; +}; + +&main_i2c1 { + /* i2c1 is used for DVI DDC, so we need to use 100kHz */ + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + + exp6: gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_exp6_pins_default>; + interrupt-parent = <&main_gpio1>; + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + p11-hog { + /* P11 - HDMI_DDC_OE */ + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_DDC_OE"; + }; + }; +}; + +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout0_pins_default>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dpi_out0: endpoint { + remote-endpoint = <&tfp410_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso new file mode 100644 index 000000000000..380a4171ee50 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721E EVM + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso new file mode 100644 index 000000000000..614198ca334c --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include <dt-bindings/gpio/gpio.h> + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp1 { + p06-hog { + /* P06 - CSI01_MUX_SEL_2 */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI01_MUX_SEL_2"; + }; + + p07-hog { + /* P01 - CSI23_MUX_SEL_2 */ + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI23_MUX_SEL_2"; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts index 85340a77fef6..26257e7989f4 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts @@ -231,6 +231,7 @@ &main_pmx0 { + /delete-property/ interrupts; main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */ @@ -525,6 +526,14 @@ output-low; line-name = "GPIO_OLDI_RSTn"; }; + + p05-hog { + /* P05 - HDMI_LS_OE */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_LS_OE"; + }; }; sii9022: bridge-hdmi@3b { diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi index 9a1ba152901f..93c62289cebb 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi @@ -519,6 +519,17 @@ status = "disabled"; }; + e5010: e5010@fd20000 { + compatible = "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "regjasper", "regmmu"; + clocks = <&k3_clks 201 0>; + clock-names = "core_clk"; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + }; + }; /* MCU domain overrides */ diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index e1a1100b1ce1..9e971106ddd3 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -790,6 +790,7 @@ CONFIG_VIDEO_IMX390=m CONFIG_VIDEO_OV2312=m CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m +CONFIG_VIDEO_OX05B1S=m CONFIG_VIDEO_DS90UB953=m CONFIG_VIDEO_DS90UB960=m CONFIG_DRM=m diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index bc48919b0a16..cf2af687dda3 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -163,6 +163,10 @@ #define SII902X_AUDIO_PORT_INDEX 3 +/* drm_display_mode clock is in kHz */ +#define SII902X_MIN_PIXEL_CLOCK 25000 +#define SII902X_MAX_PIXEL_CLOCK 165000 + struct sii902x { struct i2c_client *i2c; struct regmap *regmap; @@ -322,7 +326,11 @@ static int sii902x_get_modes(struct drm_connector *connector) static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - /* TODO: check mode */ + if (mode->clock < SII902X_MIN_PIXEL_CLOCK) + return MODE_CLOCK_LOW; + + if (mode->clock > SII902X_MAX_PIXEL_CLOCK) + return MODE_CLOCK_HIGH; return MODE_OK; } diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 3410f5093a9b..d97cd1924e19 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -720,6 +720,19 @@ config VIDEO_OV9734 To compile this driver as a module, choose M here: the module's name is ov9734. +config VIDEO_OX05B1S + tristate "OmniVision OX05B1S sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the OmniVision + OX05B1S camera. + + To compile this driver as a module, choose M here: the + module will be called OX05B1S. + config VIDEO_RDACM20 tristate "IMI RDACM20 camera support" depends on I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 0b1e811b4c13..aea3f7e03bfe 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o +obj-$(CONFIG_VIDEO_OX05B1S) += ox05b1s.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o diff --git a/drivers/media/i2c/ox05b1s.c b/drivers/media/i2c/ox05b1s.c new file mode 100644 index 000000000000..ab0c828e3948 --- /dev/null +++ b/drivers/media/i2c/ox05b1s.c @@ -0,0 +1,1139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OmniVision OX05B1S RGB-IR Image Sensor driver + * + * Copyright (c) 2023-2024 Abhishek Sharma <abhishek.sharma@ti.com> + */ + +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ctrls.h> + +#include <linux/media-bus-format.h> + +#define OX05B_CHIP_ID 0x0558 +#define OX05B_FRAMERATE_DEFAULT 60 + +#define OX05B_OUT_WIDTH 2592 +#define OX05B_OUT_HEIGHT 1944 + +#define OX05B_SYS_MODE_SEL 0x0100 +#define OX05B_SC_CHIP_ID_HI 0x300a +#define OX05B_AEC_PK_EXPO_HI 0x3501 +#define OX05B_AEC_PK_EXPO_LO 0x3502 +#define OX05B_AEC_PK_AGAIN_HI 0x3508 +#define OX05B_AEC_PK_AGAIN_LO 0x3509 +#define OX05B_AEC_PK_DGAIN_HI 0x350a +#define OX05B_AEC_PK_DGAIN_LO 0x350b +#define OX05B_DEFAULT_LINK_FREQ 480000000 + +/* + * Exposure control + * Set max value as 0x850 (frame length = 2128) - 30 = 0x0832 for 16.66 ms exposure + * Set default value to be 1000 (0x03E8). + */ +#define OX05B_EXPOSURE_MAX 0x0832 +#define OX05B_EXPOSURE_DEFAULT 0x03E8 + +/* Analog gain control */ +#define OX05B_AGAIN_MAX 0x0F80 +#define OX05B_AGAIN_DEFAULT 0x010 + +/* Digital gain control */ +#define OX05B_DGAIN_MAX 0x0FFF +#define OX05B_DGAIN_DEFAULT 0x0100 + +static const struct v4l2_area ox05b_framesizes[] = { + { + .width = OX05B_OUT_WIDTH, + .height = OX05B_OUT_HEIGHT, + }, +}; + +static const u32 ox05b_mbus_formats[] = { + MEDIA_BUS_FMT_SBGGI10_1X10, +}; + +static const struct regmap_config ox05b_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const s64 ox05b_link_freq_menu[] = { + OX05B_DEFAULT_LINK_FREQ, +}; + +static const struct reg_sequence ox05b_linear_2592x1944[] = { + {0x0107, 0x01}, {0x0104, 0x00}, {0x0301, 0x1a}, {0x0304, 0x01}, + {0x0305, 0xe0}, {0x0306, 0x04}, {0x0307, 0x01}, {0x0321, 0x03}, + {0x0324, 0x01}, {0x0325, 0x80}, {0x0341, 0x03}, {0x0344, 0x01}, + {0x0345, 0xb0}, {0x0347, 0x07}, {0x034b, 0x06}, {0x0360, 0x80}, + {0x040b, 0x5c}, {0x040c, 0xcd}, {0x2805, 0xff}, {0x2806, 0x0f}, + {0x3000, 0x00}, {0x3001, 0x00}, {0x3002, 0x10}, {0x3004, 0x00}, + {0x3009, 0x2e}, {0x3010, 0x41}, {0x3015, 0xf0}, {0x3016, 0xf0}, + {0x3017, 0xf0}, {0x3018, 0xf0}, {0x301a, 0x78}, {0x301b, 0xb4}, + {0x301f, 0xe9}, {0x3024, 0x80}, {0x302b, 0x00}, {0x3039, 0x00}, + {0x3044, 0x70}, {0x3101, 0x32}, {0x3182, 0x10}, {0x3187, 0xff}, + {0x320a, 0x00}, {0x320b, 0x00}, {0x320c, 0x00}, {0x320d, 0x00}, + {0x320e, 0x00}, {0x320f, 0x00}, {0x3211, 0x61}, {0x3212, 0x00}, + {0x3215, 0xcc}, {0x3218, 0x06}, {0x3251, 0x00}, {0x3252, 0xe4}, + {0x3253, 0x00}, {0x3304, 0x11}, {0x3305, 0x00}, {0x3306, 0x01}, + {0x3307, 0x00}, {0x3308, 0x02}, {0x3309, 0x00}, {0x330a, 0x02}, + {0x330b, 0x00}, {0x330c, 0x02}, {0x330d, 0x00}, {0x330e, 0x02}, + {0x330f, 0x00}, {0x3310, 0x02}, {0x3311, 0x00}, {0x3312, 0x02}, + {0x3313, 0x00}, {0x3314, 0x02}, {0x3315, 0x00}, {0x3316, 0x02}, + {0x3317, 0x11}, {0x3400, 0x0c}, {0x3421, 0x00}, {0x3422, 0x00}, + {0x3423, 0x00}, {0x3424, 0x00}, {0x3425, 0x00}, {0x3426, 0x00}, + {0x3427, 0x00}, {0x3428, 0x00}, {0x3429, 0x00}, {0x342a, 0x00}, + {0x342b, 0x00}, {0x342c, 0x00}, {0x342d, 0x00}, {0x342e, 0x00}, + {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x08}, {0x3503, 0xa8}, + {0x3504, 0x08}, {0x3505, 0x00}, {0x3506, 0x00}, {0x3507, 0x00}, + {0x3508, 0x01}, {0x3509, 0x00}, {0x350a, 0x01}, {0x350b, 0x00}, + {0x350c, 0x00}, {0x351e, 0x00}, {0x351f, 0x00}, {0x3541, 0x00}, + {0x3542, 0x08}, {0x3603, 0x65}, {0x3604, 0x24}, {0x3608, 0x08}, + {0x3610, 0x00}, {0x3612, 0x00}, {0x3619, 0x09}, {0x361a, 0x27}, + {0x3620, 0x40}, {0x3622, 0x15}, {0x3623, 0x0e}, {0x3624, 0x1f}, + {0x3625, 0x1f}, {0x362a, 0x01}, {0x362b, 0x00}, {0x3633, 0x88}, + {0x3634, 0x86}, {0x3636, 0x80}, {0x3638, 0x5b}, {0x363b, 0x22}, + {0x363c, 0x07}, {0x363d, 0x11}, {0x363e, 0x21}, {0x363f, 0x24}, + {0x3640, 0xd3}, {0x3641, 0x00}, {0x3650, 0xe4}, {0x3651, 0x80}, + {0x3652, 0xff}, {0x3653, 0x00}, {0x3654, 0x05}, {0x3655, 0xf8}, + {0x3656, 0x00}, {0x3660, 0x00}, {0x3664, 0x00}, {0x366a, 0x80}, + {0x366b, 0x00}, {0x3670, 0x00}, {0x3674, 0x00}, {0x3684, 0x6d}, + {0x3685, 0x6d}, {0x3686, 0x6d}, {0x3687, 0x6d}, {0x368c, 0x07}, + {0x368d, 0x07}, {0x368e, 0x07}, {0x368f, 0x07}, {0x3690, 0x04}, + {0x3691, 0x04}, {0x3692, 0x04}, {0x3693, 0x04}, {0x3698, 0x00}, + {0x369e, 0x1f}, {0x369f, 0x19}, {0x36a0, 0x05}, {0x36a2, 0x19}, + {0x36a3, 0x05}, {0x36a4, 0x07}, {0x36a5, 0x27}, {0x36a6, 0x00}, + {0x36a7, 0x80}, {0x36e3, 0x09}, {0x3700, 0x07}, {0x3701, 0x1b}, + {0x3702, 0x0a}, {0x3703, 0x21}, {0x3704, 0x19}, {0x3705, 0x07}, + {0x3706, 0x36}, {0x370a, 0x1c}, {0x370b, 0x02}, {0x370c, 0x00}, + {0x370d, 0x6e}, {0x370f, 0x80}, {0x3710, 0x10}, {0x3712, 0x09}, + {0x3714, 0x42}, {0x3715, 0x00}, {0x3716, 0x02}, {0x3717, 0xa2}, + {0x3718, 0x41}, {0x371a, 0x80}, {0x371b, 0x0a}, {0x371c, 0x0a}, + {0x371d, 0x08}, {0x371e, 0x01}, {0x371f, 0x20}, {0x3720, 0x0e}, + {0x3721, 0x22}, {0x3722, 0x0c}, {0x3727, 0x84}, {0x3728, 0x03}, + {0x3729, 0x64}, {0x372a, 0x0c}, {0x372b, 0x14}, {0x372d, 0x50}, + {0x372e, 0x14}, {0x3731, 0x11}, {0x3732, 0x24}, {0x3733, 0x00}, + {0x3734, 0x00}, {0x3735, 0x12}, {0x3736, 0x00}, {0x373b, 0x0b}, + {0x373c, 0x14}, {0x373f, 0x3e}, {0x3740, 0x12}, {0x3741, 0x12}, + {0x3753, 0x80}, {0x3754, 0x01}, {0x3756, 0x11}, {0x375c, 0x0f}, + {0x375d, 0x35}, {0x375e, 0x0f}, {0x375f, 0x37}, {0x3760, 0x0f}, + {0x3761, 0x27}, {0x3762, 0x3f}, {0x3763, 0x5d}, {0x3764, 0x01}, + {0x3765, 0x17}, {0x3766, 0x02}, {0x3768, 0x52}, {0x376a, 0x30}, + {0x376b, 0x02}, {0x376c, 0x08}, {0x376d, 0x2a}, {0x376e, 0x00}, + {0x376f, 0x18}, {0x3770, 0x2c}, {0x3771, 0x0c}, {0x3776, 0xc0}, + {0x3778, 0x00}, {0x3779, 0x80}, {0x377a, 0x00}, {0x377d, 0x14}, + {0x377e, 0x0c}, {0x379f, 0x00}, {0x37a3, 0x40}, {0x37a4, 0x03}, + {0x37a5, 0x10}, {0x37a6, 0x02}, {0x37a7, 0x0e}, {0x37a9, 0x00}, + {0x37aa, 0x08}, {0x37ab, 0x08}, {0x37ac, 0x36}, {0x37ad, 0x40}, + {0x37b0, 0x48}, {0x37d0, 0x00}, {0x37d1, 0x0b}, {0x37d2, 0x0c}, + {0x37d3, 0x10}, {0x37d4, 0x10}, {0x37d5, 0x10}, {0x37d8, 0x0e}, + {0x37d9, 0x0e}, {0x37da, 0x3c}, {0x37db, 0x52}, {0x37dc, 0x50}, + {0x37dd, 0x00}, {0x37de, 0x55}, {0x37df, 0x7d}, {0x37e5, 0x88}, + {0x37e7, 0x68}, {0x37e8, 0x07}, {0x37f0, 0x00}, {0x37f1, 0x0e}, + {0x37f2, 0x35}, {0x37f3, 0x14}, {0x37f4, 0x0c}, {0x37f5, 0x14}, + {0x37f6, 0x0c}, {0x37f7, 0x35}, {0x37f8, 0x35}, {0x37f9, 0x37}, + {0x37fa, 0x37}, {0x37fb, 0x37}, {0x3800, 0x00}, {0x3801, 0x00}, + {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0x0a}, {0x3805, 0x2f}, + {0x3806, 0x07}, {0x3807, 0xa7}, {0x3808, 0x0a}, {0x3809, 0x20}, + {0x380a, 0x07}, {0x380b, 0x98}, {0x380c, 0x01}, {0x380d, 0x78}, + {0x380e, 0x08}, {0x380f, 0x50}, {0x3810, 0x00}, {0x3811, 0x05}, + {0x3812, 0x00}, {0x3813, 0x08}, {0x3814, 0x11}, {0x3815, 0x11}, + {0x3820, 0x40}, {0x3821, 0x04}, {0x3822, 0x10}, {0x3823, 0x00}, + {0x3826, 0x00}, {0x3827, 0x00}, {0x382b, 0x03}, {0x382c, 0x0c}, + {0x382d, 0x15}, {0x382e, 0x01}, {0x3830, 0x00}, {0x3838, 0x00}, + {0x383b, 0x00}, {0x3840, 0x00}, {0x384a, 0xa2}, {0x3858, 0x00}, + {0x3859, 0x00}, {0x3860, 0x00}, {0x3861, 0x00}, {0x3866, 0x10}, + {0x3867, 0x07}, {0x3868, 0x01}, {0x3869, 0x01}, {0x386a, 0x01}, + {0x386b, 0x01}, {0x386c, 0x46}, {0x386d, 0x07}, {0x386e, 0xd2}, + {0x3871, 0x01}, {0x3872, 0x01}, {0x3873, 0x01}, {0x3874, 0x01}, + {0x3880, 0x00}, {0x3881, 0x00}, {0x3882, 0x00}, {0x3883, 0x00}, + {0x3884, 0x00}, {0x3885, 0x00}, {0x3886, 0x00}, {0x3887, 0x00}, + {0x3888, 0x00}, {0x3889, 0x00}, {0x3900, 0x13}, {0x3901, 0x19}, + {0x3902, 0x05}, {0x3903, 0x00}, {0x3904, 0x00}, {0x3908, 0x00}, + {0x3909, 0x18}, {0x390a, 0x00}, {0x390b, 0x11}, {0x390c, 0x15}, + {0x390d, 0x84}, {0x390f, 0x88}, {0x3910, 0x00}, {0x3911, 0x00}, + {0x3912, 0x03}, {0x3913, 0x62}, {0x3914, 0x00}, {0x3915, 0x06}, + {0x3916, 0x0c}, {0x3917, 0x81}, {0x3918, 0xc8}, {0x3919, 0x94}, + {0x391a, 0x17}, {0x391b, 0x05}, {0x391c, 0x81}, {0x391d, 0x05}, + {0x391e, 0x81}, {0x391f, 0x05}, {0x3920, 0x81}, {0x3921, 0x14}, + {0x3922, 0x0b}, {0x3929, 0x00}, {0x392a, 0x00}, {0x392b, 0xc8}, + {0x392c, 0x81}, {0x392f, 0x00}, {0x3930, 0x00}, {0x3931, 0x00}, + {0x3932, 0x00}, {0x3933, 0x00}, {0x3934, 0x1b}, {0x3935, 0xc0}, + {0x3936, 0x1c}, {0x3937, 0x21}, {0x3938, 0x0d}, {0x3939, 0x92}, + {0x393a, 0x85}, {0x393b, 0x8a}, {0x393c, 0x06}, {0x393d, 0x8b}, + {0x393e, 0x0f}, {0x393f, 0x14}, {0x3940, 0x0f}, {0x3941, 0x14}, + {0x3945, 0xc0}, {0x3946, 0x05}, {0x3947, 0xc0}, {0x3948, 0x01}, + {0x3949, 0x00}, {0x394a, 0x00}, {0x394b, 0x0b}, {0x394c, 0x0c}, + {0x394d, 0x0b}, {0x394e, 0x09}, {0x3951, 0xc7}, {0x3952, 0x0f}, + {0x3953, 0x0f}, {0x3954, 0x0f}, {0x3955, 0x00}, {0x3956, 0x27}, + {0x3957, 0x27}, {0x3958, 0x27}, {0x3959, 0x01}, {0x395a, 0x02}, + {0x395b, 0x14}, {0x395c, 0x36}, {0x395e, 0xc0}, {0x3964, 0x55}, + {0x3965, 0x55}, {0x3966, 0x88}, {0x3967, 0x88}, {0x3968, 0x66}, + {0x3969, 0x66}, {0x396d, 0x80}, {0x396e, 0xff}, {0x396f, 0x10}, + {0x3970, 0x80}, {0x3971, 0x80}, {0x3972, 0x00}, {0x397a, 0x55}, + {0x397b, 0x10}, {0x397c, 0x10}, {0x397d, 0x10}, {0x397e, 0x10}, + {0x3980, 0xfc}, {0x3981, 0xfc}, {0x3982, 0x66}, {0x3983, 0xfc}, + {0x3984, 0xfc}, {0x3985, 0x66}, {0x3986, 0x00}, {0x3987, 0x00}, + {0x3988, 0x00}, {0x3989, 0x00}, {0x398a, 0x00}, {0x398b, 0x00}, + {0x398c, 0x00}, {0x398d, 0x00}, {0x398e, 0x00}, {0x398f, 0x00}, + {0x3990, 0x00}, {0x3991, 0x00}, {0x3992, 0x00}, {0x3993, 0x00}, + {0x3994, 0x00}, {0x3995, 0x00}, {0x3996, 0x00}, {0x3997, 0x0f}, + {0x3998, 0x0c}, {0x3999, 0x0c}, {0x399a, 0x0c}, {0x399b, 0xf0}, + {0x399c, 0x14}, {0x399d, 0x0d}, {0x399e, 0x00}, {0x399f, 0x0c}, + {0x39a0, 0x0c}, {0x39a1, 0x0c}, {0x39a2, 0x00}, {0x39a3, 0x0f}, + {0x39a4, 0x0c}, {0x39a5, 0x0c}, {0x39a6, 0x0c}, {0x39a7, 0x0c}, + {0x39a8, 0x0f}, {0x39a9, 0xff}, {0x39aa, 0xbf}, {0x39ab, 0x3f}, + {0x39ac, 0x7e}, {0x39ad, 0xff}, {0x39ae, 0x00}, {0x39af, 0x00}, + {0x39b0, 0x00}, {0x39b1, 0x00}, {0x39b2, 0x00}, {0x39b3, 0x00}, + {0x39b4, 0x00}, {0x39b5, 0x00}, {0x39b6, 0x00}, {0x39b7, 0x00}, + {0x39b8, 0x00}, {0x39b9, 0x00}, {0x39ba, 0x00}, {0x39bb, 0x00}, + {0x39bc, 0x00}, {0x39c2, 0x00}, {0x39c3, 0x00}, {0x39c4, 0x00}, + {0x39c5, 0x00}, {0x39c7, 0x00}, {0x39c8, 0x00}, {0x39c9, 0x00}, + {0x39ca, 0x01}, {0x39cb, 0x00}, {0x39cc, 0x85}, {0x39cd, 0x09}, + {0x39cf, 0x04}, {0x39d0, 0x85}, {0x39d1, 0x09}, {0x39d2, 0x04}, + {0x39d4, 0x02}, {0x39d5, 0x0e}, {0x39db, 0x00}, {0x39dc, 0x01}, + {0x39dd, 0x0c}, {0x39e5, 0xff}, {0x39e6, 0xff}, {0x39fa, 0x38}, + {0x39fb, 0x07}, {0x39ff, 0x00}, {0x3a05, 0x00}, {0x3a06, 0x07}, + {0x3a07, 0x0d}, {0x3a08, 0x08}, {0x3a09, 0xb2}, {0x3a0a, 0x0a}, + {0x3a0b, 0x3c}, {0x3a0c, 0x0b}, {0x3a0d, 0xe1}, {0x3a0e, 0x03}, + {0x3a0f, 0x85}, {0x3a10, 0x0b}, {0x3a11, 0xff}, {0x3a12, 0x00}, + {0x3a13, 0x01}, {0x3a14, 0x0c}, {0x3a15, 0x04}, {0x3a17, 0x09}, + {0x3a18, 0x20}, {0x3a19, 0x09}, {0x3a1a, 0x9d}, {0x3a1b, 0x09}, + {0x3a1e, 0x34}, {0x3a1f, 0x09}, {0x3a20, 0x89}, {0x3a21, 0x09}, + {0x3a48, 0xbe}, {0x3a52, 0x00}, {0x3a53, 0x01}, {0x3a54, 0x0c}, + {0x3a55, 0x04}, {0x3a58, 0x0c}, {0x3a59, 0x04}, {0x3a5a, 0x01}, + {0x3a5b, 0x00}, {0x3a5c, 0x01}, {0x3a5d, 0xe8}, {0x3a62, 0x03}, + {0x3a63, 0x86}, {0x3a64, 0x0b}, {0x3a65, 0xbe}, {0x3a6a, 0xdc}, + {0x3a6b, 0x0b}, {0x3a6c, 0x1a}, {0x3a6d, 0x06}, {0x3a6e, 0x01}, + {0x3a6f, 0x04}, {0x3a70, 0xdc}, {0x3a71, 0x0b}, {0x3a83, 0x10}, + {0x3a84, 0x00}, {0x3a85, 0x08}, {0x3a87, 0x00}, {0x3a88, 0x6b}, + {0x3a89, 0x01}, {0x3a8a, 0x53}, {0x3a8f, 0x00}, {0x3a90, 0x00}, + {0x3a91, 0x00}, {0x3a92, 0x00}, {0x3a93, 0x60}, {0x3a94, 0xea}, + {0x3a98, 0x00}, {0x3a99, 0x31}, {0x3a9a, 0x01}, {0x3a9b, 0x04}, + {0x3a9c, 0xdc}, {0x3a9d, 0x0b}, {0x3aa4, 0x0f}, {0x3aad, 0x00}, + {0x3aae, 0x3e}, {0x3aaf, 0x02}, {0x3ab0, 0x77}, {0x3ab2, 0x00}, + {0x3ab3, 0x08}, {0x3ab6, 0x0b}, {0x3ab7, 0xff}, {0x3aba, 0x0b}, + {0x3abb, 0xfa}, {0x3abd, 0x05}, {0x3abe, 0x09}, {0x3abf, 0x1e}, + {0x3ac0, 0x00}, {0x3ac1, 0x63}, {0x3ac2, 0x01}, {0x3ac3, 0x55}, + {0x3ac8, 0x00}, {0x3ac9, 0x2a}, {0x3aca, 0x01}, {0x3acb, 0x36}, + {0x3acc, 0x00}, {0x3acd, 0x6f}, {0x3ad0, 0x00}, {0x3ad1, 0x79}, + {0x3ad2, 0x02}, {0x3ad3, 0x59}, {0x3ad4, 0x06}, {0x3ad5, 0x5a}, + {0x3ad6, 0x08}, {0x3ad7, 0x3a}, {0x3ad8, 0x00}, {0x3ad9, 0x79}, + {0x3ada, 0x02}, {0x3adb, 0x59}, {0x3adc, 0x09}, {0x3add, 0x89}, + {0x3ade, 0x0b}, {0x3adf, 0x69}, {0x3ae0, 0x03}, {0x3ae1, 0xc1}, + {0x3ae2, 0x0b}, {0x3ae3, 0xaf}, {0x3ae4, 0x00}, {0x3ae5, 0x3e}, + {0x3ae6, 0x02}, {0x3ae7, 0x77}, {0x3ae8, 0x00}, {0x3aea, 0x0b}, + {0x3aeb, 0xbe}, {0x3aee, 0x08}, {0x3aef, 0x80}, {0x3af0, 0x09}, + {0x3af1, 0x70}, {0x3af2, 0x08}, {0x3af3, 0x94}, {0x3af4, 0x09}, + {0x3af5, 0x5c}, {0x3af6, 0x03}, {0x3af7, 0x85}, {0x3af8, 0x08}, + {0x3af9, 0x80}, {0x3afa, 0x0b}, {0x3afb, 0xaf}, {0x3afc, 0x01}, + {0x3afd, 0x5a}, {0x3b1e, 0x00}, {0x3b20, 0xa5}, {0x3b21, 0x00}, + {0x3b22, 0x00}, {0x3b23, 0x00}, {0x3b24, 0x05}, {0x3b25, 0x00}, + {0x3b26, 0x00}, {0x3b27, 0x00}, {0x3b28, 0x1a}, {0x3b2f, 0x40}, + {0x3b40, 0x08}, {0x3b41, 0x70}, {0x3b42, 0x05}, {0x3b43, 0xf0}, + {0x3b44, 0x01}, {0x3b45, 0x54}, {0x3b46, 0x01}, {0x3b47, 0x54}, + {0x3b56, 0x08}, {0x3b80, 0x00}, {0x3b81, 0x00}, {0x3b82, 0x64}, + {0x3b83, 0x00}, {0x3b84, 0x00}, {0x3b85, 0x64}, {0x3b9d, 0x61}, + {0x3ba8, 0x38}, {0x3c11, 0x33}, {0x3c12, 0x3d}, {0x3c13, 0x00}, + {0x3c14, 0xbe}, {0x3c15, 0x0b}, {0x3c16, 0xa8}, {0x3c17, 0x03}, + {0x3c18, 0x9c}, {0x3c19, 0x0b}, {0x3c1a, 0x0f}, {0x3c1b, 0x97}, + {0x3c1c, 0x00}, {0x3c1d, 0x3c}, {0x3c1e, 0x02}, {0x3c1f, 0x78}, + {0x3c20, 0x06}, {0x3c21, 0x80}, {0x3c22, 0x08}, {0x3c23, 0x0f}, + {0x3c24, 0x97}, {0x3c25, 0x00}, {0x3c26, 0x3c}, {0x3c27, 0x02}, + {0x3c28, 0xa7}, {0x3c29, 0x09}, {0x3c2a, 0xaf}, {0x3c2b, 0x0b}, + {0x3c2c, 0x38}, {0x3c2d, 0xf9}, {0x3c2e, 0x0b}, {0x3c2f, 0xfd}, + {0x3c30, 0x05}, {0x3c35, 0x8c}, {0x3c3e, 0xc3}, {0x3c43, 0xcb}, + {0x3c44, 0x00}, {0x3c45, 0xff}, {0x3c46, 0x0b}, {0x3c48, 0x3b}, + {0x3c49, 0x40}, {0x3c4a, 0x00}, {0x3c4b, 0x5b}, {0x3c4c, 0x02}, + {0x3c4d, 0x02}, {0x3c4e, 0x00}, {0x3c4f, 0x04}, {0x3c50, 0x0c}, + {0x3c51, 0x00}, {0x3c52, 0x3b}, {0x3c53, 0x3a}, {0x3c54, 0x07}, + {0x3c55, 0x9e}, {0x3c56, 0x07}, {0x3c57, 0x9e}, {0x3c58, 0x07}, + {0x3c59, 0xe8}, {0x3c5a, 0x03}, {0x3c5b, 0x33}, {0x3c5c, 0xa8}, + {0x3c5d, 0x07}, {0x3c5e, 0xd0}, {0x3c5f, 0x07}, {0x3c60, 0x32}, + {0x3c61, 0x00}, {0x3c62, 0xd0}, {0x3c63, 0x07}, {0x3c64, 0x80}, + {0x3c65, 0x80}, {0x3c66, 0x3f}, {0x3c67, 0x01}, {0x3c68, 0x00}, + {0x3c69, 0xd0}, {0x3c6a, 0x07}, {0x3c6b, 0x01}, {0x3c6c, 0x00}, + {0x3c6d, 0xcd}, {0x3c6e, 0x07}, {0x3c6f, 0xd1}, {0x3c70, 0x07}, + {0x3c71, 0x01}, {0x3c72, 0x00}, {0x3c73, 0xc3}, {0x3c74, 0x01}, + {0x3c75, 0x00}, {0x3c76, 0xcd}, {0x3c77, 0x07}, {0x3c78, 0xea}, + {0x3c79, 0x03}, {0x3c7a, 0xcd}, {0x3c7b, 0x07}, {0x3c7c, 0x08}, + {0x3c7d, 0x06}, {0x3c7e, 0x03}, {0x3c85, 0x3a}, {0x3c86, 0x08}, + {0x3c87, 0x69}, {0x3c88, 0x0b}, {0x3c8f, 0xb2}, {0x3c90, 0x08}, + {0x3c91, 0xe1}, {0x3c92, 0x0b}, {0x3c93, 0x06}, {0x3c94, 0x03}, + {0x3c9b, 0x35}, {0x3c9c, 0x08}, {0x3c9d, 0x64}, {0x3c9e, 0x0b}, + {0x3ca5, 0xb7}, {0x3ca6, 0x08}, {0x3ca7, 0xe6}, {0x3ca8, 0x0b}, + {0x3ca9, 0x83}, {0x3caa, 0x3c}, {0x3cab, 0x01}, {0x3cac, 0x00}, + {0x3cad, 0x9e}, {0x3cae, 0x07}, {0x3caf, 0x85}, {0x3cb0, 0x03}, + {0x3cb1, 0xbc}, {0x3cb2, 0x0b}, {0x3cb7, 0x3c}, {0x3cb8, 0x01}, + {0x3cb9, 0x00}, {0x3cba, 0xbc}, {0x3cbb, 0x07}, {0x3cbc, 0xa3}, + {0x3cbd, 0x03}, {0x3cbe, 0x9e}, {0x3cbf, 0x0b}, {0x3cc4, 0x99}, + {0x3cc5, 0xe9}, {0x3cc6, 0x99}, {0x3cc7, 0xe9}, {0x3cc8, 0x33}, + {0x3cc9, 0x03}, {0x3cca, 0x33}, {0x3ccb, 0x03}, {0x3cce, 0x66}, + {0x3ccf, 0x66}, {0x3cd0, 0x00}, {0x3cd1, 0x04}, {0x3cd2, 0xf4}, + {0x3cd3, 0xb7}, {0x3cd4, 0x03}, {0x3cd5, 0x10}, {0x3cd6, 0x06}, + {0x3cd7, 0x30}, {0x3cd8, 0x08}, {0x3cd9, 0x5f}, {0x3cda, 0x0b}, + {0x3cdd, 0x44}, {0x3cde, 0x44}, {0x3cdf, 0x04}, {0x3ce0, 0x00}, + {0x3ce1, 0x00}, {0x3ce3, 0x00}, {0x3ce4, 0x00}, {0x3ce5, 0x00}, + {0x3ce6, 0x00}, {0x3ce7, 0x00}, {0x3ce8, 0x00}, {0x3ce9, 0x00}, + {0x3cea, 0x00}, {0x3ceb, 0x00}, {0x3cec, 0x00}, {0x3ced, 0x00}, + {0x3cee, 0x00}, {0x3cef, 0x85}, {0x3cf0, 0x03}, {0x3cf1, 0xaf}, + {0x3cf2, 0x0b}, {0x3cf3, 0x03}, {0x3cf4, 0x2c}, {0x3cf5, 0x00}, + {0x3cf6, 0x42}, {0x3cf7, 0x00}, {0x3cf8, 0x03}, {0x3cf9, 0x2c}, + {0x3cfa, 0x00}, {0x3cfb, 0x42}, {0x3cfc, 0x00}, {0x3cfd, 0x03}, + {0x3cfe, 0x01}, {0x3d81, 0x00}, {0x3e94, 0x0f}, {0x3e95, 0x5f}, + {0x3e96, 0x02}, {0x3e97, 0x3c}, {0x3e98, 0x00}, {0x3e9f, 0x00}, + {0x3f00, 0x00}, {0x3f05, 0x03}, {0x3f07, 0x01}, {0x3f08, 0x55}, + {0x3f09, 0x25}, {0x3f0a, 0x35}, {0x3f0b, 0x20}, {0x3f11, 0x05}, + {0x3f12, 0x05}, {0x3f40, 0x00}, {0x3f41, 0x03}, {0x3f43, 0x10}, + {0x3f44, 0x02}, {0x3f45, 0xe6}, {0x4000, 0xf9}, {0x4001, 0x2b}, + {0x4008, 0x04}, {0x4009, 0x1b}, {0x400a, 0x03}, {0x400e, 0x10}, + {0x4010, 0x04}, {0x4011, 0xf7}, {0x4032, 0x3e}, {0x4033, 0x02}, + {0x4050, 0x02}, {0x4051, 0x0d}, {0x40f9, 0x00}, {0x4200, 0x00}, + {0x4204, 0x00}, {0x4205, 0x00}, {0x4206, 0x00}, {0x4207, 0x00}, + {0x4208, 0x00}, {0x4244, 0x00}, {0x4300, 0x00}, {0x4301, 0xff}, + {0x4302, 0xf0}, {0x4303, 0x00}, {0x4304, 0xff}, {0x4305, 0xf0}, + {0x4306, 0x00}, {0x4308, 0x00}, {0x430a, 0x90}, {0x430b, 0x11}, + {0x4310, 0x00}, {0x4316, 0x00}, {0x431c, 0x00}, {0x431e, 0x00}, + {0x4410, 0x08}, {0x4433, 0x08}, {0x4434, 0xf8}, {0x4508, 0x80}, + {0x4509, 0x10}, {0x450b, 0x83}, {0x4511, 0x00}, {0x4580, 0x09}, + {0x4587, 0x00}, {0x458c, 0x00}, {0x4640, 0x00}, {0x4641, 0xc1}, + {0x4642, 0x00}, {0x4643, 0x00}, {0x4649, 0x00}, {0x4681, 0x04}, + {0x4682, 0x10}, {0x4683, 0xa0}, {0x4698, 0x07}, {0x4699, 0xf0}, + {0x4710, 0x00}, {0x4802, 0x00}, {0x481b, 0x3c}, {0x4837, 0x10}, + {0x4860, 0x00}, {0x4883, 0x00}, {0x4884, 0x09}, {0x4885, 0x80}, + {0x4886, 0x00}, {0x4888, 0x10}, {0x488b, 0x00}, {0x488c, 0x10}, + {0x4980, 0x03}, {0x4981, 0x06}, {0x4984, 0x00}, {0x4985, 0x00}, + {0x4a14, 0x04}, {0x4b01, 0x44}, {0x4b03, 0x80}, {0x4d06, 0xc8}, + {0x4d09, 0xdf}, {0x4d15, 0x7d}, {0x4d34, 0x7d}, {0x4d3c, 0x7d}, + {0x4f00, 0x7f}, {0x4f01, 0xff}, {0x4f03, 0x00}, {0x4f04, 0x18}, + {0x4f05, 0x13}, {0x5000, 0x6e}, {0x5001, 0x00}, {0x500a, 0x00}, + {0x5080, 0x00}, {0x5081, 0x00}, {0x5082, 0x00}, {0x5083, 0x00}, + {0x5100, 0x00}, {0x5103, 0x00}, {0x5180, 0x70}, {0x5181, 0x70}, + {0x5182, 0x73}, {0x5183, 0xff}, {0x5249, 0x06}, {0x524f, 0x06}, + {0x5281, 0x18}, {0x5282, 0x08}, {0x5283, 0x08}, {0x5284, 0x18}, + {0x5285, 0x18}, {0x5286, 0x08}, {0x5287, 0x08}, {0x5288, 0x18}, + {0x5289, 0x2d}, {0x6000, 0x40}, {0x6001, 0x40}, {0x6002, 0x00}, + {0x6003, 0x00}, {0x6004, 0x00}, {0x6005, 0x00}, {0x6006, 0x00}, + {0x6007, 0x00}, {0x6008, 0x00}, {0x6009, 0x00}, {0x600a, 0x00}, + {0x600b, 0x00}, {0x600c, 0x02}, {0x600d, 0x00}, {0x600e, 0x04}, + {0x600f, 0x00}, {0x6010, 0x06}, {0x6011, 0x00}, {0x6012, 0x00}, + {0x6013, 0x00}, {0x6014, 0x02}, {0x6015, 0x00}, {0x6016, 0x04}, + {0x6017, 0x00}, {0x6018, 0x06}, {0x6019, 0x00}, {0x601a, 0x01}, + {0x601b, 0x00}, {0x601c, 0x01}, {0x601d, 0x00}, {0x601e, 0x01}, + {0x601f, 0x00}, {0x6020, 0x01}, {0x6021, 0x00}, {0x6022, 0x01}, + {0x6023, 0x00}, {0x6024, 0x01}, {0x6025, 0x00}, {0x6026, 0x01}, + {0x6027, 0x00}, {0x6028, 0x01}, {0x6029, 0x00}, {0x3501, 0x08}, + {0x3502, 0x32}, {0x320a, 0x01}, {0x320b, 0x01}, {0x320c, 0x00}, + {0x320d, 0x00}, +}; + +struct ox05b { + struct device *dev; + struct clk *clk; + unsigned long clk_rate; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *pwdn_gpio; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + struct v4l2_ctrl_handler handler; + /* Added for RGB dominant stream */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *again; + struct v4l2_ctrl *dgain; + /* Added for IR dominant stream */ + struct v4l2_ctrl *ir_exposure; + struct v4l2_ctrl *ir_again; + struct v4l2_ctrl *ir_dgain; + u32 fps; + struct mutex lock; /* For streaming status */ + bool streaming; + struct v4l2_ctrl *link_freq; +}; + +static inline struct ox05b *to_ox05b(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ox05b, subdev); +} + +static int ox05b_read(struct ox05b *ox05b, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int ox05b_write(struct ox05b *ox05b, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + } + return ret; +} + +static int ox05b_write_table(struct ox05b *ox05b, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret; + + ret = regmap_multi_reg_write(ox05b->regmap, regs, nr_regs); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg table (%d)!\n", + __func__, ret); + } + return ret; +} + +static void ox05b_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + int i; + + for (i = 0; i < 2; ++i) { + format = v4l2_subdev_state_get_stream_format(state, 0, i); + format->code = ox05b_mbus_formats[0]; + format->width = ox05b_framesizes[0].width; + format->height = ox05b_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + } +} + +static int ox05b_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ox05b *ox05b = to_ox05b(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* Sensor only supports a single format. */ + code = ox05b_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(ox05b_framesizes, + ARRAY_SIZE(ox05b_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + format = v4l2_subdev_state_get_stream_format(state, fmt->pad, fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ox05b->streaming) + ret = -EBUSY; + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + + return ret; +} + +static int _ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + ox05b_init_formats(state); + + return 0; +} + +static int ox05b_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + unsigned int i; + + if (pad != 0) + return -EINVAL; + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_state_get_stream_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream - 2 virtual channels*/ + + bpp = 10; + + for (i = 0; i < 2; ++i) { + fd->entry[fd->num_entries].stream = i; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = i; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */ + + fd->num_entries++; + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 2) + return -EINVAL; + + v4l2_subdev_lock_state(state); + + ret = _ox05b_set_routing(sd, state); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _ox05b_set_routing(sd, state); + + return ret; +} + +static int ox05b_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + code->code = ox05b_mbus_formats[code->index]; + + return 0; +} + +static int ox05b_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ox05b_mbus_formats); ++i) { + if (ox05b_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(ox05b_framesizes)) + return -EINVAL; + + fse->min_width = ox05b_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ox05b_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ox05b_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = ox05b->fps; + return 0; +} + +static int ox05b_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + dev_dbg(ox05b->dev, "%s: Set framerate %dfps\n", __func__, + fi->interval.denominator / fi->interval.numerator); + if ((fi->interval.denominator / fi->interval.numerator) != ox05b->fps) { + dev_err(ox05b->dev, "%s: Framerate can only be %dfps\n", + __func__, ox05b->fps); + return -EINVAL; + } + return 0; +} + +static int ox05b_detect(struct ox05b *ox05b) +{ + int ret; + u32 id; + + ret = ox05b_read(ox05b, OX05B_SC_CHIP_ID_HI, &id, 2); + if (ret < 0) + return ret; + + if (id != OX05B_CHIP_ID) { + dev_err(ox05b->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_info(ox05b->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +static int ox05b_set_groupA(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->ir_exposure->val; + u32 again = ox05b->ir_again->val; + u32 dgain = ox05b->ir_dgain->val; + struct reg_sequence ox05b_groupA[] = { + {0x3208, 0x01}, /* Group 1 (IR Dominant VC0) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x01}, /* VC=1. This register takes effect from next frame. */ + {0x3208, 0x11}, /* Group 1 (IR Dominant VC0) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupA); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupA[i].reg, ox05b_groupA[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupA[i].reg, ox05b_groupA[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_groupB(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->exposure->val; + u32 again = ox05b->again->val; + u32 dgain = ox05b->dgain->val; + struct reg_sequence ox05b_groupB[] = { + {0x3208, 0x00}, /* Group 0 (RGB Dominant VC1) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x00}, /* VC=0. This register takes effect from next frame. */ + {0x3208, 0x10}, /* Group 0 (RGB Dominant VC1) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupB); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupB[i].reg, ox05b_groupB[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupB[i].reg, ox05b_groupB[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_AB_mode_regs(struct ox05b *ox05b) +{ + int i, ret; + struct reg_sequence ox5b_AB_mode_regs[] = { + {0x3211, 0xF1}, /* AB mode enable */ + {0x3212, 0x21}, /* Enable sync between holds of group 0 and group 1*/ + {0x3208, 0xA0}, /* Always use for repeat launch */ + }; + + for (i = 0; i < ARRAY_SIZE(ox5b_AB_mode_regs); i++) { + ret = regmap_write(ox05b->regmap, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ox05b *ox05b = container_of(ctrl->handler, struct ox05b, handler); + int ret; + + dev_dbg(ox05b->dev, "%s: %s, value: %d\n", __func__, + ctrl->name, ctrl->val); + + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (pm_runtime_suspended(ox05b->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + case V4L2_CID_ANALOGUE_GAIN: + case V4L2_CID_DIGITAL_GAIN: + ret = ox05b_set_groupB(ox05b); + break; + case V4L2_CID_IR_EXPOSURE: + case V4L2_CID_IR_ANALOGUE_GAIN: + case V4L2_CID_IR_DIGITAL_GAIN: + ret = ox05b_set_groupA(ox05b); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int ox05b_power_on(struct ox05b *ox05b) +{ + int ret; + + ret = clk_prepare_enable(ox05b->clk); + if (ret < 0) + return ret; + + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(100, 1000); + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 0); + msleep(30); + } + return 0; +} + +static int ox05b_power_off(struct ox05b *ox05b) +{ + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(1, 10); + } + + clk_disable_unprepare(ox05b->clk); + + return 0; +} + +static int ox05b_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_on(ox05b); +} + +static int ox05b_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_off(ox05b); +} + +static int ox05b_start_stream(struct ox05b *ox05b) +{ + int ret; + + ret = ox05b_write_table(ox05b, ox05b_linear_2592x1944, + ARRAY_SIZE(ox05b_linear_2592x1944)); + if (ret < 0) + return ret; + + msleep(20); + + /* set registers for IR frame */ + ret = ox05b_set_groupA(ox05b); + if (ret < 0) + return ret; + + /* set registers for RGB frame */ + ret = ox05b_set_groupB(ox05b); + if (ret < 0) + return ret; + + /* set registers specific to AB mode */ + ret = ox05b_set_AB_mode_regs(ox05b); + + /* Set active */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0x01, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby. + * we want the sensor to have sufficient time to process + * the new configurations. The same type of delays have been programmed + * in the OV2312 driver. + * TODO: check if there is a status register to poll for sensor readiness. + */ + msleep(20); + + return 0; +} + +static int ox05b_stop_stream(struct ox05b *ox05b) +{ + int ret; + + /* Set standby */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int ox05b_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ox05b *ox05b = to_ox05b(sd); + int ret; + + mutex_lock(&ox05b->lock); + if (ox05b->streaming == enable) { + mutex_unlock(&ox05b->lock); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ox05b->dev); + if (ret < 0) + goto err_unlock; + + ret = ox05b_start_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + + } else { + ret = ox05b_stop_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + pm_runtime_put(ox05b->dev); + } + + ox05b->streaming = enable; + + mutex_unlock(&ox05b->lock); + return 0; + +err_runtime_put: + pm_runtime_put(ox05b->dev); + +err_unlock: + mutex_unlock(&ox05b->lock); + dev_err(ox05b->dev, + "%s: failed to setup streaming %d\n", __func__, ret); + return ret; +} + +static const struct v4l2_subdev_video_ops ox05b_subdev_video_ops = { + .g_frame_interval = ox05b_get_frame_interval, + .s_frame_interval = ox05b_set_frame_interval, + .s_stream = ox05b_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ox05b_subdev_pad_ops = { + .init_cfg = ox05b_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ox05b_set_fmt, + .enum_mbus_code = ox05b_enum_mbus_code, + .enum_frame_size = ox05b_enum_frame_sizes, + .set_routing = ox05b_set_routing, + .get_frame_desc = ox05b_get_frame_desc, +}; + +static const struct v4l2_subdev_ops ox05b_subdev_ops = { + .video = &ox05b_subdev_video_ops, + .pad = &ox05b_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops ox05b_ctrl_ops = { + .s_ctrl = ox05b_set_ctrl, +}; + +static const struct dev_pm_ops ox05b_pm_ops = { + SET_RUNTIME_PM_OPS(ox05b_suspend, ox05b_resume, NULL) +}; + +static int ox05b_probe(struct i2c_client *client) +{ + struct ox05b *ox05b; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + /* Allocate internal struct */ + ox05b = devm_kzalloc(&client->dev, sizeof(*ox05b), GFP_KERNEL); + if (!ox05b) + return -ENOMEM; + ox05b->dev = &client->dev; + + /* Initialize I2C Regmap */ + ox05b->regmap = devm_regmap_init_i2c(client, &ox05b_regmap_config); + if (IS_ERR(ox05b->regmap)) + return PTR_ERR(ox05b->regmap); + + /* Initialize Powerdown GPIO */ + ox05b->pwdn_gpio = devm_gpiod_get_optional(ox05b->dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(ox05b->pwdn_gpio)) + return PTR_ERR(ox05b->pwdn_gpio); + + ox05b->clk = devm_clk_get(ox05b->dev, "inck"); + if (IS_ERR(ox05b->clk)) + return PTR_ERR(ox05b->clk); + + ox05b->clk_rate = clk_get_rate(ox05b->clk); + + if (ox05b->clk_rate < 6000000 || ox05b->clk_rate > 27000000) + return -EINVAL; + + /* Power on */ + ret = ox05b_power_on(ox05b); + if (ret < 0) + return ret; + + /* Detect sensor */ + ret = ox05b_detect(ox05b); + if (ret < 0) + return ret; + + /* Initialize the subdev and its controls. */ + sd = &ox05b->subdev; + v4l2_i2c_subdev_init(sd, client, &ox05b_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | + V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + ox05b->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ox05b->pad); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: media entity init failed %d\n", __func__, ret); + return ret; + } + + ox05b->fps = OX05B_FRAMERATE_DEFAULT; + mutex_init(&ox05b->lock); + /* Initialize controls */ + ctrl_hdr = &ox05b->handler; + ret = v4l2_ctrl_handler_init(ctrl_hdr, 7); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: ctrl handler init failed: %d\n", __func__, ret); + goto err_media_cleanup; + } + + ox05b->handler.lock = &ox05b->lock; + + /* Add new controls */ + ox05b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ox05b_link_freq_menu) - 1, 0, + ox05b_link_freq_menu); + if (ox05b->link_freq) + ox05b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ox05b->exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + ox05b->dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + /* Added new control for IR frames. */ + ox05b->ir_exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->ir_again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + + ox05b->ir_dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + ox05b->subdev.ctrl_handler = ctrl_hdr; + if (ox05b->handler.error) { + ret = ox05b->handler.error; + dev_err(ox05b->dev, + "%s: failed to add the ctrls: %d\n", __func__, ret); + goto err_ctrl_free; + } + + /* PM Runtime */ + pm_runtime_enable(ox05b->dev); + pm_runtime_set_suspended(ox05b->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to init subdev: %d\n", __func__, ret); + goto err_pm_disable; + } + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: v4l2 subdev register failed %d\n", __func__, ret); + goto err_subdev_cleanup; + } + + dev_info(ox05b->dev, "ox05b1s probed!\n"); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&ox05b->subdev); + +err_pm_disable: + pm_runtime_disable(ox05b->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + mutex_destroy(&ox05b->lock); + +err_media_cleanup: + media_entity_cleanup(&ox05b->subdev.entity); + + return ret; +} + +static void ox05b_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&ox05b->handler); + v4l2_subdev_cleanup(&ox05b->subdev); + media_entity_cleanup(&sd->entity); + mutex_destroy(&ox05b->lock); + + pm_runtime_disable(ox05b->dev); +} + +static const struct of_device_id ox05b_of_match[] = { + { .compatible = "ovti,ox05b" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, ox05b_of_match); + +static struct i2c_driver ox05b_i2c_driver = { + .driver = { + .name = "ox05b", + .of_match_table = ox05b_of_match, + .pm = &ox05b_pm_ops, + }, + .probe_new = ox05b_probe, + .remove = ox05b_remove, +}; + +module_i2c_driver(ox05b_i2c_driver); + +MODULE_AUTHOR("Abhishek Sharma <abhishek.sharma@ti.com>"); +MODULE_DESCRIPTION("OX05B1S RGB-IR Image Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c index 34491939ce0b..ed60d82041a6 100644 --- a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c +++ b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c @@ -1674,6 +1674,12 @@ static int e5010_resume(struct device *dev) if (ret < 0) return ret; + ret = e5010_init_device(e5010_dev); + if (ret) { + dev_err(dev, "Failed to re-enable e5010 device\n"); + return ret; + } + v4l2_m2m_resume(e5010_dev->m2m_dev); return ret; } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index e22921e7ea61..33c786eb1d90 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -793,6 +793,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB"; + case V4L2_CID_IR_EXPOSURE: return "Exposure, IR"; /* * Codec controls @@ -1111,6 +1112,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; + case V4L2_CID_IR_ANALOGUE_GAIN: return "Analogue Gain, IR"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1120,6 +1122,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN: return "Test Pattern"; case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; case V4L2_CID_DIGITAL_GAIN: return "Digital Gain"; + case V4L2_CID_IR_DIGITAL_GAIN: return "Digital Gain, IR"; /* DV controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 6267753bf2b0..5adf607b2a90 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1697,6 +1697,82 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return info; } +/* + * On Octal DTR capable flashes like Micron Xcella reads cannot start or + * end at an odd address in Octal DTR mode. Extra bytes need to be read + * at the start or end to make sure both the start address and length + * remain even. + */ +static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + u_char *tmp_buf; + size_t tmp_len; + loff_t start, end; + int ret, bytes_read; + + if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2)) + return spi_nor_read_data(nor, from, len, buf); + else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE) + return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE), + buf); + + tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + start = round_down(from, 2); + end = round_up(from + len, 2); + + /* + * Avoid allocating too much memory. The requested read length might be + * quite large. Allocating a buffer just as large (slightly bigger, in + * fact) would put unnecessary memory pressure on the system. + * + * For example if the read is from 3 to 1M, then this will read from 2 + * to 4098. The reads from 4098 to 1M will then not need a temporary + * buffer so they can proceed as normal. + */ + tmp_len = min_t(size_t, end - start, PAGE_SIZE); + + ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are read than actually requested, but that number can't be + * reported to the calling function or it will confuse its calculations. + * Calculate how many of the _requested_ bytes were read. + */ + bytes_read = ret; + + if (from != start) + ret -= from - start; + + /* + * Only account for extra bytes at the end if they were actually read. + * For example, if the total length was truncated because of temporary + * buffer size limit then the adjustment for the extra bytes at the end + * is not needed. + */ + if (start + bytes_read == end) + ret -= end - (from + len); + + if (ret < 0) { + ret = -EIO; + goto out; + } + + memcpy(buf, tmp_buf + (from - start), ret); +out: + kfree(tmp_buf); + return ret; +} + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -1714,7 +1790,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, addr = spi_nor_convert_addr(nor, addr); - ret = spi_nor_read_data(nor, addr, len, buf); + if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_read(nor, addr, len, buf); + else + ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1737,6 +1816,71 @@ read_err: } /* + * On Octal DTR capable flashes like Micron Xcella the writes cannot start or + * end at an odd address in Octal DTR mode. Extra 0xff bytes need to be appended + * or prepended to make sure the start address and end address are even. 0xff is + * used because on NOR flashes a program operation can only flip bits from 1 to + * 0, not the other way round. 0 to 1 flip needs to happen via erases. + */ +static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len, + const u8 *buf) +{ + u8 *tmp_buf; + size_t bytes_written; + loff_t start, end; + int ret; + + if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2)) + return spi_nor_write_data(nor, to, len, buf); + + tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + memset(tmp_buf, 0xff, nor->params->page_size); + + start = round_down(to, 2); + end = round_up(to + len, 2); + + memcpy(tmp_buf + (to - start), buf, len); + + ret = spi_nor_write_data(nor, start, end - start, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are written than actually requested, but that number can't + * be reported to the calling function or it will confuse its + * calculations. Calculate how many of the _requested_ bytes were + * written. + */ + bytes_written = ret; + + if (to != start) + ret -= to - start; + + /* + * Only account for extra bytes at the end if they were actually + * written. For example, if for some reason the controller could only + * complete a partial write then the adjustment for the extra bytes at + * the end is not needed. + */ + if (start + bytes_written == end) + ret -= end - (to + len); + + if (ret < 0) + ret = -EIO; + +out: + kfree(tmp_buf); + return ret; +} + +/* * Write an address range to the nor chip. Data must be written in * FLASH_PAGESIZE chunks. The address range may be any size provided * it is within the physical boundaries. @@ -1780,7 +1924,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, if (ret) goto write_err; - ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + if (nor->write_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_write(nor, addr, page_remain, + buf + i); + else + ret = spi_nor_write_data(nor, addr, page_remain, + buf + i); if (ret < 0) goto write_err; written = ret; diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index cf76bade4ace..684c6e120e1c 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -92,10 +92,14 @@ #define AM65_CPSW_PORT_REG_PRI_CTL_RX_PTYPE_RROBIN BIT(8) /* AM65_CPSW_PN_TS_CTL register fields */ +#define AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN BIT(0) +#define AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN BIT(1) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN BIT(3) #define AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN BIT(4) #define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN BIT(5) #define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT2_EN BIT(6) #define AM65_CPSW_PN_TS_CTL_TX_ANX_D_EN BIT(7) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN BIT(9) #define AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN BIT(10) #define AM65_CPSW_PN_TS_CTL_TX_HOST_TS_EN BIT(11) #define AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT 16 @@ -123,6 +127,11 @@ AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN | \ AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN) +#define AM65_CPSW_TS_RX_ANX_ALL_EN \ + (AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN) + #define AM65_CPSW_ALE_AGEOUT_DEFAULT 30 /* Number of TX/RX descriptors */ #define AM65_CPSW_MAX_TX_DESC 500 @@ -677,18 +686,6 @@ static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) dev_kfree_skb_any(skb); } -static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata) -{ - struct skb_shared_hwtstamps *ssh; - u64 ns; - - ns = ((u64)psdata[1] << 32) | psdata[0]; - - ssh = skb_hwtstamps(skb); - memset(ssh, 0, sizeof(*ssh)); - ssh->hwtstamp = ns_to_ktime(ns); -} - /* RX psdata[2] word format - checksum information */ #define AM65_CPSW_RX_PSD_CSUM_ADD GENMASK(15, 0) #define AM65_CPSW_RX_PSD_CSUM_ERR BIT(16) @@ -769,9 +766,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, skb->dev = ndev; psdata = cppi5_hdesc_get_psdata(desc_rx); - /* add RX timestamp */ - if (port->rx_ts_enabled) - am65_cpsw_nuss_rx_ts(skb, psdata); csum_info = psdata[2]; dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info); @@ -784,6 +778,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, ndev_priv = netdev_priv(ndev); am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark); skb_put(skb, pkt_len); + if (port->rx_ts_enabled) + am65_cpts_rx_timestamp(common->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); am65_cpsw_nuss_rx_csum(skb, csum_info); napi_gro_receive(&common->napi_rx, skb); @@ -1312,7 +1308,6 @@ static int am65_cpsw_nuss_ndo_slave_set_mac_address(struct net_device *ndev, static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) { - struct am65_cpsw_common *common = am65_ndev_to_common(ndev); struct am65_cpsw_port *port = am65_ndev_to_port(ndev); u32 ts_ctrl, seq_id, ts_ctrl_ltype2, ts_vlan_ltype; struct hwtstamp_config cfg; @@ -1336,11 +1331,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, case HWTSTAMP_FILTER_NONE: port->rx_ts_enabled = false; break; - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_SOME: - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: @@ -1350,10 +1340,13 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: port->rx_ts_enabled = true; - cfg.rx_filter = HWTSTAMP_FILTER_ALL; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: + return -EOPNOTSUPP; default: return -ERANGE; } @@ -1383,6 +1376,10 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN | AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN; + if (port->rx_ts_enabled) + ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN | + AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN; + writel(seq_id, port->port_base + AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG); writel(ts_vlan_ltype, port->port_base + AM65_CPSW_PORTN_REG_TS_VLAN_LTYPE_REG); @@ -1390,9 +1387,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, AM65_CPSW_PORTN_REG_TS_CTL_LTYPE2); writel(ts_ctrl, port->port_base + AM65_CPSW_PORTN_REG_TS_CTL); - /* en/dis RX timestamp */ - am65_cpts_rx_enable(common->cpts, port->rx_ts_enabled); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } @@ -1409,7 +1403,7 @@ static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev, cfg.tx_type = port->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; cfg.rx_filter = port->rx_ts_enabled ? - HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE; return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c index c66618d91c28..29e0b9ff23bf 100644 --- a/drivers/net/ethernet/ti/am65-cpts.c +++ b/drivers/net/ethernet/ti/am65-cpts.c @@ -859,29 +859,6 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp) return delay; } -/** - * am65_cpts_rx_enable - enable rx timestamping - * @cpts: cpts handle - * @en: enable - * - * This functions enables rx packets timestamping. The CPTS can timestamp all - * rx packets. - */ -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) -{ - u32 val; - - mutex_lock(&cpts->ptp_clk_lock); - val = am65_cpts_read32(cpts, control); - if (en) - val |= AM65_CPTS_CONTROL_TSTAMP_EN; - else - val &= ~AM65_CPTS_CONTROL_TSTAMP_EN; - am65_cpts_write32(cpts, val, control); - mutex_unlock(&cpts->ptp_clk_lock); -} -EXPORT_SYMBOL_GPL(am65_cpts_rx_enable); - static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid) { unsigned int ptp_class = ptp_classify_raw(skb); @@ -906,6 +883,68 @@ static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid) return 1; } +static u64 am65_cpts_get_rx_ts(struct am65_cpts *cpts, struct sk_buff *skb, + u32 skb_mtype_seqid) +{ + struct list_head *this, *next; + struct am65_cpts_event *event; + unsigned long flags; + u32 mtype_seqid; + u64 ns = 0; + + am65_cpts_fifo_read(cpts); + spin_lock_irqsave(&cpts->lock, flags); + list_for_each_safe(this, next, &cpts->events) { + event = list_entry(this, struct am65_cpts_event, list); + if (time_after(jiffies, event->tmo)) { + list_del_init(&event->list); + list_add(&event->list, &cpts->pool); + continue; + } + + mtype_seqid = event->event1 & + (AM65_CPTS_EVENT_1_MESSAGE_TYPE_MASK | + AM65_CPTS_EVENT_1_SEQUENCE_ID_MASK | + AM65_CPTS_EVENT_1_EVENT_TYPE_MASK); + + if (mtype_seqid == skb_mtype_seqid) { + ns = event->timestamp; + list_del_init(&event->list); + list_add(&event->list, &cpts->pool); + break; + } + } + spin_unlock_irqrestore(&cpts->lock, flags); + + return ns; +} + +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) +{ + struct am65_cpts_skb_cb_data *skb_cb = (struct am65_cpts_skb_cb_data *)skb->cb; + struct skb_shared_hwtstamps *ssh; + int ret; + u64 ns; + + skb_reset_mac_header(skb); + ret = am65_skb_get_mtype_seqid(skb, &skb_cb->skb_mtype_seqid); + if (!ret) + return; /* if not PTP class packet */ + + skb_cb->skb_mtype_seqid |= (AM65_CPTS_EV_RX << AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT); + + dev_dbg(cpts->dev, "%s mtype seqid %08x\n", __func__, skb_cb->skb_mtype_seqid); + + ns = am65_cpts_get_rx_ts(cpts, skb, skb_cb->skb_mtype_seqid); + if (!ns) + return; + + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); + ssh->hwtstamp = ns_to_ktime(ns); +} +EXPORT_SYMBOL_GPL(am65_cpts_rx_timestamp); + /** * am65_cpts_tx_timestamp - save tx packet for timestamping * @cpts: cpts handle diff --git a/drivers/net/ethernet/ti/am65-cpts.h b/drivers/net/ethernet/ti/am65-cpts.h index 6e14df0be113..6099d772799d 100644 --- a/drivers/net/ethernet/ti/am65-cpts.h +++ b/drivers/net/ethernet/ti/am65-cpts.h @@ -22,9 +22,9 @@ void am65_cpts_release(struct am65_cpts *cpts); struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs, struct device_node *node); int am65_cpts_phc_index(struct am65_cpts *cpts); +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en); u64 am65_cpts_ns_gettime(struct am65_cpts *cpts); int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx, struct am65_cpts_estf_cfg *cfg); @@ -48,17 +48,18 @@ static inline int am65_cpts_phc_index(struct am65_cpts *cpts) return -1; } -static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, +static inline void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) { } -static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, - struct sk_buff *skb) +static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } -static inline void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) +static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } diff --git a/drivers/net/ethernet/ti/icss_iep.c b/drivers/net/ethernet/ti/icss_iep.c index 49652b1d005f..f8faba257a25 100644 --- a/drivers/net/ethernet/ti/icss_iep.c +++ b/drivers/net/ethernet/ti/icss_iep.c @@ -54,78 +54,6 @@ #define IEP_CAP_CFG_CAPNF_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n) + 1) #define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10) -enum { - ICSS_IEP_GLOBAL_CFG_REG, - ICSS_IEP_GLOBAL_STATUS_REG, - ICSS_IEP_COMPEN_REG, - ICSS_IEP_SLOW_COMPEN_REG, - ICSS_IEP_COUNT_REG0, - ICSS_IEP_COUNT_REG1, - ICSS_IEP_CAPTURE_CFG_REG, - ICSS_IEP_CAPTURE_STAT_REG, - - ICSS_IEP_CAP6_RISE_REG0, - ICSS_IEP_CAP6_RISE_REG1, - - ICSS_IEP_CAP7_RISE_REG0, - ICSS_IEP_CAP7_RISE_REG1, - - ICSS_IEP_CMP_CFG_REG, - ICSS_IEP_CMP_STAT_REG, - ICSS_IEP_CMP0_REG0, - ICSS_IEP_CMP0_REG1, - ICSS_IEP_CMP1_REG0, - ICSS_IEP_CMP1_REG1, - - ICSS_IEP_CMP8_REG0, - ICSS_IEP_CMP8_REG1, - ICSS_IEP_SYNC_CTRL_REG, - ICSS_IEP_SYNC0_STAT_REG, - ICSS_IEP_SYNC1_STAT_REG, - ICSS_IEP_SYNC_PWIDTH_REG, - ICSS_IEP_SYNC0_PERIOD_REG, - ICSS_IEP_SYNC1_DELAY_REG, - ICSS_IEP_SYNC_START_REG, - ICSS_IEP_MAX_REGS, -}; - -/** - * struct icss_iep_plat_data - Plat data to handle SoC variants - * @config: Regmap configuration data - * @reg_offs: register offsets to capture offset differences across SoCs - * @flags: Flags to represent IEP properties - */ -struct icss_iep_plat_data { - struct regmap_config *config; - u32 reg_offs[ICSS_IEP_MAX_REGS]; - u32 flags; -}; - -struct icss_iep { - struct device *dev; - void __iomem *base; - const struct icss_iep_plat_data *plat_data; - struct regmap *map; - struct device_node *client_np; - unsigned long refclk_freq; - int clk_tick_time; /* one refclk tick time in ns */ - struct ptp_clock_info ptp_info; - struct ptp_clock *ptp_clock; - struct mutex ptp_clk_mutex; /* PHC access serializer */ - spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ - u32 def_inc; - s16 slow_cmp_inc; - u32 slow_cmp_count; - const struct icss_iep_clockops *ops; - void *clockops_data; - u32 cycle_time_ns; - u32 perout_enabled; - bool pps_enabled; - int cap_cmp_irq; - u64 period; - u32 latch_enable; -}; - static u32 icss_iep_readl(struct icss_iep *iep, int reg) { return readl(iep->base + iep->plat_data->reg_offs[reg]); diff --git a/drivers/net/ethernet/ti/icss_iep.h b/drivers/net/ethernet/ti/icss_iep.h index 7aae5ede47c0..7df995bcbbb2 100644 --- a/drivers/net/ethernet/ti/icss_iep.h +++ b/drivers/net/ethernet/ti/icss_iep.h @@ -12,7 +12,77 @@ #include <linux/ptp_clock_kernel.h> #include <linux/regmap.h> -struct icss_iep; +enum { + ICSS_IEP_GLOBAL_CFG_REG, + ICSS_IEP_GLOBAL_STATUS_REG, + ICSS_IEP_COMPEN_REG, + ICSS_IEP_SLOW_COMPEN_REG, + ICSS_IEP_COUNT_REG0, + ICSS_IEP_COUNT_REG1, + ICSS_IEP_CAPTURE_CFG_REG, + ICSS_IEP_CAPTURE_STAT_REG, + + ICSS_IEP_CAP6_RISE_REG0, + ICSS_IEP_CAP6_RISE_REG1, + + ICSS_IEP_CAP7_RISE_REG0, + ICSS_IEP_CAP7_RISE_REG1, + + ICSS_IEP_CMP_CFG_REG, + ICSS_IEP_CMP_STAT_REG, + ICSS_IEP_CMP0_REG0, + ICSS_IEP_CMP0_REG1, + ICSS_IEP_CMP1_REG0, + ICSS_IEP_CMP1_REG1, + + ICSS_IEP_CMP8_REG0, + ICSS_IEP_CMP8_REG1, + ICSS_IEP_SYNC_CTRL_REG, + ICSS_IEP_SYNC0_STAT_REG, + ICSS_IEP_SYNC1_STAT_REG, + ICSS_IEP_SYNC_PWIDTH_REG, + ICSS_IEP_SYNC0_PERIOD_REG, + ICSS_IEP_SYNC1_DELAY_REG, + ICSS_IEP_SYNC_START_REG, + ICSS_IEP_MAX_REGS, +}; + +/** + * struct icss_iep_plat_data - Plat data to handle SoC variants + * @config: Regmap configuration data + * @reg_offs: register offsets to capture offset differences across SoCs + * @flags: Flags to represent IEP properties + */ +struct icss_iep_plat_data { + struct regmap_config *config; + u32 reg_offs[ICSS_IEP_MAX_REGS]; + u32 flags; +}; + +struct icss_iep { + struct device *dev; + void __iomem *base; + const struct icss_iep_plat_data *plat_data; + struct regmap *map; + struct device_node *client_np; + unsigned long refclk_freq; + int clk_tick_time; /* one refclk tick time in ns */ + struct ptp_clock_info ptp_info; + struct ptp_clock *ptp_clock; + struct mutex ptp_clk_mutex; /* PHC access serializer */ + spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ + u32 def_inc; + s16 slow_cmp_inc; + u32 slow_cmp_count; + const struct icss_iep_clockops *ops; + void *clockops_data; + u32 cycle_time_ns; + u32 perout_enabled; + bool pps_enabled; + int cap_cmp_irq; + u64 period; + u32 latch_enable; +}; /* Firmware specific clock operations */ struct icss_iep_clockops { diff --git a/drivers/net/ethernet/ti/icssg_config.c b/drivers/net/ethernet/ti/icssg_config.c index aea2ae8a3ae9..88dc611f0fc6 100644 --- a/drivers/net/ethernet/ti/icssg_config.c +++ b/drivers/net/ethernet/ti/icssg_config.c @@ -551,7 +551,9 @@ static const struct icssg_r30_cmd emac_r32_bitmask[] = { {{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/ {{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/ {{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/ - {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/ + {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}}, /* VLAN UNWARE*/ + {{0xffff2000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* HSR_RX_OFFLOAD_ENABLE */ + {{0xdfff0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}} /* HSR_RX_OFFLOAD_DISABLE */ }; int emac_set_port_state(struct prueth_emac *emac, @@ -769,7 +771,10 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, { struct prueth *prueth = emac->prueth; struct prueth_vlan_tbl *tbl = prueth->vlan_tbl; - u8 fid_c1 = tbl[vid].fid_c1; + u8 fid_c1; + + spin_lock(&prueth->vtbl_lock); + fid_c1 = tbl[vid].fid_c1; /* FID_C1: bit0..2 port membership mask, * bit3..5 tagging mask for each port @@ -784,6 +789,7 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, } tbl[vid].fid_c1 = fid_c1; + spin_unlock(&prueth->vtbl_lock); } u16 icssg_get_pvid(struct prueth_emac *emac) @@ -846,15 +852,18 @@ int emac_fdb_erase_all(struct prueth_emac *emac) int emac_fdb_flush_multicast(struct prueth_emac *emac) { struct prueth *prueth = emac->prueth; + u8 port_mask = BIT(emac->port_id); int ret = 0; int i; ret = emac_fdb_erase_all(emac); + spin_lock(&prueth->vtbl_lock); for (i = 0; i < SZ_4K - 1; i++) { prueth->vlan_tbl[i].fid = i; - prueth->vlan_tbl[i].fid_c1 = 0; + prueth->vlan_tbl[i].fid_c1 &= ~(port_mask | port_mask << 3); } + spin_unlock(&prueth->vtbl_lock); return ret; } diff --git a/drivers/net/ethernet/ti/icssg_config.h b/drivers/net/ethernet/ti/icssg_config.h index ff61c66cec60..1f318884fa1b 100644 --- a/drivers/net/ethernet/ti/icssg_config.h +++ b/drivers/net/ethernet/ti/icssg_config.h @@ -81,6 +81,8 @@ enum icssg_port_state_cmd { ICSSG_EMAC_PORT_PREMPT_TX_DISABLE, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE, ICSSG_EMAC_PORT_VLAN_AWARE_DISABLE, + ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE, + ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE, ICSSG_EMAC_PORT_MAX_COMMANDS }; diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c index 6ad92f40c71c..f3d033723857 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg_prueth.c @@ -67,7 +67,9 @@ #define DEFAULT_UNTAG_MASK 1 #define NETIF_PRUETH_HSR_OFFLOAD (NETIF_F_HW_HSR_FWD | \ - NETIF_F_HW_HSR_DUP) + NETIF_F_HW_HSR_DUP | \ + NETIF_F_HW_HSR_TAG_INS | \ + NETIF_F_HW_HSR_TAG_RM) /* CTRLMMR_ICSSG_RGMII_CTRL register bits */ #define ICSSG_CTRL_RGMII_ID_MODE BIT(24) @@ -75,6 +77,7 @@ #define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ #define PRUETH_UNDIRECTED_PKT_DST_TAG 0 +#define PRUETH_UNDIRECTED_PKT_TAG_INS BIT(30) static void prueth_cleanup_rx_chns(struct prueth_emac *emac, struct prueth_rx_chn *rx_chn, @@ -875,6 +878,9 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_DUP)) dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); @@ -1486,7 +1492,8 @@ static void prueth_iep_settime(void *clockops_data, u64 ns) sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0); sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32; sc_desc.iepcount_set = ns % cycletime; - sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4 + /* Count from 0 to (cycle time)- emac->iep->def_inc */ + sc_desc.CMP0_current = cycletime - emac->iep->def_inc; memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc)); @@ -1677,6 +1684,13 @@ static int emac_ndo_open(struct net_device *ndev) } } + if (prueth->is_hsr_offload_mode) { + if (ndev->features & NETIF_F_HW_HSR_TAG_RM) + emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE); + else + emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE); + } + flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET; writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow); ret = emac_fdb_flow_id_updated(emac); @@ -2688,16 +2702,20 @@ static int prueth_netdevice_event(struct notifier_block *unused, if ((ndev->features & NETIF_PRUETH_HSR_OFFLOAD) && is_hsr_master(info->upper_dev)) { - if (!prueth->hsr_dev) { - prueth->hsr_dev = info->upper_dev; - - icssg_class_set_host_mac_addr(prueth->miig_rt, - prueth->hsr_dev->dev_addr); - } else { - if (prueth->hsr_dev != info->upper_dev) { - dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n"); - return -EOPNOTSUPP; + if (info->linking) { + if (!prueth->hsr_dev) { + prueth->hsr_dev = info->upper_dev; + + icssg_class_set_host_mac_addr(prueth->miig_rt, + prueth->hsr_dev->dev_addr); + } else { + if (prueth->hsr_dev != info->upper_dev) { + dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n"); + return -EOPNOTSUPP; + } } + } else { + prueth->hsr_dev = NULL; } } @@ -3280,6 +3298,7 @@ static int prueth_probe(struct platform_device *pdev) icss_iep_init_fw(prueth->iep1); } + spin_lock_init(&prueth->vtbl_lock); /* setup netdev interfaces */ if (eth0_node) { ret = prueth_netdev_init(prueth, eth0_node); diff --git a/drivers/net/ethernet/ti/icssg_prueth.h b/drivers/net/ethernet/ti/icssg_prueth.h index 03ec5b8438c2..0534c3b256ea 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.h +++ b/drivers/net/ethernet/ti/icssg_prueth.h @@ -330,6 +330,7 @@ struct prueth { unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; int default_vlan; struct devlink *devlink; + spinlock_t vtbl_lock; /* Lock for vtbl in shared memory */ }; struct emac_tx_ts_response { diff --git a/drivers/net/ethernet/ti/icssg_qos.c b/drivers/net/ethernet/ti/icssg_qos.c index 67551e3ffa86..811205f916c7 100644 --- a/drivers/net/ethernet/ti/icssg_qos.c +++ b/drivers/net/ethernet/ti/icssg_qos.c @@ -142,7 +142,8 @@ static int tas_set_trigger_list_change(struct prueth_emac *emac) u64 base_time; u64 cur_time; - cycle_time = admin_list->cycle_time - 4; /* -4ns to compensate for IEP wraparound time */ + /* subtract emac->iep->def_inc ns to compensate for IEP wrap around time */ + cycle_time = admin_list->cycle_time - emac->iep->def_inc; base_time = admin_list->base_time; cur_time = prueth_iep_gettime(emac, &sts); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 77c3c017b0d6..b3f5a4e3577d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -29,6 +29,7 @@ #include <linux/sched.h> #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> +#include <linux/sys_soc.h> #include <linux/timer.h> #define CQSPI_NAME "cadence-qspi" @@ -617,7 +618,7 @@ static int cqspi_phy_calibrate(struct cqspi_flash_pdata *f_pdata, rxhigh.tx = rxlow.tx; rxhigh.read_delay = rxlow.read_delay; - cqspi_find_rx_high(f_pdata, mem, &rxhigh); + ret = cqspi_find_rx_high(f_pdata, mem, &rxhigh); if (ret) goto out; dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", rxhigh.rx, rxhigh.tx, @@ -1275,6 +1276,7 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } @@ -1314,6 +1316,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTRD_START_MASK, reg_base + CQSPI_REG_INDIRECTRD); + readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { if (!wait_for_completion_timeout(&cqspi->transfer_complete, @@ -1569,6 +1572,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } @@ -1594,6 +1598,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTWR_START_MASK, reg_base + CQSPI_REG_INDIRECTWR); + readl(reg_base + CQSPI_REG_INDIRECTWR); /* Flush posted write. */ + /* * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access * Controller programming sequence, couple of cycles of @@ -2006,6 +2012,46 @@ err_unmap: return ret; } +static void cqspi_memcpy_fromio(const struct spi_mem_op *op, void *to, + const void __iomem *from, size_t count) +{ + if (op->data.buswidth == 8 && op->data.dtr) { + /* + * 8D-8D-8D ops with odd length should be rejected by + * supports_op() so no need to worry about that. + */ + while (count && !IS_ALIGNED((unsigned long)from, 4)) { + *(u16 *)to = __raw_readw(from); + from += 2; + to += 2; + count -= 2; + } + + /* + * The controller can work with both 32-bit and 64-bit + * platforms. 32-bit platforms won't have a readq. So use a + * readl instead. + */ + while (count >= 4) { + *(u32 *)to = __raw_readl(from); + from += 4; + to += 4; + count -= 4; + } + + while (count) { + *(u16 *)to = __raw_readw(from); + from += 2; + to += 2; + count -= 2; + } + + return; + } + + memcpy_fromio(to, from, count); +} + static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, const struct spi_mem_op *op) { @@ -2017,8 +2063,8 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, u_char *buf = op->data.buf.in; int ret; - if (!cqspi->rx_chan || !virt_addr_valid(buf)) { - memcpy_fromio(buf, cqspi->ahb_base + from, len); + if (!cqspi->rx_chan || !virt_addr_valid(buf) || len <= 16) { + cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len); return 0; } @@ -2412,6 +2458,11 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) return 0; } +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM64X", .revision = "SR1.0" }, + { /* sentinel */ } +}; + static int cqspi_probe(struct platform_device *pdev) { const struct cqspi_driver_platdata *ddata; @@ -2566,7 +2617,7 @@ static int cqspi_probe(struct platform_device *pdev) goto probe_setup_failed; } - if (cqspi->use_direct_mode) { + if (cqspi->use_direct_mode && !soc_device_match(k3_soc_devices)) { ret = cqspi_request_mmap_dma(cqspi); if (ret == -EPROBE_DEFER) goto probe_setup_failed; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index d4a4e3cab3c2..1164694b12c1 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -148,8 +148,10 @@ enum v4l2_colorfx { #define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42) #define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43) +#define V4L2_CID_IR_EXPOSURE (V4L2_CID_BASE+44) + /* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45) /* USER-class private control IDs */ @@ -1143,6 +1145,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) #define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) +#define V4L2_CID_IR_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 10) /* Image processing controls */ @@ -1155,6 +1158,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #define V4L2_CID_DEINTERLACING_MODE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 4) #define V4L2_CID_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 5) +#define V4L2_CID_IR_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 6) /* DV-class control IDs defined by V4L2 */ #define V4L2_CID_DV_CLASS_BASE (V4L2_CTRL_CLASS_DV | 0x900) diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index fa81035321ae..1b6457f357bd 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -157,7 +157,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, fail_rx_handler: netdev_upper_dev_unlink(dev, hsr_dev); fail_upper_dev_link: - if (port->hsr->fwd_offloaded) + if (!port->hsr->fwd_offloaded) dev_set_promiscuity(dev, -1); return res; @@ -220,7 +220,8 @@ void hsr_del_port(struct hsr_port *port) netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); netdev_rx_handler_unregister(port->dev); - dev_set_promiscuity(port->dev, -1); + if (!port->hsr->fwd_offloaded) + dev_set_promiscuity(port->dev, -1); netdev_upper_dev_unlink(port->dev, master->dev); } |