SAMA7G5 and Omnivision OV7740


This page describes the possibility of connecting a parallel sensor (example given is Omnivision ov7740) to the SAMA7G5 MPU.
Warning, important The board sama7g5-ek does not have a parallel sensor connector. This tutorial is applicable to custom boards which want to use this type of interface.

Introduction

Omnivision OV7740 is a parallel sensor , 8 bit Raw BAYER, that can also stream directly YUYV format.
Warning, important Being a parallel sensor, all sensor data lines must be connected to the ISC I/O lines.
Warning, important SAMA7G5 uses media controller paradigm to configure the pipeline. Please refer to this tutorial for more information about it.

Device Tree configuration

This is an example Device Tree configuration.
It uses a specific ISC I/O IOSET. One has to adapt this to its own board
The example shows how to connect endpoints between the different nodes in the DT, to have everything in place for a parallel capture.
Pointing hand The snippet below assumes that all nodes in the sama7g5.dtsi are available as in the Linux Mainline tree. The properties that are already in Linux mainline are not duplicated here.
Pointing hand The below snippet can be added as an overlay or directly to your board dts file , because it uses references to already existing nodes from sama7g5.dtsi

&csi2dc {
       /* this clock is requested by the csi2dc from the xisc,
        * and then it's passed to the sensor. It is mandatory to
        * request the same frequency, otherwise the clock subsystem
        * will change the frequency to the last one requested */     
        assigned-clock-rates = <24000000>;                                                 
        status = "okay";                                                         
                                                                                 
        ports {                                                                  
                port@0 {                                                         
                        csi2dc_in: endpoint {
                                /* csi2dc will automatically understand from the endpoint if this is a Parallel or CSI2 endpoint connection */                                    
                                remote-endpoint = <&ov7740_0>;                   
                        };                                                       
                };                                                               
        };                                                                       
};      

&flx1 {
       /* make sure flexcom1 is in TWI mode for the i2c1 subnode below... */
       atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
};
                                                                                 
&i2c1 {                                                                          
       #address-cells = <1>;                                                     
       #size-cells = <0>;                                                        
                                                                                 
       ov7740: camera@21 {                                                       
               compatible = "ovti,ov7740";                                       
               reg = <0x21>;                                                     
               pinctrl-names = "default";                                        
               pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>;        
               reset-gpios = <&pioA PIN_PA13 GPIO_ACTIVE_LOW>;                   
               powerdown-gpios = <&pioA PIN_PA12 GPIO_ACTIVE_HIGH>;              
               clocks = <&xisc>;                                                 
               clock-names = "xvclk";     /* be careful at the clock name, to be the one expected by the driver */                                       
               assigned-clocks = <&xisc>;                                        
               assigned-clock-rates = <24000000>;  /* also requested by csi2dc above */                              
               status = "okay";                                                  
                                                                                 
               port {                                                            
                       ov7740_0: endpoint {                                      
                               remote-endpoint = <&csi2dc_in>;                   
                               hsync-active = <1>;                               
                               vsync-active = <0>;                               
                               pclk-sample = <1>;                                
                       };                                                        
               };                                                                
       };                                                                        
};             

                                                                                 
&pioA {                                                                          
       pinctrl_sensor_power: sensor_power {                                      
               pinmux = <PIN_PA12__GPIO>;                                        
               bias-disable;                                                     
       };                                                                        
                                                                                 
       pinctrl_sensor_reset: sensor_reset {                                      
               pinmux = <PIN_PA13__GPIO>;                                        
               bias-disable;                                                     
       };                                                                        
};                                                                               
                                                                                 
&xisc {                                                                          
       pinctrl-names = "default";                                                
       pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit>;                   
       status = "okay";                                                          
                                                                                 
       port {                                                                    
               xisc_in: endpoint {                                               
                       hsync-active = <1>;                                       
                       vsync-active = <0>;                                       
                       pclk-sample = <1>;                                        
               };                                                                
       };                                                                        
};                                                                               
                                                                                     
&pioA {                                                                          
       pinctrl_isc_base: isc_base {                                              
               pinmux = <PIN_PA27__ISC_PCK>,                                     
                        <PIN_PA25__ISC_VSYNC>,                                   
                        <PIN_PA24__ISC_HSYNC>,                                   
                        <PIN_PA15__ISC_MCK>;                                     
               bias-disable;                                                     
       };                                                                        
        
       /* ISC uses the top data bits always, if your sensor outputs 10 bits e.g., you need to use D2-D11 */                                                                         
       pinctrl_isc_data_8bit: isc_data_8bit {                                    
               pinmux = <PIN_PA31__ISC_D11>,                                     
                        <PIN_PA30__ISC_D10>,                                     
                        <PIN_PA29__ISC_D9>,                                      
                        <PIN_PA28__ISC_D8>,                                      
                        <PIN_PA23__ISC_D7>,                                      
                        <PIN_PA22__ISC_D6>,                                      
                        <PIN_PA21__ISC_D5>,                                      
                        <PIN_PA20__ISC_D4>;                                      
               bias-disable;                                                     
       };                                                                        
};                                                                               
     

Media controller pipeline

If probed correctly, the media controller pipeline looks like this:
# media-ctl -p
Media controller API version 5.16.0

Media device information
------------------------
driver          atmel_isc_commo
model           microchip,sama7g5-isc
serial
bus info        platform:microchip-sama7g5-xisc
hw revision     0x220
driver version  5.16.0

Device topology
- entity 1: atmel_isc_scaler (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        pad0: Sink
                [fmt:SBGGR8_1X8/3264x2464 field:none colorspace:srgb
                 crop.bounds:(0,0)/3264x2464
                 crop:(0,0)/3264x2464]
                <- "csi2dc":1 [ENABLED,IMMUTABLE]
        pad1: Source
                [fmt:SBGGR8_1X8/3264x2464 field:none colorspace:srgb]
                -> "atmel_isc_common":0 [ENABLED,IMMUTABLE]

- entity 4: csi2dc (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
        pad0: Sink
                [fmt:SRGGB8_1X8/640x480 field:none colorspace:srgb]
                <- "ov7740 0-0021":0 [ENABLED]
        pad1: Source
                [fmt:SRGGB8_1X8/640x480 field:none colorspace:srgb]
                -> "atmel_isc_scaler":0 [ENABLED,IMMUTABLE]

- entity 7: ov7740 0-0021 (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev2
        pad0: Source
                [fmt:YUYV8_2X8/640x480@1/60 field:none colorspace:srgb]
                -> "csi2dc":0 [ENABLED]

- entity 17: atmel_isc_common (1 pad, 1 link)
             type Node subtype V4L flags 1
             device node name /dev/video0
        pad0: Sink
                <- "atmel_isc_scaler":1 [ENABLED,IMMUTABLE]

#

The pipeline can be also represented as a graph, as in the picture below:
graph_ov7740.png

Capturing

Capturing YUYV directly from the sensor

v4l2-ctl -v pixelformat=YUYV,height=480,width=640   # configure video format to YUYV packed 16 bits per pixel                             
media-ctl --set-v4l2 '"ov7740 0-0021":0[fmt:YUYV8_2X8/640x480@1/60 field:none colorspace:srgb]' # configure sensor to stream YUYV directly in 2 bytes per pixel 2x8
media-ctl --set-v4l2 '"csi2dc":0[fmt:YUYV8_2X8/640x480 field:none colorspace:srgb]' # configure csi2dc accordingly
media-ctl --set-v4l2 '"atmel_isc_scaler":0[fmt:YUYV8_2X8/640x480 field:none colorspace:srgb]' # configure scaler accordingly
fswebcam -r 640x480 -p YUYV -S 20 test.jpg        # capture YUYV packed 2 bytes per pixel at 640x480                               

Capturing RAW from sensor and converting in the ISC

v4l2-ctl -v pixelformat=YU12,height=480,width=640    # configure video format to YUV planar 4:2:0                             
media-ctl --set-v4l2 '"ov7740 0-0021":0[fmt:SBGGR8_1X8/640x480@1/60 field:none colorspace:srgb]' # configure sensor to stream raw bayer BGGR 8 bits 
media-ctl --set-v4l2 '"csi2dc":0[fmt:SBGGR8_1X8/640x480 field:none colorspace:srgb]' #configure csi2dc accordingly
media-ctl --set-v4l2 '"atmel_isc_scaler":0[fmt:SBGGR8_1X8/640x480 field:none colorspace:srgb]' #  configure scaler accordingly
fswebcam -r 640x480 -p YUV420P -S 20 testplanar.jpg    # simple capture at 640x480 in YUV4:2:0 planar                          

Supported sensor formats

We can always query the sensor for which formats it supports:
# v4l2-ctl -d /dev/v4l-subdev2 --list-subdev-mbus-codes
ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE (pad=0)
        0x2008: MEDIA_BUS_FMT_YUYV8_2X8
        0x3001: MEDIA_BUS_FMT_SBGGR8_1X8
#