> For the complete documentation index, see [llms.txt](https://auvidea.gitbook.io/j20/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://auvidea.gitbook.io/j20/manual/camera-adaptation.md).

# Camera adaptation

{% hint style="info" %}
This page is only for experienced users. It requires knowledge and experience about the following topics:

* Kernel development
* Devicetree syntax

The [Nvidia forum](https://forums.developer.nvidia.com/c/agx-autonomous-machines/jetson-embedded-systems/70) and its documentation about the Jetson family is a good way to get started with those kinds of work. You may start with taking a look at the [Camera Adaption](https://docs.nvidia.com/jetson/archives/r35.3.1/DeveloperGuide/text/SD/CameraDevelopment.html) Guide from Nvidia.
{% endhint %}

{% hint style="info" %}
Auvidea can also provide a quote, if you need a custom devicetree for your CSI camera on the J20, if needed. Contact <sales@auvidea.eu> or <support@auvidea.eu> for more information.
{% endhint %}

## Implementing GPIO extender

The GPIO expander populated on the J20 is used to control the `mclock` and `power-down` GPIO's on each CSI connector. Auvidea recommends implementing this chip in the Devicetree as GPIO-Chip in order to use those GPIO's directly as `reset-gpio` in the camera device node.&#x20;

<table><thead><tr><th width="152">GPIO</th><th>Note</th></tr></thead><tbody><tr><td>P15</td><td>CAM_A_PWDN</td></tr><tr><td>P14</td><td>CAM_B_PWDN</td></tr><tr><td>P13</td><td>CAM_A_MCLK</td></tr><tr><td>P12</td><td>CAM_B_MCLK</td></tr><tr><td>P11</td><td>CAM_C_PWDN</td></tr><tr><td>P10</td><td>CAM_D_PWDN</td></tr><tr><td>P9</td><td>CAM_C_MCLK</td></tr><tr><td>P8</td><td>CAM_D_MCLK</td></tr><tr><td>P7</td><td>CAM_E_PWDN</td></tr><tr><td>P6</td><td>CAM_F_PWDN</td></tr><tr><td>P5</td><td>CAM_E_MCLK</td></tr><tr><td>P4</td><td>CAM_F_MCLK</td></tr><tr><td>P3</td><td>Not connected</td></tr><tr><td>P2</td><td>Not connected</td></tr><tr><td>P1</td><td>Not connected</td></tr><tr><td>P0</td><td>LED_GPIO</td></tr></tbody></table>

<figure><img src="/files/6yUTn9vjP6Z4avJNBorB" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="Devicetree implementation" %}
Represented in the device tree for the AGX Orin would look like this:&#x20;

{% code title="j20\_port\_extender.dtsi" lineNumbers="true" %}

```cpp
/*
 * Copyright (c) 2023, AUVIDEA. All rights reserved.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or any
 * later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 */

/ {
	i2c@3180000 {
		tca6416_cam: cam_gpio_expander@20 {
			compatible = "ti,tca6416";
			reg = <0x20>;
			gpio-controller;
			#gpio-cells = <2>;
 
			led {
				gpio-hog;
				gpios = <0 0>;
				output-low;
				line-name = "led";
			};

			cam_g_rst {
				gpio-hog;
				gpios = <6 0>;
				output-high;
				line-name = "cam_g_mclk";
			};
			cam_g_pwdn {
				gpio-hog;
				gpios = <4 0>;
				output-low;
				line-name = "cam_g_pwdn";
			};
			cam_e_rst {
				gpio-hog;
				gpios = <7 0>;
				output-high;
				line-name = "cam_e_mclk";
			};
			cam_e_pwdn {
				gpio-hog;
				gpios = <5 0>;
				output-low;
				line-name = "cam_e_pwdn";
			};
			cam_d_rst {
				gpio-hog;
				gpios = <10 0>;
				output-high;
				line-name = "cam_d_mclk";
			};
			cam_d_pwdn {
				gpio-hog;
				gpios = <8 0>;
				output-low;
				line-name = "cam_d_pwdn";
			};
			cam_c_rst {
				gpio-hog;
				gpios = <11 0>;
				output-high;
				line-name = "cam_c_mclk";
			};
			cam_c_pwdn {
				gpio-hog;
				gpios = <9 0>;
				output-low;
				line-name = "cam_c_pwdn";
			};
			cam_b_rst {
				gpio-hog;
				gpios = <14 0>;
				output-high;
				line-name = "cam_b_mclk";
			};
			cam_b_pwdn {
				gpio-hog;
				gpios = <12 0>;
				output-low;
				line-name = "cam_b_pwdn";
			};
			cam_a_rst {
				gpio-hog;
				gpios = <15 0>;
				output-high;
				line-name = "cam_a_mclk";
			};
			cam_a_pwdn {
				gpio-hog;
				gpios = <13 0>;
				output-low;
				line-name = "cam_a_pwdn";
			};
		};
	};
};
```

{% endcode %}

Each camera node (if the driver supports this feature) contains a reset-gpio that can be assinged to one of the implemented GPIO's in the code above. An example usage of one of those GPIO's can be found in the following code in the `reset-gpio` property.&#x20;

{% code title="imx219.dtsi" lineNumbers="true" %}

```cpp
[...]
	i2c@31e0000 {
		rbpcv2_imx219_a@10 {
			status="okay";
			compatible = "sony,imx219";
			reg = <0x10>;
			
			// Here is the GPIO of the gpio epander used as reset-gpio
			reset-gpios = <&tca6416_cam 15 GPIO_ACTIVE_HIGH>;

			devnode = "video0";

			physical_w = "3.680";
			physical_h = "2.760";

			sensor_model = "imx219";

			use_sensor_mode_id = "true";

			mode0 { // IMX219_MODE_3280x2464_21FPS //
				mclk_khz = "24000";
				num_lanes = "2";
				tegra_sinterface = "serial_a";
[...]
```

{% endcode %}
{% endtab %}

{% tab title="Raw access implementation" %}

### Port configuration register

`0`: Output  \
`1`: Input

<table><thead><tr><th width="104">P7</th><th width="85">P6</th><th width="80">P5</th><th width="82">P4</th><th width="81">P3</th><th width="82">P2</th><th width="84">P1</th><th>P0</th></tr></thead><tbody><tr><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>1</td><td>1</td><td>0</td></tr></tbody></table>

`i2cset -y -f 2 0x20 0x06 0x0e`

<table><thead><tr><th width="99">P8</th><th width="83">P9</th><th width="81">P10</th><th width="82">P12</th><th width="88">P11</th><th width="84">P10</th><th width="83">P9</th><th>P8</th></tr></thead><tbody><tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr></tbody></table>

`i2cset -y -f 2 0x20 0x07 0x00`

### Port output register

`0`: Logical HIGH \
`1`: Logical LOW

Input pins will be ignored by this setting

<table><thead><tr><th width="107">P7</th><th width="84">P6</th><th width="84">P5</th><th width="82">P4</th><th width="79">P3</th><th width="81">P2</th><th width="82">P1</th><th>P0</th></tr></thead><tbody><tr><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr></tbody></table>

`i2cset -y -f 2 0x20 0x02 0xff`

<table><thead><tr><th width="112">P8</th><th width="83">P9</th><th width="82">P10</th><th width="81">P12</th><th width="81">P11</th><th width="81">P10</th><th width="77">P9</th><th>P8</th></tr></thead><tbody><tr><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr></tbody></table>

`i2cset -y -f 2 0x20 0x03 0xff`

### Script

<pre class="language-bash" data-title="enable_imx219.sh" data-line-numbers><code class="lang-bash">#!/bin/bash

# Port configuration register

# 0: Output
# 1: Input

# | P7  | P6  | P5  | P4  | P3  | P2  | P1  | P0  |
# | --- | --- | --- | --- | --- | --- | --- | --- |
# | 0   | 0   | 0   | 0   | 1   | 1   | 1   | 0   |

i2cset -y -f 2 0x20 0x06 0x0e

# | P8  | P9  | P10 | P12 | P11 | P10 | P9  | P8  |
# | --- | --- | --- | --- | --- | --- | --- | --- |
<strong># | 0   | 0   | 0   | 0   | 0   | 0   | 0   | 0   |
</strong>
i2cset -y -f 2 0x20 0x07 0x00

# Port output register

# 0: Logical HIGH
# 1: Logical LOW

# (Input pins will be ignored)

# | P7  | P6  | P5  | P4  | P3  | P2  | P1  | P0  |
# | --- | --- | --- | --- | --- | --- | --- | --- |
# | 1   | 1   | 1   | 1   | 1   | 1   | 1    | 1  |

i2cset -y -f 2 0x20 0x02 0xff

# | P8  | P9  | P10 | P12 | P11 | P10 | P9  | P8  |
# | --- | --- | --- | --- | --- | --- | --- | --- |
# | 1   | 1   | 1   | 1   | 1   | 1   | 1    | 1  |

i2cset -y -f 2 0x20 0x03 0xff
</code></pre>

{% endtab %}
{% endtabs %}

## CSI-Routing

{% hint style="info" %}
The following documentation assumes that you are comfortable with the CSI/VI interface from the Nvidia Jetson family&#x20;
{% endhint %}

{% tabs %}
{% tab title="AGX-Orin Devkit" %}

<figure><img src="/files/3h7hKtG9UV6xXNsu5rvQ" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="AGX-Xavier Devkit" %}

<figure><img src="/files/aDpBS1PVeoyyVwgFInCs" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="TX1-Devkit" %}

<figure><img src="/files/CENGDBaluZhJjnZYRsed" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

### Example CSI/VI implementation

The following example CSI/VI devicetree would implement the J20 on the AGX Orin Devkit

{% hint style="info" %}
The TX1-Devkit uses a different CSI-Lanes than the AGX-Xavier and AGX-Orin Devkit as shown above. \
-> There might be some differences in the Devicetree implementation for the AGX-Orin Devkit.&#x20;
{% endhint %}

{% code title="tegra234-p3737-0000-camera-vicsi-imx219-J20.dtsi" lineNumbers="true" %}

```c
/ {
	tegra-capture-vi {
		status = "okay";
		num-channels = <6>;
		ports {
			status = "okay";
			#address-cells = <1>;
			#size-cells = <0>;
			port@0 { // CSI A
				status="okay";
				reg = <0>;
				imx219_vi_in0: endpoint {
					status="okay";
					port-index = <0>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out0>;
				};
			};
			port@1 { // CSI B
				status="okay";
				reg = <1>;
				imx219_vi_in1: endpoint {
					status="okay";
					port-index = <1>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out1>;
				};
			};
			port@2 { // CSI C
				status="okay";
				reg = <2>;
				imx219_vi_in2: endpoint {
					status="okay";
					port-index = <2>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out2>;
				};
			};
			port@3 { // CSI D
				status="okay";
				reg = <3>;
				imx219_vi_in3: endpoint {
					status="okay";
					port-index = <3>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out3>;
				};
			};
			port@4 { // CSI E
				status="okay";
				reg = <4>;
				imx219_vi_in4: endpoint {
					status="okay";
					port-index = <4>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out4>;
				};
			};
			port@5 { // CSI G
				status="okay";
				reg = <5>;
				imx219_vi_in6: endpoint {
					status="okay";
					port-index = <5>;
					bus-width = <2>;
					remote-endpoint = <&imx219_csi_out6>;
				};
			};
		};
	};

	host1x@13e00000 {
		nvcsi@15a00000 {
			status = "okay";
			num-channels = <6>;
			#address-cells = <1>;
			#size-cells = <0>;
			channel@0 { // CSI A
				reg = <0>;
				ports {
					status="okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						status="okay";
						imx219_csi_in0: endpoint@0 {
							port-index = <0>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out0>;
							status="okay";
						};
					};
					port@1 {
						reg = <1>;
						status="okay";
						imx219_csi_out0: endpoint@1 {
							remote-endpoint = <&imx219_vi_in0>;
							status="okay";
						};
					};
				};
			};
			channel@1 {// CSI B
				reg = <1>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						imx219_csi_in1: endpoint@2 {
							port-index = <1>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out1>;
						};
					};
					port@1 {
						reg = <1>;
						imx219_csi_out1: endpoint@3 {
							remote-endpoint = <&imx219_vi_in1>;
						};
					};
				};
			};
			channel@2 { // CSI C
				reg = <2>;
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						imx219_csi_in2: endpoint@4 {
							port-index = <2>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out2>;
						};
					};
					port@1 {
						reg = <1>;
						imx219_csi_out2: endpoint@5 {
							remote-endpoint = <&imx219_vi_in2>;
						};
					};
				};
			};
			channel@3 { // CSI D
				reg = <3>;
				ports {
					status="okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						status="okay";
						imx219_csi_in3: endpoint@6 {
							port-index = <3>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out3>;
							status="okay";
						};
					};
					port@1 {
						reg = <1>;
						status="okay";
						imx219_csi_out3: endpoint@7 {
							remote-endpoint = <&imx219_vi_in3>;
							status="okay";
						};
					};
				};
			};
			channel@4 { // CSI E
				reg = <4>;
				ports {
					status="okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						status="okay";
						imx219_csi_in4: endpoint@8 {
							port-index = <4>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out4>;
							status="okay";
						};
					};
					port@1 {
						reg = <1>;
						status="okay";
						imx219_csi_out4: endpoint@9 {
							remote-endpoint = <&imx219_vi_in4>;
							status="okay";
						};
					};
				};
			};
			channel@5 { // CSI G
				reg = <5>;
				ports {
					status="okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						reg = <0>;
						status="okay";
						imx219_csi_in6: endpoint@10 {
							port-index = <6>;
							bus-width = <2>;
							remote-endpoint = <&imx219_out6>;
							status="okay";
						};
					};
					port@1 {
						reg = <1>;
						status="okay";
						imx219_csi_out6: endpoint@11 {
							remote-endpoint = <&imx219_vi_in6>;
							status="okay";
						};
					};
				};
			};
		};
	};
};
```

{% endcode %}
