Date   

[PATCH 4.19.y-cip 26/40] arm64: dts: renesas: r8a774a1: Add VIN and CSI-2 nodes

Lad Prabhakar
 

From: Biju Das <biju.das@...>

commit 0c85e78fb1d3742c36ff085999624cc912128776 upstream.

Add VIN and CSI-2 nodes to RZ/G2M SoC dtsi.

Signed-off-by: Biju Das <biju.das@...>
Reviewed-by: Fabrizio Castro <fabrizio.castro@...>
Signed-off-by: Simon Horman <horms+renesas@...>
[PL: manually applied the changes]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
arch/arm64/boot/dts/renesas/r8a774a1.dtsi | 367 ++++++++++++++++++++++
1 file changed, 367 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
index 90f5fb49957e..6cef662c1a32 100644
--- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
@@ -1410,6 +1410,262 @@
status = "disabled";
};

+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef0000 0 0x1000>;
+ interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 811>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 811>;
+ renesas,id = <0>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin0csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin0>;
+ };
+ vin0csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin0>;
+ };
+ };
+ };
+ };
+
+ vin1: video@e6ef1000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef1000 0 0x1000>;
+ interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 810>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 810>;
+ renesas,id = <1>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin1csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin1>;
+ };
+ vin1csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin1>;
+ };
+ };
+ };
+ };
+
+ vin2: video@e6ef2000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef2000 0 0x1000>;
+ interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 809>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 809>;
+ renesas,id = <2>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin2csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin2>;
+ };
+ vin2csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin2>;
+ };
+ };
+ };
+ };
+
+ vin3: video@e6ef3000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef3000 0 0x1000>;
+ interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 808>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 808>;
+ renesas,id = <3>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin3csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin3>;
+ };
+ vin3csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin3>;
+ };
+ };
+ };
+ };
+
+ vin4: video@e6ef4000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef4000 0 0x1000>;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 807>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 807>;
+ renesas,id = <4>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin4csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin4>;
+ };
+ vin4csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin4>;
+ };
+ };
+ };
+ };
+
+ vin5: video@e6ef5000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef5000 0 0x1000>;
+ interrupts = <GIC_SPI 175 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 806>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 806>;
+ renesas,id = <5>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin5csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin5>;
+ };
+ vin5csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin5>;
+ };
+ };
+ };
+ };
+
+ vin6: video@e6ef6000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef6000 0 0x1000>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 805>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 805>;
+ renesas,id = <6>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin6csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin6>;
+ };
+ vin6csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin6>;
+ };
+ };
+ };
+ };
+
+ vin7: video@e6ef7000 {
+ compatible = "renesas,vin-r8a774a1";
+ reg = <0 0xe6ef7000 0 0x1000>;
+ interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 804>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 804>;
+ renesas,id = <7>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ vin7csi20: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&csi20vin7>;
+ };
+ vin7csi40: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&csi40vin7>;
+ };
+ };
+ };
+ };
+
rcar_sound: sound@ec500000 {
/*
* #sound-dai-cells is required
@@ -2366,6 +2622,117 @@
};
};

+ csi20: csi2@fea80000 {
+ compatible = "renesas,r8a774a1-csi2";
+ reg = <0 0xfea80000 0 0x10000>;
+ interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 714>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 714>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ csi20vin0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vin0csi20>;
+ };
+ csi20vin1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vin1csi20>;
+ };
+ csi20vin2: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&vin2csi20>;
+ };
+ csi20vin3: endpoint@3 {
+ reg = <3>;
+ remote-endpoint = <&vin3csi20>;
+ };
+ csi20vin4: endpoint@4 {
+ reg = <4>;
+ remote-endpoint = <&vin4csi20>;
+ };
+ csi20vin5: endpoint@5 {
+ reg = <5>;
+ remote-endpoint = <&vin5csi20>;
+ };
+ csi20vin6: endpoint@6 {
+ reg = <6>;
+ remote-endpoint = <&vin6csi20>;
+ };
+ csi20vin7: endpoint@7 {
+ reg = <7>;
+ remote-endpoint = <&vin7csi20>;
+ };
+ };
+ };
+ };
+
+ csi40: csi2@feaa0000 {
+ compatible = "renesas,r8a774a1-csi2";
+ reg = <0 0xfeaa0000 0 0x10000>;
+ interrupts = <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 716>;
+ power-domains = <&sysc 32>;
+ resets = <&cpg 716>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <1>;
+
+ csi40vin0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vin0csi40>;
+ };
+ csi40vin1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vin1csi40>;
+ };
+ csi40vin2: endpoint@2 {
+ reg = <2>;
+ remote-endpoint = <&vin2csi40>;
+ };
+ csi40vin3: endpoint@3 {
+ reg = <3>;
+ remote-endpoint = <&vin3csi40>;
+ };
+ csi40vin4: endpoint@4 {
+ reg = <4>;
+ remote-endpoint = <&vin4csi40>;
+ };
+ csi40vin5: endpoint@5 {
+ reg = <5>;
+ remote-endpoint = <&vin5csi40>;
+ };
+ csi40vin6: endpoint@6 {
+ reg = <6>;
+ remote-endpoint = <&vin6csi40>;
+ };
+ csi40vin7: endpoint@7 {
+ reg = <7>;
+ remote-endpoint = <&vin7csi40>;
+ };
+ };
+
+ };
+ };
+
prr: chipid@fff00044 {
compatible = "renesas,prr";
reg = <0 0xfff00044 0 4>;
--
2.17.1


[PATCH 4.19.y-cip 25/40] media: rcar-csi2: Enable support for r8a774a1

Lad Prabhakar
 

From: Biju Das <biju.das@...>

commit d4b87d459a4cfc8009ec4ee92893d84cef277f61 upstream.

Add the MIPI CSI-2 driver support for RZ/G2M(r8a774a1) SoC.
The CSI-2 module of RZ/G2M is similar to R-Car M3-W.

Signed-off-by: Biju Das <biju.das@...>
Reviewed-by: Fabrizio Castro <fabrizio.castro@...>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index e6a531c4fde5..fa13e3ab0709 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -975,6 +975,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
};

static const struct of_device_id rcar_csi2_of_table[] = {
+ {
+ .compatible = "renesas,r8a774a1-csi2",
+ .data = &rcar_csi2_info_r8a7796,
+ },
{
.compatible = "renesas,r8a774c0-csi2",
.data = &rcar_csi2_info_r8a77990,
--
2.17.1


[PATCH 4.19.y-cip 24/40] media: dt-bindings: media: rcar-csi2: Add r8a774a1 support

Lad Prabhakar
 

From: Biju Das <biju.das@...>

commit 29f6c4227e450cd9d20615c08478bd4d3e04a711 upstream.

Document RZ/G2M (R8A774A1) SoC bindings.

The RZ/G2M SoC is similar to R-Car M3-W (R8A7796).

Signed-off-by: Biju Das <biju.das@...>
Reviewed-by: Fabrizio Castro <fabrizio.castro@...>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Reviewed-by: Rob Herring <robh@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt b/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
index 4e9a4f7b5ef2..d4965822aee9 100644
--- a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
+++ b/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt
@@ -8,6 +8,7 @@ R-Car VIN module, which provides the video capture capabilities.
Mandatory properties
--------------------
- compatible: Must be one or more of the following
+ - "renesas,r8a774a1-csi2" for the R8A774A1 device.
- "renesas,r8a774c0-csi2" for the R8A774C0 device.
- "renesas,r8a7795-csi2" for the R8A7795 device.
- "renesas,r8a7796-csi2" for the R8A7796 device.
--
2.17.1


[PATCH 4.19.y-cip 23/40] media: rcar-vin: Enable support for r8a774a1

Lad Prabhakar
 

From: Biju Das <biju.das@...>

commit f29a317b9c33be536ab516a89a921719f907137e upstream.

Add the SoC specific information for RZ/G2M(r8a774a1) SoC.
The VIN module of RZ/G2M is similar to R-Car M3-W.

Signed-off-by: Biju Das <biju.das@...>
Reviewed-by: Fabrizio Castro <fabrizio.castro@...>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-core.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 79d1a8a730ad..c8856fed737f 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -1118,6 +1118,10 @@ static const struct rvin_info rcar_info_r8a77995 = {
};

static const struct of_device_id rvin_of_id_table[] = {
+ {
+ .compatible = "renesas,vin-r8a774a1",
+ .data = &rcar_info_r8a7796,
+ },
{
.compatible = "renesas,vin-r8a774c0",
.data = &rcar_info_r8a77990,
--
2.17.1


[PATCH 4.19.y-cip 22/40] media: dt-bindings: media: rcar_vin: Add r8a774a1 support

Lad Prabhakar
 

From: Biju Das <biju.das@...>

commit b8f92200d16e68e51c55f8ea7c2e251c423aac76 upstream.

Document RZ/G2M (R8A774A1) SoC bindings.

The RZ/G2M SoC is similar to R-Car M3-W (R8A7796).

Signed-off-by: Biju Das <biju.das@...>
Reviewed-by: Fabrizio Castro <fabrizio.castro@...>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Reviewed-by: Rob Herring <robh@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
Documentation/devicetree/bindings/media/rcar_vin.txt | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt
index 2dc9e32d6b4f..5bc5d6b9d5bc 100644
--- a/Documentation/devicetree/bindings/media/rcar_vin.txt
+++ b/Documentation/devicetree/bindings/media/rcar_vin.txt
@@ -12,6 +12,7 @@ on Gen3 and RZ/G2 platforms to a CSI-2 receiver.
- compatible: Must be one or more of the following
- "renesas,vin-r8a7743" for the R8A7743 device
- "renesas,vin-r8a7745" for the R8A7745 device
+ - "renesas,vin-r8a774a1" for the R8A774A1 device
- "renesas,vin-r8a774c0" for the R8A774C0 device
- "renesas,vin-r8a7778" for the R8A7778 device
- "renesas,vin-r8a7779" for the R8A7779 device
--
2.17.1


[PATCH 4.19.y-cip 21/40] arm64: dts: renesas: r8a774c0-cat874: Add support for AISTARVISION MIPI Adapter V2.1

Lad Prabhakar
 

commit 0e36587c0832af5df894f5e5fcc45fb5a05cea5b upstream.

This patch adds support for AISTARVISION MIPI Adapter V2.1 board connected
to G2E board. Common file aistarvision-mipi-adapter-2.1.dtsi is created
which have the camera endpoint nodes for imx219 and ov5645 so that this can
be re-used with other G2x platforms.

r8a774c0-ek874-mipi-2.1.dts file enables the required VIN/CSI nodes and by
default ties ov5645 camera endpoint to CSI2.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Link: https://lore.kernel.org/r/1587397794-11237-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@...>
[PL: manually applied changes to Makefile file]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
arch/arm64/boot/dts/renesas/Makefile | 3 +-
.../aistarvision-mipi-adapter-2.1.dtsi | 94 +++++++++++++++++++
.../dts/renesas/r8a774c0-ek874-mipi-2.1.dts | 72 ++++++++++++++
3 files changed, 168 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
create mode 100644 arch/arm64/boot/dts/renesas/r8a774c0-ek874-mipi-2.1.dts

diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
index 16d63679f358..0783033209d9 100644
--- a/arch/arm64/boot/dts/renesas/Makefile
+++ b/arch/arm64/boot/dts/renesas/Makefile
@@ -12,7 +12,8 @@ dtb-$(CONFIG_ARCH_R8A774B1) += r8a774b1-hihope-rzg2n-ex.dtb \
dtb-$(CONFIG_ARCH_R8A774B1) += r8a774b1-hihope-rzg2n-ex-idk-1110wr.dtb \
r8a774b1-hihope-rzg2n-rev2-ex-idk-1110wr.dtb
dtb-$(CONFIG_ARCH_R8A774C0) += r8a774c0-cat874.dtb r8a774c0-ek874.dtb \
- r8a774c0-ek874-idk-2121wr.dtb
+ r8a774c0-ek874-idk-2121wr.dtb \
+ r8a774c0-ek874-mipi-2.1.dtb
dtb-$(CONFIG_ARCH_R8A774E1) += r8a774e1-hihope-rzg2h.dtb
dtb-$(CONFIG_ARCH_R8A774E1) += r8a774e1-hihope-rzg2h-ex.dtb
dtb-$(CONFIG_ARCH_R8A774E1) += r8a774e1-hihope-rzg2h-ex-idk-1110wr.dtb
diff --git a/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi b/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
new file mode 100644
index 000000000000..dac6ff49020f
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/aistarvision-mipi-adapter-2.1.dtsi
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the AISTARVISION MIPI Adapter V2.1
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+/ {
+ ov5645_vdddo_1v8: 1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vdddo";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ov5645_vdda_2v8: 2p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vdda";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ ov5645_vddd_1v5: 1p5v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vddd";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ };
+
+ imx219_vana_2v8: 2p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vana";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+
+ imx219_vdig_1v8: 1p8v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vdig";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ };
+
+ imx219_vddl_1v2: 1p2v {
+ compatible = "regulator-fixed";
+ regulator-name = "camera_vddl";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ osc25250_clk: osc25250_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ };
+};
+
+&MIPI_PARENT_I2C {
+ ov5645: ov5645@3c {
+ compatible = "ovti,ov5645";
+ reg = <0x3c>;
+ clock-names = "xclk";
+ clocks = <&osc25250_clk>;
+ clock-frequency = <24000000>;
+ vdddo-supply = <&ov5645_vdddo_1v8>;
+ vdda-supply = <&ov5645_vdda_2v8>;
+ vddd-supply = <&ov5645_vddd_1v5>;
+
+ port {
+ ov5645_ep: endpoint {
+ };
+ };
+ };
+
+ imx219: imx219@10 {
+ compatible = "sony,imx219";
+ reg = <0x10>;
+ clocks = <&osc25250_clk>;
+ VANA-supply = <&imx219_vana_2v8>;
+ VDIG-supply = <&imx219_vdig_1v8>;
+ VDDL-supply = <&imx219_vddl_1v2>;
+
+ port {
+ imx219_ep: endpoint {
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/renesas/r8a774c0-ek874-mipi-2.1.dts b/arch/arm64/boot/dts/renesas/r8a774c0-ek874-mipi-2.1.dts
new file mode 100644
index 000000000000..f0829e905506
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a774c0-ek874-mipi-2.1.dts
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the Silicon Linux RZ/G2E 96board platform (CAT874)
+ * connected with aistarvision-mipi-v2-adapter board
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+#include "r8a774c0-ek874.dts"
+#define MIPI_PARENT_I2C i2c3
+#include "aistarvision-mipi-adapter-2.1.dtsi"
+
+/ {
+ model = "Silicon Linux RZ/G2E evaluation kit EK874 (CAT874 + CAT875) with aistarvision-mipi-v2-adapter board";
+ compatible = "si-linux,cat875", "si-linux,cat874", "renesas,r8a774c0";
+};
+
+&i2c3 {
+ status = "okay";
+};
+
+&vin4 {
+ status = "okay";
+};
+
+&vin5 {
+ status = "okay";
+};
+
+&csi40 {
+ status = "okay";
+
+ ports {
+ port {
+ csi40_in: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ remote-endpoint = <&ov5645_ep>;
+ };
+ };
+ };
+};
+
+&ov5645 {
+ enable-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
+
+ port {
+ ov5645_ep: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ remote-endpoint = <&csi40_in>;
+ };
+ };
+};
+
+&imx219 {
+ port {
+ imx219_ep: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ link-frequencies = /bits/ 64 <456000000>;
+ /* uncomment remote-endpoint property to tie imx219 to
+ * CSI2 also make sure remote-endpoint for ov5645 camera
+ * is commented and remote endpoint phandle in csi40_in
+ * is imx219_ep
+ */
+ /* remote-endpoint = <&csi40_in>; */
+ };
+ };
+};
--
2.17.1


[PATCH 4.19.y-cip 20/40] media: i2c: imx219: take lock in imx219_enum_mbus_code/frame_size

Lad Prabhakar
 

From: Hans Verkuil <hverkuil-cisco@...>

commit 81015221a269e0d9bf6dbc3fda099b09a876ebb7 upstream.

These two functions did not take the imx219->mutex lock, but
imx219_get_format_code checks that a lock is taken, so it issues
a warning:

[ 8.738717] WARNING: CPU: 2 PID: 60 at drivers/media/i2c/imx219.c:653 imx219_get_format_code+0xac/0xc0
[ 8.748113] Modules linked in:
[ 8.751214] CPU: 2 PID: 60 Comm: kworker/2:1 Tainted: G W 5.8.0-rc1-arm64 #148
[ 8.759821] Hardware name: NVIDIA Jetson TX1 Developer Kit (DT)
[ 8.765806] Workqueue: events deferred_probe_work_func
[ 8.771003] pstate: 60000005 (nZCv daif -PAN -UAO BTYPE=--)
[ 8.776635] pc : imx219_get_format_code+0xac/0xc0
[ 8.781390] lr : imx219_get_format_code+0xa8/0xc0
[ 8.786143] sp : ffff800012a538f0
[ 8.789495] x29: ffff800012a538f0 x28: ffff800012838e90
[ 8.794867] x27: ffff0000f28c5800 x26: ffff800011161c68
[ 8.800237] x25: ffff0000f2a5a3f8 x24: 0000000000000018
[ 8.805605] x23: ffff0000f284ef18 x22: ffff0000f2a5a080
[ 8.810974] x21: ffff0000f284ff00 x20: ffff0000f2a5a080
[ 8.816343] x19: 000000000000300f x18: 00000000ffffffff
[ 8.821712] x17: ffff800011c77268 x16: 00000000000040d7
[ 8.827081] x15: 00000000000040d8 x14: 0000000000000000
[ 8.832451] x13: 00000000000040d4 x12: ffff800011d19300
[ 8.837819] x11: 00000000000208c0 x10: 0000000000000004
[ 8.843188] x9 : 000000003baa2ecd x8 : 000000008b3f9c73
[ 8.848558] x7 : 0000000000000008 x6 : 0000000000000034
[ 8.853929] x5 : 0000000000000000 x4 : 0000000000000001
[ 8.859297] x3 : ffff800010a2a8a8 x2 : ffff0000f84a8000
[ 8.864666] x1 : 0000000000000000 x0 : 0000000000000000
[ 8.870034] Call trace:
[ 8.872515] imx219_get_format_code+0xac/0xc0
[ 8.876921] imx219_enum_mbus_code+0x38/0x60
[ 8.881241] call_enum_mbus_code+0x50/0x70
[ 8.885387] tegra_vi_graph_notify_complete+0x290/0x5e8
[ 8.890670] v4l2_async_notifier_try_complete.part.0+0x48/0x68
[ 8.896563] v4l2_async_register_subdev+0x100/0x1c0
[ 8.901497] v4l2_async_register_subdev_sensor_common+0x70/0xf0
[ 8.907477] imx219_probe+0x590/0x728
[ 8.911184] i2c_device_probe+0xe4/0x2b0
[ 8.915151] really_probe+0xd8/0x330
[ 8.918768] driver_probe_device+0x58/0xb8
[ 8.922909] __device_attach_driver+0x84/0xc8
[ 8.927315] bus_for_each_drv+0x78/0xc8
[ 8.931193] __device_attach+0xe4/0x140
[ 8.935072] device_initial_probe+0x14/0x20
[ 8.939301] bus_probe_device+0x9c/0xa8
[ 8.943179] deferred_probe_work_func+0x74/0xb0
[ 8.947759] process_one_work+0x2c4/0x740
[ 8.951813] worker_thread+0x4c/0x430
[ 8.955518] kthread+0x158/0x178
[ 8.958786] ret_from_fork+0x10/0x1c
[ 8.962401] irq event stamp: 63536
[ 8.965846] hardirqs last enabled at (63535): [<ffff800010082398>] el1_irq+0xd8/0x180
[ 8.973846] hardirqs last disabled at (63536): [<ffff8000100a6484>] do_debug_exception+0x16c/0x258
[ 8.982895] softirqs last enabled at (63534): [<ffff800010080d4c>] _stext+0x54c/0x594
[ 8.990896] softirqs last disabled at (63525): [<ffff8000100c8350>] irq_exit+0x100/0x138
[ 8.999066] ---[ end trace ebfbcd84b75ef921 ]---
[ 9.004354] ------------[ cut here ]------------

Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Reviewed-by: Dave Stevenson <dave.stevenson@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 386717fb2b99..a2829c7012aa 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -811,7 +811,9 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index >= (ARRAY_SIZE(codes) / 4))
return -EINVAL;

+ mutex_lock(&imx219->mutex);
code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
+ mutex_unlock(&imx219->mutex);

return 0;
}
@@ -821,11 +823,15 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_size_enum *fse)
{
struct imx219 *imx219 = to_imx219(sd);
+ u32 code;

if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;

- if (fse->code != imx219_get_format_code(imx219, fse->code))
+ mutex_lock(&imx219->mutex);
+ code = imx219_get_format_code(imx219, fse->code);
+ mutex_unlock(&imx219->mutex);
+ if (fse->code != code)
return -EINVAL;

fse->min_width = supported_modes[fse->index].width;
--
2.17.1


[PATCH 4.19.y-cip 19/40] media: i2c: imx219: Selection compliance fixes

Lad Prabhakar
 

From: Hans Verkuil <hverkuil-cisco@...>

commit 1ed36ecd1459b653cced8929bfb37dba94b64c5d upstream.

To comply with the intended usage of the V4L2 selection target when
used to retrieve a sensor image properties, adjust the rectangles
returned by the imx219 driver.

The top/left crop coordinates of the TGT_CROP rectangle were set to
(0, 0) instead of (8, 8) which is the offset from the larger physical
pixel array rectangle. This was also a mismatch with the default values
crop rectangle value, so this is corrected. Found with v4l2-compliance.

While at it, add V4L2_SEL_TGT_CROP_BOUNDS support: CROP_DEFAULT and
CROP_BOUNDS have the same size as the non-active pixels are not readable
using the selection API. Found with v4l2-compliance.

[reword commit message, use macros for pixel offsets]

Fixes: e6d4ef7d58aa7 ("media: i2c: imx219: Implement get_selection")
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Jacopo Mondi <jacopo@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index c92d935a87ce..386717fb2b99 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -476,8 +476,8 @@ static const struct imx219_mode supported_modes[] = {
.width = 3280,
.height = 2464,
.crop = {
- .left = 0,
- .top = 0,
+ .left = IMX219_PIXEL_ARRAY_LEFT,
+ .top = IMX219_PIXEL_ARRAY_TOP,
.width = 3280,
.height = 2464
},
@@ -492,8 +492,8 @@ static const struct imx219_mode supported_modes[] = {
.width = 1920,
.height = 1080,
.crop = {
- .left = 680,
- .top = 692,
+ .left = 688,
+ .top = 700,
.width = 1920,
.height = 1080
},
@@ -508,8 +508,8 @@ static const struct imx219_mode supported_modes[] = {
.width = 1640,
.height = 1232,
.crop = {
- .left = 0,
- .top = 0,
+ .left = IMX219_PIXEL_ARRAY_LEFT,
+ .top = IMX219_PIXEL_ARRAY_TOP,
.width = 3280,
.height = 2464
},
@@ -524,8 +524,8 @@ static const struct imx219_mode supported_modes[] = {
.width = 640,
.height = 480,
.crop = {
- .left = 1000,
- .top = 752,
+ .left = 1008,
+ .top = 760,
.width = 1280,
.height = 960
},
@@ -1011,6 +1011,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
return 0;

case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r.top = IMX219_PIXEL_ARRAY_TOP;
sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
--
2.17.1


[PATCH 4.19.y-cip 18/40] media: i2c: imx219: Fix a bug in imx219_enum_frame_size

Lad Prabhakar
 

From: Dafna Hirschfeld <dafna.hirschfeld@...>

commit b2bbf1aac61186ef904fd28079e847d3feadb89e upstream.

When enumerating the frame sizes, the value sent to
imx219_get_format_code should be fse->code
(the code from the ioctl) and not imx219->fmt.code
which is the code set currently in the driver.

Fixes: 22da1d56e982 ("media: i2c: imx219: Add support for RAW8 bit bayer format")
Signed-off-by: Dafna Hirschfeld <dafna.hirschfeld@...>
Reviewed-by: Helen Koike <helen.koike@...>
Reviewed-by: Dave Stevenson <dave.stevenson@...>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index c50530d2a728..c92d935a87ce 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -825,7 +825,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;

- if (fse->code != imx219_get_format_code(imx219, imx219->fmt.code))
+ if (fse->code != imx219_get_format_code(imx219, fse->code))
return -EINVAL;

fse->min_width = supported_modes[fse->index].width;
--
2.17.1


[PATCH 4.19.y-cip 17/40] media: i2c: imx219: Implement get_selection

Lad Prabhakar
 

From: Jacopo Mondi <jacopo@...>

commit e6d4ef7d58aa7e64aa735e1b3c7b670e4fb34d6f upstream.

Implement the get_selection pad operation for the IMX219 sensor driver.
The supported targets report the sensor's native size, the crop default
rectangle and the crop rectangle.

Reviewed-by: Laurent Pinchart <laurent.pinchart@...>
Signed-off-by: Jacopo Mondi <jacopo@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 94 ++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index e2db55f70cd6..c50530d2a728 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -113,6 +113,14 @@
#define IMX219_TESTP_BLUE_DEFAULT 0
#define IMX219_TESTP_GREENB_DEFAULT 0

+/* IMX219 native and active pixel array size. */
+#define IMX219_NATIVE_WIDTH 3296U
+#define IMX219_NATIVE_HEIGHT 2480U
+#define IMX219_PIXEL_ARRAY_LEFT 8U
+#define IMX219_PIXEL_ARRAY_TOP 8U
+#define IMX219_PIXEL_ARRAY_WIDTH 3280U
+#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
+
struct imx219_reg {
u16 address;
u8 val;
@@ -130,6 +138,9 @@ struct imx219_mode {
/* Frame height */
unsigned int height;

+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+
/* V-timing */
unsigned int vts_def;

@@ -464,6 +475,12 @@ static const struct imx219_mode supported_modes[] = {
/* 8MPix 15fps mode */
.width = 3280,
.height = 2464,
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 3280,
+ .height = 2464
+ },
.vts_def = IMX219_VTS_15FPS,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
@@ -474,6 +491,12 @@ static const struct imx219_mode supported_modes[] = {
/* 1080P 30fps cropped */
.width = 1920,
.height = 1080,
+ .crop = {
+ .left = 680,
+ .top = 692,
+ .width = 1920,
+ .height = 1080
+ },
.vts_def = IMX219_VTS_30FPS_1080P,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
@@ -484,6 +507,12 @@ static const struct imx219_mode supported_modes[] = {
/* 2x2 binned 30fps mode */
.width = 1640,
.height = 1232,
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 3280,
+ .height = 2464
+ },
.vts_def = IMX219_VTS_30FPS_BINNED,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
@@ -494,6 +523,12 @@ static const struct imx219_mode supported_modes[] = {
/* 640x480 30fps mode */
.width = 640,
.height = 480,
+ .crop = {
+ .left = 1000,
+ .top = 752,
+ .width = 1280,
+ .height = 960
+ },
.vts_def = IMX219_VTS_30FPS_640x480,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_640_480_regs),
@@ -655,6 +690,7 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
struct imx219 *imx219 = to_imx219(sd);
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_rect *try_crop;

mutex_lock(&imx219->mutex);

@@ -665,6 +701,13 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
MEDIA_BUS_FMT_SRGGB10_1X10);
try_fmt->field = V4L2_FIELD_NONE;

+ /* Initialize try_crop rectangle. */
+ try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+ try_crop->top = IMX219_PIXEL_ARRAY_TOP;
+ try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
+ try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
+ try_crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
+
mutex_unlock(&imx219->mutex);

return 0;
@@ -929,6 +972,56 @@ static int imx219_set_framefmt(struct imx219 *imx219)
return -EINVAL;
}

+static const struct v4l2_rect *
+__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&imx219->sd, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &imx219->mode->crop;
+ }
+
+ return NULL;
+}
+
+static int imx219_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct imx219 *imx219 = to_imx219(sd);
+
+ mutex_lock(&imx219->mutex);
+ sel->r = *__imx219_get_pad_crop(imx219, cfg, sel->pad,
+ sel->which);
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX219_NATIVE_WIDTH;
+ sel->r.height = IMX219_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = IMX219_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int imx219_start_streaming(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -1153,6 +1246,7 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
.enum_mbus_code = imx219_enum_mbus_code,
.get_fmt = imx219_get_pad_format,
.set_fmt = imx219_set_pad_format,
+ .get_selection = imx219_get_selection,
.enum_frame_size = imx219_enum_frame_size,
};

--
2.17.1


[PATCH 4.19.y-cip 16/40] media: i2c: imx219: Add support for cropped 640x480 resolution

Lad Prabhakar
 

commit 25130b8ad409d5532f3763bcf891af74f550a70d upstream.

This patch adds mode table entry for capturing cropped 640x480 resolution

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Acked-by: Dave Stevenson <dave.stevenson@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 70 +++++++++++++++++++++++++++++++++++++-
1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index d94c94c38e75..e2db55f70cd6 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -55,6 +55,7 @@
#define IMX219_VTS_15FPS 0x0dc6
#define IMX219_VTS_30FPS_1080P 0x06e3
#define IMX219_VTS_30FPS_BINNED 0x06e3
+#define IMX219_VTS_30FPS_640x480 0x06e3
#define IMX219_VTS_MAX 0xffff

#define IMX219_VBLANK_MIN 4
@@ -139,7 +140,7 @@ struct imx219_mode {
/*
* Register sets lifted off the i2C interface from the Raspberry Pi firmware
* driver.
- * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
*/
static const struct imx219_reg mode_3280x2464_regs[] = {
{0x0100, 0x00},
@@ -314,6 +315,63 @@ static const struct imx219_reg mode_1640_1232_regs[] = {
{0x0163, 0x78},
};

+static const struct imx219_reg mode_640_480_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x05},
+ {0x30eb, 0x0c},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+ {0x0164, 0x03},
+ {0x0165, 0xe8},
+ {0x0166, 0x08},
+ {0x0167, 0xe7},
+ {0x0168, 0x02},
+ {0x0169, 0xf0},
+ {0x016a, 0x06},
+ {0x016b, 0xaf},
+ {0x016c, 0x02},
+ {0x016d, 0x80},
+ {0x016e, 0x01},
+ {0x016f, 0xe0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x03},
+ {0x0175, 0x03},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x06},
+ {0x0625, 0x68},
+ {0x0626, 0x04},
+ {0x0627, 0xd0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+};
+
static const struct imx219_reg raw8_framefmt_regs[] = {
{0x018c, 0x08},
{0x018d, 0x08},
@@ -432,6 +490,16 @@ static const struct imx219_mode supported_modes[] = {
.regs = mode_1640_1232_regs,
},
},
+ {
+ /* 640x480 30fps mode */
+ .width = 640,
+ .height = 480,
+ .vts_def = IMX219_VTS_30FPS_640x480,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_640_480_regs),
+ .regs = mode_640_480_regs,
+ },
+ },
};

struct imx219 {
--
2.17.1


[PATCH 4.19.y-cip 15/40] media: i2c: imx219: Add support for RAW8 bit bayer format

Lad Prabhakar
 

commit 22da1d56e982151e0bdfafe9de6fe94098a51356 upstream.

IMX219 sensor is capable for RAW8/RAW10 modes. This commit adds support
for RAW8 bayer format.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Signed-off-by: Dave Stevenson <dave.stevenson@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 148 +++++++++++++++++++++++++++++--------
1 file changed, 116 insertions(+), 32 deletions(-)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index f1ae93569542..d94c94c38e75 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -169,15 +169,12 @@ static const struct imx219_reg mode_3280x2464_regs[] = {
{0x0171, 0x01},
{0x0174, 0x00},
{0x0175, 0x00},
- {0x018c, 0x0a},
- {0x018d, 0x0a},
{0x0301, 0x05},
{0x0303, 0x01},
{0x0304, 0x03},
{0x0305, 0x03},
{0x0306, 0x00},
{0x0307, 0x39},
- {0x0309, 0x0a},
{0x030b, 0x01},
{0x030c, 0x00},
{0x030d, 0x72},
@@ -231,15 +228,12 @@ static const struct imx219_reg mode_1920_1080_regs[] = {
{0x0171, 0x01},
{0x0174, 0x00},
{0x0175, 0x00},
- {0x018c, 0x0a},
- {0x018d, 0x0a},
{0x0301, 0x05},
{0x0303, 0x01},
{0x0304, 0x03},
{0x0305, 0x03},
{0x0306, 0x00},
{0x0307, 0x39},
- {0x0309, 0x0a},
{0x030b, 0x01},
{0x030c, 0x00},
{0x030d, 0x72},
@@ -291,15 +285,12 @@ static const struct imx219_reg mode_1640_1232_regs[] = {
{0x0171, 0x01},
{0x0174, 0x01},
{0x0175, 0x01},
- {0x018c, 0x0a},
- {0x018d, 0x0a},
{0x0301, 0x05},
{0x0303, 0x01},
{0x0304, 0x03},
{0x0305, 0x03},
{0x0306, 0x00},
{0x0307, 0x39},
- {0x0309, 0x0a},
{0x030b, 0x01},
{0x030c, 0x00},
{0x030d, 0x72},
@@ -323,6 +314,18 @@ static const struct imx219_reg mode_1640_1232_regs[] = {
{0x0163, 0x78},
};

+static const struct imx219_reg raw8_framefmt_regs[] = {
+ {0x018c, 0x08},
+ {0x018d, 0x08},
+ {0x0309, 0x08},
+};
+
+static const struct imx219_reg raw10_framefmt_regs[] = {
+ {0x018c, 0x0a},
+ {0x018d, 0x0a},
+ {0x0309, 0x0a},
+};
+
static const char * const imx219_test_pattern_menu[] = {
"Disabled",
"Color Bars",
@@ -349,6 +352,27 @@ static const char * const imx219_supply_name[] = {

#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)

+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+};
+
/*
* Initialisation delay between XCLR low->high and the moment when the sensor
* can start capture (i.e. can leave software stanby) must be not less than:
@@ -414,6 +438,8 @@ struct imx219 {
struct v4l2_subdev sd;
struct media_pad pad;

+ struct v4l2_mbus_framefmt fmt;
+
struct clk *xclk; /* system clock to IMX219 */
u32 xclk_freq;

@@ -520,19 +546,40 @@ static int imx219_write_regs(struct imx219 *imx219,
}

/* Get bayer order based on flip setting. */
-static u32 imx219_get_format_code(struct imx219 *imx219)
+static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
{
- /*
- * Only one bayer order is supported.
- * It depends on the flip settings.
- */
- static const u32 codes[2][2] = {
- { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
- { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
- };
+ unsigned int i;

lockdep_assert_held(&imx219->mutex);
- return codes[imx219->vflip->val][imx219->hflip->val];
+
+ for (i = 0; i < ARRAY_SIZE(codes); i++)
+ if (codes[i] == code)
+ break;
+
+ if (i >= ARRAY_SIZE(codes))
+ i = 0;
+
+ i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
+ (imx219->hflip->val ? 1 : 0);
+
+ return codes[i];
+}
+
+static void imx219_set_default_format(struct imx219 *imx219)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = &imx219->fmt;
+ fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ fmt->colorspace,
+ fmt->ycbcr_enc);
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+ fmt->width = supported_modes[0].width;
+ fmt->height = supported_modes[0].height;
+ fmt->field = V4L2_FIELD_NONE;
}

static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -546,7 +593,8 @@ static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
try_fmt->height = supported_modes[0].height;
- try_fmt->code = imx219_get_format_code(imx219);
+ try_fmt->code = imx219_get_format_code(imx219,
+ MEDIA_BUS_FMT_SRGGB10_1X10);
try_fmt->field = V4L2_FIELD_NONE;

mutex_unlock(&imx219->mutex);
@@ -649,14 +697,10 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
{
struct imx219 *imx219 = to_imx219(sd);

- /*
- * Only one bayer order is supported (though it depends on the flip
- * settings)
- */
- if (code->index > 0)
+ if (code->index >= (ARRAY_SIZE(codes) / 4))
return -EINVAL;

- code->code = imx219_get_format_code(imx219);
+ code->code = imx219_get_format_code(imx219, codes[code->index * 4]);

return 0;
}
@@ -670,7 +714,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;

- if (fse->code != imx219_get_format_code(imx219))
+ if (fse->code != imx219_get_format_code(imx219, imx219->fmt.code))
return -EINVAL;

fse->min_width = supported_modes[fse->index].width;
@@ -697,9 +741,7 @@ static void imx219_update_pad_format(struct imx219 *imx219,
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = imx219_get_format_code(imx219);
fmt->format.field = V4L2_FIELD_NONE;
-
imx219_reset_colorspace(&fmt->format);
}

@@ -711,10 +753,12 @@ static int __imx219_get_pad_format(struct imx219 *imx219,
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
/* update the code which could change due to vflip or hflip: */
- try_fmt->code = imx219_get_format_code(imx219);
+ try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
fmt->format = *try_fmt;
} else {
imx219_update_pad_format(imx219, imx219->mode, fmt);
+ fmt->format.code = imx219_get_format_code(imx219,
+ imx219->fmt.code);
}

return 0;
@@ -742,11 +786,18 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
const struct imx219_mode *mode;
struct v4l2_mbus_framefmt *framefmt;
int exposure_max, exposure_def, hblank;
+ unsigned int i;

mutex_lock(&imx219->mutex);

+ for (i = 0; i < ARRAY_SIZE(codes); i++)
+ if (codes[i] == fmt->format.code)
+ break;
+ if (i >= ARRAY_SIZE(codes))
+ i = 0;
+
/* Bayer order varies with flips */
- fmt->format.code = imx219_get_format_code(imx219);
+ fmt->format.code = imx219_get_format_code(imx219, codes[i]);

mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
@@ -756,7 +807,9 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
*framefmt = fmt->format;
- } else if (imx219->mode != mode) {
+ } else if (imx219->mode != mode ||
+ imx219->fmt.code != fmt->format.code) {
+ imx219->fmt = fmt->format;
imx219->mode = mode;
/* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
@@ -787,6 +840,27 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
return 0;
}

+static int imx219_set_framefmt(struct imx219 *imx219)
+{
+ switch (imx219->fmt.code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return imx219_write_regs(imx219, raw8_framefmt_regs,
+ ARRAY_SIZE(raw8_framefmt_regs));
+
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ return imx219_write_regs(imx219, raw10_framefmt_regs,
+ ARRAY_SIZE(raw10_framefmt_regs));
+ }
+
+ return -EINVAL;
+}
+
static int imx219_start_streaming(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -801,6 +875,13 @@ static int imx219_start_streaming(struct imx219 *imx219)
return ret;
}

+ ret = imx219_set_framefmt(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set frame format: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
if (ret)
@@ -1253,6 +1334,9 @@ static int imx219_probe(struct i2c_client *client)
/* Initialize source pad */
imx219->pad.flags = MEDIA_PAD_FL_SOURCE;

+ /* Initialize default format */
+ imx219_set_default_format(imx219);
+
ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
if (ret) {
dev_err(dev, "failed to init entity pads: %d\n", ret);
--
2.17.1


[PATCH 4.19.y-cip 14/40] media: i2c: imx219: Fix power sequence

Lad Prabhakar
 

commit ca45448a56659c6df6e0436188e97f6cc65dea8a upstream.

When supporting Rpi Camera v2 Module on the RZ/G2E, found the driver had
some issues with rcar mipi-csi driver. The sensor never entered into LP-11
state.

The powerup sequence in the datasheet[1] shows the sensor entering into
LP-11 in streaming mode, so to fix this issue transitions are performed
from "streaming -> standby" in the probe() after power up.

With this commit the sensor is able to enter LP-11 mode during power up,
as expected by some CSI-2 controllers.

[1] https://publiclab.org/system/images/photos/000/023/294/original/
RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Acked-by: Dave Stevenson <dave.stevenson@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/imx219.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index c67b2cf5c32c..f1ae93569542 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -1224,6 +1224,23 @@ static int imx219_probe(struct i2c_client *client)
/* Set default mode to max resolution */
imx219->mode = &supported_modes[0];

+ /* sensor doesn't enter LP-11 state upon power up until and unless
+ * streaming is started, so upon power up switch the modes to:
+ * streaming -> standby
+ */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+ if (ret < 0)
+ goto error_power_off;
+ usleep_range(100, 110);
+
+ /* put sensor back to standby mode */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+ if (ret < 0)
+ goto error_power_off;
+ usleep_range(100, 110);
+
ret = imx219_init_controls(imx219);
if (ret)
goto error_power_off;
--
2.17.1


[PATCH 4.19.y-cip 13/40] media: i2c: Add driver for Sony IMX219 sensor

Lad Prabhakar
 

From: Dave Stevenson <dave.stevenson@...>

commit 1283b3b8f82b9004fbb94398cade5c8e797a2c8d upstream.

Adds a driver for the 8MPix Sony IMX219 CSI2 sensor.
Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
currently only supports 2 lanes.
8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned)
@ 30fps are currently supported.

[Sakari Ailus: make imx219_check_hwcfg static]

Signed-off-by: Dave Stevenson <dave.stevenson@...>
Signed-off-by: Andrey Konovalov <andrey.konovalov@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
[PL: passed single arg to v4l2_fwnode_endpoint_alloc_parse(); replaced
fwnode_handle_put() with of_node_put(); included linux/of_graph.h;
replaced fwnode_graph_get_next_endpoint() with
of_graph_get_next_endpoint(); manually applied changes to Makefile]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/i2c/Kconfig | 11 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/imx219.c | 1312 ++++++++++++++++++++++++++++++++++++
3 files changed, 1324 insertions(+)
create mode 100644 drivers/media/i2c/imx219.c

diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 8b1ae1d6680b..e93ac35eca00 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -597,6 +597,17 @@ config VIDEO_APTINA_PLL
config VIDEO_SMIAPP_PLL
tristate

+config VIDEO_IMX219
+ tristate "Sony IMX219 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX219 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx219.
+
config VIDEO_IMX258
tristate "Sony IMX258 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 520b3c3bf48c..8b4fe01411b9 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
+obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
new file mode 100644
index 000000000000..c67b2cf5c32c
--- /dev/null
+++ b/drivers/media/i2c/imx219.c
@@ -0,0 +1,1312 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Sony IMX219 cameras.
+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
+ *
+ * Based on Sony imx258 camera driver
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
+ * Copyright 2018 Qtechnology A/S
+ *
+ * Flip handling taken from the Sony IMX319 driver.
+ * Copyright (C) 2018 Intel Corporation
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <asm/unaligned.h>
+
+#define IMX219_REG_VALUE_08BIT 1
+#define IMX219_REG_VALUE_16BIT 2
+
+#define IMX219_REG_MODE_SELECT 0x0100
+#define IMX219_MODE_STANDBY 0x00
+#define IMX219_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX219_REG_CHIP_ID 0x0000
+#define IMX219_CHIP_ID 0x0219
+
+/* External clock frequency is 24.0M */
+#define IMX219_XCLK_FREQ 24000000
+
+/* Pixel rate is fixed at 182.4M for all the modes */
+#define IMX219_PIXEL_RATE 182400000
+
+#define IMX219_DEFAULT_LINK_FREQ 456000000
+
+/* V_TIMING internal */
+#define IMX219_REG_VTS 0x0160
+#define IMX219_VTS_15FPS 0x0dc6
+#define IMX219_VTS_30FPS_1080P 0x06e3
+#define IMX219_VTS_30FPS_BINNED 0x06e3
+#define IMX219_VTS_MAX 0xffff
+
+#define IMX219_VBLANK_MIN 4
+
+/*Frame Length Line*/
+#define IMX219_FLL_MIN 0x08a6
+#define IMX219_FLL_MAX 0xffff
+#define IMX219_FLL_STEP 1
+#define IMX219_FLL_DEFAULT 0x0c98
+
+/* HBLANK control - read only */
+#define IMX219_PPL_DEFAULT 3448
+
+/* Exposure control */
+#define IMX219_REG_EXPOSURE 0x015a
+#define IMX219_EXPOSURE_MIN 4
+#define IMX219_EXPOSURE_STEP 1
+#define IMX219_EXPOSURE_DEFAULT 0x640
+#define IMX219_EXPOSURE_MAX 65535
+
+/* Analog gain control */
+#define IMX219_REG_ANALOG_GAIN 0x0157
+#define IMX219_ANA_GAIN_MIN 0
+#define IMX219_ANA_GAIN_MAX 232
+#define IMX219_ANA_GAIN_STEP 1
+#define IMX219_ANA_GAIN_DEFAULT 0x0
+
+/* Digital gain control */
+#define IMX219_REG_DIGITAL_GAIN 0x0158
+#define IMX219_DGTL_GAIN_MIN 0x0100
+#define IMX219_DGTL_GAIN_MAX 0x0fff
+#define IMX219_DGTL_GAIN_DEFAULT 0x0100
+#define IMX219_DGTL_GAIN_STEP 1
+
+#define IMX219_REG_ORIENTATION 0x0172
+
+/* Test Pattern Control */
+#define IMX219_REG_TEST_PATTERN 0x0600
+#define IMX219_TEST_PATTERN_DISABLE 0
+#define IMX219_TEST_PATTERN_SOLID_COLOR 1
+#define IMX219_TEST_PATTERN_COLOR_BARS 2
+#define IMX219_TEST_PATTERN_GREY_COLOR 3
+#define IMX219_TEST_PATTERN_PN9 4
+
+/* Test pattern colour components */
+#define IMX219_REG_TESTP_RED 0x0602
+#define IMX219_REG_TESTP_GREENR 0x0604
+#define IMX219_REG_TESTP_BLUE 0x0606
+#define IMX219_REG_TESTP_GREENB 0x0608
+#define IMX219_TESTP_COLOUR_MIN 0
+#define IMX219_TESTP_COLOUR_MAX 0x03ff
+#define IMX219_TESTP_COLOUR_STEP 1
+#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX
+#define IMX219_TESTP_GREENR_DEFAULT 0
+#define IMX219_TESTP_BLUE_DEFAULT 0
+#define IMX219_TESTP_GREENB_DEFAULT 0
+
+struct imx219_reg {
+ u16 address;
+ u8 val;
+};
+
+struct imx219_reg_list {
+ unsigned int num_of_regs;
+ const struct imx219_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx219_mode {
+ /* Frame width */
+ unsigned int width;
+ /* Frame height */
+ unsigned int height;
+
+ /* V-timing */
+ unsigned int vts_def;
+
+ /* Default register values */
+ struct imx219_reg_list reg_list;
+};
+
+/*
+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
+ * driver.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4.
+ */
+static const struct imx219_reg mode_3280x2464_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x0c},
+ {0x30eb, 0x05},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0164, 0x00},
+ {0x0165, 0x00},
+ {0x0166, 0x0c},
+ {0x0167, 0xcf},
+ {0x0168, 0x00},
+ {0x0169, 0x00},
+ {0x016a, 0x09},
+ {0x016b, 0x9f},
+ {0x016c, 0x0c},
+ {0x016d, 0xd0},
+ {0x016e, 0x09},
+ {0x016f, 0xa0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x00},
+ {0x0175, 0x00},
+ {0x018c, 0x0a},
+ {0x018d, 0x0a},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x0309, 0x0a},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x0c},
+ {0x0625, 0xd0},
+ {0x0626, 0x09},
+ {0x0627, 0xa0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_1920_1080_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x05},
+ {0x30eb, 0x0c},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+ {0x0164, 0x02},
+ {0x0165, 0xa8},
+ {0x0166, 0x0a},
+ {0x0167, 0x27},
+ {0x0168, 0x02},
+ {0x0169, 0xb4},
+ {0x016a, 0x06},
+ {0x016b, 0xeb},
+ {0x016c, 0x07},
+ {0x016d, 0x80},
+ {0x016e, 0x04},
+ {0x016f, 0x38},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x00},
+ {0x0175, 0x00},
+ {0x018c, 0x0a},
+ {0x018d, 0x0a},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x0309, 0x0a},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x07},
+ {0x0625, 0x80},
+ {0x0626, 0x04},
+ {0x0627, 0x38},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_1640_1232_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x0c},
+ {0x30eb, 0x05},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0164, 0x00},
+ {0x0165, 0x00},
+ {0x0166, 0x0c},
+ {0x0167, 0xcf},
+ {0x0168, 0x00},
+ {0x0169, 0x00},
+ {0x016a, 0x09},
+ {0x016b, 0x9f},
+ {0x016c, 0x06},
+ {0x016d, 0x68},
+ {0x016e, 0x04},
+ {0x016f, 0xd0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x01},
+ {0x0175, 0x01},
+ {0x018c, 0x0a},
+ {0x018d, 0x0a},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x0309, 0x0a},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x06},
+ {0x0625, 0x68},
+ {0x0626, 0x04},
+ {0x0627, 0xd0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+};
+
+static const char * const imx219_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Solid Color",
+ "Grey Color Bars",
+ "PN9"
+};
+
+static const int imx219_test_pattern_val[] = {
+ IMX219_TEST_PATTERN_DISABLE,
+ IMX219_TEST_PATTERN_COLOR_BARS,
+ IMX219_TEST_PATTERN_SOLID_COLOR,
+ IMX219_TEST_PATTERN_GREY_COLOR,
+ IMX219_TEST_PATTERN_PN9,
+};
+
+/* regulator supplies */
+static const char * const imx219_supply_name[] = {
+ /* Supplies can be enabled in any order */
+ "VANA", /* Analog (2.8V) supply */
+ "VDIG", /* Digital Core (1.8V) supply */
+ "VDDL", /* IF (1.2V) supply */
+};
+
+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
+
+/*
+ * Initialisation delay between XCLR low->high and the moment when the sensor
+ * can start capture (i.e. can leave software stanby) must be not less than:
+ * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>)
+ * where
+ * t4 is fixed, and is max 200uS,
+ * t5 is fixed, and is 6000uS,
+ * t6 depends on the sensor external clock, and is max 32000 clock periods.
+ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
+ * So for any acceptable external clock t6 is always within the range of
+ * 1185 to 5333 uS, and is always less than t5.
+ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
+ * initialize the sensor over I2C, and then exit the software standby.
+ *
+ * This start-up time can be optimized a bit more, if we start the writes
+ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
+ * initialization over I2C may complete before (t4+t5) expires, and we must
+ * ensure that capture is not started before (t4+t5).
+ *
+ * This delay doesn't account for the power supply startup time. If needed,
+ * this should be taken care of via the regulator framework. E.g. in the
+ * case of DT for regulator-fixed one should define the startup-delay-us
+ * property.
+ */
+#define IMX219_XCLR_MIN_DELAY_US 6200
+#define IMX219_XCLR_DELAY_RANGE_US 1000
+
+/* Mode configs */
+static const struct imx219_mode supported_modes[] = {
+ {
+ /* 8MPix 15fps mode */
+ .width = 3280,
+ .height = 2464,
+ .vts_def = IMX219_VTS_15FPS,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
+ .regs = mode_3280x2464_regs,
+ },
+ },
+ {
+ /* 1080P 30fps cropped */
+ .width = 1920,
+ .height = 1080,
+ .vts_def = IMX219_VTS_30FPS_1080P,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
+ .regs = mode_1920_1080_regs,
+ },
+ },
+ {
+ /* 2x2 binned 30fps mode */
+ .width = 1640,
+ .height = 1232,
+ .vts_def = IMX219_VTS_30FPS_BINNED,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
+ .regs = mode_1640_1232_regs,
+ },
+ },
+};
+
+struct imx219 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct clk *xclk; /* system clock to IMX219 */
+ u32 xclk_freq;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* V4L2 Controls */
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+
+ /* Current mode */
+ const struct imx219_mode *mode;
+
+ /*
+ * Mutex for serialized access:
+ * Protect sensor module set pad format and start/stop streaming safely.
+ */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx219, sd);
+}
+
+/* Read registers up to 2 at a time */
+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+ u8 data_buf[4] = { 0, };
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = ARRAY_SIZE(addr_buf);
+ msgs[0].buf = addr_buf;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_buf[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = get_unaligned_be32(data_buf);
+
+ return 0;
+}
+
+/* Write registers up to 2 at a time */
+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ u8 buf[6];
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+/* Write a list of registers */
+static int imx219_write_regs(struct imx219 *imx219,
+ const struct imx219_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "Failed to write reg 0x%4.4x. error = %d\n",
+ regs[i].address, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx219_get_format_code(struct imx219 *imx219)
+{
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ static const u32 codes[2][2] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
+ };
+
+ lockdep_assert_held(&imx219->mutex);
+ return codes[imx219->vflip->val][imx219->hflip->val];
+}
+
+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+ mutex_lock(&imx219->mutex);
+
+ /* Initialize try_fmt */
+ try_fmt->width = supported_modes[0].width;
+ try_fmt->height = supported_modes[0].height;
+ try_fmt->code = imx219_get_format_code(imx219);
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+}
+
+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx219 *imx219 =
+ container_of(ctrl->handler, struct imx219, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exposure_max, exposure_def;
+
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = imx219->mode->height + ctrl->val - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx219->exposure,
+ imx219->exposure->minimum,
+ exposure_max, imx219->exposure->step,
+ exposure_def);
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
+ IMX219_REG_VALUE_08BIT, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
+ IMX219_REG_VALUE_16BIT,
+ imx219_test_pattern_val[ctrl->val]);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
+ imx219->hflip->val |
+ imx219->vflip->val << 1);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = imx219_write_reg(imx219, IMX219_REG_VTS,
+ IMX219_REG_VALUE_16BIT,
+ imx219->mode->height + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_RED:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENR:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_BLUE:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENB:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ default:
+ dev_info(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
+ .s_ctrl = imx219_set_ctrl,
+};
+
+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+
+ /*
+ * Only one bayer order is supported (though it depends on the flip
+ * settings)
+ */
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = imx219_get_format_code(imx219);
+
+ return 0;
+}
+
+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != imx219_get_format_code(imx219))
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ fmt->colorspace,
+ fmt->ycbcr_enc);
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+}
+
+static void imx219_update_pad_format(struct imx219 *imx219,
+ const struct imx219_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.code = imx219_get_format_code(imx219);
+ fmt->format.field = V4L2_FIELD_NONE;
+
+ imx219_reset_colorspace(&fmt->format);
+}
+
+static int __imx219_get_pad_format(struct imx219 *imx219,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
+ /* update the code which could change due to vflip or hflip: */
+ try_fmt->code = imx219_get_format_code(imx219);
+ fmt->format = *try_fmt;
+ } else {
+ imx219_update_pad_format(imx219, imx219->mode, fmt);
+ }
+
+ return 0;
+}
+
+static int imx219_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ mutex_lock(&imx219->mutex);
+ ret = __imx219_get_pad_format(imx219, cfg, fmt);
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+}
+
+static int imx219_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ const struct imx219_mode *mode;
+ struct v4l2_mbus_framefmt *framefmt;
+ int exposure_max, exposure_def, hblank;
+
+ mutex_lock(&imx219->mutex);
+
+ /* Bayer order varies with flips */
+ fmt->format.code = imx219_get_format_code(imx219);
+
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+ imx219_update_pad_format(imx219, mode, fmt);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+ *framefmt = fmt->format;
+ } else if (imx219->mode != mode) {
+ imx219->mode = mode;
+ /* Update limits and set FPS to default */
+ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
+ IMX219_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+ __v4l2_ctrl_s_ctrl(imx219->vblank,
+ mode->vts_def - mode->height);
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = mode->vts_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx219->exposure,
+ imx219->exposure->minimum,
+ exposure_max, imx219->exposure->step,
+ exposure_def);
+ /*
+ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
+ * depends on mode->width only, and is not changeble in any
+ * way other than changing the mode.
+ */
+ hblank = IMX219_PPL_DEFAULT - mode->width;
+ __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
+ hblank);
+ }
+
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+}
+
+static int imx219_start_streaming(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ const struct imx219_reg_list *reg_list;
+ int ret;
+
+ /* Apply default values of current mode */
+ reg_list = &imx219->mode->reg_list;
+ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ return ret;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ /* set stream on register */
+ return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+}
+
+static void imx219_stop_streaming(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+
+ /* set stream off register */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+ if (ret)
+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
+}
+
+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&imx219->mutex);
+ if (imx219->streaming == enable) {
+ mutex_unlock(&imx219->mutex);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ goto err_unlock;
+ }
+
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = imx219_start_streaming(imx219);
+ if (ret)
+ goto err_rpm_put;
+ } else {
+ imx219_stop_streaming(imx219);
+ pm_runtime_put(&client->dev);
+ }
+
+ imx219->streaming = enable;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(imx219->vflip, enable);
+ __v4l2_ctrl_grab(imx219->hflip, enable);
+
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+err_unlock:
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+}
+
+/* Power/clock management functions */
+static int imx219_power_on(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
+ imx219->supplies);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(imx219->xclk);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to enable clock\n",
+ __func__);
+ goto reg_off;
+ }
+
+ gpiod_set_value_cansleep(imx219->reset_gpio, 1);
+ usleep_range(IMX219_XCLR_MIN_DELAY_US,
+ IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
+
+ return 0;
+
+reg_off:
+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+
+ return ret;
+}
+
+static int imx219_power_off(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ gpiod_set_value_cansleep(imx219->reset_gpio, 0);
+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+ clk_disable_unprepare(imx219->xclk);
+
+ return 0;
+}
+
+static int __maybe_unused imx219_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ if (imx219->streaming)
+ imx219_stop_streaming(imx219);
+
+ return 0;
+}
+
+static int __maybe_unused imx219_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ if (imx219->streaming) {
+ ret = imx219_start_streaming(imx219);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ imx219_stop_streaming(imx219);
+ imx219->streaming = 0;
+
+ return ret;
+}
+
+static int imx219_get_regulators(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ unsigned int i;
+
+ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
+ imx219->supplies[i].supply = imx219_supply_name[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ IMX219_NUM_SUPPLIES,
+ imx219->supplies);
+}
+
+/* Verify chip ID */
+static int imx219_identify_module(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+ u32 val;
+
+ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
+ IMX219_REG_VALUE_16BIT, &val);
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id %x\n",
+ IMX219_CHIP_ID);
+ return ret;
+ }
+
+ if (val != IMX219_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ IMX219_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx219_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx219_video_ops = {
+ .s_stream = imx219_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
+ .enum_mbus_code = imx219_enum_mbus_code,
+ .get_fmt = imx219_get_pad_format,
+ .set_fmt = imx219_set_pad_format,
+ .enum_frame_size = imx219_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx219_subdev_ops = {
+ .core = &imx219_core_ops,
+ .video = &imx219_video_ops,
+ .pad = &imx219_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
+ .open = imx219_open,
+};
+
+/* Initialize control handlers */
+static int imx219_init_controls(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ unsigned int height = imx219->mode->height;
+ int exposure_max, exposure_def, hblank;
+ int i, ret;
+
+ ctrl_hdlr = &imx219->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
+ if (ret)
+ return ret;
+
+ mutex_init(&imx219->mutex);
+ ctrl_hdlr->lock = &imx219->mutex;
+
+ /* By default, PIXEL_RATE is read only */
+ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ IMX219_PIXEL_RATE,
+ IMX219_PIXEL_RATE, 1,
+ IMX219_PIXEL_RATE);
+
+ /* Initial vblank/hblank/exposure parameters based on current mode */
+ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
+ IMX219_VTS_MAX - height, 1,
+ imx219->mode->vts_def - height);
+ hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
+ imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (imx219->hblank)
+ imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ exposure_max = imx219->mode->vts_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX219_EXPOSURE_MIN, exposure_max,
+ IMX219_EXPOSURE_STEP,
+ exposure_def);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
+ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
+ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
+
+ imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx219->hflip)
+ imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx219->vflip)
+ imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
+ 0, 0, imx219_test_pattern_menu);
+ for (i = 0; i < 4; i++) {
+ /*
+ * The assumption is that
+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+ */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_TEST_PATTERN_RED + i,
+ IMX219_TESTP_COLOUR_MIN,
+ IMX219_TESTP_COLOUR_MAX,
+ IMX219_TESTP_COLOUR_STEP,
+ IMX219_TESTP_COLOUR_MAX);
+ /* The "Solid color" pattern is white by default */
+ }
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ goto error;
+ }
+
+ imx219->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ mutex_destroy(&imx219->mutex);
+
+ return ret;
+}
+
+static void imx219_free_controls(struct imx219 *imx219)
+{
+ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
+ mutex_destroy(&imx219->mutex);
+}
+
+static int imx219_check_hwcfg(struct device *dev)
+{
+ struct v4l2_fwnode_endpoint *ep_cfg;
+ struct device_node *ep;
+ int ret = -EINVAL;
+
+ ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!ep) {
+ dev_err(dev, "missing endpoint node\n");
+ return -EINVAL;
+ }
+
+ ep_cfg = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep));
+ if (IS_ERR(ep_cfg)) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto error_out;
+ }
+
+ /* Check the number of MIPI CSI2 data lanes */
+ if (ep_cfg->bus.mipi_csi2.num_data_lanes != 2) {
+ dev_err(dev, "only 2 data lanes are currently supported\n");
+ goto error_out;
+ }
+
+ /* Check the link frequency set in device tree */
+ if (!ep_cfg->nr_of_link_frequencies) {
+ dev_err(dev, "link-frequency property not found in DT\n");
+ goto error_out;
+ }
+
+ if (ep_cfg->nr_of_link_frequencies != 1 ||
+ ep_cfg->link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
+ dev_err(dev, "Link frequency not supported: %lld\n",
+ ep_cfg->link_frequencies[0]);
+ goto error_out;
+ }
+
+ ret = 0;
+
+error_out:
+ v4l2_fwnode_endpoint_free(ep_cfg);
+ of_node_put(ep);
+
+ return ret;
+}
+
+static int imx219_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx219 *imx219;
+ int ret;
+
+ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
+ if (!imx219)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
+
+ /* Check the hardware configuration in device tree */
+ if (imx219_check_hwcfg(dev))
+ return -EINVAL;
+
+ /* Get system clock (xclk) */
+ imx219->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(imx219->xclk)) {
+ dev_err(dev, "failed to get xclk\n");
+ return PTR_ERR(imx219->xclk);
+ }
+
+ imx219->xclk_freq = clk_get_rate(imx219->xclk);
+ if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
+ imx219->xclk_freq);
+ return -EINVAL;
+ }
+
+ ret = imx219_get_regulators(imx219);
+ if (ret) {
+ dev_err(dev, "failed to get regulators\n");
+ return ret;
+ }
+
+ /* Request optional enable pin */
+ imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+
+ /*
+ * The sensor must be powered for imx219_identify_module()
+ * to be able to read the CHIP_ID register
+ */
+ ret = imx219_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = imx219_identify_module(imx219);
+ if (ret)
+ goto error_power_off;
+
+ /* Set default mode to max resolution */
+ imx219->mode = &supported_modes[0];
+
+ ret = imx219_init_controls(imx219);
+ if (ret)
+ goto error_power_off;
+
+ /* Initialize subdev */
+ imx219->sd.internal_ops = &imx219_internal_ops;
+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
+ if (ret) {
+ dev_err(dev, "failed to init entity pads: %d\n", ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
+ if (ret < 0) {
+ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* Enable runtime PM and turn off the device */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+error_media_entity:
+ media_entity_cleanup(&imx219->sd.entity);
+
+error_handler_free:
+ imx219_free_controls(imx219);
+
+error_power_off:
+ imx219_power_off(dev);
+
+ return ret;
+}
+
+static int imx219_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ imx219_free_controls(imx219);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ imx219_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ return 0;
+}
+
+static const struct of_device_id imx219_dt_ids[] = {
+ { .compatible = "sony,imx219" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
+
+static const struct dev_pm_ops imx219_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
+ SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
+};
+
+static struct i2c_driver imx219_i2c_driver = {
+ .driver = {
+ .name = "imx219",
+ .of_match_table = imx219_dt_ids,
+ .pm = &imx219_pm_ops,
+ },
+ .probe_new = imx219_probe,
+ .remove = imx219_remove,
+};
+
+module_i2c_driver(imx219_i2c_driver);
+
+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@...");
+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
+MODULE_LICENSE("GPL v2");
--
2.17.1


[PATCH 4.19.y-cip 12/40] media: dt-bindings: media: i2c: Add IMX219 CMOS sensor binding

Lad Prabhakar
 

From: Andrey Konovalov <andrey.konovalov@...>

commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream.

Add YAML device tree binding for IMX219 CMOS image sensor, and
the relevant MAINTAINERS entries.

Signed-off-by: Andrey Konovalov <andrey.konovalov@...>
Reviewed-by: Rob Herring <robh@...>
Signed-off-by: Sakari Ailus <sakari.ailus@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
[PL: manually applied changes to MAINTAINERS file]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
.../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++
MAINTAINERS | 8 ++
2 files changed, 122 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml

diff --git a/Documentation/devicetree/bindings/media/i2c/imx219.yaml b/Documentation/devicetree/bindings/media/i2c/imx219.yaml
new file mode 100644
index 000000000000..32d6b693274f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/imx219.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
+
+maintainers:
+ - Dave Stevenson <dave.stevenson@...>
+
+description: |-
+ The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor
+ with an active array size of 3280H x 2464V. It is programmable through
+ I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet.
+ Image data is sent through MIPI CSI-2, which is configured as either 2 or
+ 4 data lanes.
+
+properties:
+ compatible:
+ const: sony,imx219
+
+ reg:
+ description: I2C device address
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ VDIG-supply:
+ description:
+ Digital I/O voltage supply, 1.8 volts
+
+ VANA-supply:
+ description:
+ Analog voltage supply, 2.8 volts
+
+ VDDL-supply:
+ description:
+ Digital core voltage supply, 1.2 volts
+
+ reset-gpios:
+ description: |-
+ Reference to the GPIO connected to the xclr pin, if any.
+ Must be released (set high) after all supplies are applied.
+
+ # See ../video-interfaces.txt for more details
+ port:
+ type: object
+ properties:
+ endpoint:
+ type: object
+ properties:
+ data-lanes:
+ description: |-
+ The sensor supports either two-lane, or four-lane operation.
+ If this property is omitted four-lane operation is assumed.
+ For two-lane operation the property must be set to <1 2>.
+ items:
+ - const: 1
+ - const: 2
+
+ clock-noncontinuous:
+ type: boolean
+ description: |-
+ MIPI CSI-2 clock is non-continuous if this property is present,
+ otherwise it's continuous.
+
+ link-frequencies:
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint64-array
+ description:
+ Allowed data bus frequencies.
+
+ required:
+ - link-frequencies
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - VANA-supply
+ - VDIG-supply
+ - VDDL-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ imx219: sensor@10 {
+ compatible = "sony,imx219";
+ reg = <0x10>;
+ clocks = <&imx219_clk>;
+ VANA-supply = <&imx219_vana>; /* 2.8v */
+ VDIG-supply = <&imx219_vdig>; /* 1.8v */
+ VDDL-supply = <&imx219_vddl>; /* 1.2v */
+
+ port {
+ imx219_0: endpoint {
+ remote-endpoint = <&csi1_ep>;
+ data-lanes = <1 2>;
+ clock-noncontinuous;
+ link-frequencies = /bits/ 64 <456000000>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 1061db6fbc32..47986d4b599a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13565,6 +13565,14 @@ S: Maintained
F: drivers/ssb/
F: include/linux/ssb/

+SONY IMX219 SENSOR DRIVER
+M: Dave Stevenson <dave.stevenson@...>
+L: linux-media@...
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/imx219.c
+F: Documentation/devicetree/bindings/media/i2c/imx219.yaml
+
SONY IMX258 SENSOR DRIVER
M: Sakari Ailus <sakari.ailus@...>
L: linux-media@...
--
2.17.1


[PATCH 4.19.y-cip 11/40] media: rcar-csi2: Add support for MEDIA_BUS_FMT_SRGGB8_1X8 format

Lad Prabhakar
 

commit 675616554d0a5caff138008ee9bd4623bc4390b2 upstream.

This patch adds support for MEDIA_BUS_FMT_SRGGB8_1X8 format for CSI2
input.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 1c910fdbf4c0..e6a531c4fde5 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -315,6 +315,7 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = {
{ .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 },
+ { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 },
};

static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
--
2.17.1


[PATCH 4.19.y-cip 10/40] media: rcar-vin: Add support for MEDIA_BUS_FMT_SRGGB8_1X8 format

Lad Prabhakar
 

commit e87c1a81f158d6fc7b3346eb88c2d76a044f837d upstream.

Add support for MEDIA_BUS_FMT_SRGGB8_1X8 format in rcar-vin by setting
format type to RAW8 in VNMC register and appropriately setting the bpp
and bytesperline to enable V4L2_PIX_FMT_SRGGB8.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
[PL: manually applied the changes; rvin_parallel_subdevice_attach()
updated to handle MEDIA_BUS_FMT_SRGGB8_1X8 format; VNIS_REG is set
accordingly in rvin_crop_scale_comp() for V4L2_PIX_FMT_SRGGB8]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-core.c | 1 +
drivers/media/platform/rcar-vin/rcar-dma.c | 9 +++++++++
drivers/media/platform/rcar-vin/rcar-v4l2.c | 4 ++++
3 files changed, 14 insertions(+)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index bd298bbbc48d..79d1a8a730ad 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -447,6 +447,7 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
case MEDIA_BUS_FMT_UYVY8_2X8:
case MEDIA_BUS_FMT_UYVY10_2X10:
case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
vin->mbus_code = code.code;
vin_dbg(vin, "Found media bus format for %s: %d\n",
subdev->name, vin->mbus_code);
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 5bab9f8159f6..0d56957a54cc 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -85,6 +85,7 @@
#define VNMC_INF_YUV8_BT601 (1 << 16)
#define VNMC_INF_YUV10_BT656 (2 << 16)
#define VNMC_INF_YUV10_BT601 (3 << 16)
+#define VNMC_INF_RAW8 (4 << 16)
#define VNMC_INF_YUV16 (5 << 16)
#define VNMC_INF_RGB888 (6 << 16)
#define VNMC_VUP (1 << 10)
@@ -599,6 +600,8 @@ void rvin_crop_scale_comp(struct rvin_dev *vin)

if (vin->format.pixelformat == V4L2_PIX_FMT_NV16)
rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG);
+ else if (vin->format.pixelformat == V4L2_PIX_FMT_SRGGB8)
+ rvin_write(vin, ALIGN(vin->format.width / 2, 0x10), VNIS_REG);
else
rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG);
}
@@ -677,6 +680,9 @@ static int rvin_setup(struct rvin_dev *vin)

input_is_yuv = true;
break;
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ vnmc |= VNMC_INF_RAW8;
+ break;
default:
break;
}
@@ -730,6 +736,9 @@ static int rvin_setup(struct rvin_dev *vin)
/* Note: not supported on M1 */
dmr = VNDMR_EXRGB;
break;
+ case V4L2_PIX_FMT_SRGGB8:
+ dmr = 0;
+ break;
default:
vin_err(vin, "Invalid pixelformat (0x%x)\n",
vin->format.pixelformat);
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 1236e6e8228c..c07e57f707ec 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -54,6 +54,10 @@ static const struct rvin_video_format rvin_formats[] = {
.fourcc = V4L2_PIX_FMT_XBGR32,
.bpp = 4,
},
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .bpp = 1,
+ },
};

const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat)
--
2.17.1


[PATCH 4.19.y-cip 09/40] media: rcar-vin: Invalidate pipeline if conversion is not possible on input formats

Lad Prabhakar
 

commit fd22e8eb4145852223b36b0e6c7e308ed5905ad2 upstream.

Up until now the VIN was capable to convert any of its supported input mbus
formats to any of it's supported output pixel formats. With the addition of
RAW formats this is no longer true.

This patch invalidates the pipeline by adding a check if given vin input
format can be converted to supported output pixel format.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@...>
[PL: dropped changes from rvin_enum_fmt_vid_cap()]
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-dma.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index e51620c6cc40..5bab9f8159f6 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1042,11 +1042,15 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
case MEDIA_BUS_FMT_UYVY8_2X8:
case MEDIA_BUS_FMT_UYVY10_2X10:
case MEDIA_BUS_FMT_RGB888_1X24:
- vin->mbus_code = fmt.format.code;
+ break;
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8)
+ return -EPIPE;
break;
default:
return -EPIPE;
}
+ vin->mbus_code = fmt.format.code;

switch (fmt.format.field) {
case V4L2_FIELD_TOP:
--
2.17.1


[PATCH 4.19.y-cip 08/40] media: rcar-csi2: Update V3M and E3 start procedure

Lad Prabhakar
 

From: Niklas Söderlund <niklas.soderlund+renesas@...>

commit c1421f1d6c29d6b6234e5b0894ef16b3f2a172e0 upstream.

The latest datasheet (rev 1.50) updates the start procedure for V3M and
E3. Update the driver to match these changes.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Ulrich Hecht <uli+renesas@...>
Reviewed-by: Laurent Pinchart <laurent.pinchart@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 007e2383d34e..1c910fdbf4c0 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -898,11 +898,11 @@ static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps)
static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv)
{
static const struct phtw_value step1[] = {
- { .data = 0xed, .code = 0x34 },
- { .data = 0xed, .code = 0x44 },
- { .data = 0xed, .code = 0x54 },
- { .data = 0xed, .code = 0x84 },
- { .data = 0xed, .code = 0x94 },
+ { .data = 0xee, .code = 0x34 },
+ { .data = 0xee, .code = 0x44 },
+ { .data = 0xee, .code = 0x54 },
+ { .data = 0xee, .code = 0x84 },
+ { .data = 0xee, .code = 0x94 },
{ /* sentinel */ },
};

--
2.17.1


[PATCH 4.19.y-cip 07/40] media: rcar-vin: fix wrong return value in rvin_set_channel_routing()

Lad Prabhakar
 

From: Niklas Söderlund <niklas.soderlund+renesas@...>

commit 8d19d5d03b4d09177b0ae87f964eb751e6f51b7b upstream.

If the operation in rvin_set_channel_routing() is successful the 'ret'
variable contains the runtime PM use count for the VIN master device.
The intention is not to return the use count to the caller but to return
0 on success else none zero.

Fix this by always returning 0 if the operation is successful.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@...>
Reviewed-by: Laurent Pinchart <laurent.pinchart@...>
Signed-off-by: Hans Verkuil <hverkuil-cisco@...>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@...>
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...>
---
drivers/media/platform/rcar-vin/rcar-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 70a8cc433a03..e51620c6cc40 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1343,5 +1343,5 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)

pm_runtime_put(vin->dev);

- return ret;
+ return 0;
}
--
2.17.1

2961 - 2980 of 9202