From 7f67a45ee7c008c3d8e45fde6fa9c4287fb3bc9e Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Date: Thu, 20 Jul 2023 13:18:34 +0200
Subject: [PATCH] overlays: Add overlay for the OV64A40 Arducam Camera Module

Arducam have integrated an Omnivision OV64A40 with a ROHM BU64754 VCM
with a Raspberry Pi compatible cable pinout.

Provide an overlay to support the module.

Also add support to the camera mux overlays.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 arch/arm/boot/dts/overlays/Makefile           |  1 +
 arch/arm/boot/dts/overlays/README             | 25 +++++
 .../dts/overlays/camera-mux-2port-overlay.dts | 32 +++++++
 .../dts/overlays/camera-mux-4port-overlay.dts | 64 +++++++++++++
 .../arm/boot/dts/overlays/ov64a40-overlay.dts | 91 +++++++++++++++++++
 arch/arm/boot/dts/overlays/ov64a40.dtsi       | 34 +++++++
 6 files changed, 247 insertions(+)
 create mode 100644 arch/arm/boot/dts/overlays/ov64a40-overlay.dts
 create mode 100644 arch/arm/boot/dts/overlays/ov64a40.dtsi

--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -175,6 +175,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
 	mz61581.dtbo \
 	ov2311.dtbo \
 	ov5647.dtbo \
+	ov64a40.dtbo \
 	ov7251.dtbo \
 	ov9281.dtbo \
 	papirus.dtbo \
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -817,6 +817,7 @@ Params: cam0-arducam-64mp       Select A
         cam0-imx708             Select IMX708 for camera on port 0
         cam0-ov2311             Select OV2311 for camera on port 0
         cam0-ov5647             Select OV5647 for camera on port 0
+        cam0-ov64a40            Select OV64A40 for camera on port 0
         cam0-ov7251             Select OV7251 for camera on port 0
         cam0-ov9281             Select OV9281 for camera on port 0
         cam0-imx290-clk-freq    Set clock frequency for an IMX290 on port 0
@@ -829,6 +830,7 @@ Params: cam0-arducam-64mp       Select A
         cam1-imx708             Select IMX708 for camera on port 1
         cam1-ov2311             Select OV2311 for camera on port 1
         cam1-ov5647             Select OV5647 for camera on port 1
+        cam1-ov64a40            Select OV64A40 for camera on port 1
         cam1-ov7251             Select OV7251 for camera on port 1
         cam1-ov9281             Select OV9281 for camera on port 1
         cam1-imx290-clk-freq    Set clock frequency for an IMX290 on port 1
@@ -850,6 +852,7 @@ Params: cam0-arducam-64mp       Select A
         cam0-imx708             Select IMX708 for camera on port 0
         cam0-ov2311             Select OV2311 for camera on port 0
         cam0-ov5647             Select OV5647 for camera on port 0
+        cam0-ov64a40            Select OV64A40 for camera on port 0
         cam0-ov7251             Select OV7251 for camera on port 0
         cam0-ov9281             Select OV9281 for camera on port 0
         cam0-imx290-clk-freq    Set clock frequency for an IMX290 on port 0
@@ -862,6 +865,7 @@ Params: cam0-arducam-64mp       Select A
         cam1-imx708             Select IMX708 for camera on port 1
         cam1-ov2311             Select OV2311 for camera on port 1
         cam1-ov5647             Select OV5647 for camera on port 1
+        cam1-ov64a40            Select OV64A40 for camera on port 1
         cam1-ov7251             Select OV7251 for camera on port 1
         cam1-ov9281             Select OV9281 for camera on port 1
         cam1-imx290-clk-freq    Set clock frequency for an IMX290 on port 1
@@ -874,6 +878,7 @@ Params: cam0-arducam-64mp       Select A
         cam2-imx708             Select IMX708 for camera on port 2
         cam2-ov2311             Select OV2311 for camera on port 2
         cam2-ov5647             Select OV5647 for camera on port 2
+        cam2-ov64a40            Select OV64A40 for camera on port 2
         cam2-ov7251             Select OV7251 for camera on port 2
         cam2-ov9281             Select OV9281 for camera on port 2
         cam2-imx290-clk-freq    Set clock frequency for an IMX290 on port 2
@@ -886,6 +891,7 @@ Params: cam0-arducam-64mp       Select A
         cam3-imx708             Select IMX708 for camera on port 3
         cam3-ov2311             Select OV2311 for camera on port 3
         cam3-ov5647             Select OV5647 for camera on port 3
+        cam3-ov64a40            Select OV64A40 for camera on port 3
         cam3-ov7251             Select OV7251 for camera on port 3
         cam3-ov9281             Select OV9281 for camera on port 3
         cam3-imx290-clk-freq    Set clock frequency for an IMX290 on port 3
@@ -3222,6 +3228,25 @@ Params: rotation                Mounting
         vcm                     Configure a VCM focus drive on the sensor.
 
 
+Name:   ov64a40
+Info:   Arducam OV64A40 camera module.
+        Uses Unicam 1, which is the standard camera connector on most Pi
+        variants.
+Load:   dtoverlay=ov64a40,<param>=<val>
+Params: rotation                Mounting rotation of the camera sensor (0 or
+                                180, default 0)
+        orientation             Sensor orientation (0 = front, 1 = rear,
+                                2 = external, default external)
+        media-controller        Configure use of Media Controller API for
+                                configuring the sensor (default on)
+        cam0                    Adopt the default configuration for CAM0 on a
+                                Compute Module (CSI0, i2c_vc, and cam0_reg).
+        vcm                     Select lens driver state. Default is enabled,
+                                but vcm=off will disable.
+        link-frequency          Allowable link frequency values to use in Hz:
+                                456000000 (default), 360000000
+
+
 Name:   ov7251
 Info:   Omnivision OV7251 camera module.
         Uses Unicam 1, which is the standard camera connector on most Pi
--- a/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts
+++ b/arch/arm/boot/dts/overlays/camera-mux-2port-overlay.dts
@@ -189,6 +189,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_0
+					#define cam_endpoint ov64a40_0_ep
+					#define vcm_node ov64a40_0_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 
 				i2c@1 {
@@ -289,6 +299,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_1
+					#define cam_endpoint ov64a40_1_ep
+					#define vcm_node ov64a40_1_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 			};
 		};
@@ -450,6 +470,12 @@
 		cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>,
 			      <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>,
 			      <&ov2311_0>, "status=okay";
+		cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>,
+			      <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>,
+			      <&mux_in0>, "clock-noncontinuous?",
+			      <&ov64a40_0>, "status=okay",
+			      <&ov64a40_0_vcm>, "status=okay",
+			      <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>;
 
 		cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>,
 				    <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>,
@@ -496,6 +522,12 @@
 		cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>,
 			      <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>,
 			      <&ov2311_1>, "status=okay";
+		cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>,
+			      <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>,
+			      <&mux_in1>, "clock-noncontinuous?",
+			      <&ov64a40_1>, "status=okay",
+			      <&ov64a40_1_vcm>, "status=okay",
+			      <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>;
 
 		cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0",
 				       <&imx290_0>,"clock-frequency:0";
--- a/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts
+++ b/arch/arm/boot/dts/overlays/camera-mux-4port-overlay.dts
@@ -247,6 +247,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_0
+					#define cam_endpoint ov64a40_0_ep
+					#define vcm_node ov64a40_0_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 
 				i2c@1 {
@@ -347,6 +357,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_1
+					#define cam_endpoint ov64a40_1_ep
+					#define vcm_node ov64a40_1_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 
 				i2c@2 {
@@ -447,6 +467,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_2
+					#define cam_endpoint ov64a40_2_ep
+					#define vcm_node ov64a40_2_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 
 				i2c@3 {
@@ -547,6 +577,16 @@
 					#undef cam_node
 					#undef cam_endpoint
 					#undef cam1_clk
+
+					#define cam_node ov64a40_3
+					#define cam_endpoint ov64a40_3_ep
+					#define vcm_node ov64a40_3_vcm
+					#define cam1_clk clk_24mhz
+					#include "ov64a40.dtsi"
+					#undef cam_node
+					#undef cam_endpoint
+					#undef vcm_node
+					#undef cam1_clk
 				};
 			};
 		};
@@ -725,6 +765,12 @@
 		cam0-ov2311 = <&mux_in0>, "remote-endpoint:0=",<&ov2311_0_ep>,
 			      <&ov2311_0_ep>, "remote-endpoint:0=",<&mux_in0>,
 			      <&ov2311_0>, "status=okay";
+		cam0-ov64a40 = <&mux_in0>, "remote-endpoint:0=",<&ov64a40_0_ep>,
+			      <&ov64a40_0_ep>, "remote-endpoint:0=",<&mux_in0>,
+			      <&mux_in0>, "clock-noncontinuous?",
+			      <&ov64a40_0>, "status=okay",
+			      <&ov64a40_0_vcm>, "status=okay",
+			      <&ov64a40_0>,"lens-focus:0=", <&ov64a40_0_vcm>;
 
 		cam1-arducam-64mp = <&mux_in1>, "remote-endpoint:0=",<&arducam_64mp_1_ep>,
 				    <&arducam_64mp_1_ep>, "remote-endpoint:0=",<&mux_in1>,
@@ -771,6 +817,12 @@
 		cam1-ov2311 = <&mux_in1>, "remote-endpoint:0=",<&ov2311_1_ep>,
 			      <&ov2311_1_ep>, "remote-endpoint:0=",<&mux_in1>,
 			      <&ov2311_1>, "status=okay";
+		cam1-ov64a40 = <&mux_in1>, "remote-endpoint:0=",<&ov64a40_1_ep>,
+			      <&ov64a40_1_ep>, "remote-endpoint:0=",<&mux_in1>,
+			      <&mux_in1>, "clock-noncontinuous?",
+			      <&ov64a40_1>, "status=okay",
+			      <&ov64a40_1_vcm>, "status=okay",
+			      <&ov64a40_1>,"lens-focus:0=", <&ov64a40_1_vcm>;
 
 		cam2-arducam-64mp = <&mux_in2>, "remote-endpoint:0=",<&arducam_64mp_2_ep>,
 				    <&arducam_64mp_2_ep>, "remote-endpoint:0=",<&mux_in2>,
@@ -817,6 +869,12 @@
 		cam2-ov2311 = <&mux_in2>, "remote-endpoint:0=",<&ov2311_2_ep>,
 			      <&ov2311_2_ep>, "remote-endpoint:0=",<&mux_in2>,
 			      <&ov2311_2>, "status=okay";
+		cam2-ov64a40 = <&mux_in2>, "remote-endpoint:0=",<&ov64a40_2_ep>,
+			      <&ov64a40_2_ep>, "remote-endpoint:0=",<&mux_in2>,
+			      <&mux_in2>, "clock-noncontinuous?",
+			      <&ov64a40_2>, "status=okay",
+			      <&ov64a40_2_vcm>, "status=okay",
+			      <&ov64a40_2>,"lens-focus:0=", <&ov64a40_2_vcm>;
 
 		cam3-arducam-64mp = <&mux_in3>, "remote-endpoint:0=",<&arducam_64mp_3_ep>,
 				    <&arducam_64mp_3_ep>, "remote-endpoint:0=",<&mux_in3>,
@@ -863,6 +921,12 @@
 		cam3-ov2311 = <&mux_in3>, "remote-endpoint:0=",<&ov2311_3_ep>,
 			      <&ov2311_3_ep>, "remote-endpoint:0=",<&mux_in3>,
 			      <&ov2311_3>, "status=okay";
+		cam3-ov64a40 = <&mux_in3>, "remote-endpoint:0=",<&ov64a40_3_ep>,
+			      <&ov64a40_3_ep>, "remote-endpoint:0=",<&mux_in3>,
+			      <&mux_in3>, "clock-noncontinuous?",
+			      <&ov64a40_3>, "status=okay",
+			      <&ov64a40_3_vcm>, "status=okay",
+			      <&ov64a40_3>,"lens-focus:0=", <&ov64a40_3_vcm>;
 
 		cam0-imx290-clk-freq = <&clk_imx290>,"clock-frequency:0",
 				       <&imx290_0>,"clock-frequency:0";
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/ov64a40-overlay.dts
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for OV64A40 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+/{
+	compatible = "brcm,bcm2835";
+
+	i2c_frag: fragment@0 {
+		target = <&i2c_csi_dsi>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			#include "ov64a40.dtsi"
+		};
+	};
+
+	csi_frag: fragment@1 {
+		target = <&csi1>;
+		csi: __overlay__ {
+			status = "okay";
+			brcm,media-controller;
+
+			port{
+				csi_ep: endpoint{
+					remote-endpoint = <&cam_endpoint>;
+					clock-lanes = <0>;
+					data-lanes = <1 2>;
+				};
+			};
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c0if>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	clk_frag: fragment@3 {
+		target = <&cam1_clk>;
+		__overlay__ {
+			clock-frequency = <24000000>;
+			status = "okay";
+		};
+	};
+
+	fragment@4 {
+		target = <&i2c0mux>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@5 {
+		target = <&cam_node>;
+		__overlay__ {
+			lens-focus = <&vcm_node>;
+		};
+	};
+
+	__overrides__ {
+		rotation = <&cam_node>,"rotation:0";
+		orientation = <&cam_node>,"orientation:0";
+		media-controller = <&csi>,"brcm,media-controller?";
+		cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+		       <&csi_frag>, "target:0=",<&csi0>,
+		       <&clk_frag>, "target:0=",<&cam0_clk>,
+		       <&cam_node>, "clocks:0=",<&cam0_clk>,
+		       <&cam_node>, "avdd-supply:0=",<&cam0_reg>,
+		       <&vcm_node>, "vdd-supply:0=",<&cam0_reg>;
+		vcm = <&vcm_node>, "status",
+		      <0>, "=5";
+		link-frequency = <&cam_endpoint>,"link-frequencies#0";
+	};
+};
+
+&cam_node {
+	status = "okay";
+};
+
+&cam_endpoint {
+	remote-endpoint = <&csi_ep>;
+};
+
+&vcm_node {
+	status = "okay";
+};
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/ov64a40.dtsi
@@ -0,0 +1,34 @@
+// Fragment that configures an OV64A40
+
+cam_node: ov64a40@36 {
+	compatible = "ovti,ov64a40";
+	reg = <0x36>;
+	status = "disabled";
+
+	clocks = <&cam1_clk>;
+	clock-names = "xclk";
+
+	avdd-supply = <&cam1_reg>;	/* 2.8v */
+	dovdd-supply = <&cam_dummy_reg>;/* 1.8v */
+	dvdd-supply = <&cam_dummy_reg>;	/* 1.1v */
+
+	rotation = <180>;
+	orientation = <2>;
+
+	port {
+		cam_endpoint: endpoint {
+			bus-type = <4>;
+			clock-lanes = <0>;
+			data-lanes = <1 2>;
+			link-frequencies =
+				/bits/ 64 <456000000>;
+		};
+	};
+};
+
+vcm_node: bu64754@76 {
+	compatible = "rohm,bu64754";
+	reg = <0x76>;
+	status = "disabled";
+	vdd-supply = <&cam1_reg>;
+};
