TCA9546 not detecting all the sensors

Hello,

I’m using a setup with 4 GMSL2 cameras and TCA9546 module from Leopard Imaging (LI JXAV 4 CAM ADPT), the driver and the 4 cameras are working correctly with JetPack 4.x and all the 4 cameras are detected in i2c buses 30, 31, 32 and 33
I ported the driver and device tree into Jetpack 5.x i’m able to capture perfectly mipi data, but i’m only able to detect the sensor in i2c busses 30 and 32, and the same sensors are not detected in i2c busses 31 and 33 as the following

To summarize :
J1 ==> i2c-30 ==> Bus created and cameras slaves address are detected
J2 ==> i2c-31 ==> Bus created and cameras slaves address are NOT detected
J3 ==> i2c-32 ==> Bus created and cameras slaves address are detected
J4 ==> i2c-33 ==> Bus created and cameras slaves address are NOT detected

I’m wondering if the TCA9546 is not correctly configured, you can check my device tree at the bottom of this topic

# Not detected camera
jetson@jetson-desktop:~$ i2cdetect -r -y 31
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: UU -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
50: -- -- -- -- 54 -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- --               

# Detected camera          
jetson@jetson-desktop:~$ i2cdetect -r -y 30
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: UU -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
50: 50 -- -- -- 54 -- -- -- 58 -- -- -- -- -- -- -- 
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- --

I also updated my device tree by following imx390 sensor in Jetpack 5.x

/*
 * Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <t19x-common-modules/tegra194-camera-ar0820-a00.dtsi>
#include "dt-bindings/clock/tegra194-clock.h"

#define CAM0_RST_L	TEGRA194_MAIN_GPIO(H, 3)
#define CAM0_PWDN	TEGRA194_MAIN_GPIO(H, 6)
#define CAM1_RST_L	TEGRA194_MAIN_GPIO(T, 6)
#define CAM1_PWDN	TEGRA194_MAIN_GPIO(T, 5)
#define SLVS_CAM0_RST_L	TEGRA194_MAIN_GPIO(Y, 1)
#define CAMERA_I2C_MUX_BUS(x) (0x1E + x)

/* camera control gpio definitions */

/ {

	/* set camera gpio direction to output */
	gpio@2200000 {
		camera-control-output-low {
			status = "okay";
			gpio-hog;
			output-low;
			gpios = <CAM0_RST_L 0 CAM0_PWDN 0
				 CAM1_RST_L 0 CAM1_PWDN 0
				 SLVS_CAM0_RST_L 0>;
			label = "cam0-rst", "cam0-pwdn",
				"cam1-rst", "cam1-pwdn",
				"slvs-cam0-rst";
		};
	};
	
	i2c@3180000 {
		tca9546@70 {
			status = "okay";
			compatible = "nxp,pca9546";
			reg = <0x70>;
			#address-cells = <1>;
			#size-cells = <0>;
			skip_mux_detect = "yes";
			vif-supply = <&p2822_vdd_1v8_cvb>;
			vcc-supply = <&p2822_vdd_1v8_cvb>;
			vcc-pullup-supply = <&battery_reg>;
			force_bus_start = <CAMERA_I2C_MUX_BUS(0)>;

			i2c@0 {
				reg = <0>;
				i2c-mux,deselect-on-exit;
				#address-cells = <1>;
				#size-cells = <0>;
				dser_a: max9296@48 {
					compatible = "maxim,max9296";
					reg = <0x48>;
					csi-mode = "2x4";
					max-src = <2>;
					reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
				};
				ser_a: max9295@40 {
				    compatible = "maxim,max9295";
				    reg = <0x40>;
				};

				ar0820_a@10 {
					def-addr = <0x10>;
					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
							<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
					clock-names = "extperiph1", "pllp_grtba";
					mclk = "extperiph1";
					nvidia,gmsl-ser-device = <&ser_a>;
					nvidia,gmsl-dser-device = <&dser_a>;
				};

			};


			i2c@1 {
				reg = <1>;
				i2c-mux,deselect-on-exit;
				#address-cells = <1>;
				#size-cells = <0>;
				dser_c: max9296@48 {
					compatible = "maxim,max9296";
					reg = <0x48>;
					csi-mode = "2x4";
					max-src = <2>;
					reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
				};
				ser_c: max9295@40 {
				    compatible = "maxim,max9295";
				    reg = <0x40>;
				};

				ar0820_c@10 {
					def-addr = <0x10>;
					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
							<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
					clock-names = "extperiph1", "pllp_grtba";
					mclk = "extperiph1";
					nvidia,gmsl-ser-device = <&ser_c>;
					nvidia,gmsl-dser-device = <&dser_c>;
				};

			};

			i2c@2 {
				reg = <2>;
				i2c-mux,deselect-on-exit;
				#address-cells = <1>;
				#size-cells = <0>;
				dser_e: max9296@48 {
					compatible = "maxim,max9296";
					reg = <0x48>;
					csi-mode = "2x4";
					max-src = <2>;
					reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
				};
				ser_e: max9295@40 {
				    compatible = "maxim,max9295";
				    reg = <0x40>;
				};

				ar0820_e@10 {
					def-addr = <0x10>;
					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
							<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
					clock-names = "extperiph1", "pllp_grtba";
					mclk = "extperiph1";
					nvidia,gmsl-ser-device = <&ser_e>;
					nvidia,gmsl-dser-device = <&dser_e>;
				};

			};

			i2c@3 {
				reg = <3>;
				i2c-mux,deselect-on-exit;
				#address-cells = <1>;
				#size-cells = <0>;
				dser_g: max9296@48 {
					compatible = "maxim,max9296";
					reg = <0x48>;
					csi-mode = "2x4";
					max-src = <2>;
					reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
				};
				ser_g: max9295@40 {
				    compatible = "maxim,max9295";
				    reg = <0x40>;
				};

				ar0820_g@10 {
					def-addr = <0x10>;
					/* Define any required hw resources needed by driver */
					/* ie. clocks, io pins, power sources */
					clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
							<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
					clock-names = "extperiph1", "pllp_grtba";
					mclk = "extperiph1";
					nvidia,gmsl-ser-device = <&ser_g>;
					nvidia,gmsl-dser-device = <&dser_g>;
				};

			};
		};
	};
};

Is there any reason why i’m not able to detect the cameras in i2c busses 31 and 33 ?

Thanks

Please check the kernel message to check if imx390 probe for each bus to know more information.

Hi @ShaneCCC

I am using ar0820 sensor, and yes it’s probing for each bus, i think the problem come from mux in fact that even if the the sensor is not probing, the address of the deserializer max9296 should appear in each bus when scanning this latters.

Is there any particular configuration in JetPack 5.x to make the 4 i2c busses working correctly ?

Thanks

No, there’s no particular configuration for the MUX driver only the start bus,

force_bus_start = <CAMERA_I2C_MUX_BUS(0)>;

Did you see the (31,33) sensor driver probe? Any error?

@ShaneCCC

That my dmseg logs for the mux the ar0820 for 4 I2C busses

As you can see, there is the 4 i2c busses, i pluged 2 cameras, the one on i2c-30 is working perfectly, i am able to start a stream but the one in i2c-31 is not even detected

jetson@jetson-desktop:~$ sudo dmesg | grep pca
[sudo] password for jetson: 
[    7.922375] pca954x 2-0070: [PCA954x] probing
[    7.931967] pca954x 2-0070: pca954x_probe: forcing device bus number, start 30.
[    7.938746] pca954x 2-0070: device detect skipped.
[    8.111479] pca954x 2-0070: registered 4 multiplexed busses for I2C switch pca9546
jetson@jetson-desktop:~$ sudo dmesg | grep ar0820
[    7.945124] ar0820 30-0010: probing v4l2 sensor.
[    7.948747] ar0820 30-0010: tegracam sensor driver:ar0820_v2.0.6
[    7.954226] ar0820 30-0010: board setup failed
[    7.986723] ar0820 31-0010: probing v4l2 sensor.
[    7.990237] ar0820 31-0010: tegracam sensor driver:ar0820_v2.0.6
[    7.995937] ar0820 31-0010: board setup failed
[    8.028502] ar0820 32-0010: probing v4l2 sensor.
[    8.032213] ar0820 32-0010: tegracam sensor driver:ar0820_v2.0.6
[    8.037955] ar0820 32-0010: board setup failed
[    8.070855] ar0820 33-0010: probing v4l2 sensor.
[    8.074247] ar0820 33-0010: tegracam sensor driver:ar0820_v2.0.6
[    8.080105] ar0820 33-0010: board setup failed
[    8.541543] ar0820 30-0010: probing v4l2 sensor.
[    8.551042] debugfs: Directory 'ar0820_a' with parent '/' already present!
[    8.561986] ar0820 30-0010: tegracam sensor driver:ar0820_v2.0.6
[    8.943565] tegra-camrtc-capture-vi tegra-capture-vi: subdev ar0820 30-0010 bound
[    8.945264] ar0820 30-0010: Detected AR0820 sensor
[    9.162727] ar0820 31-0010: probing v4l2 sensor.
[    9.164481] debugfs: Directory 'ar0820_c' with parent '/' already present!
[    9.166154] ar0820 31-0010: tegracam sensor driver:ar0820_v2.0.6
[    9.319747] ar0820 31-0010: gmsl serializer setup failed
[    9.320858] ar0820 31-0010: ar0820_probe gmsl serdes setup failed
[    9.322113] ar0820: probe of 31-0010 failed with error -110
[    9.323293] ar0820 32-0010: probing v4l2 sensor.
[    9.324523] debugfs: Directory 'ar0820_e' with parent '/' already present!
[    9.325700] ar0820 32-0010: tegracam sensor driver:ar0820_v2.0.6
[    9.533356] ar0820 32-0010: gmsl serializer setup failed
[    9.534266] ar0820 32-0010: ar0820_probe gmsl serdes setup failed
[    9.535285] ar0820: probe of 32-0010 failed with error -110
[    9.536280] ar0820 33-0010: probing v4l2 sensor.
[    9.537289] debugfs: Directory 'ar0820_f' with parent '/' already present!
[    9.538433] ar0820 33-0010: tegracam sensor driver:ar0820_v2.0.6
[    9.746656] ar0820 33-0010: gmsl serializer setup failed
[    9.747400] ar0820 33-0010: ar0820_probe gmsl serdes setup failed
[    9.748190] ar0820: probe of 33-0010 failed with error -110

I think it’s HW issue instead of software cause the i2c unable detected.

@ShaneCCC I exchanged the MIPI board (Mux) and cameras, and also i switched to another Jetson, and still the same issue, i really think that is a software problem related to drivers or device tree…

@SimonZhu
Could you provide the driver for J5.1.1?

Thanks

@chakibdace
Are you using below camera kit?

  1. Nvidia Jetson AGX Xavier Developer kit x 1
  2. LI-AR0820-GMSL2 x 4
  3. LI-JXAV-MIPI-ADPT-4CAM x 1
  4. FAW-1233-03 x 4
  5. LI-GMSL2-IPX-DESER x 4

@SimonZhu

Yes, i’ve seen that there is no release yet for LI AR0280 camera for JetPack, but i needed to port the driver to JetPack 5.x
It’s working perfectly for 2 cameras, but as you can see in this topic, the cameras are not being detected in i2c-31 and i2c-33.
And i am wondering if it’s related to tca9546 mux config in the DT

If MAX9296 is not detected On the 31 and 33 buses, but 30 and 32 are, it is most likely due to Reset, and you can add some delay to the Power On/Off of MAX9296.

In addition, please check again whether your device tree is correct. If possible, you can provide me with your device tree and Max9295.c.

@chakibdace
Please try the suggestions from zwc.

@leopard-zwc, I see, but i’m wondering why it has not this behavior in JetPack 4.x, but it has in JetPack 5.x

You can have the mode file dtsi below


/ {

	tegra-capture-vi {
		status = "okay";
		num-channels = <4>;
		ports {
			#address-cells = <1>;
			#size-cells = <0>;
			port@0 {
				status = "okay";
				reg = <0>;
				ar0820_vi_in0: endpoint {
					status = "okay";
					port-index = <0>;
					bus-width = <4>;
					remote-endpoint = <&ar0820_csi_out0>;
				};
			};

			port@1 {
				status = "okay";
				reg = <1>;
				ar0820_vi_in1: endpoint {
					status = "okay";
					port-index = <2>;
					bus-width = <4>;
					remote-endpoint = <&ar0820_csi_out1>;
				};
			};

			port@2 {
				status = "okay";
				reg = <2>;
				ar0820_vi_in2: endpoint {
					status = "okay";
					port-index = <4>;
					bus-width = <4>;
					remote-endpoint = <&ar0820_csi_out2>;
				};


			port@3 {
				status = "okay";
				reg = <3>;
				ar0820_vi_in3: endpoint {
					status = "okay";
					port-index = <5>;
					bus-width = <4>;
					remote-endpoint = <&ar0820_csi_out3>;
				};
			};
		};
	};
};	

	host1x@13e00000 {
		nvcsi@15a00000 {
			num-channels = <4>;
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";
			channel@0 {
				status = "okay";
				reg = <0>;
				ports {
					status = "okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_csi_in0: endpoint@0 {
							status = "okay";
							port-index = <0>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_ar0820_out0>;
						};
					};
					port@1 {
						status = "okay";
						reg = <1>;
						ar0820_csi_out0: endpoint@1 {
							status = "okay";
							remote-endpoint = <&ar0820_vi_in0>;
						};
					};
				};
			};

			channel@1 {
				status = "okay";
				reg = <1>;
				ports {
					status = "okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_csi_in1: endpoint@2 {
							status = "okay";
							port-index = <2>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_ar0820_out1>;
						};
					};
					port@1 {
						status = "okay";
						reg = <1>;
						ar0820_csi_out1: endpoint@3 {
							status = "okay";
							remote-endpoint = <&ar0820_vi_in1>;
						};
					};
				};
			};

			channel@2 {
				status = "okay";
				reg = <2>;
				ports {
					status = "okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_csi_in2: endpoint@4 {
							status = "okay";
							port-index = <4>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_ar0820_out2>;
						};
					};
					port@1 {
						status = "okay";
						reg = <1>;
						ar0820_csi_out2: endpoint@5 {
							status = "okay";
							remote-endpoint = <&ar0820_vi_in2>;
						};
					};
				};
			};

			channel@3 {
				status = "okay";
				reg = <3>;
				ports {
					status = "okay";
					#address-cells = <1>;
					#size-cells = <0>;
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_csi_in3: endpoint@6 {
							status = "okay";
							port-index = <6>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_ar0820_out3>;
						};
					};
					port@1 {
						status = "okay";
						reg = <1>;
						ar0820_csi_out3: endpoint@7 {
							status = "okay";
							remote-endpoint = <&ar0820_vi_in3>;
						};
					};
				};
			};
		};
	};

	i2c@3180000 {
		tca9546@70 {
			i2c@0 {
			ar0820_a@10 {
				status = "okay";
				compatible = "onsemi,ar0820";
				/* I2C device address */
				reg = <0x10>;

				/* Physical dimensions of sensor */
				physical_w = "3.674";
				physical_h = "2.738";

				sensor_model = "ar0820";

				post_crop_frame_drop = "0";

				use_sensor_mode_id = "true";
 
				mode0 {/*mode AR0820_MODE_3848X2168_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_a";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "3848";
					active_h = "2168";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "74250000";
					serdes_pix_clk_hz = "200000000";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};

				mode1 {/*mode AR0820_MODE_1920X1080_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_a";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "1920";
					active_h = "1080";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "296236800";
					serdes_pix_clk_hz = "833333333";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					status = "okay";
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_ar0820_out0: endpoint {
							status = "okay";
							port-index = <0>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_csi_in0>;
							};
						};
					};
				gmsl-link {			
					src-csi-port = "a";
					dst-csi-port = "a";
					serdes-csi-link = "a";
					csi-mode = "1x4";
					st-vc = <0>;
					num-lanes = <4>;
					streams = "ued-u1", "raw12";
					};
				};
				eeprom_a@50 {
					status = "okay";
					compatible = "atmel,24c32";
					reg = <0x50>;
					pagesize = <32>;
				};
			};

		i2c@1 {
			ar0820_c@10 {
				status = "okay";
				compatible = "onsemi,ar0820";
				/* I2C device address */
				reg = <0x10>;

				/* Physical dimensions of sensor */
				physical_w = "3.674";
				physical_h = "2.738";

				sensor_model = "ar0820";

				post_crop_frame_drop = "0";

				use_sensor_mode_id = "true";
 
				mode0 {/*mode AR0820_MODE_3848X2168_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_c";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "3848";
					active_h = "2168";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "74250000";
					serdes_pix_clk_hz = "200000000";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};

				mode1 {/*mode AR0820_MODE_1920X1080_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_c";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "1920";
					active_h = "1080";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "296236800";
					serdes_pix_clk_hz = "833333333";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					status = "okay";
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_ar0820_out1: endpoint {
							status = "okay";
							port-index = <2>;
							bus-width = <4>;
							remote-endpoint = <&ar0820_csi_in1>;
							};
						};
					};
				gmsl-link {			
					src-csi-port = "a";
					dst-csi-port = "a";
					serdes-csi-link = "a";
					csi-mode = "1x4";
					st-vc = <0>;
					num-lanes = <4>;
					streams = "ued-u1", "raw12";
					};
				};
				eeprom_b@50 {
					status = "okay";
					compatible = "atmel,24c32";
					reg = <0x50>;
					pagesize = <32>;
				};
			};

		i2c@2 {
			ar0820_e@10 {
				status = "okay";
				compatible = "onsemi,ar0820";
				/* I2C device address */
				reg = <0x10>;

				/* Physical dimensions of sensor */
				physical_w = "3.674";
				physical_h = "2.738";

				sensor_model = "ar0820";

				post_crop_frame_drop = "0";

				use_sensor_mode_id = "true";
 
				mode0 {/*mode AR0820_MODE_3848X2168_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_e";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "3848";
					active_h = "2168";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "74250000";
					serdes_pix_clk_hz = "200000000";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};

				mode1 {/*mode AR0820_MODE_1920X1080_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_e";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "1920";
					active_h = "1080";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "296236800";
					serdes_pix_clk_hz = "833333333";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					status = "okay";
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_ar0820_out2: endpoint {
							status = "okay";
							port-index = <4>;
							bus-width = <2>;
							remote-endpoint = <&ar0820_csi_in2>;
							};
						};
					};
				gmsl-link {			
					src-csi-port = "a";
					dst-csi-port = "a";
					serdes-csi-link = "a";
					csi-mode = "1x4";
					st-vc = <0>;
					num-lanes = <4>;
					streams = "ued-u1", "raw12";
					};
				};
				eeprom_c@50 {
					status = "okay";
					compatible = "atmel,24c32";
					reg = <0x50>;
					pagesize = <32>;
				};
			};

		i2c@3 {
			ar0820_g@10 {
				status = "okay";
				compatible = "onsemi,ar0820";
				/* I2C device address */
				reg = <0x10>;

				/* Physical dimensions of sensor */
				physical_w = "3.674";
				physical_h = "2.738";

				sensor_model = "ar0820";

				post_crop_frame_drop = "0";

				use_sensor_mode_id = "true";
 
				mode0 {/*mode AR0820_MODE_3848X2168_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_g";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "3848";
					active_h = "2168";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "74250000";
					serdes_pix_clk_hz = "200000000";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};

				mode1 {/*mode AR0820_MODE_1920X1080_30FPS*/
					mclk_khz = "24000";
					num_lanes = "4";
					tegra_sinterface = "serial_g";
					discontinuous_clk = "no";
					dpcm_enable = "false";
					cil_settletime = "0";

					dynamic_pixel_bit_depth = "12";
					csi_pixel_bit_depth = "12";
					mode_type = "bayer";
					pixel_phase = "grbg";

					active_w = "1920";
					active_h = "1080";
					readout_orientation = "0";
					line_length = "4440";
					inherent_gain = "1";
					mclk_multiplier = "14.58";
					pix_clk_hz = "296236800";
					serdes_pix_clk_hz = "833333333";

					gain_factor = "1";
					min_gain_val = "1";
					max_gain_val = "15";
					step_gain_val = "1";
					default_gain = "1";
					min_hdr_ratio = "1";
					max_hdr_ratio = "1";
					framerate_factor = "1000000";
					min_framerate = "30000000";
					max_framerate = "30000000";
					step_framerate = "1";
					default_framerate ="30000000";
					exposure_factor ="1000000";
					min_exp_time = "15";
					max_exp_time = "33333";
					step_exp_time = "1";
					default_exp_time = "33333";

					embedded_metadata_height = "0";
				};
				ports {
					#address-cells = <1>;
					#size-cells = <0>;
					status = "okay";
					port@0 {
						status = "okay";
						reg = <0>;
						ar0820_ar0820_out3: endpoint {
							status = "okay";
							port-index = <6>;
							bus-width = <2>;
							remote-endpoint = <&ar0820_csi_in3>;
							};
						};
					};
				gmsl-link {			
					src-csi-port = "a";
					dst-csi-port = "a";
					serdes-csi-link = "a";
					csi-mode = "1x4";
					st-vc = <0>;
					num-lanes = <4>;
					streams = "ued-u1", "raw12";
					};
				};
				eeprom_d@50 {
					status = "okay";
					compatible = "atmel,24c32";
					reg = <0x50>;
					pagesize = <32>;
				};
			};

		};
	};
};
/ {

	tegra-camera-platform {
		status = "okay";
		compatible = "nvidia, tegra-camera-platform";
		/**
		* Physical settings to calculate max ISO BW
		*
		* num_csi_lanes = <>;
		* Total number of CSI lanes when all cameras are active
		*
		* max_lane_speed = <>;
		* Max lane speed in Kbit/s
		*
		* min_bits_per_pixel = <>;
		* Min bits per pixel
		*
		* vi_peak_byte_per_pixel = <>;
		* Max byte per pixel for the VI ISO case
		*
		* vi_bw_margin_pct = <>;
		* Vi bandwidth margin in percentage
		*
		* max_pixel_rate = <>;
		* Max pixel rate in Kpixel/s for the ISP ISO case
		*
		* isp_peak_byte_per_pixel = <>;
		* Max byte per pixel for the ISP ISO case
		*
		* isp_bw_margin_pct = <>;
		* Isp bandwidth margin in percentage
		*/
		num_csi_lanes = <4>;
		max_lane_speed = <1500000>;
		min_bits_per_pixel = <12>;
		vi_peak_byte_per_pixel = <2>;
		vi_bw_margin_pct = <25>;
		max_pixel_rate = <750000>;
		isp_peak_byte_per_pixel = <5>;
		isp_bw_margin_pct = <25>;

		/**
		 * The general guideline for naming badge_info contains 3 parts, and is as follows,
		 * The first part is the camera_board_id for the module; if the module is in a FFD
		 * platform, then use the platform name for this part.
		 * The second part contains the position of the module, ex. "rear" or "front".
		 * The third part contains the last 6 characters of a part number which is found
		 * in the module's specsheet from the vender.
		 */
		modules {
			module0 {
				status = "okay";
				badge = "ar0820_bottomleft";
				position = "bottomleft";
				orientation = "1";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "ar0820 30-0010";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9546@70/i2c@0/ar0820_a@10";
				};
			};

			module1 {
				status = "okay";
				badge = "ar0820_bottomright";
				position = "bottomright";
				orientation = "1";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "ar0820 31-0010";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9546@70/i2c@1/ar0820_c@10";
				};
			};
			module2 {
				status = "okay";
				badge = "ar0820_topleft";
				position = "topleft";
				orientation = "1";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "ar0820 32-0010";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9546@70/i2c@2/ar0820_e@10";
				};
			};
			module3 {
				status = "okay";
				badge = "ar0820_topright";
				position = "topright";
				orientation = "1";
				drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver v4l2 device name */
					devname = "ar0820 33-0010";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@3180000/tca9546@70/i2c@3/ar0820_g@10";
				};
			};
		};
	};
};


The ar0820 dtsi 

#include <t19x-common-modules/tegra194-camera-ar0820-a00.dtsi>
#include “dt-bindings/clock/tegra194-clock.h”

#define CAM0_RST_L TEGRA194_MAIN_GPIO(H, 3)
#define CAM0_PWDN TEGRA194_MAIN_GPIO(H, 6)
#define CAM1_RST_L TEGRA194_MAIN_GPIO(T, 6)
#define CAM1_PWDN TEGRA194_MAIN_GPIO(T, 5)
#define SLVS_CAM0_RST_L TEGRA194_MAIN_GPIO(Y, 1)
#define CAMERA_I2C_MUX_BUS(x) (0x1E + x)

/* camera control gpio definitions */

/ {

/* set camera gpio direction to output */
gpio@2200000 {
	camera-control-output-low {
		status = "okay";
		gpio-hog;
		output-low;
		gpios = <CAM0_RST_L 0 CAM0_PWDN 0
			 CAM1_RST_L 0 CAM1_PWDN 0
			 SLVS_CAM0_RST_L 0>;
		label = "cam0-rst", "cam0-pwdn",
			"cam1-rst", "cam1-pwdn",
			"slvs-cam0-rst";
	};
};

i2c@3180000 {
	tca9546@70 {
		status = "okay";
		compatible = "nxp,pca9546";
		reg = <0x70>;
		#address-cells = <1>;
		#size-cells = <0>;
		skip_mux_detect = "yes";
		vif-supply = <&p2822_vdd_1v8_cvb>;
		vcc-supply = <&p2822_vdd_1v8_cvb>;
		//vcc_lp = "vcc";
		vcc-pullup-supply = <&battery_reg>;
		force_bus_start = <CAMERA_I2C_MUX_BUS(0)>;
		
		i2c@0 {
			reg = <0>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_a: max9296@48 {
				compatible = "maxim,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_a: max9295@40 {
			    compatible = "maxim,max9295";
			    reg = <0x40>;
			};

			ar0820_a@10 {
				def-addr = <0x10>;
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				nvidia,gmsl-ser-device = <&ser_a>;
				nvidia,gmsl-dser-device = <&dser_a>;
			};

		};


		i2c@1 {
			reg = <1>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_c: max9296@48 {
				compatible = "maxim,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_c: max9295@40 {
			    compatible = "maxim,max9295";
			    reg = <0x40>;
			};

			ar0820_c@10 {
				def-addr = <0x10>;
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				nvidia,gmsl-ser-device = <&ser_c>;
				nvidia,gmsl-dser-device = <&dser_c>;
			};

		};

		i2c@2 {
			reg = <2>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_e: max9296@48 {
				compatible = "maxim,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_e: max9295@40 {
			    compatible = "maxim,max9295";
			    reg = <0x40>;
			};

			ar0820_e@10 {
				def-addr = <0x10>;
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				nvidia,gmsl-ser-device = <&ser_e>;
				nvidia,gmsl-dser-device = <&dser_e>;
			};

		};

		i2c@3 {
			reg = <3>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_g: max9296@48 {
				compatible = "maxim,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_g: max9295@40 {
			    compatible = "maxim,max9295";
			    reg = <0x40>;
			};

			ar0820_g@10 {
				def-addr = <0x10>;
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						<&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				nvidia,gmsl-ser-device = <&ser_g>;
				nvidia,gmsl-dser-device = <&dser_g>;
			};

		};
	};
};

};


code of max9296.c

#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/camera_common.h>
#include <linux/module.h>
#include <media/max9296.h>

/* register specifics */
#define MAX9296_DST_CSI_MODE_ADDR 0x330
#define MAX9296_LANE_MAP1_ADDR 0x333
#define MAX9296_LANE_MAP2_ADDR 0x334

#define MAX9296_LANE_CTRL0_ADDR 0x40A
#define MAX9296_LANE_CTRL1_ADDR 0x44A
#define MAX9296_LANE_CTRL2_ADDR 0x48A
#define MAX9296_LANE_CTRL3_ADDR 0x4CA

#define MAX9296_TX11_PIPE_X_EN_ADDR 0x40B
#define MAX9296_TX45_PIPE_X_DST_CTRL_ADDR 0x42D

#define MAX9296_PIPE_X_SRC_0_MAP_ADDR 0x40D
#define MAX9296_PIPE_X_DST_0_MAP_ADDR 0x40E
#define MAX9296_PIPE_X_SRC_1_MAP_ADDR 0x40F
#define MAX9296_PIPE_X_DST_1_MAP_ADDR 0x410
#define MAX9296_PIPE_X_SRC_2_MAP_ADDR 0x411
#define MAX9296_PIPE_X_DST_2_MAP_ADDR 0x412

#define MAX9296_PIPE_X_ST_SEL_ADDR 0x50

#define MAX9296_PWDN_PHYS_ADDR 0x332
#define MAX9296_PHY1_CLK_ADDR 0x320
#define MAX9296_CTRL0_ADDR 0x10
#define MAX9296_DEV_ID_ADDR 0x0D

/* data defines */
#define MAX9296_CSI_MODE_4X2 0x1
#define MAX9296_CSI_MODE_2X4 0x4
#define MAX9296_LANE_MAP1_4X2 0x44
#define MAX9296_LANE_MAP2_4X2 0x44
#define MAX9296_LANE_MAP1_2X4 0x4E
#define MAX9296_LANE_MAP2_2X4 0xE4

#define MAX9296_LANE_CTRL_MAP(num_lanes)
(((num_lanes) << 6) & 0xF0)

#define MAX9296_ALLPHYS_NOSTDBY 0xF0
#define MAX9296_ST_ID_SEL_INVALID 0xF

#define MAX9296_PHY1_CLK 0x2C

#define MAX9296_RESET_ALL 0x80

/* Dual GMSL MAX9296A/B */
#define MAX9296_A_ID 0x94
#define MAX9296_B_ID 0x96
#define MAX9296_MAX_SOURCES 2

#define MAX9296_MAX_PIPES 4

#define MAX9296_PIPE_X 0
#define MAX9296_PIPE_Y 1
#define MAX9296_PIPE_Z 2
#define MAX9296_PIPE_U 3
#define MAX9296_PIPE_INVALID 0xF

#define MAX9296_CSI_CTRL_0 0
#define MAX9296_CSI_CTRL_1 1
#define MAX9296_CSI_CTRL_2 2
#define MAX9296_CSI_CTRL_3 3

#define MAX9296_INVAL_ST_ID 0xFF

/* Use reset value as per spec, confirm with vendor */
#define MAX9296_RESET_ST_ID 0x00

struct max9296_source_ctx {
struct gmsl_link_ctx *g_ctx;
bool st_enabled;
};

struct pipe_ctx {
u32 id;
u32 dt_type;
u32 dst_csi_ctrl;
u32 st_count;
u32 st_id_sel;
};

struct max9296 {
struct i2c_client *i2c_client;
struct regmap *regmap;
u32 num_src;
u32 max_src;
u32 num_src_found;
u32 src_link;
bool splitter_enabled;
struct max9296_source_ctx sources[MAX9296_MAX_SOURCES];
struct mutex lock;
u32 sdev_ref;
bool lane_setup;
bool link_setup;
struct pipe_ctx pipe[MAX9296_MAX_PIPES];
u8 csi_mode;
u8 lane_mp1;
u8 lane_mp2;
int reset_gpio;
int pw_ref;
struct regulator *vdd_cam_1v2;
};

static int max9296_write_reg(struct device *dev,
u16 addr, u8 val)
{
struct max9296 *priv;
int err;

priv = dev_get_drvdata(dev);

err = regmap_write(priv->regmap, addr, val);
if (err)
	dev_err(dev,
	"%s:i2c write failed, 0x%x = %x\n",
	__func__, addr, val);

/* delay before next i2c command as required for SERDES link */
usleep_range(100, 110);

return err;

}

static int max9296_read_reg(struct device *dev, u16 addr, u32 *val)
{
struct max9296 *priv;
int err;
priv = dev_get_drvdata(dev);
err = regmap_read(priv->regmap, addr, val);

dev_dbg(dev, "%s:i2c reading , 0x%x = 0x%x\n", __func__, addr, *val);
if (err) {
	dev_err(dev,
		"%s:i2c read failed, 0x%x = 0x%x\n",
		__func__, addr, *val);
}

/* delay before next i2c command as required for SERDES link */
usleep_range(100, 110);
return err;

}

static int max9296_get_sdev_idx(struct device *dev,
struct device *s_dev, unsigned int *idx)
{
struct max9296 *priv = dev_get_drvdata(dev);
unsigned int i;
int err = 0;

mutex_lock(&priv->lock);
for (i = 0; i < priv->max_src; i++) {
	if (priv->sources[i].g_ctx->s_dev == s_dev)
		break;
}
if (i == priv->max_src) {
	dev_err(dev, "no sdev found\n");
	err = -EINVAL;
	goto ret;
}

if (idx)
	*idx = i;

ret:
mutex_unlock(&priv->lock);
return err;
}

static void max9296_pipes_reset(struct max9296 priv)
{
/

* This is default pipes combination. add more mappings
* for other combinations and requirements.
*/
struct pipe_ctx pipe_defaults = {
{MAX9296_PIPE_X, GMSL_CSI_DT_RAW_12,
MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID},
{MAX9296_PIPE_Y, GMSL_CSI_DT_RAW_12,
MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID},
{MAX9296_PIPE_Z, GMSL_CSI_DT_EMBED,
MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID},
{MAX9296_PIPE_U, GMSL_CSI_DT_EMBED,
MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID}
};

/*
 * Add DT props for num-streams and stream sequence, and based on that
 * set the appropriate pipes defaults.
 * For now default it supports "2 RAW12 and 2 EMBED" 1:1 mappings.
 */
memcpy(priv->pipe, pipe_defaults, sizeof(pipe_defaults));

}

static void max9296_reset_ctx(struct max9296 *priv)
{
unsigned int i;

priv->link_setup = false;
priv->lane_setup = false;
priv->num_src_found = 0;
priv->src_link = 0;
priv->splitter_enabled = false;
max9296_pipes_reset(priv);
for (i = 0; i < priv->num_src; i++)
	priv->sources[i].st_enabled = false;

}

int max9296_power_on(struct device *dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
int err = 0;
unsigned int retry;
u32 chip_id = 0x00;
int ret = -ETIMEDOUT;

for (retry = 10; ret && retry > 0; retry--) 
{
	ret = max9296_read_reg(dev, MAX9296_DEV_ID_ADDR, &chip_id);
}

if (ret)
{
	dev_err(dev, "MAX9296 deserializer chip not found\n");
	return -ETIMEDOUT;
}

dev_info(dev, "Found %s deserializer chip with ID=0x%x\n", 
		(chip_id == MAX9296_A_ID) ? "MAX9296A" :
		(chip_id == MAX9296_B_ID) ? "MAX9296B" :
		"Unknown MAXIM", chip_id);

mutex_lock(&priv->lock);
if (priv->pw_ref == 0) {
	usleep_range(1, 2);
	if (priv->reset_gpio)
		gpio_set_value(priv->reset_gpio, 0);

	usleep_range(30, 50);

	if (priv->vdd_cam_1v2) {
		err = regulator_enable(priv->vdd_cam_1v2);
		if (unlikely(err))
			goto ret;
	}

	usleep_range(30, 50);

	/*exit reset mode: XCLR */
	if (priv->reset_gpio) {
		gpio_set_value(priv->reset_gpio, 0);
		usleep_range(30, 50);
		gpio_set_value(priv->reset_gpio, 1);
		usleep_range(30, 50);
	}

	/* delay to settle reset */
	msleep(20);
}

priv->pw_ref++;

ret:
mutex_unlock(&priv->lock);

return err;

}
EXPORT_SYMBOL(max9296_power_on);

void max9296_power_off(struct device *dev)
{
struct max9296 *priv = dev_get_drvdata(dev);

mutex_lock(&priv->lock);
priv->pw_ref--;

if (priv->pw_ref == 0) {
	/* enter reset mode: XCLR */
	usleep_range(1, 2);
	if (priv->reset_gpio)
		gpio_set_value(priv->reset_gpio, 0);

	if (priv->vdd_cam_1v2)
		regulator_disable(priv->vdd_cam_1v2);
}

mutex_unlock(&priv->lock);

}
EXPORT_SYMBOL(max9296_power_off);

static int max9296_write_link(struct device *dev, u32 link)
{
if (link == GMSL_SERDES_CSI_LINK_A) {
max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x01);
max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x21);
} else if (link == GMSL_SERDES_CSI_LINK_B) {
max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x02);
max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x22);
} else {
dev_err(dev, “%s: invalid gmsl link\n”, func);
return -EINVAL;
}

/* delay to settle link */
msleep(100);

return 0;

}

int max9296_setup_link(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
int err = 0;
unsigned int i = 0;

err = max9296_get_sdev_idx(dev, s_dev, &i);
if (err)
	return err;

mutex_lock(&priv->lock);

if (!priv->splitter_enabled) {
	err = max9296_write_link(dev,
			priv->sources[i].g_ctx->serdes_csi_link);
	if (err)
		goto ret;

	priv->link_setup = true;
}

ret:
mutex_unlock(&priv->lock);

return err;

}
EXPORT_SYMBOL(max9296_setup_link);

int max9296_setup_control(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
int err = 0;
unsigned int i = 0;

err = max9296_get_sdev_idx(dev, s_dev, &i);
if (err)
	return err;

mutex_lock(&priv->lock);

if (!priv->link_setup) {
	dev_err(dev, "%s: invalid state\n", __func__);
	err = -EINVAL;
	goto error;
}

if (priv->sources[i].g_ctx->serdev_found) {
	priv->num_src_found++;
	priv->src_link = priv->sources[i].g_ctx->serdes_csi_link;
}

/* Enable splitter mode */
if ((priv->max_src > 1U) &&
	(priv->num_src_found > 0U) &&
	(priv->splitter_enabled == false)) {
	max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x03);
	max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x23);

	priv->splitter_enabled = true;

	/* delay to settle link */
	msleep(100);
}

max9296_write_reg(dev,
		MAX9296_PWDN_PHYS_ADDR, MAX9296_ALLPHYS_NOSTDBY);

priv->sdev_ref++;

/* Reset splitter mode if all devices are not found */
if ((priv->sdev_ref == priv->max_src) &&
	(priv->splitter_enabled == true) &&
	(priv->num_src_found > 0U) &&
	(priv->num_src_found < priv->max_src)) {
	err = max9296_write_link(dev, priv->src_link);
	if (err)
		goto error;

	priv->splitter_enabled = false;
}

error:
mutex_unlock(&priv->lock);
return err;
}
EXPORT_SYMBOL(max9296_setup_control);

int max9296_reset_control(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
int err = 0;

mutex_lock(&priv->lock);
if (!priv->sdev_ref) {
	dev_info(dev, "%s: dev is already in reset state\n", __func__);
	goto ret;
}

priv->sdev_ref--;
if (priv->sdev_ref == 0) {
	max9296_reset_ctx(priv);
	max9296_write_reg(dev, MAX9296_CTRL0_ADDR, MAX9296_RESET_ALL);

	/* delay to settle reset */
	msleep(100);
}

ret:
mutex_unlock(&priv->lock);

return err;

}
EXPORT_SYMBOL(max9296_reset_control);

int max9296_sdev_register(struct device *dev, struct gmsl_link_ctx *g_ctx)
{
struct max9296 *priv = NULL;
unsigned int i;
int err = 0;

if (!dev || !g_ctx || !g_ctx->s_dev) {
	dev_err(dev, "%s: invalid input params\n", __func__);
	return -EINVAL;
}

priv = dev_get_drvdata(dev);

mutex_lock(&priv->lock);

if (priv->num_src > priv->max_src) {
	dev_err(dev,
		"%s: MAX9296 inputs size exhausted\n", __func__);
	err = -ENOMEM;
	goto error;
}

/* Check csi mode compatibility */
if (!((priv->csi_mode == MAX9296_CSI_MODE_2X4) ?
		((g_ctx->csi_mode == GMSL_CSI_1X4_MODE) ||
			(g_ctx->csi_mode == GMSL_CSI_2X4_MODE)) :
		((g_ctx->csi_mode == GMSL_CSI_2X2_MODE) ||
			(g_ctx->csi_mode == GMSL_CSI_4X2_MODE)))) {
	dev_err(dev,
		"%s: csi mode not supported\n", __func__);
	err = -EINVAL;
	goto error;
}

for (i = 0; i < priv->num_src; i++) {
	if (g_ctx->serdes_csi_link ==
		priv->sources[i].g_ctx->serdes_csi_link) {
		dev_err(dev,
			"%s: serdes csi link is in use\n", __func__);
		err = -EINVAL;
		goto error;
	}
	/*
	 * All sdevs should have same num-csi-lanes regardless of
	 * dst csi port selected.
	 * Later if there is any usecase which requires each port
	 * to be configured with different num-csi-lanes, then this
	 * check should be performed per port.
	 */
	if (g_ctx->num_csi_lanes !=
			priv->sources[i].g_ctx->num_csi_lanes) {
		dev_err(dev,
			"%s: csi num lanes mismatch\n", __func__);
		err = -EINVAL;
		goto error;
	}
}

priv->sources[priv->num_src].g_ctx = g_ctx;
priv->sources[priv->num_src].st_enabled = false;

priv->num_src++;

error:
mutex_unlock(&priv->lock);
return err;
}
EXPORT_SYMBOL(max9296_sdev_register);

int max9296_sdev_unregister(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = NULL;
int err = 0;
unsigned int i = 0;

if (!dev || !s_dev) {
	dev_err(dev, "%s: invalid input params\n", __func__);
	return -EINVAL;
}

priv = dev_get_drvdata(dev);
mutex_lock(&priv->lock);

if (priv->num_src == 0) {
	dev_err(dev, "%s: no source found\n", __func__);
	err = -ENODATA;
	goto error;
}

for (i = 0; i < priv->num_src; i++) {
	if (s_dev == priv->sources[i].g_ctx->s_dev) {
		priv->sources[i].g_ctx = NULL;
		break;
	}
}

if (i == priv->num_src) {
	dev_err(dev,
		"%s: requested device not found\n", __func__);
	err = -EINVAL;
	goto error;
}
priv->num_src--;

error:
mutex_unlock(&priv->lock);
return err;
}
EXPORT_SYMBOL(max9296_sdev_unregister);

static int max9296_get_available_pipe(struct device *dev,
u32 st_data_type, u32 dst_csi_port)
{
struct max9296 *priv = dev_get_drvdata(dev);
int i;

for (i = 0; i < MAX9296_MAX_PIPES; i++) {
	/*
	 * TODO: Enable a pipe for multi stream configuration having
	 * similar stream data type. For now use st_count as a flag
	 * for 1 to 1 mapping in pipe and stream data type, same can
	 * be extended as count for many to 1 mapping. Would also need
	 * few more checks such as input stream id select, dst port etc.
	 */
	if ((priv->pipe[i].dt_type == st_data_type) &&
		((dst_csi_port == GMSL_CSI_PORT_A) ?
			(priv->pipe[i].dst_csi_ctrl ==
				MAX9296_CSI_CTRL_0) ||
			(priv->pipe[i].dst_csi_ctrl ==
				MAX9296_CSI_CTRL_1) :
			(priv->pipe[i].dst_csi_ctrl ==
				MAX9296_CSI_CTRL_2) ||
			(priv->pipe[i].dst_csi_ctrl ==
				MAX9296_CSI_CTRL_3)) &&
		(!priv->pipe[i].st_count))
		break;
}

if (i == MAX9296_MAX_PIPES) {
	dev_err(dev, "%s: all pipes are busy\n", __func__);
	return -ENOMEM;
}

return i;

}

struct reg_pair {
u16 addr;
u8 val;
};

static int max9296_setup_pipeline(struct device *dev,
struct gmsl_link_ctx *g_ctx)
{
struct max9296 *priv = dev_get_drvdata(dev);
struct gmsl_stream *g_stream;
struct reg_pair *map_list;
u32 arr_sz = 0;
int pipe_id = 0;
u32 i = 0;
u32 j = 0;
u32 vc_idx = 0;

for (i = 0; i < g_ctx->num_streams; i++) {
	/* Base data type mapping: pipeX/RAW12/CSICNTR1 */
	struct reg_pair map_pipe_raw12[] = {
		/* addr, val */
		{MAX9296_TX11_PIPE_X_EN_ADDR, 0x7},
		{MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15},
		{MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x2C},
		{MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x2C},
		{MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00},
		{MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00},
		{MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01},
		{MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01},
	};

	/* Base data type mapping: pipeX/EMBED/CSICNTR1 */
	struct reg_pair map_pipe_embed[] = {
		/* addr, val */
		{MAX9296_TX11_PIPE_X_EN_ADDR, 0x7},
		{MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15},
		{MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x12},
		{MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x12},
		{MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00},
		{MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00},
		{MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01},
		{MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01},
	};

	g_stream = &g_ctx->streams[i];
	g_stream->des_pipe = MAX9296_PIPE_INVALID;

	if (g_stream->st_data_type == GMSL_CSI_DT_RAW_12) {
		map_list = map_pipe_raw12;
		arr_sz = ARRAY_SIZE(map_pipe_raw12);
	} else if (g_stream->st_data_type == GMSL_CSI_DT_EMBED) {
		map_list = map_pipe_embed;
		arr_sz = ARRAY_SIZE(map_pipe_embed);
	} else if (g_stream->st_data_type == GMSL_CSI_DT_UED_U1) {
		dev_dbg(dev,
			"%s: No mapping for GMSL_CSI_DT_UED_U1\n",
			__func__);
		continue;
	} else {
		dev_err(dev, "%s: Invalid data type\n", __func__);
		return -EINVAL;
	}

	pipe_id = max9296_get_available_pipe(dev,
			g_stream->st_data_type, g_ctx->dst_csi_port);
	if (pipe_id < 0)
		return pipe_id;

	for (j = 0, vc_idx = 3; j < arr_sz; j++, vc_idx += 2) {
		/* update pipe configuration */
		map_list[j].addr += (0x40 * pipe_id);
		/* update vc id configuration */
		if (vc_idx < arr_sz)
			map_list[vc_idx].val |=
				(g_ctx->dst_vc << 6);

		max9296_write_reg(dev, map_list[j].addr,
					map_list[j].val);
	}

	/* Set stream id select input */
	if (g_stream->st_id_sel == GMSL_ST_ID_UNUSED) {
		dev_err(dev, "%s: Invalid stream st_id_sel\n",
			__func__);
		return -EINVAL;
	}

	g_stream->des_pipe = MAX9296_PIPE_X_ST_SEL_ADDR + pipe_id;

	/* Update pipe internals */
	priv->pipe[pipe_id].st_count++;
	priv->pipe[pipe_id].st_id_sel = g_stream->st_id_sel;
}

return 0;

}

int max9296_start_streaming(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
struct gmsl_link_ctx *g_ctx;
struct gmsl_stream *g_stream;
int err = 0;
unsigned int i = 0;

err = max9296_get_sdev_idx(dev, s_dev, &i);
if (err)
	return err;

mutex_lock(&priv->lock);
g_ctx = priv->sources[i].g_ctx;

for (i = 0; i < g_ctx->num_streams; i++) {
	g_stream = &g_ctx->streams[i];

	if (g_stream->des_pipe != MAX9296_PIPE_INVALID)
		max9296_write_reg(dev, g_stream->des_pipe,
					g_stream->st_id_sel);
}
mutex_unlock(&priv->lock);

return 0;

}
EXPORT_SYMBOL(max9296_start_streaming);

int max9296_stop_streaming(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
struct gmsl_link_ctx *g_ctx;
struct gmsl_stream *g_stream;
int err = 0;
unsigned int i = 0;

err = max9296_get_sdev_idx(dev, s_dev, &i);
if (err)
	return err;

mutex_lock(&priv->lock);
g_ctx = priv->sources[i].g_ctx;

for (i = 0; i < g_ctx->num_streams; i++) {
	g_stream = &g_ctx->streams[i];

	if (g_stream->des_pipe != MAX9296_PIPE_INVALID)
		max9296_write_reg(dev, g_stream->des_pipe,
					MAX9296_RESET_ST_ID);
}

mutex_unlock(&priv->lock);

return 0;

}
EXPORT_SYMBOL(max9296_stop_streaming);

int max9296_setup_streaming(struct device *dev, struct device *s_dev)
{
struct max9296 *priv = dev_get_drvdata(dev);
struct gmsl_link_ctx *g_ctx;
int err = 0;
unsigned int i = 0;
u16 lane_ctrl_addr;

err = max9296_get_sdev_idx(dev, s_dev, &i);
if (err)
	return err;

mutex_lock(&priv->lock);
if (priv->sources[i].st_enabled)
	goto ret;

g_ctx = priv->sources[i].g_ctx;

err = max9296_setup_pipeline(dev, g_ctx);
if (err)
	goto ret;

/* Derive CSI lane map register */
switch(g_ctx->dst_csi_port) {
case GMSL_CSI_PORT_A:
case GMSL_CSI_PORT_D:
	lane_ctrl_addr = MAX9296_LANE_CTRL1_ADDR;
	break;
case GMSL_CSI_PORT_B:
case GMSL_CSI_PORT_E:
	lane_ctrl_addr = MAX9296_LANE_CTRL2_ADDR;
	break;
case GMSL_CSI_PORT_C:
	lane_ctrl_addr = MAX9296_LANE_CTRL0_ADDR;
	break;
case GMSL_CSI_PORT_F:
	lane_ctrl_addr = MAX9296_LANE_CTRL3_ADDR;
	break;
default:
	dev_err(dev, "%s: invalid gmsl csi port!\n", __func__);
	err = -EINVAL;
	goto ret;
};

/*
 * rewrite num_lanes to same dst port should not be an issue,
 * as the device compatibility is already
 * checked during sdev registration against the des properties.
 */
max9296_write_reg(dev, lane_ctrl_addr,
	MAX9296_LANE_CTRL_MAP(g_ctx->num_csi_lanes-1));

if (!priv->lane_setup) {
	max9296_write_reg(dev,
		MAX9296_DST_CSI_MODE_ADDR, priv->csi_mode);
	max9296_write_reg(dev,
		MAX9296_LANE_MAP1_ADDR, priv->lane_mp1);
	max9296_write_reg(dev,
		MAX9296_LANE_MAP2_ADDR, priv->lane_mp2);
	max9296_write_reg(dev,
		MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK);

	priv->lane_setup = true;
}

priv->sources[i].st_enabled = true;

ret:
mutex_unlock(&priv->lock);
return err;
}
EXPORT_SYMBOL(max9296_setup_streaming);

static const struct of_device_id max9296_of_match = {
{ .compatible = “maxim,max9296”, },
{ },
};
MODULE_DEVICE_TABLE(of, max9296_of_match);

static int max9296_parse_dt(struct max9296 *priv,
struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
int err = 0;
const char *str_value;
int value;
const struct of_device_id *match;

if (!node)
	return -EINVAL;

match = of_match_device(max9296_of_match, &client->dev);
if (!match) {
	dev_err(&client->dev, "Failed to find matching dt id\n");
	return -EFAULT;
}

err = of_property_read_string(node, "csi-mode", &str_value);
if (err < 0) {
	dev_err(&client->dev, "csi-mode property not found\n");
	return err;
}

if (!strcmp(str_value, "2x4")) {
	priv->csi_mode = MAX9296_CSI_MODE_2X4;
	priv->lane_mp1 = MAX9296_LANE_MAP1_2X4;
	priv->lane_mp2 = MAX9296_LANE_MAP2_2X4;
} else if (!strcmp(str_value, "4x2")) {
	priv->csi_mode = MAX9296_CSI_MODE_4X2;
	priv->lane_mp1 = MAX9296_LANE_MAP1_4X2;
	priv->lane_mp2 = MAX9296_LANE_MAP2_4X2;
} else {
	dev_err(&client->dev, "invalid csi mode\n");
	return -EINVAL;
}

err = of_property_read_u32(node, "max-src", &value);
if (err < 0) {
	dev_err(&client->dev, "No max-src info\n");
	return err;
}
priv->max_src = value;

priv->reset_gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (priv->reset_gpio < 0) {
	dev_err(&client->dev, "reset-gpios not found %d\n", err);
	return err;
}

/* digital 1.2v */
if (of_get_property(node, "vdd_cam_1v2-supply", NULL)) {
	priv->vdd_cam_1v2 = regulator_get(&client->dev, "vdd_cam_1v2");
	if (IS_ERR(priv->vdd_cam_1v2)) {
		dev_err(&client->dev,
			"vdd_cam_1v2 regulator get failed\n");
		err = PTR_ERR(priv->vdd_cam_1v2);
		priv->vdd_cam_1v2 = NULL;
		return err;
	}
} else {
	priv->vdd_cam_1v2 = NULL;
}

return 0;

}

static struct regmap_config max9296_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
};

static int max9296_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max9296 *priv;
int err = 0;

dev_info(&client->dev, "[MAX9296]: probing GMSL Deserializer\n");

priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
priv->i2c_client = client;
priv->regmap = devm_regmap_init_i2c(priv->i2c_client,
			&max9296_regmap_config);
if (IS_ERR(priv->regmap)) {
	dev_err(&client->dev,
		"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
	return -ENODEV;
}

err = max9296_parse_dt(priv, client);
if (err) {
	dev_err(&client->dev, "unable to parse dt\n");
	return -EFAULT;
}

max9296_pipes_reset(priv);

if (priv->max_src > MAX9296_MAX_SOURCES) {
	dev_err(&client->dev,
		"max sources more than currently supported\n");
	return -EINVAL;
}

mutex_init(&priv->lock);

dev_set_drvdata(&client->dev, priv);

/* dev communication gets validated when GMSL link setup is done */
dev_info(&client->dev, "%s:  success\n", __func__);

return err;

}

static int max9296_remove(struct i2c_client *client)
{
struct max9296 *priv;

if (client != NULL) {
	priv = dev_get_drvdata(&client->dev);
	mutex_destroy(&priv->lock);
	i2c_unregister_device(client);
	client = NULL;
}

return 0;

}

static const struct i2c_device_id max9296_id = {
{ “max9296”, 0 },
{ },
};

MODULE_DEVICE_TABLE(i2c, max9296_id);

static struct i2c_driver max9296_i2c_driver = {
.driver = {
.name = “max9296”,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(max9296_of_match),
},
.probe = max9296_probe,
.remove = max9296_remove,
.id_table = max9296_id,
};

static int __init max9296_init(void)
{
return i2c_add_driver(&max9296_i2c_driver);
}

static void __exit max9296_exit(void)
{
i2c_del_driver(&max9296_i2c_driver);
}

module_init(max9296_init);
module_exit(max9296_exit);

MODULE_DESCRIPTION(“Dual GMSL Deserializer driver max9296”);
MODULE_AUTHOR(“Sudhir Vyas <svyas@nvidia.com”);
MODULE_LICENSE(“GPL v2”);


Thank you for your support

@leopard-zwc the deserializer should be detected even if the max9296 driver is not loaded in fact that it’s just i2c communication, but in my case the i2c slave address is not even appearing when scanning the i2c bus
You can see that i changed the max9296 slave address in the device tree so i can see the i2c address appearing

#  i2c-30
jetson@jetson-desktop:~$ i2cdetect -r -y 30
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: UU -- -- -- -- -- -- UU 48 -- -- -- -- -- -- -- 
50: UU -- -- -- 54 -- -- -- 58 -- -- -- -- -- -- -- 
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- --         

# i2c-31                
jetson@jetson-desktop:~$ i2cdetect -r -y 31
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: UU -- -- -- -- -- -- UU -- -- -- -- -- -- -- -- 
50: -- -- -- -- 54 -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: UU -- -- -- -- -- -- --  

I see that the four RESET pins you used are CAM0_RST_L, which is unreasonable. Please also use the other three reset pins.

Hey @leopard-zwc thank you for your support, i’ve noticed that i changed it

I am using CAM0_RST CAM0_PWDN CAM1_RST and CAM1_PWDN but it didn’t solve the issue…

Please refer to the code below to configure reset for your device tree.

#define CAM0_RST_L TEGRA194_MAIN_GPIO(H, 3)
#define CAM0_PWDN TEGRA194_MAIN_GPIO(H, 6)
#define CAM1_RST_L TEGRA194_MAIN_GPIO(T, 6)
#define CAM1_PWDN TEGRA194_MAIN_GPIO(T, 5)
#define CAMERA_I2C_MUX_BUS(x) (0x1E + x)

/* camera control gpio definitions */

/ {
gpio@2200000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST_L 0 CAM0_PWDN 0>;
label = “cam0-rst”, “cam0-pwdn”;
};
};

i2c@3180000 {
	tca9546@70 {
		compatible = "nxp,pca9546";
		reg = <0x70>;
		#address-cells = <1>;
		#size-cells = <0>;
		skip_mux_detect = "yes";
		vcc-supply = <&p2822_vdd_1v8_cvb>;
		vcc_lp = "vcc";
		force_bus_start = <CAMERA_I2C_MUX_BUS(0)>;

		i2c@0 {
			reg = <0>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_a: max9296@48 {
				compatible = "nvidia,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_a: max9295@62 {
				compatible = "nvidia,max9295";
				reg = <0x62>;
			};

			ar0820_a@10 {
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				def-addr = <0x10>;
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						 <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
				nvidia,gmsl-ser-device = <&ser_a>;
				nvidia,gmsl-dser-device = <&dser_a>;
			};
		};
		i2c@1 {
			reg = <1>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_c: max9296@48 {
				compatible = "nvidia,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM0_PWDN GPIO_ACTIVE_HIGH>;
			};
			ser_c: max9295@62 {
				compatible = "nvidia,max9295";
				reg = <0x62>;
			};

			ar0820_c@10 {
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				def-addr = <0x10>;
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						 <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				reset-gpios = <&tegra_main_gpio CAM0_PWDN GPIO_ACTIVE_HIGH>;
				nvidia,gmsl-ser-device = <&ser_c>;
				nvidia,gmsl-dser-device = <&dser_c>;
			};
		};
		i2c@2 {
			reg = <2>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_e: max9296@48 {
				compatible = "nvidia,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM1_RST_L GPIO_ACTIVE_HIGH>;
			};
			ser_e: max9295@62 {
				compatible = "nvidia,max9295";
				reg = <0x62>;
			};

			ar0820_e@10 {
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				def-addr = <0x10>;
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						 <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				reset-gpios = <&tegra_main_gpio CAM1_RST_L GPIO_ACTIVE_HIGH>;
				nvidia,gmsl-ser-device = <&ser_e>;
				nvidia,gmsl-dser-device = <&dser_e>;
			};
		};
		i2c@3 {
			reg = <3>;
			i2c-mux,deselect-on-exit;
			#address-cells = <1>;
			#size-cells = <0>;
			dser_g: max9296@48 {
				compatible = "nvidia,max9296";
				reg = <0x48>;
				csi-mode = "2x4";
				max-src = <2>;
				reset-gpios = <&tegra_main_gpio CAM1_PWDN GPIO_ACTIVE_HIGH>;
			};
			ser_g: max9295@62 {
				compatible = "nvidia,max9295";
				reg = <0x62>;
			};

			ar0820_g@10 {
				/* Define any required hw resources needed by driver */
				/* ie. clocks, io pins, power sources */
				def-addr = <0x10>;
				clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>,
						 <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>;
				clock-names = "extperiph1", "pllp_grtba";
				mclk = "extperiph1";
				reset-gpios = <&tegra_main_gpio CAM1_PWDN GPIO_ACTIVE_HIGH>;
				nvidia,gmsl-ser-device = <&ser_g>;
				nvidia,gmsl-dser-device = <&dser_g>;
			};
		};
	};
};

};

1 Like

Hello @leopard-zwc i used this DT to make the new for the Jetpack 5 i changed some properties like compatible to make this latter same as the driver source code but i am still having the issue where i am able to detect only i2c-30 and i2c-32…

Hi all i was able to solve the issue, i’m able to detect the 4 of the camera module in the 4 MUX ports by removing the max9296_read_reg to read the ID of the chip and prints that produce this latter is detected, i dunno why it has this behavior.

Well now i’m facing another issue, the serializer is not initialized correctly, you can see in the logs below that it takes random value instead of getting the right value of ser address or the num of lanes from the gmsl-link node, is there any reason for this behavior, it keeps doing it 1/4 times

jetson@jetson-desktop:~$ sudo dmesg | grep max9295
[sudo] password for jetson: 
[    7.765569] max9295 30-0040: [MAX9295]: probing GMSL Serializer
[    7.771335] max9295 30-0040: max9295_probe:  success
[    7.807583] max9295 31-0040: [MAX9295]: probing GMSL Serializer
[    7.813153] max9295 31-0040: max9295_probe:  success
[    7.849755] max9295 32-0040: [MAX9295]: probing GMSL Serializer
[    7.855370] max9295 32-0040: max9295_probe:  success
[    7.892178] max9295 33-0040: [MAX9295]: probing GMSL Serializer
[    7.897501] max9295 33-0040: max9295_probe:  success
[    8.369390] max9295 30-0040: max9295_sdev_pair: device already paired
[    8.732924] max9295 30-0040: invalid ser slave address 0x52ad3a8 expected : 0x40 max9295_setup_control
[    9.367719] max9295 32-0040: max9295_sdev_pair: device already paired
[    9.505125] max9295 32-0040: max9295_write_reg:i2c write failed, 0x10 = 21
[    9.713082] max9295 32-0040: max9295_write_reg:i2c write failed, 0xd = 0
[    9.714409] max9295 32-0040: invalid ser slave address 0x0 expected : 0x40 max9295_setup_control
[    9.723838] max9295 33-0040: max9295_sdev_pair: device already paired
[    9.861121] max9295 33-0040: max9295_write_reg:i2c write failed, 0x10 = 21
[   10.069104] max9295 33-0040: max9295_write_reg:i2c write failed, 0xd = 0
[   10.070424] max9295 33-0040: invalid ser slave address 0x0 expected : 0x40 max9295_setup_control

@ShaneCCC @leopard-zwc do you have any idea ?

Thank you for your support