summaryrefslogtreecommitdiffstats
path: root/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas')
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch2
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch4
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch49
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch51
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch197
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch45
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch77
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch304
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch44
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch90
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch60
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch53
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch53
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch162
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch53
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch1689
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch1021
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch154
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch51
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch51
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch51
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch30
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch4450
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch72
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch58
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch39
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch39
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch39
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch77
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch77
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch75
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch252
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch55
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch33
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch33
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch54
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch55
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch47
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch1162
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch36
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch67
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch866
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch6345
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch534
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch132
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch289
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch62
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch48
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch481
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch58
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch94
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch37
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch67
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch429
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch104
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch70
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch96
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch82
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch127
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch158
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch54
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch40
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch150
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch29
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch42
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch139
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch34
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch85
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch80
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch68
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch36
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch48
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch690
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch6794
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch4855
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch218
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch62
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch5202
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch165
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch135
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch579
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch1445
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch52
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch189
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch83
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch169
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch118
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch1843
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch97
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch46
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch33
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch120
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch85
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch1949
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch30
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch102
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch74
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch37
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch43
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch55
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch4377
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch620
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch1014
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch106
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch32
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch28
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch74
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg2
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg3
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg2
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc103
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg4
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg3
113 files changed, 53501 insertions, 32 deletions
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch
index 2f6fa35f..4b800adc 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch
@@ -262,7 +262,7 @@ index ff25470..2cce294 100644
- if ((fmtinfo->alpha) &&
+ dev_dbg(vsp1->dev, "rpf#%d: alpha=%x, fourcc=%x\n", rpf->entity.index, fmtinfo->alpha, fmtinfo->fourcc);
+
-+ if (0 && (fmtinfo->alpha) &&
++ if (fmtinfo->alpha &&
(fmtinfo->fourcc != V4L2_PIX_FMT_ARGB555)) {
/* When the input contains an alpha channel enable the
* alpha multiplier. If the input is premultiplied we
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch
index 8ec4be85..08fa2038 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0285-iommu-ipmmu-vmsa-Add-r8a779-7-8-0-whitelist.patch
@@ -19,12 +19,12 @@ index cdbfc53..52e292a 100644
NULL, /* Terminator */
};
-+/* R-Car E3 (R8A77970) */
++/* R-Car V3M (R8A77970) */
+static struct ipmmu_whitelist *r8a77970_whitelist[] = {
+ NULL, /* Terminator */
+};
+
-+/* R-Car E3 (R8A77980) */
++/* R-Car V3H (R8A77980) */
+static struct ipmmu_whitelist *r8a77980_whitelist[] = {
+ NULL, /* Terminator */
+};
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch
index 538ca4a6..5e455335 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch
@@ -14,9 +14,9 @@ Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 38 ++++++
drivers/gpu/drm/rcar-du/rcar_du_plane.c | 2 +
drivers/gpu/drm/rcar-du/rcar_du_plane.h | 5 +
- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 228 +++++++++++++++++++++++++++-----
+ drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 229 ++++++++++++++++++++++++++------
drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 7 +-
- 7 files changed, 249 insertions(+), 37 deletions(-)
+ 7 files changed, 249 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 9c0152d..5f1a175 100644
@@ -110,7 +110,7 @@ index d66ae53..f74bc6a 100644
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
-index 1b70db3..e934b4c 100644
+index 5818c59..74e0bb1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -11,6 +11,7 @@
@@ -146,7 +146,7 @@ index e0ddecf..3e9dfdb 100644
static inline struct rcar_du_plane_state *
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
-index c44d336..2b076cf 100644
+index 0c352a0..e53c20e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -11,6 +11,7 @@
@@ -492,34 +492,33 @@ index c44d336..2b076cf 100644
else
return -EINVAL;
-@@ -633,8 +777,10 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
+@@ -633,7 +777,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
drm_plane_helper_add(&plane->plane,
&rcar_du_vsp_plane_helper_funcs);
-+#if 0 // ...use same set of properties for all planes
- if (type == DRM_PLANE_TYPE_PRIMARY)
- continue;
-+#endif
-
- drm_object_attach_property(&plane->plane.base,
- rcdu->props.alpha, 255);
-@@ -647,6 +793,16 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
+- if (type == DRM_PLANE_TYPE_PRIMARY) {
++ // ...use same set of properties for all planes
++ if (0 && type == DRM_PLANE_TYPE_PRIMARY) {
+ drm_plane_create_zpos_immutable_property(&plane->plane,
+ 0);
+ } else {
+@@ -648,6 +793,16 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
0);
- drm_plane_create_zpos_property(&plane->plane, 1, 1,
+ drm_plane_create_zpos_property(&plane->plane, 1, 1,
vsp->num_planes - 1);
-+ drm_object_attach_property(&plane->plane.base,
-+ rcdu->props.alphaplane, 0);
-+ drm_object_attach_property(&plane->plane.base,
-+ rcdu->props.blend, 0);
-+ drm_object_attach_property(&plane->plane.base,
-+ rcdu->props.ckey, 0);
-+ drm_object_attach_property(&plane->plane.base,
-+ rcdu->props.ckey_set0, 0);
-+ drm_object_attach_property(&plane->plane.base,
-+ rcdu->props.ckey_set1, 0);
++ drm_object_attach_property(&plane->plane.base,
++ rcdu->props.alphaplane, 0);
++ drm_object_attach_property(&plane->plane.base,
++ rcdu->props.blend, 0);
++ drm_object_attach_property(&plane->plane.base,
++ rcdu->props.ckey, 0);
++ drm_object_attach_property(&plane->plane.base,
++ rcdu->props.ckey_set0, 0);
++ drm_object_attach_property(&plane->plane.base,
++ rcdu->props.ckey_set1, 0);
+ }
}
- return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
index 93dbb9e..083d065 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch
new file mode 100644
index 00000000..9557ae91
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0420-media-i2c-ov2311-fix-otp-id-read.patch
@@ -0,0 +1,51 @@
+From 3ef8db409fb567da880f15a08df5cea08f3f2a45 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 18 Sep 2019 14:18:49 +0300
+Subject: [PATCH] media: i2c: ov2311: fix otp id read
+
+The OTP ID may fail if power rail comes early and imager
+get into lpm mode.
+Hence read otp id after full setup and stream enable
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov2311.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov2311.c b/drivers/media/i2c/soc_camera/ov2311.c
+index f04f271..c61059d 100644
+--- a/drivers/media/i2c/soc_camera/ov2311.c
++++ b/drivers/media/i2c/soc_camera/ov2311.c
+@@ -376,7 +376,6 @@ static void ov2311_otp_id_read(struct i2c_client *client)
+ struct ov2311_priv *priv = to_ov2311(client);
+ int i;
+
+- reg16_write(client, 0x100, 1);
+ reg16_write(client, 0x3d81, 1);
+ usleep_range(25000, 25500); /* wait 25 ms */
+
+@@ -384,8 +383,6 @@ static void ov2311_otp_id_read(struct i2c_client *client)
+ /* first 6 bytes are equal on all ov2311 */
+ reg16_read(client, 0x7000 + i + 6, &priv->id[i]);
+ }
+-
+- reg16_write(client, 0x100, 0);
+ }
+
+ static ssize_t ov2311_otp_id_show(struct device *dev,
+@@ -432,10 +429,10 @@ static int ov2311_initialize(struct i2c_client *client)
+
+ /* check revision */
+ reg16_read(client, OV2311_REV, &rev);
+- /* Read OTP IDs */
+- ov2311_otp_id_read(client);
+ /* Program wizard registers */
+ ov2311_set_regs(client, ov2311_regs_wizard_r1c, ARRAY_SIZE(ov2311_regs_wizard_r1c));
++ /* Read OTP IDs */
++ ov2311_otp_id_read(client);
+
+ dev_info(&client->dev, "ov2311 PID %x (rev %x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, rev, OV2311_MAX_WIDTH, OV2311_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch
new file mode 100644
index 00000000..bbae277a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0421-media-i2c-imx390-add-user-defined-size-for-register-.patch
@@ -0,0 +1,197 @@
+From 5dc710a5cfcaf038155e2a6c6c1a5becfb684a41 Mon Sep 17 00:00:00 2001
+From: Petr Nechaev <petr.nechaev@cogentembedded.com>
+Date: Thu, 3 Oct 2019 14:04:23 +0300
+Subject: [PATCH] media: i2c: imx390: add user defined size for register access
+
+This adds user defined size during VIDIOC_DBG_G/S_REGISTER
+
+Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imx390.c | 20 +++++++----
+ drivers/media/i2c/soc_camera/max9286.h | 61 ++++++++++++++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ti9x4.h | 48 ++++++++++++++++++++++++++
+ 3 files changed, 123 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c
+index 87279d0..b1df1ba 100644
+--- a/drivers/media/i2c/soc_camera/imx390.c
++++ b/drivers/media/i2c/soc_camera/imx390.c
+@@ -213,16 +213,18 @@ static int imx390_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 s = reg->size;
+ int ret;
+- u8 val = 0;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
++ if (!s)
++ s = 4;
++ if (s > sizeof(reg->val))
++ s = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&reg->val, s);
+ if (ret < 0)
+ return ret;
+
+- reg->val = val;
+- reg->size = sizeof(u8);
+-
+ return 0;
+ }
+
+@@ -230,8 +232,14 @@ static int imx390_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 s = reg->size;
++
++ if (!s)
++ s = 4;
++ if (s > sizeof(reg->val))
++ s = sizeof(reg->val);
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ return reg16_write_n(client, (u16)reg->reg, (u8*)&reg->val, s);
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h
+index 2875b3c..b53ac27 100644
+--- a/drivers/media/i2c/soc_camera/max9286.h
++++ b/drivers/media/i2c/soc_camera/max9286.h
+@@ -131,6 +131,67 @@ static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
+ return ret < 0 ? ret : 0;
+ }
+
++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, val, n);
++ if (ret == n)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
++{
++ int ret, retries;
++ u8 buf[2 + n];
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ memcpy(&buf[2], val, n);
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2 + n);
++ if (ret == 2 + n)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2[n];
++ ret = reg16_read_n(client, reg, val2, n);
++ if (ret < 0)
++ return ret;
++
++ if (memcmp(val, val2, n)) {
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x-0x%x "
++ "'%*phN'->'%*phN'\n", client->addr, reg, reg + n,
++ n, val, n, val2);
++ ret = -EBADE;
++ }
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
+
+ static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
+ {
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.h b/drivers/media/i2c/soc_camera/ti9x4.h
+index b53b4c6..6825f8a 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.h
++++ b/drivers/media/i2c/soc_camera/ti9x4.h
+@@ -109,6 +109,53 @@ static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
+ return ret < 0 ? ret : 0;
+ }
+
++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, val, n);
++ if (ret == n)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
++{
++ int ret, retries;
++ u8 buf[2 + n];
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ memcpy(&buf[2], val, n);
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2 + n);
++ if (ret == 2 + n)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
+ static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
+ {
+ int ret, retries;
+@@ -154,3 +201,4 @@ static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
+ return ret < 0 ? ret : 0;
+ }
+ #endif /* _TI9X4_H */
++
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch
new file mode 100644
index 00000000..2225db0d
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch
@@ -0,0 +1,45 @@
+From b0b23fee0c630e00e5a117a1fc48cf11de356822 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Fri, 25 Oct 2019 00:59:49 +0300
+Subject: [PATCH] mmc: core: mmc: Try other timings if the higher one fails
+
+Do not bail out in case the higher supported timing
+setup fails. Try other supported timings as well.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/mmc/core/mmc.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index bad5c1b..c7c1c54 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -1473,12 +1473,21 @@ static int mmc_select_timing(struct mmc_card *card)
+ if (!mmc_can_ext_csd(card))
+ goto bus_speed;
+
+- if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
+ err = mmc_select_hs400es(card);
+- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
++ if (!err)
++ goto bus_speed;
++ }
++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) {
+ err = mmc_select_hs200(card);
+- else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
++ if (!err)
++ goto bus_speed;
++ }
++ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) {
+ err = mmc_select_hs(card);
++ if (!err)
++ goto bus_speed;
++ }
+
+ if (err && err != -EBADMSG)
+ return err;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch
new file mode 100644
index 00000000..9928e879
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch
@@ -0,0 +1,77 @@
+From 45e394a4669fa60e5e0837f68148907af7b757eb Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 1 Nov 2019 21:46:47 +0300
+Subject: [PATCH] media: i2c: ap0101_ar014x: add AP0102 chip
+
+This add AP0102 ISP support
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ap0101_ar014x.c | 31 ++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+index c35e5a0..4df5793 100644
+--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+@@ -1,7 +1,7 @@
+ /*
+- * ON Semiconductor AP0101-AR014X sensor camera driver
++ * ON Semiconductor AP010X-AR014X sensor camera driver
+ *
+- * Copyright (C) 2018 Cogent Embedded, Inc.
++ * Copyright (C) 2018-2019 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -26,6 +26,7 @@ static const int ap0101_i2c_addr[] = {0x5d, 0x48};
+
+ #define AP0101_PID 0x0000
+ #define AP0101_VERSION_REG 0x0160
++#define AP0102_VERSION_REG 0x0064
+
+ #define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8
+
+@@ -432,24 +433,28 @@ static int ap0101_initialize(struct i2c_client *client)
+ /* check model ID */
+ reg16_read16(client, AP0101_PID, &pid);
+
+- if (pid == AP0101_VERSION_REG)
++ if (pid == AP0101_VERSION_REG || pid == AP0102_VERSION_REG)
+ break;
+ }
+
+- /* check and show model ID */
+- reg16_read16(client, AP0101_PID, &pid);
+-
+- if (pid != AP0101_VERSION_REG) {
+- dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ if (pid != AP0101_VERSION_REG && pid != AP0102_VERSION_REG) {
++ dev_err(&client->dev, "Product ID error %x\n", pid);
+ ret = -ENODEV;
+ goto err;
+ }
+ #if 1
+- /* read resolution used by current firmware */
+- reg16_read16(client, 0xca90, &val);
+- priv->max_width = val;
+- reg16_read16(client, 0xca92, &val);
+- priv->max_height = val;
++ if (pid == AP0101_VERSION_REG) {
++ /* read resolution used by current firmware */
++ reg16_read16(client, 0xca90, &val);
++ priv->max_width = val;
++ reg16_read16(client, 0xca92, &val);
++ priv->max_height = val;
++ } else if (pid == AP0102_VERSION_REG) {
++ reg16_read16(client, 0xcae4, &val);
++ priv->max_width = val;
++ reg16_read16(client, 0xcae6, &val);
++ priv->max_height = val;
++ }
+ #else
+ priv->max_width = AP0101_MAX_WIDTH;
+ priv->max_height = AP0101_MAX_HEIGHT;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch
new file mode 100644
index 00000000..7de384e3
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch
@@ -0,0 +1,304 @@
+From 291865bff36306d70c6975e73eb299d977abbc2c Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Tue, 5 Nov 2019 19:40:06 +0300
+Subject: [PATCH] arm64: dts: renesas: ulcb-vb: Fix lvds0 port routing
+
+This fixes LVDS port routing on all H3ULCB VideoBox
+boards which is needed for the FDPLink output.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts | 8 +++++---
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts | 8 +++++---
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts | 11 +++++++++--
+ arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts | 8 +++++---
+ arch/arm64/boot/dts/renesas/ulcb-vb.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 2 +-
+ arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi | 2 +-
+ 14 files changed, 90 insertions(+), 28 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts
+index db9f80f..310d2df 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb.dts
+@@ -34,8 +34,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts
+index 6d51ffd..65b9aa5 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts
+@@ -40,8 +40,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts
+index 64815d4..a3b51da 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts
+@@ -15,10 +15,12 @@
+ model = "Renesas H3ULCB Videobox Mini board based on r8a7795";
+ };
+
+-&du {
++&lvds0 {
++ status = "okay";
++
+ ports {
+- port@3 {
+- endpoint {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts
+index ce16cab..1f8c229 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts
+index 1a9d0be..aa99875 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts
+index 1351c6f..fb45133 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts
+index 352cc0d..b415e88 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vbm.dts
+@@ -15,10 +15,12 @@
+ model = "Renesas H3ULCB with 8GiB (4 x 2 GiB) Videobox Mini board based on r8a7795";
+ };
+
+-&du {
++&lvds0 {
++ status = "okay";
++
+ ports {
+- port@3 {
+- endpoint {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts
+index 26c15f4..9517ff0 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts
+index 43c20b0..5f97b60 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts
+index 816c7da..56d43d07 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts
+@@ -33,8 +33,15 @@
+ remote-endpoint = <&rcar_dw_hdmi1_in>;
+ };
+ };
+- port@3 {
+- endpoint {
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts
+index 053a60e..7fcf527 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts
+@@ -15,10 +15,12 @@
+ model = "Renesas H3ULCB Videobox Mini board based on r8a7795";
+ };
+
+-&du {
++&lvds0 {
++ status = "okay";
++
+ ports {
+- port@3 {
+- endpoint {
++ port@1 {
++ lvds0_out: endpoint {
+ remote-endpoint = <&lvds_in>;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi
+index 67903db..6fb2b38 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi
+@@ -145,7 +145,7 @@
+
+ port {
+ lvds_in: endpoint {
+- remote-endpoint = <&du_out_lvds0>;
++ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
+index 50cdfd8..1a73059 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
+@@ -137,7 +137,7 @@
+
+ port {
+ lvds_in: endpoint {
+- remote-endpoint = <&du_out_lvds0>;
++ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi
+index 067607a..b7e3817 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi
+@@ -36,7 +36,7 @@
+
+ port {
+ lvds_in: endpoint {
+- remote-endpoint = <&du_out_lvds0>;
++ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch
new file mode 100644
index 00000000..a2809257
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch
@@ -0,0 +1,44 @@
+From 7cd42e725a0221bb9c0443b15311fe3f5d37ed97 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 9 Oct 2019 18:34:48 +0300
+Subject: [PATCH] arm64: dts: r8a7798-v3hsk-vb-4/8ch: change i2c rate to 400khz
+
+Change i2c rate to 400kHz for bus with cameras.
+This speeds up the cameras backchannel transactions.
+The restriction of 100khz for cs2300 looks not needed for rev C1 chip.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
+index 12ef357..4ca62c6 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
+@@ -142,7 +142,7 @@
+ pinctrl-names = "default";
+ status = "okay";
+
+- clock-frequency = <100000>;
++ clock-frequency = <400000>;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
+index 861b90f..b635132 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
+@@ -142,7 +142,7 @@
+ pinctrl-names = "default";
+ status = "okay";
+
+- clock-frequency = <100000>;
++ clock-frequency = <400000>;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch
new file mode 100644
index 00000000..6a89c310
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0426-media-i2c-ov106xx-change-order.patch
@@ -0,0 +1,90 @@
+From a9fc14847d14cb2dabad47064b1821928e8a743a Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 6 Nov 2019 15:17:50 +0300
+Subject: [PATCH] media: i2c: ov106xx: change order
+
+Put OV2775, OX03A tail becase they force change serilzier gpios.
+Becase of this chagne the further autodetection becomes broken.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov106xx.c | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index c7f1bbe..624f0be 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -79,6 +79,12 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
++ ret = ap0101_probe(client, did);
++ if (!ret) {
++ chip_id = ID_AP0101_AR014X;
++ goto out;
++ }
++
+ ret = ov495_probe(client, did);
+ if (!ret) {
+ chip_id = ID_OV495_OV2775;
+@@ -139,12 +145,6 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = ap0101_probe(client, did);
+- if (!ret) {
+- chip_id = ID_AP0101_AR014X;
+- goto out;
+- }
+-
+ ret = gw4200_probe(client, did);
+ if (!ret) {
+ chip_id = ID_GW4200_AR014X;
+@@ -157,33 +157,33 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = ov2775_probe(client, did);
++ ret = imx390_probe(client, did);
+ if (!ret) {
+- chip_id = ID_OV2775;
++ chip_id = ID_IMX390;
+ goto out;
+ }
+
+- ret = imx390_probe(client, did);
++ ret = isx016_probe(client, did);
+ if (!ret) {
+- chip_id = ID_IMX390;
++ chip_id = ID_ISX016;
+ goto out;
+ }
+
+- ret = ox03a_probe(client, did);
++ ret = isx019_probe(client, did);
+ if (!ret) {
+- chip_id = ID_OX03A;
++ chip_id = ID_ISX019;
+ goto out;
+ }
+
+- ret = isx016_probe(client, did);
++ ret = ov2775_probe(client, did);
+ if (!ret) {
+- chip_id = ID_ISX016;
++ chip_id = ID_OV2775;
+ goto out;
+ }
+
+- ret = isx019_probe(client, did);
++ ret = ox03a_probe(client, did);
+ if (!ret) {
+- chip_id = ID_ISX019;
++ chip_id = ID_OX03A;
+ goto out;
+ }
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch
new file mode 100644
index 00000000..c4c74b51
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0427-media-i2c-gw5200-fix-imager-hang.patch
@@ -0,0 +1,60 @@
+From 424d69732e6085cc527c66fef8e2bea5584ebc4f Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 7 Nov 2019 20:31:27 +0300
+Subject: [PATCH] media: i2c: gw5200: fix imager hang
+
+The LI-GW5200-IMX390 firmare may hang on any of 16bit i2c transaction.
+Since the GW5200 is forceed detection then no problem to put it head
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gw5200_imx390.c | 2 +-
+ drivers/media/i2c/soc_camera/ov106xx.c | 12 ++++++------
+ 2 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gw5200_imx390.c b/drivers/media/i2c/soc_camera/gw5200_imx390.c
+index e750a85..2fcfced 100644
+--- a/drivers/media/i2c/soc_camera/gw5200_imx390.c
++++ b/drivers/media/i2c/soc_camera/gw5200_imx390.c
+@@ -22,7 +22,7 @@
+
+ #include "gw5200_imx390.h"
+
+-static const int gw5200_i2c_addr[] = {0x6d};
++static const int gw5200_i2c_addr[] = {0x6c};
+
+ #define GW5200_PID 0x00
+ #define GW5200_VERSION_REG 0x00
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 624f0be..208267c 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -61,6 +61,12 @@ static int ov106xx_probe(struct i2c_client *client,
+ int ret = -1;
+ chip_id = -EINVAL;
+
++ ret = gw5200_probe(client, did);
++ if (!ret) {
++ chip_id = ID_GW5200_IMX390;
++ goto out;
++ }
++
+ ret = ar0231_probe(client, did);
+ if (!ret) {
+ chip_id = ID_AR0231;
+@@ -151,12 +157,6 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = gw5200_probe(client, did);
+- if (!ret) {
+- chip_id = ID_GW5200_IMX390;
+- goto out;
+- }
+-
+ ret = imx390_probe(client, did);
+ if (!ret) {
+ chip_id = ID_IMX390;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch
new file mode 100644
index 00000000..ec40f20d
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch
@@ -0,0 +1,53 @@
+From 63a0c5c8fef06c0894a81d6e31b2b3eeec452f74 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Sat, 9 Nov 2019 20:22:31 +0300
+Subject: [PATCH 1/2] arch64: dts: renesas: r8a77970: Fix IPMMU probe order
+
+This moves the main IPMMU node in front of all the other IPMMU
+nodes to prevent PROBE_DEFER errors and late initialization
+of the slave IPMMU devices.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77970.dtsi | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+index 7ecbc01..456eeb6 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+@@ -1121,6 +1121,15 @@
+ <&ipmmu_ds1 22>, <&ipmmu_ds1 23>;
+ };
+
++ ipmmu_mm: mmu@e67b0000 {
++ compatible = "renesas,ipmmu-r8a77970";
++ reg = <0 0xe67b0000 0 0x1000>;
++ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
++ power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
++ #iommu-cells = <1>;
++ };
++
+ ipmmu_ds1: mmu@e7740000 {
+ compatible = "renesas,ipmmu-r8a77970";
+ reg = <0 0xe7740000 0 0x1000>;
+@@ -1137,15 +1146,6 @@
+ #iommu-cells = <1>;
+ };
+
+- ipmmu_mm: mmu@e67b0000 {
+- compatible = "renesas,ipmmu-r8a77970";
+- reg = <0 0xe67b0000 0 0x1000>;
+- interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+- power-domains = <&sysc R8A77970_PD_ALWAYS_ON>;
+- #iommu-cells = <1>;
+- };
+-
+ ipmmu_rt: mmu@ffc80000 {
+ compatible = "renesas,ipmmu-r8a77970";
+ reg = <0 0xffc80000 0 0x1000>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch
new file mode 100644
index 00000000..634576cc
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch
@@ -0,0 +1,53 @@
+From 86a07c0c042acb9f06c11c9319294d83d6ecbb59 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Sat, 9 Nov 2019 20:33:36 +0300
+Subject: [PATCH 2/2] arch64: dts: renesas: r8a77980: Fix IPMMU probe order
+
+This moves the main IPMMU node in front of all the other IPMMU
+nodes to prevent PROBE_DEFER errors and late initialization
+of the slave IPMMU devices.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77980.dtsi | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+index 045b517..0d25b35 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+@@ -1636,6 +1636,15 @@
+ status = "disabled";
+ };
+
++ ipmmu_mm: mmu@e67b0000 {
++ compatible = "renesas,ipmmu-r8a77980";
++ reg = <0 0xe67b0000 0 0x1000>;
++ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
++ power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
++ #iommu-cells = <1>;
++ };
++
+ ipmmu_ds1: mmu@e7740000 {
+ compatible = "renesas,ipmmu-r8a77980";
+ reg = <0 0xe7740000 0 0x1000>;
+@@ -1652,15 +1661,6 @@
+ #iommu-cells = <1>;
+ };
+
+- ipmmu_mm: mmu@e67b0000 {
+- compatible = "renesas,ipmmu-r8a77980";
+- reg = <0 0xe67b0000 0 0x1000>;
+- interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+- power-domains = <&sysc R8A77980_PD_ALWAYS_ON>;
+- #iommu-cells = <1>;
+- };
+-
+ ipmmu_rt: mmu@ffc80000 {
+ compatible = "renesas,ipmmu-r8a77980";
+ reg = <0 0xffc80000 0 0x1000>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch
new file mode 100644
index 00000000..cdec2996
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch
@@ -0,0 +1,162 @@
+From 8eb36a5043bfb90974d3149f29197cb7f72df171 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 12 Nov 2019 22:57:34 +0300
+Subject: [PATCH] media: i2c: ar0140: update driver to use rGPIO and dynamic
+ i2c
+
+This fix driver to use remote gpio from deserizlier and dynamic
+i2c probing
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0140.c | 36 +++++++++++++++++++++-------------
+ drivers/media/i2c/soc_camera/ar0140.h | 4 +---
+ drivers/media/i2c/soc_camera/ov106xx.c | 22 ++++++++++-----------
+ 3 files changed, 34 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c
+index b156fc5..ec2b2e5 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.c
++++ b/drivers/media/i2c/soc_camera/ar0140.c
+@@ -22,7 +22,7 @@
+
+ #include "ar0140.h"
+
+-#define AR0140_I2C_ADDR 0x10
++static const int ar0140_i2c_addr[] = {0x10, 0x20};
+
+ #define AR0140_PID 0x3000
+ #define AR0140_VERSION_REG 0x0051
+@@ -407,15 +407,30 @@ static DEVICE_ATTR(otp_id_ar0140, S_IRUGO, ar0140_otp_id_show, NULL);
+ static int ar0140_initialize(struct i2c_client *client)
+ {
+ struct ar0140_priv *priv = to_ar0140(client);
+- u16 val = 0;
+- u16 pid = 0;
++ u16 val = 0, pid = 0;
+ int ret = 0;
+- int tmp_addr;
++ int tmp_addr, i;
+
+- ar0140_s_port(client, 1);
++ for (i = 0; i < ARRAY_SIZE(ar0140_i2c_addr); i++) {
++ tmp_addr = client->addr;
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x4_addr;
++ reg8_write(client, 0x5d, ar0140_i2c_addr[i] << 1); /* Sensor native I2C address */
++ usleep_range(2000, 2500);
++ }
++ if (priv->max9286_addr) {
++ client->addr = priv->max9271_addr;
++ reg8_write(client, 0x0a, ar0140_i2c_addr[i] << 1); /* Sensor native I2C address */
++ usleep_range(2000, 2500);
++ };
++ client->addr = tmp_addr;
+
+- /* check and show model ID */
+- reg16_read16(client, AR0140_PID, &pid);
++ /* check model ID */
++ reg16_read16(client, AR0140_PID, &pid);
++
++ if (pid == AR0140_VERSION_REG)
++ break;
++ }
+
+ if (pid != AR0140_VERSION_REG) {
+ dev_dbg(&client->dev, "Product ID error %x\n", pid);
+@@ -452,7 +467,6 @@ static int ar0140_initialize(struct i2c_client *client)
+ pid, AR0140_MAX_WIDTH, AR0140_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ err:
+ ar0140_s_port(client, 0);
+-
+ return ret;
+ }
+
+@@ -499,7 +513,6 @@ static int ar0140_parse_dt(struct device_node *np, struct ar0140_priv *priv)
+ client->addr = priv->max9271_addr; /* Serializer I2C address */
+
+ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */
+- reg8_write(client, 0x0A, AR0140_I2C_ADDR << 1); /* Sensor native I2C address */
+ usleep_range(2000, 2500); /* wait 2ms */
+ };
+ if (priv->ti9x4_addr) {
+@@ -508,14 +521,9 @@ static int ar0140_parse_dt(struct device_node *np, struct ar0140_priv *priv)
+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
+ usleep_range(2000, 2500); /* wait 2ms */
+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
+- reg8_write(client, 0x5d, AR0140_I2C_ADDR << 1); /* Sensor native I2C address */
+-
+- reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - reset */
+ }
+ client->addr = tmp_addr;
+
+- mdelay(10);
+-
+ return 0;
+ }
+
+diff --git a/drivers/media/i2c/soc_camera/ar0140.h b/drivers/media/i2c/soc_camera/ar0140.h
+index f90762c..2993478 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.h
++++ b/drivers/media/i2c/soc_camera/ar0140.h
+@@ -467,9 +467,7 @@ static const struct ar0140_reg ar0140_regs_wizard[] = {
+ // patch start
+ {0x3012, 0x0206}, // COARSE_INTEGRATION_TIME_: T1 exposure - max=0x400
+ // patch end
+-// enable trigger
+-{0x340A, 0x0070}, // GPIO_CONTROL1: GPIO3 is trigger
+-{0x340C, 0x0080}, // GPIO_CONTROL2: GPIO3 is trigger
++// enable trigger (trigger pin is dedicated)
+ {0x30CE, 0x0120}, // TRIGGER_MODE
+ //{0x30DC, 0x0120}, // TRIGGER_DELAY
+ };
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 208267c..08d3816 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -67,6 +67,12 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
++ ret = ar0140_probe(client, did);
++ if (!ret) {
++ chip_id = ID_AR0140;
++ goto out;
++ }
++
+ ret = ar0231_probe(client, did);
+ if (!ret) {
+ chip_id = ID_AR0231;
+@@ -85,11 +91,11 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = ap0101_probe(client, did);
+- if (!ret) {
+- chip_id = ID_AP0101_AR014X;
+- goto out;
+- }
++ ret = ap0101_probe(client, did);
++ if (!ret) {
++ chip_id = ID_AP0101_AR014X;
++ goto out;
++ }
+
+ ret = ov495_probe(client, did);
+ if (!ret) {
+@@ -127,12 +133,6 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = ar0140_probe(client, did);
+- if (!ret) {
+- chip_id = ID_AR0140;
+- goto out;
+- }
+-
+ ret = ar0143_probe(client, did);
+ if (!ret) {
+ chip_id = ID_AR0143;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch
new file mode 100644
index 00000000..79006e58
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0431-media-i2c-ti9x4-update-remote-gpio-function.patch
@@ -0,0 +1,53 @@
+From 9098f3a6deac6fb81695cf7fbf97e32ac3e0c399 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 15 Nov 2019 14:31:52 +0300
+Subject: [PATCH] media: i2c: ti9x4: update remote gpio function
+
+Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side:
+this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by
+unstable/bad link, hence unstable backchannel
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ti9x4.c | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+index 0cfcfaa..aa85d92 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -327,14 +327,29 @@ static int ti9x4_initialize(struct i2c_client *client)
+ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
+ usleep_range(1000, 1500); /* wait 1ms */
+
++ /*
++ * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side:
++ * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by
++ * unstable/bad link, hence unstable backchannel
++ */
+ client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */
+ switch (priv->ser_id) {
+ case TI913_ID:
+ reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */
+ break;
+ case TI953_ID:
+- reg8_write(client, 0x0d, 0xf0); /* Enable all remote GPIOs */
+- reg8_write(client, 0x0e, 0xf0); /* Enable serializer GPIOs */
++ reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 |
++ (priv->gpio[1] & 0x1) << 1 |
++ (priv->gpio[2] & 0x1) << 2 |
++ (priv->gpio[3] & 0x1) << 3 |
++ (priv->gpio[0] & 0x2) << 3 |
++ (priv->gpio[1] & 0x2) << 4 |
++ (priv->gpio[2] & 0x2) << 5 |
++ (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */
++ reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) |
++ (!!priv->gpio[1] << 5) |
++ (!!priv->gpio[2] << 6) |
++ (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */
+ break;
+ }
+ client->addr = priv->des_addr;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch
new file mode 100644
index 00000000..eb37d0a9
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0432-media-i2c-soc_camera-add-AR0220.patch
@@ -0,0 +1,1689 @@
+From b79fd9163f868b78aea5ba634b52541d518f10a5 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 18 Nov 2019 19:07:21 +0300
+Subject: [PATCH] media: i2c: soc_camera: add AR0220
+
+This adds AR0220 imager glue driver
+The chip is appended to AR0233 glue for further rework of all AR0XXX chips
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0220.c | 539 -----------------------------
+ drivers/media/i2c/soc_camera/ar0220.h | 39 +--
+ drivers/media/i2c/soc_camera/ar0220_rev4.h | 370 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ar0233.c | 164 ++++++---
+ drivers/media/i2c/soc_camera/ar0233.h | 7 -
+ drivers/media/i2c/soc_camera/ar0233_rev1.h | 26 +-
+ drivers/media/i2c/soc_camera/ar0233_rev2.h | 38 +-
+ drivers/media/i2c/soc_camera/ov106xx.c | 54 ++-
+ 8 files changed, 549 insertions(+), 688 deletions(-)
+ delete mode 100644 drivers/media/i2c/soc_camera/ar0220.c
+ create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev4.h
+
+diff --git a/drivers/media/i2c/soc_camera/ar0220.c b/drivers/media/i2c/soc_camera/ar0220.c
+deleted file mode 100644
+index b1ca101..0000000
+--- a/drivers/media/i2c/soc_camera/ar0220.c
++++ /dev/null
+@@ -1,539 +0,0 @@
+-/*
+- * ON Semiconductor AR0220 sensor camera driver
+- *
+- * Copyright (C) 2017-2018 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/i2c.h>
+-#include <linux/module.h>
+-#include <linux/of_graph.h>
+-#include <linux/videodev2.h>
+-
+-#include <media/soc_camera.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ctrls.h>
+-
+-#include "ar0220.h"
+-
+-#define AR0220_I2C_ADDR 0x10
+-//#define AR0220_I2C_ADDR 0x54 // eeprom
+-
+-#define AR0220_PID 0x3000
+-#define AR0220_VERSION_REG 0x0C54
+-
+-#define AR0220_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG14_1X14
+-
+-struct ar0220_priv {
+- struct v4l2_subdev sd;
+- struct v4l2_ctrl_handler hdl;
+- struct media_pad pad;
+- struct v4l2_rect rect;
+- int init_complete;
+- u8 id[6];
+- int exposure;
+- int gain;
+- int autogain;
+- /* serializers */
+- int ti9x4_addr;
+- int ti9x3_addr;
+- int port;
+- int gpio_resetb;
+- int gpio_fsin;
+-};
+-
+-static inline struct ar0220_priv *to_ar0220(const struct i2c_client *client)
+-{
+- return container_of(i2c_get_clientdata(client), struct ar0220_priv, sd);
+-}
+-
+-static int ar0220_set_regs(struct i2c_client *client,
+- const struct ar0220_reg *regs, int nr_regs)
+-{
+- int i;
+-
+- for (i = 0; i < nr_regs; i++) {
+- if (regs[i].reg == AR0220_DELAY) {
+- mdelay(regs[i].val);
+- continue;
+- }
+-
+- reg16_write16(client, regs[i].reg, regs[i].val);
+- }
+-
+- return 0;
+-}
+-
+-static int ar0220_s_stream(struct v4l2_subdev *sd, int enable)
+-{
+- return 0;
+-}
+-
+-static int ar0220_get_fmt(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_format *format)
+-{
+- struct v4l2_mbus_framefmt *mf = &format->format;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+-
+- if (format->pad)
+- return -EINVAL;
+-
+- mf->width = priv->rect.width;
+- mf->height = priv->rect.height;
+- mf->code = AR0220_MEDIA_BUS_FMT;
+- mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+- mf->field = V4L2_FIELD_NONE;
+-
+- return 0;
+-}
+-
+-static int ar0220_set_fmt(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_format *format)
+-{
+- struct v4l2_mbus_framefmt *mf = &format->format;
+-
+- mf->code = AR0220_MEDIA_BUS_FMT;
+- mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+- mf->field = V4L2_FIELD_NONE;
+-
+- if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+- cfg->try_fmt = *mf;
+-
+- return 0;
+-}
+-
+-static int ar0220_enum_mbus_code(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_mbus_code_enum *code)
+-{
+- if (code->pad || code->index > 0)
+- return -EINVAL;
+-
+- code->code = AR0220_MEDIA_BUS_FMT;
+-
+- return 0;
+-}
+-
+-static int ar0220_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+-
+- memcpy(edid->edid, priv->id, 6);
+-
+- edid->edid[6] = 0xff;
+- edid->edid[7] = client->addr;
+- edid->edid[8] = AR0220_VERSION_REG >> 8;
+- edid->edid[9] = AR0220_VERSION_REG & 0xff;
+-
+- return 0;
+-}
+-
+-static int ar0220_set_selection(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_selection *sel)
+-{
+- struct v4l2_rect *rect = &sel->r;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+-
+- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+- sel->target != V4L2_SEL_TGT_CROP)
+- return -EINVAL;
+-
+- rect->left = ALIGN(rect->left, 2);
+- rect->top = ALIGN(rect->top, 2);
+- rect->width = ALIGN(rect->width, 2);
+- rect->height = ALIGN(rect->height, 2);
+-
+- if ((rect->left + rect->width > AR0220_MAX_WIDTH) ||
+- (rect->top + rect->height > AR0220_MAX_HEIGHT))
+- *rect = priv->rect;
+-
+- priv->rect.left = rect->left;
+- priv->rect.top = rect->top;
+- priv->rect.width = rect->width;
+- priv->rect.height = rect->height;
+-
+- return 0;
+-}
+-
+-static int ar0220_get_selection(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_selection *sel)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+-
+- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+- return -EINVAL;
+-
+- switch (sel->target) {
+- case V4L2_SEL_TGT_CROP_BOUNDS:
+- sel->r.left = 0;
+- sel->r.top = 0;
+- sel->r.width = AR0220_MAX_WIDTH;
+- sel->r.height = AR0220_MAX_HEIGHT;
+- return 0;
+- case V4L2_SEL_TGT_CROP_DEFAULT:
+- sel->r.left = 0;
+- sel->r.top = 0;
+- sel->r.width = AR0220_MAX_WIDTH;
+- sel->r.height = AR0220_MAX_HEIGHT;
+- return 0;
+- case V4L2_SEL_TGT_CROP:
+- sel->r = priv->rect;
+- return 0;
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int ar0220_g_mbus_config(struct v4l2_subdev *sd,
+- struct v4l2_mbus_config *cfg)
+-{
+- cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+- cfg->type = V4L2_MBUS_CSI2;
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-static int ar0220_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- int ret;
+- u16 val = 0;
+-
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
+-
+- reg->val = val;
+- reg->size = sizeof(u16);
+-
+- return 0;
+-}
+-
+-static int ar0220_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+-
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
+-}
+-#endif
+-
+-static struct v4l2_subdev_core_ops ar0220_core_ops = {
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- .g_register = ar0220_g_register,
+- .s_register = ar0220_s_register,
+-#endif
+-};
+-
+-static int ar0220_s_ctrl(struct v4l2_ctrl *ctrl)
+-{
+- struct v4l2_subdev *sd = to_sd(ctrl);
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+- int ret = -EINVAL;
+-
+- if (!priv->init_complete)
+- return 0;
+-
+- switch (ctrl->id) {
+- case V4L2_CID_BRIGHTNESS:
+- case V4L2_CID_CONTRAST:
+- case V4L2_CID_SATURATION:
+- case V4L2_CID_HUE:
+- case V4L2_CID_GAMMA:
+- case V4L2_CID_SHARPNESS:
+- case V4L2_CID_AUTOGAIN:
+- case V4L2_CID_GAIN:
+- case V4L2_CID_EXPOSURE:
+- case V4L2_CID_HFLIP:
+- case V4L2_CID_VFLIP:
+- break;
+- }
+-
+- return ret;
+-}
+-
+-static const struct v4l2_ctrl_ops ar0220_ctrl_ops = {
+- .s_ctrl = ar0220_s_ctrl,
+-};
+-
+-static struct v4l2_subdev_video_ops ar0220_video_ops = {
+- .s_stream = ar0220_s_stream,
+- .g_mbus_config = ar0220_g_mbus_config,
+-};
+-
+-static const struct v4l2_subdev_pad_ops ar0220_subdev_pad_ops = {
+- .get_edid = ar0220_get_edid,
+- .enum_mbus_code = ar0220_enum_mbus_code,
+- .get_selection = ar0220_get_selection,
+- .set_selection = ar0220_set_selection,
+- .get_fmt = ar0220_get_fmt,
+- .set_fmt = ar0220_set_fmt,
+-};
+-
+-static struct v4l2_subdev_ops ar0220_subdev_ops = {
+- .core = &ar0220_core_ops,
+- .video = &ar0220_video_ops,
+- .pad = &ar0220_subdev_pad_ops,
+-};
+-
+-static void ar0220_otp_id_read(struct i2c_client *client)
+-{
+-}
+-
+-static ssize_t ar0220_otp_id_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct ar0220_priv *priv = to_ar0220(client);
+-
+- return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+- priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+-}
+-
+-static DEVICE_ATTR(otp_id_ar0220, S_IRUGO, ar0220_otp_id_show, NULL);
+-
+-static int ar0220_initialize(struct i2c_client *client)
+-{
+- struct ar0220_priv *priv = to_ar0220(client);
+- u16 val = 0;
+- u16 pid = 0;
+- int ret = 0;
+- int tmp_addr;
+-
+- /* check and show model ID */
+- reg16_read16(client, AR0220_PID, &pid);
+-
+- if (pid != AR0220_VERSION_REG) {
+- dev_dbg(&client->dev, "Product ID error %x\n", pid);
+- ret = -ENODEV;
+- goto err;
+- }
+-
+- /* setup XCLK */
+- tmp_addr = client->addr;
+- if (priv->ti9x4_addr) {
+- /* CLK_OUT=22.5792*160*M/N/CLKDIV -> CLK_OUT=27MHz: CLKDIV=2, M=15, N=251: 22.5792*160/8*15/251=26.987MHz=CLK_OUT */
+- client->addr = priv->ti9x3_addr; /* Serializer I2C address */
+- reg8_write(client, 0x06, 0x6f); /* Set CLKDIV and M */
+- reg8_write(client, 0x07, 0xfb); /* Set N */
+- }
+- client->addr = tmp_addr;
+-
+- /* Program wizard registers */
+- ar0220_set_regs(client, ar0220_regs_wizard, ARRAY_SIZE(ar0220_regs_wizard));
+-
+- /* Enable stream */
+- reg16_read16(client, 0x301a, &val); // read inital reset_register value
+- val |= (1 << 2); // Set streamOn bit
+- reg16_write16(client, 0x301a, val); // Start Streaming
+-
+- /* Read OTP IDs */
+- ar0220_otp_id_read(client);
+-
+- dev_info(&client->dev, "ar0220 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+- pid, AR0220_MAX_WIDTH, AR0220_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+-err:
+- return ret;
+-}
+-
+-static int ar0220_parse_dt(struct device_node *np, struct ar0220_priv *priv)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
+- int i;
+- struct device_node *endpoint = NULL, *rendpoint = NULL;
+- int tmp_addr = 0;
+-
+- for (i = 0; ; i++) {
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (!endpoint)
+- break;
+-
+-
+- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
+- if (!rendpoint)
+- continue;
+-
+- if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) &&
+- !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") &&
+- !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) &&
+- !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port))
+- break;
+- }
+-
+- of_node_put(endpoint);
+-
+- if (!priv->ti9x4_addr) {
+- dev_err(&client->dev, "deserializer does not present\n");
+- return -EINVAL;
+- }
+-
+- /* setup I2C translator address */
+- tmp_addr = client->addr;
+- if (priv->ti9x4_addr) {
+- client->addr = priv->ti9x4_addr; /* Deserializer I2C address */
+-
+- reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
+- usleep_range(2000, 2500); /* wait 2ms */
+- reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
+- reg8_write(client, 0x5d, AR0220_I2C_ADDR << 1); /* Sensor native I2C address */
+-
+-// reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */
+- }
+- client->addr = tmp_addr;
+-
+- mdelay(10);
+-
+- return 0;
+-}
+-
+-static int ar0220_probe(struct i2c_client *client,
+- const struct i2c_device_id *did)
+-{
+- struct ar0220_priv *priv;
+- int ret;
+-
+- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- v4l2_i2c_subdev_init(&priv->sd, client, &ar0220_subdev_ops);
+- priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+-
+- priv->exposure = 0x100;
+- priv->gain = 0x100;
+- priv->autogain = 1;
+- v4l2_ctrl_handler_init(&priv->hdl, 4);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_CONTRAST, 0, 16, 1, 7);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_SATURATION, 0, 7, 1, 2);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_HUE, 0, 23, 1, 12);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_GAMMA, -128, 128, 1, 0);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_SHARPNESS, 0, 10, 1, 3);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_HFLIP, 0, 1, 1, 1);
+- v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops,
+- V4L2_CID_VFLIP, 0, 1, 1, 0);
+- priv->sd.ctrl_handler = &priv->hdl;
+-
+- ret = priv->hdl.error;
+- if (ret)
+- goto cleanup;
+-
+- v4l2_ctrl_handler_setup(&priv->hdl);
+-
+- priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+- priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
+- ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
+- if (ret < 0)
+- goto cleanup;
+-
+- ret = ar0220_parse_dt(client->dev.of_node, priv);
+- if (ret)
+- goto cleanup;
+-
+- ret = ar0220_initialize(client);
+- if (ret < 0)
+- goto cleanup;
+-
+- priv->rect.left = 0;
+- priv->rect.top = 0;
+- priv->rect.width = AR0220_MAX_WIDTH;
+- priv->rect.height = AR0220_MAX_HEIGHT;
+-
+- ret = v4l2_async_register_subdev(&priv->sd);
+- if (ret)
+- goto cleanup;
+-
+- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0220) != 0) {
+- dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
+- goto cleanup;
+- }
+-
+- priv->init_complete = 1;
+-
+- return 0;
+-
+-cleanup:
+- media_entity_cleanup(&priv->sd.entity);
+- v4l2_ctrl_handler_free(&priv->hdl);
+- v4l2_device_unregister_subdev(&priv->sd);
+-#ifdef CONFIG_SOC_CAMERA_AR0220
+- v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
+- client->addr, client->adapter->name);
+-#endif
+- return ret;
+-}
+-
+-static int ar0220_remove(struct i2c_client *client)
+-{
+- struct ar0220_priv *priv = i2c_get_clientdata(client);
+-
+- device_remove_file(&client->dev, &dev_attr_otp_id_ar0220);
+- v4l2_async_unregister_subdev(&priv->sd);
+- media_entity_cleanup(&priv->sd.entity);
+- v4l2_ctrl_handler_free(&priv->hdl);
+- v4l2_device_unregister_subdev(&priv->sd);
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_SOC_CAMERA_AR0220
+-static const struct i2c_device_id ar0220_id[] = {
+- { "ar0220", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, ar0220_id);
+-
+-static const struct of_device_id ar0220_of_ids[] = {
+- { .compatible = "aptina,ar0220", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, ar0220_of_ids);
+-
+-static struct i2c_driver ar0220_i2c_driver = {
+- .driver = {
+- .name = "ar0220",
+- .of_match_table = ar0220_of_ids,
+- },
+- .probe = ar0220_probe,
+- .remove = ar0220_remove,
+- .id_table = ar0220_id,
+-};
+-
+-module_i2c_driver(ar0220_i2c_driver);
+-
+-MODULE_DESCRIPTION("SoC Camera driver for AR0220");
+-MODULE_AUTHOR("Vladimir Barinov");
+-MODULE_LICENSE("GPL");
+-#endif
+diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h
+index 205c351..e372a9c 100644
+--- a/drivers/media/i2c/soc_camera/ar0220.h
++++ b/drivers/media/i2c/soc_camera/ar0220.h
+@@ -1,7 +1,7 @@
+ /*
+- * ON Semiconductor AR0220 sensor camera wizard 1820x940@44/RCCB/MIPI
++ * ON Semiconductor AR0220 sensor camera wizard 1848x948@30/BGGR/MIPI
+ *
+- * Copyright (C) 2017 Cogent Embedded, Inc.
++ * Copyright (C) 2019 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -12,32 +12,15 @@
+ //#define AR0220_DISPLAY_PATTERN_FIXED
+ //#define AR0220_DISPLAY_PATTERN_COLOR_BAR
+
+-#define AR0220_MAX_WIDTH 1820
+-#define AR0220_MAX_HEIGHT 944
++#define AR0220_MAX_WIDTH 1828
++#define AR0220_MAX_HEIGHT 948
+
+-#define AR0220_DELAY 0xffff
++#define AR0220_SENSOR_WIDTH 1828
++#define AR0220_SENSOR_HEIGHT 948
+
+-struct ar0220_reg {
+- u16 reg;
+- u16 val;
+-};
++#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_MAX_WIDTH) / 2)
++#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_MAX_HEIGHT) / 2)
++#define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1)
++#define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1)
+
+-static const struct ar0220_reg ar0220_regs_wizard[] = {
+-{0x301A, 0x0018}, // RESET_REGISTER
+-{AR0220_DELAY, 500}, // Wait 500ms
+-{0x3070, 0x0000}, // 1: Solid color test pattern,
+- // 2: Full color bar test pattern,
+- // 3: Fade to grey color bar test pattern,
+- //256: Walking 1 test pattern (12 bit)
+-{0x3072, 0x0123}, // R
+-{0x3074, 0x0456}, // G(GR row)
+-{0x3076, 0x0abc}, // B
+-{0x3078, 0x0def}, // G(GB row)
+-#ifdef AR0220_DISPLAY_PATTERN_FIXED
+-{0x3070, 0x0001},
+-#endif
+-#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR
+-{0x3070, 0x0002},
+-#endif
+-{AR0220_DELAY, 100}, // Wait 100ms
+-};
++#include "ar0220_rev4.h"
+diff --git a/drivers/media/i2c/soc_camera/ar0220_rev4.h b/drivers/media/i2c/soc_camera/ar0220_rev4.h
+new file mode 100644
+index 0000000..55923a3
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0220_rev4.h
+@@ -0,0 +1,370 @@
++/*
++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static const struct ar0xxx_reg ar0220_rev4_Reset[] = {
++{0x301A, 0x0018}, // Stream off and setup MIPI
++{AR_DELAY, 200},
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#ifdef AR0220_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++#endif
++#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++{AR_DELAY, 100},
++{ }
++}; /* Reset */
++
++static const struct ar0xxx_reg ar0220_rev4_Recommended_Settings[] = {
++// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby
++{0x3500, 0x0100}, //This is a self clearing bit
++{AR_DELAY, 1}, //Delay => 4100 * Extclk
++
++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017
++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL
++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL
++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL
++
++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29
++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25
++
++// DLO settings
++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable
++// These settings match AR0138 REV3 settings
++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138
++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6
++{0x3104, 0x6060}, // T3
++{0x3106, 0x6060}, // T4
++
++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2
++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17
++
++// boost settings
++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed,
++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in
++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin)
++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin)
++//PYTHON= loadBoosterSettings()
++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16,
++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd
++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd
++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd,
++//{0x3532, 0x826C // updated (12/14)
++{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018
++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin)
++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14)
++
++{0x3540, 0xC63C}, // eclipse clamp updated 5/16
++{0x3542, 0x4637}, // eclipse clamp updated 5/16
++{0x3544, 0x3750}, // eclipse clamp updated 5/16
++{0x3546, 0x5656}, // eclipse clamp updated 5/16
++{0x3548, 0x5600}, // eclipse clamp updated 5/16
++
++//{0x3566, 0xBF38}, // col_mem settings, sa_park_en
++{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN
++
++{0x30BA, 0x0112}, // Add dither after delay buffer decompander
++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9
++{ }
++}; /* Rev3 Recommended Settings */
++
++static const struct ar0xxx_reg ar0220_rev4_REV3_Optimized_Sequencer[] = {
++{0x2512, 0x8000},
++{0x2510, 0x0905},
++{0x2510, 0x3350},
++{0x2510, 0x2004},
++{0x2510, 0x1460},
++{0x2510, 0x1578},
++{0x2510, 0x1360},
++{0x2510, 0x7B24},
++{0x2510, 0xFF24},
++{0x2510, 0xFF24},
++{0x2510, 0xEA24},
++{0x2510, 0x1022},
++{0x2510, 0x2410},
++{0x2510, 0x155A},
++{0x2510, 0x1342},
++{0x2510, 0x1440},
++{0x2510, 0x24FF},
++{0x2510, 0x24FF},
++{0x2510, 0x24EA},
++{0x2510, 0x2324},
++{0x2510, 0x647A},
++{0x2510, 0x2404},
++{0x2510, 0x052C},
++{0x2510, 0x400A},
++{0x2510, 0xFF0A},
++{0x2510, 0x850A},
++{0x2510, 0x0608},
++{0x2510, 0x3851},
++{0x2510, 0x0905},
++{0x2510, 0x15DC},
++{0x2510, 0x134C},
++{0x2510, 0x0004},
++{0x2510, 0x0801},
++{0x2510, 0x0408},
++{0x2510, 0x1180},
++{0x2510, 0x1002},
++{0x2510, 0x1016},
++{0x2510, 0x1181},
++{0x2510, 0x1189},
++{0x2510, 0x1056},
++{0x2510, 0x1210},
++{0x2510, 0x0D09},
++{0x2510, 0x0714},
++{0x2510, 0x4114},
++{0x2510, 0x4009},
++{0x2510, 0x0815},
++{0x2510, 0xCC13},
++{0x2510, 0xCC15},
++{0x2510, 0x8813},
++{0x2510, 0x8809},
++{0x2510, 0x1111},
++{0x2510, 0x9909},
++{0x2510, 0x0B11},
++{0x2510, 0xD909},
++{0x2510, 0x0B12},
++{0x2510, 0x1409},
++{0x2510, 0x0112},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x1212},
++{0x2510, 0x1011},
++{0x2510, 0xDD11},
++{0x2510, 0xD910},
++{0x2510, 0x5609},
++{0x2510, 0x1111},
++{0x2510, 0xDB09},
++{0x2510, 0x1D11},
++{0x2510, 0xFB09},
++{0x2510, 0x0911},
++{0x2510, 0xBB12},
++{0x2510, 0x1A12},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x5010},
++{0x2510, 0xF610},
++{0x2510, 0xE609},
++{0x2510, 0x0315},
++{0x2510, 0xAB13},
++{0x2510, 0xAB12},
++{0x2510, 0x4012},
++{0x2510, 0x6009},
++{0x2510, 0x2315},
++{0x2510, 0x8809},
++{0x2510, 0x0113},
++{0x2510, 0x880B},
++{0x2510, 0x0906},
++{0x2510, 0x158D},
++{0x2510, 0x138D},
++{0x2510, 0x090B},
++{0x2510, 0x1066},
++{0x2510, 0x1588},
++{0x2510, 0x1388},
++{0x2510, 0x0C09},
++{0x2510, 0x0410},
++{0x2510, 0xE612},
++{0x2510, 0x6212},
++{0x2510, 0x6011},
++{0x2510, 0xBF11},
++{0x2510, 0xFB10},
++{0x2510, 0x6609},
++{0x2510, 0x3B11},
++{0x2510, 0xBB12},
++{0x2510, 0x6312},
++{0x2510, 0x6009},
++{0x2510, 0x0115},
++{0x2510, 0x5A11},
++{0x2510, 0xB812},
++{0x2510, 0xA012},
++{0x2510, 0x0010},
++{0x2510, 0x2610},
++{0x2510, 0x0013},
++{0x2510, 0x0211},
++{0x2510, 0x8014},
++{0x2510, 0x007A},
++{0x2510, 0x0611},
++{0x2510, 0x0005},
++{0x2510, 0x0708},
++{0x2510, 0x4137},
++{0x2510, 0x502C},
++{0x2510, 0x2CFE},
++{0x2510, 0x112C},
++{AR_DELAY, 300},
++
++{0x1008, 0x02B6}, //fine_integration_time_min
++{0x100c, 0x0452}, //fine_integration_time2_min
++{0x100e, 0x05EE}, //fine_integration_time3_min
++{0x1010, 0x011A}, //fine_integration_time4_min
++
++{0x3230, 0x0254}, //fine_correction
++{0x3232, 0x03F0}, //fine_correction2
++{0x3234, 0x058C}, //fine_correction3
++{0x3236, 0x00B8}, //fine_correction4
++//{0x32e6, 0x009A}, //min_subrow
++{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin
++{ }
++}; /* AR0220AT REV3 Optimized Sequencer */
++
++static const struct ar0xxx_reg ar0220_rev4_pll_23_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */
++{0x3030, 44}, //PLL_MULTIPLIER
++{0x302E, 2}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev4_pll_25_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */
++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
++{0x3030, 102}, //PLL_MULTIPLIER
++{0x302E, 5}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev4_pll_27_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */
++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
++{0x3030, 56}, //PLL_MULTIPLIER
++{0x302E, 3}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev4_Readout_Mode_Configuration[] = {
++{0x30A2, 1}, // x_odd_inc_
++{0x30A6, 1}, // y_odd_inc_
++{0x3040, 0}, // read_mode
++{ }
++}; /* Readout Mode Configuration */
++
++static const struct ar0xxx_reg ar0220_rev4_Full_Res_FOV[] = {
++{0x3004, AR0220_X_START}, // X_ADDR_START_
++{0x3008, AR0220_X_END}, // X_ADDR_END_
++{0x3002, AR0220_Y_START}, // Y_ADDR_START_
++{0x3006, AR0220_Y_END}, // Y_ADDR_END_
++{ }
++}; /* Full Res FOV */
++
++static const struct ar0xxx_reg ar0220_rev4_hdr_Timing_and_Exposure[] = {
++{0x3082, 0x8}, // operation_mode_ctrl
++{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2
++#ifdef AR0231_EMBEDDED_LINE
++{0x3064, 0x1982}, // SMIA_TEST
++#else
++{0x3064, 0x1802}, // SMIA_TEST
++#endif
++//{0x33E0, 0xC80},
++//{0x3180, 0x80},
++//{0x33E4, 0x80},
++
++{0x306e, 9010}, // datapath_select,ime_mode,0
++
++{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742)
++{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338)
++{0x3042, 0}, // extra_delay
++
++{0x3238, 0x444}, // exposure_ratio
++{0x3012, 1000}, // coarse_integration_time_
++{0x3014, 1526}, // fine_integration_time_
++{0x321E, 1526}, // fine_integration_time2
++{0x3222, 282}, // fine_integration_time3
++{0x32EA, 0x3C0E},
++//{0x32EC, 0x7151},
++
++{0x30B0, 0x800}, // enable_subrow_pair_reset
++{0x32E8, 637}, // max subrow margin for 3exp HDR
++{ }
++}; /* 3exp 36FPS Timing and Exposure */
++
++static const struct ar0xxx_reg ar0220_rev4_hdr_12bit_output[] = {
++{0x31D0, 1}, // companding
++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12
++{ }
++}; /* HDR Serial 4 lane 12 bit Output */
++
++static const struct ar0xxx_reg ar0220_rev4_mipi_12bit_4lane[] = {
++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes
++//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x3344, 0x0011}, // default, VC=0
++//{0x3348, 0x0111}, // default, VC=1
++//{0x334C, 0x0211}, // default, VC=2
++//{0x3350, 0x0311}, // default, VC=3
++{0x31B0, 0x46}, // frame_preamble
++{0x31B2, 0x31}, // line_preamble
++{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17
++{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17
++{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17
++{0x31BA, 0x0186}, //MIPI_TIMING_3
++{0x31BC, 0x0785}, //MIPI_TIMING_4
++{ }
++}; /* HDR MIPI 12 bit Settings */
++
++static const struct ar0xxx_reg ar0220_rev4_Recommended_HDR_Settings[] = {
++{ }
++}; /* Recommended HDR Settings */
++
++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev4[] = {
++ ar0220_rev4_Reset,
++ ar0220_rev4_Recommended_Settings,
++ ar0220_rev4_pll_23_4lane_12b,
++ ar0220_rev4_Readout_Mode_Configuration,
++ ar0220_rev4_Full_Res_FOV,
++ ar0220_rev4_hdr_Timing_and_Exposure,
++ ar0220_rev4_hdr_12bit_output,
++ ar0220_rev4_mipi_12bit_4lane,
++ ar0220_rev4_Recommended_HDR_Settings,
++ NULL,
++};
++
++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = {
++ ar0220_rev4_Reset,
++ ar0220_rev4_Recommended_Settings,
++ ar0220_rev4_REV3_Optimized_Sequencer,
++ ar0220_rev4_pll_23_4lane_12b,
++ ar0220_rev4_Readout_Mode_Configuration,
++ ar0220_rev4_Full_Res_FOV,
++ ar0220_rev4_hdr_Timing_and_Exposure,
++ ar0220_rev4_hdr_12bit_output,
++ ar0220_rev4_mipi_12bit_4lane,
++ ar0220_rev4_Recommended_HDR_Settings,
++ NULL,
++};
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index 9294267..500fa75 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -1,7 +1,7 @@
+ /*
+- * ON Semiconductor AR0233 sensor camera driver
++ * ON Semiconductor AR0220/233 sensor camera driver
+ *
+- * Copyright (C) 2018 Cogent Embedded, Inc.
++ * Copyright (C) 2018-2019 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -20,15 +20,33 @@
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ctrls.h>
+
++#define AR_DELAY 0xffff
++static int AR_MAX_WIDTH;
++static int AR_MAX_HEIGHT;
++static int AR_X_START;
++static int AR_Y_START;
++static int AR_X_END;
++static int AR_Y_END;
++
++struct ar0xxx_reg {
++ u16 reg;
++ u16 val;
++};
++
++#include "ar0220.h"
+ #include "ar0233.h"
+
+ static const int ar0233_i2c_addr[] = {0x10, 0x20};
+
+-#define AR0233_PID 0x3000
+-#define AR0233_REV 0x31FE
+-#define AR0233_VERSION_REG 0x0956
++#define AR_PID_REG 0x3000
++#define AR_REV_REG 0x31FE
+
+-#define AR0233_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12
++enum {
++ AR0220_PID = 0x0C54,
++ AR0233_PID = 0x0956,
++} chipid;
++
++#define AR_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12
+
+ struct ar0233_priv {
+ struct v4l2_subdev sd;
+@@ -57,9 +75,9 @@ static inline struct ar0233_priv *to_ar0233(const struct i2c_client *client)
+ return container_of(i2c_get_clientdata(client), struct ar0233_priv, sd);
+ }
+
+-static int ar0233_set_regs(struct i2c_client *client, const struct ar0233_reg **pregs)
++static int ar0233_set_regs(struct i2c_client *client, const struct ar0xxx_reg **pregs)
+ {
+- const struct ar0233_reg *regs;
++ const struct ar0xxx_reg *regs;
+ int i, j;
+
+ for (j = 0; ; j++) {
+@@ -72,7 +90,7 @@ static int ar0233_set_regs(struct i2c_client *client, const struct ar0233_reg **
+ if (!regs[i].reg && !regs[i].val)
+ break;
+
+- if (regs[i].reg == AR0233_DELAY) {
++ if (regs[i].reg == AR_DELAY) {
+ mdelay(regs[i].val);
+ continue;
+ }
+@@ -97,13 +115,13 @@ static int ar0233_set_window(struct v4l2_subdev *sd)
+ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height);
+
+ /* horiz crop start */
+- reg16_write16(client, 0x3004, priv->rect.left + AR0233_X_START);
++ reg16_write16(client, 0x3004, priv->rect.left + AR_X_START);
+ /* horiz crop end */
+- reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0233_X_START);
++ reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR_X_START);
+ /* vert crop start */
+- reg16_write16(client, 0x3002, priv->rect.top + AR0233_Y_START);
++ reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START);
+ /* vert crop end */
+- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0233_Y_START);
++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START);
+
+ return 0;
+ };
+@@ -121,7 +139,7 @@ static int ar0233_get_fmt(struct v4l2_subdev *sd,
+
+ mf->width = priv->rect.width;
+ mf->height = priv->rect.height;
+- mf->code = AR0233_MEDIA_BUS_FMT;
++ mf->code = AR_MEDIA_BUS_FMT;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ mf->field = V4L2_FIELD_NONE;
+
+@@ -134,7 +152,7 @@ static int ar0233_set_fmt(struct v4l2_subdev *sd,
+ {
+ struct v4l2_mbus_framefmt *mf = &format->format;
+
+- mf->code = AR0233_MEDIA_BUS_FMT;
++ mf->code = AR_MEDIA_BUS_FMT;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ mf->field = V4L2_FIELD_NONE;
+
+@@ -151,7 +169,7 @@ static int ar0233_enum_mbus_code(struct v4l2_subdev *sd,
+ if (code->pad || code->index > 0)
+ return -EINVAL;
+
+- code->code = AR0233_MEDIA_BUS_FMT;
++ code->code = AR_MEDIA_BUS_FMT;
+
+ return 0;
+ }
+@@ -165,8 +183,8 @@ static int ar0233_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+
+ edid->edid[6] = 0xff;
+ edid->edid[7] = client->addr;
+- edid->edid[8] = AR0233_VERSION_REG >> 8;
+- edid->edid[9] = AR0233_VERSION_REG & 0xff;
++ edid->edid[8] = chipid >> 8;
++ edid->edid[9] = chipid & 0xff;
+
+ return 0;
+ }
+@@ -188,8 +206,8 @@ static int ar0233_set_selection(struct v4l2_subdev *sd,
+ rect->width = ALIGN(rect->width, 2);
+ rect->height = ALIGN(rect->height, 2);
+
+- if ((rect->left + rect->width > AR0233_MAX_WIDTH) ||
+- (rect->top + rect->height > AR0233_MAX_HEIGHT))
++ if ((rect->left + rect->width > AR_MAX_WIDTH) ||
++ (rect->top + rect->height > AR_MAX_HEIGHT))
+ *rect = priv->rect;
+
+ priv->rect.left = rect->left;
+@@ -216,14 +234,14 @@ static int ar0233_get_selection(struct v4l2_subdev *sd,
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = AR0233_MAX_WIDTH;
+- sel->r.height = AR0233_MAX_HEIGHT;
++ sel->r.width = AR_MAX_WIDTH;
++ sel->r.height = AR_MAX_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = AR0233_MAX_WIDTH;
+- sel->r.height = AR0233_MAX_HEIGHT;
++ sel->r.width = AR_MAX_WIDTH;
++ sel->r.height = AR_MAX_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+@@ -400,6 +418,7 @@ static DEVICE_ATTR(otp_id_ar0233, S_IRUGO, ar0233_otp_id_show, NULL);
+ static int ar0233_initialize(struct i2c_client *client)
+ {
+ struct ar0233_priv *priv = to_ar0233(client);
++ char chip_name[10] = "unknown";
+ u16 val = 0;
+ u16 pid = 0, rev = 0;
+ int ret = 0;
+@@ -416,42 +435,85 @@ static int ar0233_initialize(struct i2c_client *client)
+ client->addr = tmp_addr;
+
+ /* check model ID */
+- reg16_read16(client, AR0233_PID, &pid);
++ reg16_read16(client, AR_PID_REG, &pid);
+
+- if (pid == AR0233_VERSION_REG)
++ if (pid == AR0220_PID || pid == AR0233_PID)
+ break;
+ }
+
+- if (pid != AR0233_VERSION_REG) {
++ if (pid != AR0220_PID && pid != AR0233_PID) {
+ dev_dbg(&client->dev, "Product ID error %x\n", pid);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* check revision */
+- reg16_read16(client, AR0233_REV, &rev);
++ reg16_read16(client, AR_REV_REG, &rev);
+ /* Read OTP IDs */
+ ar0233_otp_id_read(client);
+- /* Program wizard registers */
+- switch (rev & 0xf) {
+- case 0x1:
+- ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev1);
+- break;
+- case 0x2:
+- if (extclk == 27) {
+- ar0233_regs_hdr_mipi_12bit_30fps_rev2[4] = ar0233_rev2_pll_27_102_4lane_12b;
+- ar0233_regs_seplus_mipi_12bit_30fps_rev2[2] = ar0233_rev2_pll_27_102_4lane_12b;
+- }
+
+- if (strcmp(mode, "hdr") == 0)
+- ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev2);
+- else if (strcmp(mode, "seplus") == 0)
+- ar0233_set_regs(client, ar0233_regs_seplus_mipi_12bit_30fps_rev2);
+- else
+- dev_err(&client->dev, "Unsupported mode %s\n", mode);
+- break;
+- default:
+- dev_err(&client->dev, "Unsupported chip revision\n");
++ switch (pid) {
++ case AR0220_PID:
++ chipid = ID_AR0220;
++ strncpy(chip_name, "AR0220", 10);
++ AR_MAX_WIDTH = AR0220_MAX_WIDTH;
++ AR_MAX_HEIGHT = AR0220_MAX_HEIGHT;
++ AR_X_START = AR0220_X_START;
++ AR_Y_START = AR0220_Y_START;
++ AR_X_END = AR0220_X_END;
++ AR_Y_END = AR0220_Y_END;
++
++ switch (rev & 0xf) {
++ case 0x1:
++ case 0x2:
++ case 0x3:
++ if (extclk == 25) {
++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_25_4lane_12b;
++ }
++ if (extclk == 27) {
++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_27_4lane_12b;
++ }
++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev3);
++ break;
++ case 0x4:
++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev4);
++ break;
++ default:
++ dev_err(&client->dev, "Unsupported chip revision\n");
++ }
++ break;
++ case AR0233_PID:
++ chipid = ID_AR0233;
++ strncpy(chip_name, "AR0233", 10);
++ AR_MAX_WIDTH = AR0233_MAX_WIDTH;
++ AR_MAX_HEIGHT = AR0233_MAX_HEIGHT;
++ AR_X_START = AR0233_X_START;
++ AR_Y_START = AR0233_Y_START;
++ AR_X_END = AR0233_X_END;
++ AR_Y_END = AR0233_Y_END;
++
++ /* Program wizard registers */
++ switch (rev & 0xf) {
++ case 0x1:
++ ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev1);
++ break;
++ case 0x2:
++ if (extclk == 27) {
++ ar0233_regs_hdr_mipi_12bit_30fps_rev2[4] = ar0233_rev2_pll_27_102_4lane_12b;
++ ar0233_regs_seplus_mipi_12bit_30fps_rev2[2] = ar0233_rev2_pll_27_102_4lane_12b;
++ }
++
++ if (strcmp(mode, "hdr") == 0)
++ ar0233_set_regs(client, ar0233_regs_hdr_mipi_12bit_30fps_rev2);
++ else if (strcmp(mode, "seplus") == 0)
++ ar0233_set_regs(client, ar0233_regs_seplus_mipi_12bit_30fps_rev2);
++ else
++ dev_err(&client->dev, "Unsupported mode %s\n", mode);
++ break;
++ default:
++ dev_err(&client->dev, "Unsupported chip revision\n");
++ }
++ break;
+ }
+
+ /* Enable trigger */
+@@ -468,8 +530,8 @@ static int ar0233_initialize(struct i2c_client *client)
+ val |= (1 << 2); // Set streamOn bit
+ reg16_write16(client, 0x301a, val); // Start Streaming
+
+- dev_info(&client->dev, "ar0233 PID %x (rev%x), res %dx%d, mode=%s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+- pid, rev & 0xf, AR0233_MAX_WIDTH, AR0233_MAX_HEIGHT, mode, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ dev_info(&client->dev, "%s PID %x (rev%x), res %dx%d, mode=%s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", chip_name,
++ pid, rev & 0xf, AR_MAX_WIDTH, AR_MAX_HEIGHT, mode, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ err:
+ return ret;
+ }
+@@ -586,8 +648,8 @@ static int ar0233_probe(struct i2c_client *client,
+
+ priv->rect.left = 0;
+ priv->rect.top = 0;
+- priv->rect.width = AR0233_MAX_WIDTH;
+- priv->rect.height = AR0233_MAX_HEIGHT;
++ priv->rect.width = AR_MAX_WIDTH;
++ priv->rect.height = AR_MAX_HEIGHT;
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret)
+diff --git a/drivers/media/i2c/soc_camera/ar0233.h b/drivers/media/i2c/soc_camera/ar0233.h
+index 5f2bada..33b661a 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.h
++++ b/drivers/media/i2c/soc_camera/ar0233.h
+@@ -15,8 +15,6 @@
+ #define AR0233_MAX_WIDTH 2048
+ #define AR0233_MAX_HEIGHT 1280
+
+-#define AR0233_DELAY 0xffff
+-
+ #define AR0233_SENSOR_WIDTH 2072
+ #define AR0233_SENSOR_HEIGHT 1296
+
+@@ -25,10 +23,5 @@
+ #define AR0233_X_END (AR0233_X_START + AR0233_MAX_WIDTH - 1)
+ #define AR0233_Y_END (AR0233_Y_START + AR0233_MAX_HEIGHT - 1)
+
+-struct ar0233_reg {
+- u16 reg;
+- u16 val;
+-};
+-
+ #include "ar0233_rev1.h"
+ #include "ar0233_rev2.h"
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+index ddc1612..0389e51 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+@@ -9,9 +9,9 @@
+ * option) any later version.
+ */
+
+-static const struct ar0233_reg ar0233_rev1_Reset[] = {
++static const struct ar0xxx_reg ar0233_rev1_Reset[] = {
+ {0x301A, 0x0018}, // Stream off and setup MIPI
+-{AR0233_DELAY, 200},
++{AR_DELAY, 200},
+ {0x3070, 0x0000}, // 1: Solid color test pattern,
+ // 2: Full color bar test pattern,
+ // 3: Fade to grey color bar test pattern,
+@@ -26,11 +26,11 @@ static const struct ar0233_reg ar0233_rev1_Reset[] = {
+ #ifdef AR0233_DISPLAY_PATTERN_COLOR_BAR
+ {0x3070, 0x0002},
+ #endif
+-{AR0233_DELAY, 100},
++{AR_DELAY, 100},
+ { }
+ }; /* Reset */
+
+-static const struct ar0233_reg ar0233_rev1_Sequencer_Settings[] = {
++static const struct ar0xxx_reg ar0233_rev1_Sequencer_Settings[] = {
+ /* Design_recommended_settings_v5 */
+ {0x356C, 0xEA55}, //mte.Sensor.Register("DAC_LD_108_109").Value = 0xEA55& -- ADC write Memory delay 7
+ {0x3566, 0x2407}, //mte.Sensor.Register("DAC_LD_102_103").Value = 0x2407& -- Enable column amp bypass for 1x
+@@ -1095,12 +1095,12 @@ static const struct ar0233_reg ar0233_rev1_Sequencer_Settings[] = {
+ {0x2510, 0xffff},
+ {0x2510, 0xffff},
+ {0x2510, 0xffff},
+-{AR0233_DELAY, 100},
++{AR_DELAY, 100},
+ /* Sequencer_LFM_HDR_v6 */
+ { }
+ }; /* Sequencer_Settings */
+
+-static const struct ar0233_reg ar0233_rev1_HDR_3exp_12bit[] = {
++static const struct ar0xxx_reg ar0233_rev1_HDR_3exp_12bit[] = {
+ {0x3082, 0x8}, //num_exp = 3
+ {0x3110, 0x11}, //Set bypass pix comb for HDR,Pre_hdr_gain_enable_07Jul
+ {0x30BA, 0x1122}, //num_exp_max =3
+@@ -1116,7 +1116,7 @@ static const struct ar0233_reg ar0233_rev1_HDR_3exp_12bit[] = {
+ { }
+ }; /* HDR_3exp_12bit */
+
+-static const struct ar0233_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = {
++static const struct ar0xxx_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = {
+ /* PCLK=DES_REFCLK /PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */
+ /* PCLK=23MHz/2 *54/1/6= 103.5Mhz - TI serializers */
+ {0x3030, 54}, //PLL_MULTIPLIER ; 0x3030 [11:0]
+@@ -1129,7 +1129,7 @@ static const struct ar0233_reg ar0233_rev1_Serial_12bit_Timing_Setup_103p5[] = {
+ { }
+ }; /* Serial_12bit_Timing_Setup_103p5 */
+
+-static const struct ar0233_reg ar0233_rev1_MIPI_4Lane_12BITS[] = {
++static const struct ar0xxx_reg ar0233_rev1_MIPI_4Lane_12BITS[] = {
+ {0x31AE, 0x204}, //MIPI enable, 4 lanes
+ {0x31B0, 0x4B}, //frame_preamble
+ {0x31B2, 0x33}, //line_preamble
+@@ -1145,7 +1145,7 @@ static const struct ar0233_reg ar0233_rev1_MIPI_4Lane_12BITS[] = {
+ { }
+ }; /* MIPI_4Lane_12BITS */
+
+-static const struct ar0233_reg ar0233_rev1_Full_resolution[] = {
++static const struct ar0xxx_reg ar0233_rev1_Full_resolution[] = {
+ {0x3004, AR0233_X_START}, // X_ADDR_START_
+ {0x3008, AR0233_X_END}, // X_ADDR_END_
+ {0x3002, AR0233_Y_START}, // Y_ADDR_START_
+@@ -1155,7 +1155,7 @@ static const struct ar0233_reg ar0233_rev1_Full_resolution[] = {
+ { }
+ }; /* Full_resolution */
+
+-static const struct ar0233_reg ar0233_rev1_disable_embed_data_stat[] = {
++static const struct ar0xxx_reg ar0233_rev1_disable_embed_data_stat[] = {
+ {0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1
+ #ifdef AR0233_EMBEDDED_LINE
+ {0x3064, 0x0180}, //Enable embedded data and stat
+@@ -1165,7 +1165,7 @@ static const struct ar0233_reg ar0233_rev1_disable_embed_data_stat[] = {
+ { }
+ }; /* disable_embed_data_stat */
+
+-static const struct ar0233_reg ar0233_rev1_Gain_3p28x[] = {
++static const struct ar0xxx_reg ar0233_rev1_Gain_3p28x[] = {
+ {0x3022, 0x01}, // GROUPED_PARAMETER_HOLD_
+ {0x3362, 0x000F}, // DC_GAIN
+ {0x3366, 0x1111},
+@@ -1174,7 +1174,7 @@ static const struct ar0233_reg ar0233_rev1_Gain_3p28x[] = {
+ { }
+ }; /* Gain_3.28x */
+
+-static const struct ar0233_reg ar0233_rev1_MEC_DLO_default[] = {
++static const struct ar0xxx_reg ar0233_rev1_MEC_DLO_default[] = {
+ {0x3D00, 0x6F73}, // control
+ {0x3D02, 0x0033},
+ {0x3364, 0x068C}, // dcg_trim = 13.1
+@@ -1260,7 +1260,7 @@ static const struct ar0233_reg ar0233_rev1_MEC_DLO_default[] = {
+ }; /* MEC_DLO_default */
+
+ /* 3Exp HDR, 1280P, MIPI 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */
+-static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev1[] = {
++static const struct ar0xxx_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev1[] = {
+ ar0233_rev1_Reset,
+ ar0233_rev1_Sequencer_Settings,
+ ar0233_rev1_disable_embed_data_stat,
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+index 7085fbc..7f71056 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+@@ -9,9 +9,9 @@
+ * option) any later version.
+ */
+
+-static const struct ar0233_reg ar0233_rev2_Reset[] = {
++static const struct ar0xxx_reg ar0233_rev2_Reset[] = {
+ {0x301A, 0x0018}, // Stream off and setup MIPI
+-{AR0233_DELAY, 200},
++{AR_DELAY, 200},
+ {0x3070, 0x0000}, // 1: Solid color test pattern,
+ // 2: Full color bar test pattern,
+ // 3: Fade to grey color bar test pattern,
+@@ -26,11 +26,11 @@ static const struct ar0233_reg ar0233_rev2_Reset[] = {
+ #ifdef AR0233_DISPLAY_PATTERN_COLOR_BAR
+ {0x3070, 0x0002},
+ #endif
+-{AR0233_DELAY, 100},
++{AR_DELAY, 100},
+ { }
+ }; /* Reset */
+
+-static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = {
++static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = {
+ /* Design_recommended_settings_REV2_V9 */
+ {0x3C72, 0x0076},
+ {0x3C74, 0x0031},
+@@ -1106,7 +1106,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = {
+ {0x2510, 0xffff},
+ {0x2510, 0x3426},
+ {0x2510, 0x3614},
+-{AR0233_DELAY, 100},
++{AR_DELAY, 100},
+ /* Sequence_hidy_ar0233_REV2_V13 */
+
+ /* Pre_hdr_gain_enable */
+@@ -1124,7 +1124,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_LFM_HDR[] = {
+ { }
+ }; /* O1_Recommended_Defaults_LFM_HDR */
+
+-static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[] = {
++static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[] = {
+ /* Design_recommended_settings_REV2_seplus */
+ {0x3086, 0x0000},
+ {0x3092, 0x400C},
+@@ -2243,7 +2243,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[
+ {0x2510, 0xFFFF},
+ {0x2510, 0xFFFF},
+ {0x2510, 0xFFFF},
+-{AR0233_DELAY, 100},
++{AR_DELAY, 100},
+ /* Sequence_hidy_ar0233_REV2_seplus */
+
+ {0x3E14, 0x003F},
+@@ -2264,7 +2264,7 @@ static const struct ar0233_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[
+ { }
+ }; /* O1_Recommended_Defaults_SE_T1_LIN_T2 */
+
+-static const struct ar0233_reg ar0233_rev2_disable_embed_data_stat[] = {
++static const struct ar0xxx_reg ar0233_rev2_disable_embed_data_stat[] = {
+ {0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1
+ {0x350e, 0x2089}, // bit0 must be set for vflip=1
+ #ifdef AR0233_EMBEDDED_LINE
+@@ -2275,7 +2275,7 @@ static const struct ar0233_reg ar0233_rev2_disable_embed_data_stat[] = {
+ { }
+ }; /* disable_embed_data_stat */
+
+-static const struct ar0233_reg ar0233_rev2_HDR_3exp_12bit[] = {
++static const struct ar0xxx_reg ar0233_rev2_HDR_3exp_12bit[] = {
+ {0x3082, 0x8}, //num_exp = 3
+ {0x30BA, 0x1122}, //num_exp_max =3
+ {0x31AC, 0x140C}, //12 bit output
+@@ -2289,7 +2289,7 @@ static const struct ar0233_reg ar0233_rev2_HDR_3exp_12bit[] = {
+ { }
+ }; /* HDR_3exp_12bit */
+
+-static const struct ar0233_reg ar0233_rev2_SEPLUS_12bit[] = {
++static const struct ar0xxx_reg ar0233_rev2_SEPLUS_12bit[] = {
+ {0x3082, 0x4}, //num_exp = 2
+ {0x30BA, 0x1121}, //num_exp_max =2
+ {0x31AC, 0x140C}, //12 bit output
+@@ -2305,7 +2305,7 @@ static const struct ar0233_reg ar0233_rev2_SEPLUS_12bit[] = {
+ { }
+ }; /* HDR_3exp_12bit */
+
+-static const struct ar0233_reg ar0233_rev2_pll_23_102_4lane_12b[] = {
++static const struct ar0xxx_reg ar0233_rev2_pll_23_102_4lane_12b[] = {
+ // serial_data_rate was *2 in REV1. but not in REV2
+ /* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */
+ /* PCLK=23Mhz/0x3 *0x50/1/6= 102Mhz - TI serializers */
+@@ -2319,7 +2319,7 @@ static const struct ar0233_reg ar0233_rev2_pll_23_102_4lane_12b[] = {
+ { }
+ }; /* pll_23_102_4lane_12b */
+
+-static const struct ar0233_reg ar0233_rev2_pll_27_102_4lane_12b[] = {
++static const struct ar0xxx_reg ar0233_rev2_pll_27_102_4lane_12b[] = {
+ // serial_data_rate was *2 in REV1. but not in REV2
+ /* PCLK=27Mhz/0x3 *0x44/1/6= 102Mhz - TI serializers */
+ {0x3030, 0x44}, //PLL_MULTIPLIER
+@@ -2332,7 +2332,7 @@ static const struct ar0233_reg ar0233_rev2_pll_27_102_4lane_12b[] = {
+ { }
+ }; /* pll_27_102_4lane_12b */
+
+-static const struct ar0233_reg ar0233_rev2_mipi_12bit_4lane[] = {
++static const struct ar0xxx_reg ar0233_rev2_mipi_12bit_4lane[] = {
+ {0x31AE, 0x204}, //serial type and lane
+ {0x31B0, 0x67}, //frame_preamble
+ {0x31B2, 0x30}, //line_preamble
+@@ -2348,7 +2348,7 @@ static const struct ar0233_reg ar0233_rev2_mipi_12bit_4lane[] = {
+ { }
+ }; /* mipi_12bit_4lane */
+
+-static const struct ar0233_reg ar0233_rev2_LUT_24_to_12[] = {
++static const struct ar0xxx_reg ar0233_rev2_LUT_24_to_12[] = {
+ {0x31AC, 0x180C},
+ {0x31D0, 0x01}, //companding
+ {0x33DA, 0},
+@@ -2371,7 +2371,7 @@ static const struct ar0233_reg ar0233_rev2_LUT_24_to_12[] = {
+ { }
+ }; /* LUT_24_to_12 */
+
+-static const struct ar0233_reg ar0233_rev2_Full_resolution[] = {
++static const struct ar0xxx_reg ar0233_rev2_Full_resolution[] = {
+ {0x3004, AR0233_X_START}, // X_ADDR_START_
+ {0x3008, AR0233_X_END}, // X_ADDR_END_
+ {0x3002, AR0233_Y_START}, // Y_ADDR_START_
+@@ -2381,14 +2381,14 @@ static const struct ar0233_reg ar0233_rev2_Full_resolution[] = {
+ { }
+ }; /* Full_resolution */
+
+-static const struct ar0233_reg ar0233_rev2_HDR_ratio_gain_default[] = {
++static const struct ar0xxx_reg ar0233_rev2_HDR_ratio_gain_default[] = {
+ {0x3362, 0x000F}, //HCG
+ {0x3366, 0x1111}, //1x
+ {0x3238, 0x0444}, // Ratio 16x, Use retio setting
+ { }
+ }; /* HDR_ratio_gain_default */
+
+-static const struct ar0233_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = {
++static const struct ar0xxx_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = {
+ {0x3362, 0x0001}, // DC_GAIN
+ {0x3238, 0x8446}, // EXPOSURE_RATIO
+ {0x562E, 0x0111}, // OCL_T1_GAIN_
+@@ -2401,7 +2401,7 @@ static const struct ar0233_reg ar0233_rev2_SEPLUS_ratio_gain_default[] = {
+ }; /* SEPLUS_ratio_gain_default */
+
+ /* 3Exp HDR, 1280P, MIPI 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */
+-static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = {
++static const struct ar0xxx_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = {
+ ar0233_rev2_Reset,
+ ar0233_rev2_O1_Recommended_Defaults_LFM_HDR,
+ ar0233_rev2_disable_embed_data_stat,
+@@ -2415,7 +2415,7 @@ static const struct ar0233_reg *ar0233_regs_hdr_mipi_12bit_30fps_rev2[] = {
+ };
+
+ /* SE_T1 + Lin_T2, 1280P, MIPI 750MBPS 4-lane 12-bit, 30fps, EXTCLK=23MHz (comes from deser) */
+-static const struct ar0233_reg *ar0233_regs_seplus_mipi_12bit_30fps_rev2[] = {
++static const struct ar0xxx_reg *ar0233_regs_seplus_mipi_12bit_30fps_rev2[] = {
+ ar0233_rev2_Reset,
+ ar0233_rev2_Full_resolution,
+ ar0233_rev2_pll_23_102_4lane_12b,
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 08d3816..876b3c1 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -9,28 +9,6 @@
+ * option) any later version.
+ */
+
+-#include "ov10635.c"
+-#include "ov10640.c"
+-#include "ov490_ov10640.c"
+-#include "ov495_ov2775.c"
+-#include "ar0132.c"
+-#include "ar0140.c"
+-#include "ar0143.c"
+-#include "ar0220.c"
+-#include "ar0231.c"
+-#include "ar0233.c"
+-#include "ar0323.c"
+-#include "ap0101_ar014x.c"
+-#include "gw4200_ar014x.c"
+-#include "gw5200_imx390.c"
+-#include "ov2775.c"
+-#include "imx390.c"
+-#include "ox03a.c"
+-#include "isx016.c"
+-#include "isx019.c"
+-#include "ov2311.c"
+-#include "ar0147.c"
+-
+ static enum {
+ ID_OV10635,
+ ID_OV10640,
+@@ -55,6 +33,27 @@ static enum {
+ ID_OV2311,
+ } chip_id;
+
++#include "ov10635.c"
++#include "ov10640.c"
++#include "ov490_ov10640.c"
++#include "ov495_ov2775.c"
++#include "ar0132.c"
++#include "ar0140.c"
++#include "ar0143.c"
++#include "ar0231.c"
++#include "ar0233.c"
++#include "ar0323.c"
++#include "ap0101_ar014x.c"
++#include "gw4200_ar014x.c"
++#include "gw5200_imx390.c"
++#include "ov2775.c"
++#include "imx390.c"
++#include "ox03a.c"
++#include "isx016.c"
++#include "isx019.c"
++#include "ov2311.c"
++#include "ar0147.c"
++
+ static int ov106xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+ {
+@@ -145,12 +144,6 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
+- ret = ar0220_probe(client, did);
+- if (!ret) {
+- chip_id = ID_AR0220;
+- goto out;
+- }
+-
+ ret = gw4200_probe(client, did);
+ if (!ret) {
+ chip_id = ID_GW4200_AR014X;
+@@ -220,9 +213,6 @@ static int ov106xx_remove(struct i2c_client *client)
+ case ID_AR0147:
+ ar0147_remove(client);
+ break;
+- case ID_AR0220:
+- ar0220_remove(client);
+- break;
+ case ID_AR0231:
+ ar0231_remove(client);
+ break;
+@@ -259,6 +249,8 @@ static int ov106xx_remove(struct i2c_client *client)
+ case ID_OV2311:
+ ov2311_remove(client);
+ break;
++ default:
++ break;
+ };
+
+ return 0;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch
new file mode 100644
index 00000000..96a30a14
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0433-media-i2c-ar0220-add-rev2-rev3.patch
@@ -0,0 +1,1021 @@
+From 8bfe841bb241b2c0582a1f2a82aa3207efc9a282 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 18 Nov 2019 20:20:03 +0300
+Subject: [PATCH] media: i2c: ar0220: add rev2, rev3
+
+This adds REV2, REV3 imager versions
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0220.h | 2 +
+ drivers/media/i2c/soc_camera/ar0220_rev2.h | 349 +++++++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ar0220_rev3.h | 218 +++++++++++++++++
+ drivers/media/i2c/soc_camera/ar0220_rev4.h | 364 +----------------------------
+ drivers/media/i2c/soc_camera/ar0233.c | 19 +-
+ 5 files changed, 591 insertions(+), 361 deletions(-)
+ create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev2.h
+ create mode 100644 drivers/media/i2c/soc_camera/ar0220_rev3.h
+
+diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h
+index e372a9c..59a949e 100644
+--- a/drivers/media/i2c/soc_camera/ar0220.h
++++ b/drivers/media/i2c/soc_camera/ar0220.h
+@@ -23,4 +23,6 @@
+ #define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1)
+ #define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1)
+
++#include "ar0220_rev2.h"
++#include "ar0220_rev3.h"
+ #include "ar0220_rev4.h"
+diff --git a/drivers/media/i2c/soc_camera/ar0220_rev2.h b/drivers/media/i2c/soc_camera/ar0220_rev2.h
+new file mode 100644
+index 0000000..c66872d
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0220_rev2.h
+@@ -0,0 +1,349 @@
++/*
++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static const struct ar0xxx_reg ar0220_rev2_Reset[] = {
++{0x301A, 0x0018}, // Stream off and setup MIPI
++{AR_DELAY, 200},
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#ifdef AR0220_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++#endif
++#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++{AR_DELAY, 100},
++{ }
++}; /* Reset */
++
++static const struct ar0xxx_reg ar0220_rev2_Recommended_Settings[] = {
++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017
++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL
++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL
++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL
++
++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29
++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25
++
++// DLO settings
++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable
++// These settings match AR0138 REV3 settings
++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138
++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6
++{0x3104, 0x6060}, // T3
++{0x3106, 0x6060}, // T4
++
++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2
++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17
++
++// boost settings
++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed,
++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in
++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin)
++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin)
++//PYTHON= loadBoosterSettings()
++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16,
++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd
++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd
++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd,
++{0x3532, 0x826C}, // updated (12/14)
++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin)
++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14)
++
++{0x3540, 0xC63C}, // eclipse clamp updated 5/16
++{0x3542, 0x4637}, // eclipse clamp updated 5/16
++{0x3544, 0x3750}, // eclipse clamp updated 5/16
++{0x3546, 0x5656}, // eclipse clamp updated 5/16
++{0x3548, 0x5600}, // eclipse clamp updated 5/16
++
++{0x3566, 0xBF38}, // col_mem settings, sa_park_en
++
++{0x30BA, 0x0112}, // Add dither after delay buffer decompander
++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9
++{ }
++}; /* Rev2 Recommended Settings */
++
++static const struct ar0xxx_reg ar0220_rev2_REV2_Optimized_Sequencer[] = {
++{0x2512, 0x8000},
++{0x2510, 0x0905},
++{0x2510, 0x3350},
++{0x2510, 0x2004},
++{0x2510, 0x1460},
++{0x2510, 0x1578},
++{0x2510, 0x1360},
++{0x2510, 0x7B24},
++{0x2510, 0xFF24},
++{0x2510, 0xFF24},
++{0x2510, 0xEA24},
++{0x2510, 0x1022},
++{0x2510, 0x2410},
++{0x2510, 0x155A},
++{0x2510, 0x1342},
++{0x2510, 0x1440},
++{0x2510, 0x24FF},
++{0x2510, 0x24FF},
++{0x2510, 0x24EA},
++{0x2510, 0x2324},
++{0x2510, 0x647A},
++{0x2510, 0x2404},
++{0x2510, 0x052C},
++{0x2510, 0x400A},
++{0x2510, 0xFF0A},
++{0x2510, 0x850A},
++{0x2510, 0x0608},
++{0x2510, 0x3851},
++{0x2510, 0x0905},
++{0x2510, 0x15DC},
++{0x2510, 0x134C},
++{0x2510, 0x0004},
++{0x2510, 0x0801},
++{0x2510, 0x0408},
++{0x2510, 0x1180},
++{0x2510, 0x1002},
++{0x2510, 0x1016},
++{0x2510, 0x1181},
++{0x2510, 0x1189},
++{0x2510, 0x1056},
++{0x2510, 0x1210},
++{0x2510, 0x0D09},
++{0x2510, 0x0714},
++{0x2510, 0x4114},
++{0x2510, 0x4009},
++{0x2510, 0x0815},
++{0x2510, 0xCC13},
++{0x2510, 0xCC15},
++{0x2510, 0x8813},
++{0x2510, 0x8809},
++{0x2510, 0x1111},
++{0x2510, 0x9909},
++{0x2510, 0x0B11},
++{0x2510, 0xD909},
++{0x2510, 0x0B12},
++{0x2510, 0x1409},
++{0x2510, 0x0112},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x1212},
++{0x2510, 0x1011},
++{0x2510, 0xDD11},
++{0x2510, 0xD910},
++{0x2510, 0x5609},
++{0x2510, 0x1111},
++{0x2510, 0xDB09},
++{0x2510, 0x1D11},
++{0x2510, 0xFB09},
++{0x2510, 0x0911},
++{0x2510, 0xBB12},
++{0x2510, 0x1A12},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x5010},
++{0x2510, 0xF610},
++{0x2510, 0xE609},
++{0x2510, 0x0315},
++{0x2510, 0xAB13},
++{0x2510, 0xAB12},
++{0x2510, 0x4012},
++{0x2510, 0x6009},
++{0x2510, 0x2315},
++{0x2510, 0x8809},
++{0x2510, 0x0113},
++{0x2510, 0x880B},
++{0x2510, 0x0906},
++{0x2510, 0x158D},
++{0x2510, 0x138D},
++{0x2510, 0x090B},
++{0x2510, 0x1066},
++{0x2510, 0x1588},
++{0x2510, 0x1388},
++{0x2510, 0x0C09},
++{0x2510, 0x0410},
++{0x2510, 0xE612},
++{0x2510, 0x6212},
++{0x2510, 0x6011},
++{0x2510, 0xBF11},
++{0x2510, 0xFB10},
++{0x2510, 0x6609},
++{0x2510, 0x3B11},
++{0x2510, 0xBB12},
++{0x2510, 0x6312},
++{0x2510, 0x6009},
++{0x2510, 0x0115},
++{0x2510, 0x5A11},
++{0x2510, 0xB812},
++{0x2510, 0xA012},
++{0x2510, 0x0010},
++{0x2510, 0x2610},
++{0x2510, 0x0013},
++{0x2510, 0x0211},
++{0x2510, 0x8014},
++{0x2510, 0x007A},
++{0x2510, 0x0611},
++{0x2510, 0x0005},
++{0x2510, 0x0708},
++{0x2510, 0x4137},
++{0x2510, 0x502C},
++{0x2510, 0x2CFE},
++{0x2510, 0x112C},
++{AR_DELAY, 300},
++
++{0x1008, 0x02B6}, //fine_integration_time_min
++{0x100c, 0x0452}, //fine_integration_time2_min
++{0x100e, 0x05EE}, //fine_integration_time3_min
++{0x1010, 0x011A}, //fine_integration_time4_min
++
++{0x3230, 0x0254}, //fine_correction
++{0x3232, 0x03F0}, //fine_correction2
++{0x3234, 0x058C}, //fine_correction3
++{0x3236, 0x00B8}, //fine_correction4
++{0x32e6, 0x009A}, //min_subrow
++{ }
++}; /* AR0220AT REV2 Optimized Sequencer */
++
++static const struct ar0xxx_reg ar0220_rev2_pll_23_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */
++{0x3030, 44}, //PLL_MULTIPLIER
++{0x302E, 2}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev2_pll_25_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */
++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
++{0x3030, 102}, //PLL_MULTIPLIER
++{0x302E, 5}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev2_pll_27_4lane_12b[] = {
++/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */
++/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
++{0x3030, 56}, //PLL_MULTIPLIER
++{0x302E, 3}, //PRE_PLL_CLK_DIV
++{0x302C, 1}, //P1 divider (vt_sys_clk_div)
++{0x302A, 6}, //P2 divider (vt_pix_clk_div)
++{0x3038, 1}, //P3 divider (op_sys_clk_div)
++{0x3036, 12}, //P4 divider (op_word_clk_div)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++{ }
++}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */
++
++static const struct ar0xxx_reg ar0220_rev2_Readout_Mode_Configuration[] = {
++{0x30A2, 1}, // x_odd_inc_
++{0x30A6, 1}, // y_odd_inc_
++{0x3040, 0}, // read_mode
++{ }
++}; /* Readout Mode Configuration */
++
++static const struct ar0xxx_reg ar0220_rev2_Full_Res_FOV[] = {
++{0x3004, AR0220_X_START}, // X_ADDR_START_
++{0x3008, AR0220_X_END}, // X_ADDR_END_
++{0x3002, AR0220_Y_START}, // Y_ADDR_START_
++{0x3006, AR0220_Y_END}, // Y_ADDR_END_
++{ }
++}; /* Full Res FOV */
++
++static const struct ar0xxx_reg ar0220_rev2_hdr_Timing_and_Exposure[] = {
++{0x3082, 0x8}, // operation_mode_ctrl
++{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2
++#ifdef AR0231_EMBEDDED_LINE
++{0x3064, 0x1982}, // SMIA_TEST
++#else
++{0x3064, 0x1802}, // SMIA_TEST
++#endif
++//{0x33E0, 0xC80},
++//{0x3180, 0x80},
++//{0x33E4, 0x80},
++
++{0x306e, 9010}, // datapath_select,ime_mode,0
++
++{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742)
++{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338)
++{0x3042, 0}, // extra_delay
++
++{0x3238, 0x444}, // exposure_ratio
++{0x3012, 1000}, // coarse_integration_time_
++{0x3014, 1526}, // fine_integration_time_
++{0x321E, 1526}, // fine_integration_time2
++{0x3222, 282}, // fine_integration_time3
++{0x32EA, 0x3C0E},
++//{0x32EC, 0x7151},
++
++{0x30B0, 0x800}, // enable_subrow_pair_reset
++{0x32E8, 637}, // max subrow margin for 3exp HDR
++{ }
++}; /* 3exp 36FPS Timing and Exposure */
++
++static const struct ar0xxx_reg ar0220_rev2_hdr_12bit_output[] = {
++{0x31D0, 1}, // companding
++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12
++{ }
++}; /* HDR Serial 4 lane 12 bit Output */
++
++static const struct ar0xxx_reg ar0220_rev2_mipi_12bit_4lane[] = {
++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes
++//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C
++//{0x3344, 0x0011}, // default, VC=0
++//{0x3348, 0x0111}, // default, VC=1
++//{0x334C, 0x0211}, // default, VC=2
++//{0x3350, 0x0311}, // default, VC=3
++{0x31B0, 0x46}, // frame_preamble
++{0x31B2, 0x31}, // line_preamble
++{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17
++{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17
++{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17
++{0x31BA, 0x0186}, //MIPI_TIMING_3
++{0x31BC, 0x0785}, //MIPI_TIMING_4
++{ }
++}; /* HDR MIPI 12 bit Settings */
++
++static const struct ar0xxx_reg ar0220_rev2_Recommended_HDR_Settings[] = {
++{ }
++}; /* Recommended HDR Settings */
++
++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev2[] = {
++ ar0220_rev2_Reset,
++ ar0220_rev2_Recommended_Settings,
++ ar0220_rev2_REV2_Optimized_Sequencer,
++ ar0220_rev2_pll_23_4lane_12b,
++ ar0220_rev2_Readout_Mode_Configuration,
++ ar0220_rev2_Full_Res_FOV,
++ ar0220_rev2_hdr_Timing_and_Exposure,
++ ar0220_rev2_hdr_12bit_output,
++ ar0220_rev2_mipi_12bit_4lane,
++ ar0220_rev2_Recommended_HDR_Settings,
++ NULL,
++};
+diff --git a/drivers/media/i2c/soc_camera/ar0220_rev3.h b/drivers/media/i2c/soc_camera/ar0220_rev3.h
+new file mode 100644
+index 0000000..6dad762
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0220_rev3.h
+@@ -0,0 +1,218 @@
++/*
++ * ON Semiconductor AR0220 sensor camera wizard 1848x944@30/BGGR/MIPI
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static const struct ar0xxx_reg ar0220_rev3_Recommended_Settings[] = {
++// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby
++{0x3500, 0x0100}, //This is a self clearing bit
++{AR_DELAY, 1}, //Delay => 4100 * Extclk
++
++{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017
++{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL
++{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL
++{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
++{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL
++
++{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29
++{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25
++
++// DLO settings
++{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable
++// These settings match AR0138 REV3 settings
++{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138
++{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6
++{0x3104, 0x6060}, // T3
++{0x3106, 0x6060}, // T4
++
++{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2
++{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17
++
++// boost settings
++// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed,
++// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in
++// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin)
++// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin)
++//PYTHON= loadBoosterSettings()
++//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16,
++//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd
++//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd
++//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd,
++//{0x3532, 0x826C // updated (12/14)
++{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018
++{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin)
++{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14)
++
++{0x3540, 0xC63C}, // eclipse clamp updated 5/16
++{0x3542, 0x4637}, // eclipse clamp updated 5/16
++{0x3544, 0x3750}, // eclipse clamp updated 5/16
++{0x3546, 0x5656}, // eclipse clamp updated 5/16
++{0x3548, 0x5600}, // eclipse clamp updated 5/16
++
++//{0x3566, 0xBF38}, // col_mem settings, sa_park_en
++{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN
++
++{0x30BA, 0x0112}, // Add dither after delay buffer decompander
++{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9
++{ }
++}; /* Rev3 Recommended Settings */
++
++static const struct ar0xxx_reg ar0220_rev3_REV3_Optimized_Sequencer[] = {
++{0x2512, 0x8000},
++{0x2510, 0x0905},
++{0x2510, 0x3350},
++{0x2510, 0x2004},
++{0x2510, 0x1460},
++{0x2510, 0x1578},
++{0x2510, 0x1360},
++{0x2510, 0x7B24},
++{0x2510, 0xFF24},
++{0x2510, 0xFF24},
++{0x2510, 0xEA24},
++{0x2510, 0x1022},
++{0x2510, 0x2410},
++{0x2510, 0x155A},
++{0x2510, 0x1342},
++{0x2510, 0x1440},
++{0x2510, 0x24FF},
++{0x2510, 0x24FF},
++{0x2510, 0x24EA},
++{0x2510, 0x2324},
++{0x2510, 0x647A},
++{0x2510, 0x2404},
++{0x2510, 0x052C},
++{0x2510, 0x400A},
++{0x2510, 0xFF0A},
++{0x2510, 0x850A},
++{0x2510, 0x0608},
++{0x2510, 0x3851},
++{0x2510, 0x0905},
++{0x2510, 0x15DC},
++{0x2510, 0x134C},
++{0x2510, 0x0004},
++{0x2510, 0x0801},
++{0x2510, 0x0408},
++{0x2510, 0x1180},
++{0x2510, 0x1002},
++{0x2510, 0x1016},
++{0x2510, 0x1181},
++{0x2510, 0x1189},
++{0x2510, 0x1056},
++{0x2510, 0x1210},
++{0x2510, 0x0D09},
++{0x2510, 0x0714},
++{0x2510, 0x4114},
++{0x2510, 0x4009},
++{0x2510, 0x0815},
++{0x2510, 0xCC13},
++{0x2510, 0xCC15},
++{0x2510, 0x8813},
++{0x2510, 0x8809},
++{0x2510, 0x1111},
++{0x2510, 0x9909},
++{0x2510, 0x0B11},
++{0x2510, 0xD909},
++{0x2510, 0x0B12},
++{0x2510, 0x1409},
++{0x2510, 0x0112},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x1212},
++{0x2510, 0x1011},
++{0x2510, 0xDD11},
++{0x2510, 0xD910},
++{0x2510, 0x5609},
++{0x2510, 0x1111},
++{0x2510, 0xDB09},
++{0x2510, 0x1D11},
++{0x2510, 0xFB09},
++{0x2510, 0x0911},
++{0x2510, 0xBB12},
++{0x2510, 0x1A12},
++{0x2510, 0x1010},
++{0x2510, 0xD612},
++{0x2510, 0x5010},
++{0x2510, 0xF610},
++{0x2510, 0xE609},
++{0x2510, 0x0315},
++{0x2510, 0xAB13},
++{0x2510, 0xAB12},
++{0x2510, 0x4012},
++{0x2510, 0x6009},
++{0x2510, 0x2315},
++{0x2510, 0x8809},
++{0x2510, 0x0113},
++{0x2510, 0x880B},
++{0x2510, 0x0906},
++{0x2510, 0x158D},
++{0x2510, 0x138D},
++{0x2510, 0x090B},
++{0x2510, 0x1066},
++{0x2510, 0x1588},
++{0x2510, 0x1388},
++{0x2510, 0x0C09},
++{0x2510, 0x0410},
++{0x2510, 0xE612},
++{0x2510, 0x6212},
++{0x2510, 0x6011},
++{0x2510, 0xBF11},
++{0x2510, 0xFB10},
++{0x2510, 0x6609},
++{0x2510, 0x3B11},
++{0x2510, 0xBB12},
++{0x2510, 0x6312},
++{0x2510, 0x6009},
++{0x2510, 0x0115},
++{0x2510, 0x5A11},
++{0x2510, 0xB812},
++{0x2510, 0xA012},
++{0x2510, 0x0010},
++{0x2510, 0x2610},
++{0x2510, 0x0013},
++{0x2510, 0x0211},
++{0x2510, 0x8014},
++{0x2510, 0x007A},
++{0x2510, 0x0611},
++{0x2510, 0x0005},
++{0x2510, 0x0708},
++{0x2510, 0x4137},
++{0x2510, 0x502C},
++{0x2510, 0x2CFE},
++{0x2510, 0x112C},
++{AR_DELAY, 300},
++
++{0x1008, 0x02B6}, //fine_integration_time_min
++{0x100c, 0x0452}, //fine_integration_time2_min
++{0x100e, 0x05EE}, //fine_integration_time3_min
++{0x1010, 0x011A}, //fine_integration_time4_min
++
++{0x3230, 0x0254}, //fine_correction
++{0x3232, 0x03F0}, //fine_correction2
++{0x3234, 0x058C}, //fine_correction3
++{0x3236, 0x00B8}, //fine_correction4
++//{0x32e6, 0x009A}, //min_subrow
++{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin
++{ }
++}; /* AR0220AT REV3 Optimized Sequencer */
++
++/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
++static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = {
++ ar0220_rev2_Reset,
++ ar0220_rev3_Recommended_Settings,
++ ar0220_rev3_REV3_Optimized_Sequencer,
++ ar0220_rev2_pll_23_4lane_12b,
++ ar0220_rev2_Readout_Mode_Configuration,
++ ar0220_rev2_Full_Res_FOV,
++ ar0220_rev2_hdr_Timing_and_Exposure,
++ ar0220_rev2_hdr_12bit_output,
++ ar0220_rev2_mipi_12bit_4lane,
++ ar0220_rev2_Recommended_HDR_Settings,
++ NULL,
++};
+diff --git a/drivers/media/i2c/soc_camera/ar0220_rev4.h b/drivers/media/i2c/soc_camera/ar0220_rev4.h
+index 55923a3..14dfe13 100644
+--- a/drivers/media/i2c/soc_camera/ar0220_rev4.h
++++ b/drivers/media/i2c/soc_camera/ar0220_rev4.h
+@@ -9,362 +9,16 @@
+ * option) any later version.
+ */
+
+-static const struct ar0xxx_reg ar0220_rev4_Reset[] = {
+-{0x301A, 0x0018}, // Stream off and setup MIPI
+-{AR_DELAY, 200},
+-{0x3070, 0x0000}, // 1: Solid color test pattern,
+- // 2: Full color bar test pattern,
+- // 3: Fade to grey color bar test pattern,
+- //256: Walking 1 test pattern (12 bit)
+-{0x3072, 0x0123}, // R
+-{0x3074, 0x0456}, // G(GR row)
+-{0x3076, 0x0abc}, // B
+-{0x3078, 0x0def}, // G(GB row)
+-#ifdef AR0220_DISPLAY_PATTERN_FIXED
+-{0x3070, 0x0001},
+-#endif
+-#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR
+-{0x3070, 0x0002},
+-#endif
+-{AR_DELAY, 100},
+-{ }
+-}; /* Reset */
+-
+-static const struct ar0xxx_reg ar0220_rev4_Recommended_Settings[] = {
+-// Set the SREG_WRITE_ALL bit to remove potential higher current during intial standby
+-{0x3500, 0x0100}, //This is a self clearing bit
+-{AR_DELAY, 1}, //Delay => 4100 * Extclk
+-
+-{0x3092, 0x0824}, // row noise dither enabled, dither scale=0 udpated 6/30/2017
+-{0x3096, 0x227C}, // row noise adjust top update 4/27/2017 with Jan-4 timing...YL
+-{0x3098, 0x227C}, // row noise adjust bot update 4/27/2017 with Jan-4 timing...YL
+-{0x3750, 0x227C}, // row noise adjust top gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
+-{0x3752, 0x227C}, // row noise adjust btm gain ... these are for T1, 4/27/2017 with Jan-4 timing...YL
+-{0x351C, 0x00B3}, // vaapix load cap=11, agnd load cap=3 updated 4/27 with Jan-4 timing...YL
+-
+-{0x3364, 172}, // set dual conversion gain ratio (HCG/LCG) to 5.3x (~172/32) updated 3/29
+-{0x337A, 0x0BB8}, // dblc scale factor 0.733x, updated 4/25
+-
+-// DLO settings
+-{0x3110, 0x0011}, // Pre-HDR gain enable; Pixel_width_enable
+-// These settings match AR0138 REV3 settings
+-{0x3100, 0x4000}, // dlo control. turn on dlo noise filter. set barrier dither select to 0 to match AR0138
+-{0x3102, 0x6060}, // "better" filter settings. This is S2=96 and range=6
+-{0x3104, 0x6060}, // T3
+-{0x3106, 0x6060}, // T4
+-
+-{0x32EC, 0x72A2}, // shut_ctrl2_t3_sh_adcance=2
+-{0x350E, 0x0F14}, // adc_pedestal_dither_en=15 (from 231) to minimize RTN periodical bumps... updated 8/9/17
+-
+-// boost settings
+-// Load booster settings. Early CREV4 headboards and parts will require booster settings to be manually programmed,
+-// while CREV4 ES samples have part-specific booster settings programmed in OTPM. Booster settings are instored in
+-// following 4 registers: 0x3520, 0x3522, 0x3524, and 0x352C. (9/22/2017 Lin)
+-// Remove soft trim booster settings for CRev3-1 sensors as they are boosters trimmed. (01/14/2018 Lin)
+-//PYTHON= loadBoosterSettings()
+-//{0x3520, 0x1288 // RSTHI=3.9v, use fine_code=18 and coarse_code=0, Casey's rec'd, updated 12/16,
+-//{0x3522, 0x860C // ROWHI=3.6v, Vrst_lo for hcg_lg change from 8 to 6 for eclipse margin 9/27, HTOL updated 12/16, use fine_code=12 and coarse_code=0, Casey's rec'd
+-//{0x3524, 0x0C12 // DCGHI=3.6v, TXHI=3.9v updated HTOL voltage 12/16 Casey's rec'd
+-//{0x352c, 0x0012 // RSTWELLHI=3.9v using fine_code=18 and coarse_code=0 HTOL voltage updated 12/16 C. Hoekstra rec'd,
+-//{0x3532, 0x826C // updated (12/14)
+-{0x3528, 0x3633}, //update vtxlo for lcg_lg to 0.3V for blue blooming issue 6/1/2018
+-{0x3532, 0xAE6C}, // ECL settings updated (1/9 Lin)
+-{0x353a, 0x9000}, // use AGND based boosters, enable continuous boost for RSTHI_WELL, TXHI_WELL (12/14)
+-
+-{0x3540, 0xC63C}, // eclipse clamp updated 5/16
+-{0x3542, 0x4637}, // eclipse clamp updated 5/16
+-{0x3544, 0x3750}, // eclipse clamp updated 5/16
+-{0x3546, 0x5656}, // eclipse clamp updated 5/16
+-{0x3548, 0x5600}, // eclipse clamp updated 5/16
+-
+-//{0x3566, 0xBF38}, // col_mem settings, sa_park_en
+-{0x3566, 0x3F28}, // col_mem settings, sa_park_en 5/2/2019 disable READOUT_PARK_ENABLE and SA_PARK_EN
+-
+-{0x30BA, 0x0112}, // Add dither after delay buffer decompander
+-{0x30BA, 0x0112}, //stop read back of dtest register from analog core to remove dark row on top 5/9
+-{ }
+-}; /* Rev3 Recommended Settings */
+-
+-static const struct ar0xxx_reg ar0220_rev4_REV3_Optimized_Sequencer[] = {
+-{0x2512, 0x8000},
+-{0x2510, 0x0905},
+-{0x2510, 0x3350},
+-{0x2510, 0x2004},
+-{0x2510, 0x1460},
+-{0x2510, 0x1578},
+-{0x2510, 0x1360},
+-{0x2510, 0x7B24},
+-{0x2510, 0xFF24},
+-{0x2510, 0xFF24},
+-{0x2510, 0xEA24},
+-{0x2510, 0x1022},
+-{0x2510, 0x2410},
+-{0x2510, 0x155A},
+-{0x2510, 0x1342},
+-{0x2510, 0x1440},
+-{0x2510, 0x24FF},
+-{0x2510, 0x24FF},
+-{0x2510, 0x24EA},
+-{0x2510, 0x2324},
+-{0x2510, 0x647A},
+-{0x2510, 0x2404},
+-{0x2510, 0x052C},
+-{0x2510, 0x400A},
+-{0x2510, 0xFF0A},
+-{0x2510, 0x850A},
+-{0x2510, 0x0608},
+-{0x2510, 0x3851},
+-{0x2510, 0x0905},
+-{0x2510, 0x15DC},
+-{0x2510, 0x134C},
+-{0x2510, 0x0004},
+-{0x2510, 0x0801},
+-{0x2510, 0x0408},
+-{0x2510, 0x1180},
+-{0x2510, 0x1002},
+-{0x2510, 0x1016},
+-{0x2510, 0x1181},
+-{0x2510, 0x1189},
+-{0x2510, 0x1056},
+-{0x2510, 0x1210},
+-{0x2510, 0x0D09},
+-{0x2510, 0x0714},
+-{0x2510, 0x4114},
+-{0x2510, 0x4009},
+-{0x2510, 0x0815},
+-{0x2510, 0xCC13},
+-{0x2510, 0xCC15},
+-{0x2510, 0x8813},
+-{0x2510, 0x8809},
+-{0x2510, 0x1111},
+-{0x2510, 0x9909},
+-{0x2510, 0x0B11},
+-{0x2510, 0xD909},
+-{0x2510, 0x0B12},
+-{0x2510, 0x1409},
+-{0x2510, 0x0112},
+-{0x2510, 0x1010},
+-{0x2510, 0xD612},
+-{0x2510, 0x1212},
+-{0x2510, 0x1011},
+-{0x2510, 0xDD11},
+-{0x2510, 0xD910},
+-{0x2510, 0x5609},
+-{0x2510, 0x1111},
+-{0x2510, 0xDB09},
+-{0x2510, 0x1D11},
+-{0x2510, 0xFB09},
+-{0x2510, 0x0911},
+-{0x2510, 0xBB12},
+-{0x2510, 0x1A12},
+-{0x2510, 0x1010},
+-{0x2510, 0xD612},
+-{0x2510, 0x5010},
+-{0x2510, 0xF610},
+-{0x2510, 0xE609},
+-{0x2510, 0x0315},
+-{0x2510, 0xAB13},
+-{0x2510, 0xAB12},
+-{0x2510, 0x4012},
+-{0x2510, 0x6009},
+-{0x2510, 0x2315},
+-{0x2510, 0x8809},
+-{0x2510, 0x0113},
+-{0x2510, 0x880B},
+-{0x2510, 0x0906},
+-{0x2510, 0x158D},
+-{0x2510, 0x138D},
+-{0x2510, 0x090B},
+-{0x2510, 0x1066},
+-{0x2510, 0x1588},
+-{0x2510, 0x1388},
+-{0x2510, 0x0C09},
+-{0x2510, 0x0410},
+-{0x2510, 0xE612},
+-{0x2510, 0x6212},
+-{0x2510, 0x6011},
+-{0x2510, 0xBF11},
+-{0x2510, 0xFB10},
+-{0x2510, 0x6609},
+-{0x2510, 0x3B11},
+-{0x2510, 0xBB12},
+-{0x2510, 0x6312},
+-{0x2510, 0x6009},
+-{0x2510, 0x0115},
+-{0x2510, 0x5A11},
+-{0x2510, 0xB812},
+-{0x2510, 0xA012},
+-{0x2510, 0x0010},
+-{0x2510, 0x2610},
+-{0x2510, 0x0013},
+-{0x2510, 0x0211},
+-{0x2510, 0x8014},
+-{0x2510, 0x007A},
+-{0x2510, 0x0611},
+-{0x2510, 0x0005},
+-{0x2510, 0x0708},
+-{0x2510, 0x4137},
+-{0x2510, 0x502C},
+-{0x2510, 0x2CFE},
+-{0x2510, 0x112C},
+-{AR_DELAY, 300},
+-
+-{0x1008, 0x02B6}, //fine_integration_time_min
+-{0x100c, 0x0452}, //fine_integration_time2_min
+-{0x100e, 0x05EE}, //fine_integration_time3_min
+-{0x1010, 0x011A}, //fine_integration_time4_min
+-
+-{0x3230, 0x0254}, //fine_correction
+-{0x3232, 0x03F0}, //fine_correction2
+-{0x3234, 0x058C}, //fine_correction3
+-{0x3236, 0x00B8}, //fine_correction4
+-//{0x32e6, 0x009A}, //min_subrow
+-{0x32e6, 0x00BC}, //min_subrow 188 2/6/2018 Lin
+-{ }
+-}; /* AR0220AT REV3 Optimized Sequencer */
+-
+-static const struct ar0xxx_reg ar0220_rev4_pll_23_4lane_12b[] = {
+-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
+-/* PCLK=23Mhz/2 *44/1/12 *2= 84Mhz - TI serializers */
+-{0x3030, 44}, //PLL_MULTIPLIER
+-{0x302E, 2}, //PRE_PLL_CLK_DIV
+-{0x302C, 1}, //P1 divider (vt_sys_clk_div)
+-{0x302A, 6}, //P2 divider (vt_pix_clk_div)
+-{0x3038, 1}, //P3 divider (op_sys_clk_div)
+-{0x3036, 12}, //P4 divider (op_word_clk_div)
+-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
+-{ }
+-}; /* PLL Setup Serial 4 lane 12-bit Output 23Mhz MCLK */
+-
+-static const struct ar0xxx_reg ar0220_rev4_pll_25_4lane_12b[] = {
+-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
+-/* PCLK=25Mhz/5 *102/1/12 *2= 85Mhz - IN-CAMERA REFCLK */
+-/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
+-{0x3030, 102}, //PLL_MULTIPLIER
+-{0x302E, 5}, //PRE_PLL_CLK_DIV
+-{0x302C, 1}, //P1 divider (vt_sys_clk_div)
+-{0x302A, 6}, //P2 divider (vt_pix_clk_div)
+-{0x3038, 1}, //P3 divider (op_sys_clk_div)
+-{0x3036, 12}, //P4 divider (op_word_clk_div)
+-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
+-{ }
+-}; /* PLL Setup Serial 4 lane 12-bit Output 25Mhz MCLK */
+-
+-static const struct ar0xxx_reg ar0220_rev4_pll_27_4lane_12b[] = {
+-/* PCLK=DES_REFCLK/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
+-/* PCLK=27Mhz/3 *56/1/12 *2= 84Mhz - IN-CAMERA REFCLK */
+-/* PCLK=23Mhz/3 *56/1/12 *2= 71Mhz - TI serializers */
+-{0x3030, 56}, //PLL_MULTIPLIER
+-{0x302E, 3}, //PRE_PLL_CLK_DIV
+-{0x302C, 1}, //P1 divider (vt_sys_clk_div)
+-{0x302A, 6}, //P2 divider (vt_pix_clk_div)
+-{0x3038, 1}, //P3 divider (op_sys_clk_div)
+-{0x3036, 12}, //P4 divider (op_word_clk_div)
+-{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
+-{ }
+-}; /* PLL Setup Serial 4 lane 12-bit Output 27Mhz MCLK */
+-
+-static const struct ar0xxx_reg ar0220_rev4_Readout_Mode_Configuration[] = {
+-{0x30A2, 1}, // x_odd_inc_
+-{0x30A6, 1}, // y_odd_inc_
+-{0x3040, 0}, // read_mode
+-{ }
+-}; /* Readout Mode Configuration */
+-
+-static const struct ar0xxx_reg ar0220_rev4_Full_Res_FOV[] = {
+-{0x3004, AR0220_X_START}, // X_ADDR_START_
+-{0x3008, AR0220_X_END}, // X_ADDR_END_
+-{0x3002, AR0220_Y_START}, // Y_ADDR_START_
+-{0x3006, AR0220_Y_END}, // Y_ADDR_END_
+-{ }
+-}; /* Full Res FOV */
+-
+-static const struct ar0xxx_reg ar0220_rev4_hdr_Timing_and_Exposure[] = {
+-{0x3082, 0x8}, // operation_mode_ctrl
+-{0x30BA, 0x1112}, // digital_ctrl: num_exp_max=2
+-#ifdef AR0231_EMBEDDED_LINE
+-{0x3064, 0x1982}, // SMIA_TEST
+-#else
+-{0x3064, 0x1802}, // SMIA_TEST
+-#endif
+-//{0x33E0, 0xC80},
+-//{0x3180, 0x80},
+-//{0x33E4, 0x80},
+-
+-{0x306e, 9010}, // datapath_select,ime_mode,0
+-
+-{0x300A, AR0220_SENSOR_HEIGHT + 794}, // frame_length_lines_ (1742)
+-{0x300C, AR0220_SENSOR_WIDTH/2 + 424}, // line_length_pck_ (1338)
+-{0x3042, 0}, // extra_delay
+-
+-{0x3238, 0x444}, // exposure_ratio
+-{0x3012, 1000}, // coarse_integration_time_
+-{0x3014, 1526}, // fine_integration_time_
+-{0x321E, 1526}, // fine_integration_time2
+-{0x3222, 282}, // fine_integration_time3
+-{0x32EA, 0x3C0E},
+-//{0x32EC, 0x7151},
+-
+-{0x30B0, 0x800}, // enable_subrow_pair_reset
+-{0x32E8, 637}, // max subrow margin for 3exp HDR
+-{ }
+-}; /* 3exp 36FPS Timing and Exposure */
+-
+-static const struct ar0xxx_reg ar0220_rev4_hdr_12bit_output[] = {
+-{0x31D0, 1}, // companding
+-{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12
+-{ }
+-}; /* HDR Serial 4 lane 12 bit Output */
+-
+-static const struct ar0xxx_reg ar0220_rev4_mipi_12bit_4lane[] = {
+-{0x31AE, 0x204}, // serial_format: MIPI 4 lanes
+-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x3344, 0x0011}, // default, VC=0
+-//{0x3348, 0x0111}, // default, VC=1
+-//{0x334C, 0x0211}, // default, VC=2
+-//{0x3350, 0x0311}, // default, VC=3
+-{0x31B0, 0x46}, // frame_preamble
+-{0x31B2, 0x31}, // line_preamble
+-{0x31B4, 0x2144}, //MIPI_TIMING_0 update @504Mbps 12 bit, 04/17
+-{0x31B6, 0x3145}, //MIPI_TIMING_1 update @504Mbps 12 bit, 04/17
+-{0x31B8, 0x3147}, //MIPI_TIMING_2 update @504Mbps 12 bit, 04/17
+-{0x31BA, 0x0186}, //MIPI_TIMING_3
+-{0x31BC, 0x0785}, //MIPI_TIMING_4
+-{ }
+-}; /* HDR MIPI 12 bit Settings */
+-
+-static const struct ar0xxx_reg ar0220_rev4_Recommended_HDR_Settings[] = {
+-{ }
+-}; /* Recommended HDR Settings */
+-
+ /* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
+ static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev4[] = {
+- ar0220_rev4_Reset,
+- ar0220_rev4_Recommended_Settings,
+- ar0220_rev4_pll_23_4lane_12b,
+- ar0220_rev4_Readout_Mode_Configuration,
+- ar0220_rev4_Full_Res_FOV,
+- ar0220_rev4_hdr_Timing_and_Exposure,
+- ar0220_rev4_hdr_12bit_output,
+- ar0220_rev4_mipi_12bit_4lane,
+- ar0220_rev4_Recommended_HDR_Settings,
+- NULL,
+-};
+-
+-/* 3exp HDR, Full Resolution, MIPI 4-lane 12-bit 36FPS, EXTCLK=23MHz (comes from deser) */
+-static const struct ar0xxx_reg *ar0220_regs_hdr_mipi_12bit_36fps_rev3[] = {
+- ar0220_rev4_Reset,
+- ar0220_rev4_Recommended_Settings,
+- ar0220_rev4_REV3_Optimized_Sequencer,
+- ar0220_rev4_pll_23_4lane_12b,
+- ar0220_rev4_Readout_Mode_Configuration,
+- ar0220_rev4_Full_Res_FOV,
+- ar0220_rev4_hdr_Timing_and_Exposure,
+- ar0220_rev4_hdr_12bit_output,
+- ar0220_rev4_mipi_12bit_4lane,
+- ar0220_rev4_Recommended_HDR_Settings,
++ ar0220_rev2_Reset,
++ ar0220_rev3_Recommended_Settings,
++ ar0220_rev2_pll_23_4lane_12b,
++ ar0220_rev2_Readout_Mode_Configuration,
++ ar0220_rev2_Full_Res_FOV,
++ ar0220_rev2_hdr_Timing_and_Exposure,
++ ar0220_rev2_hdr_12bit_output,
++ ar0220_rev2_mipi_12bit_4lane,
++ ar0220_rev2_Recommended_HDR_Settings,
+ NULL,
+ };
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index 500fa75..312b9fe 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -463,16 +463,23 @@ static int ar0233_initialize(struct i2c_client *client)
+ AR_X_END = AR0220_X_END;
+ AR_Y_END = AR0220_Y_END;
+
++ if (extclk == 25) {
++ ar0220_regs_hdr_mipi_12bit_36fps_rev2[3] = ar0220_rev2_pll_25_4lane_12b;
++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev2_pll_25_4lane_12b;
++ ar0220_regs_hdr_mipi_12bit_36fps_rev4[2] = ar0220_rev2_pll_25_4lane_12b;
++ }
++ if (extclk == 27) {
++ ar0220_regs_hdr_mipi_12bit_36fps_rev2[3] = ar0220_rev2_pll_27_4lane_12b;
++ ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev2_pll_27_4lane_12b;
++ ar0220_regs_hdr_mipi_12bit_36fps_rev4[2] = ar0220_rev2_pll_27_4lane_12b;
++ }
++
+ switch (rev & 0xf) {
+ case 0x1:
+ case 0x2:
++ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev2);
++ break;
+ case 0x3:
+- if (extclk == 25) {
+- ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_25_4lane_12b;
+- }
+- if (extclk == 27) {
+- ar0220_regs_hdr_mipi_12bit_36fps_rev3[3] = ar0220_rev4_pll_27_4lane_12b;
+- }
+ ar0233_set_regs(client, ar0220_regs_hdr_mipi_12bit_36fps_rev3);
+ break;
+ case 0x4:
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch
new file mode 100644
index 00000000..2bd283b3
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch
@@ -0,0 +1,154 @@
+From 164a97c4370a29ee27145c5d1c44fe03ec2ce7b1 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 20 Nov 2019 16:41:12 +0300
+Subject: [PATCH] media: i2c: max9286: parse crossbard from cmdline
+
+This allows to change crossbar by command line parameter
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9286.c | 93 +++++++++++++++++++---------------
+ 1 file changed, 51 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index 3184ff1..b185566 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -56,6 +56,7 @@ struct max9286_priv {
+ int dbl;
+ int dt;
+ int hsgen;
++ char cb[16];
+ int hts;
+ int vts;
+ int hts_delay;
+@@ -140,6 +141,10 @@ static int switchin = 0;
+ module_param(switchin, int, 0644);
+ MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)");
+
++static long crossbar = 0xba9876543210;
++module_param(crossbar, long, 0644);
++MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)");
++
+ enum {
+ RGB888_DT = 0,
+ RGB565_DT,
+@@ -421,54 +426,53 @@ static void max9286_gmsl_link_setup(struct i2c_client *client, int idx)
+ switch (priv->dt) {
+ case YUV8_DT:
+ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
+- reg8_write(client, 0x20, 7);
+- reg8_write(client, 0x21, 6);
+- reg8_write(client, 0x22, 5);
+- reg8_write(client, 0x23, 4);
+- reg8_write(client, 0x24, 3);
+- reg8_write(client, 0x25, 2);
+- reg8_write(client, 0x26, 1);
+- reg8_write(client, 0x27, 0);
++ reg8_write(client, 0x20, priv->cb[7]);
++ reg8_write(client, 0x21, priv->cb[6]);
++ reg8_write(client, 0x22, priv->cb[5]);
++ reg8_write(client, 0x23, priv->cb[4]);
++ reg8_write(client, 0x24, priv->cb[3]);
++ reg8_write(client, 0x25, priv->cb[2]);
++ reg8_write(client, 0x26, priv->cb[1]);
++ reg8_write(client, 0x27, priv->cb[0]);
+
+ /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, 23);
+- reg8_write(client, 0x31, 22);
+- reg8_write(client, 0x32, 21);
+- reg8_write(client, 0x33, 20);
+- reg8_write(client, 0x34, 19);
+- reg8_write(client, 0x35, 18);
+- reg8_write(client, 0x36, 17);
+- reg8_write(client, 0x37, 16);
+-
++ reg8_write(client, 0x30, priv->cb[7] + 16);
++ reg8_write(client, 0x31, priv->cb[6] + 16);
++ reg8_write(client, 0x32, priv->cb[5] + 16);
++ reg8_write(client, 0x33, priv->cb[4] + 16);
++ reg8_write(client, 0x34, priv->cb[3] + 16);
++ reg8_write(client, 0x35, priv->cb[2] + 16);
++ reg8_write(client, 0x36, priv->cb[1] + 16);
++ reg8_write(client, 0x37, priv->cb[0] + 16);
+ break;
+ case RAW12_DT:
+ /* setup crossbar for RAW12: reverse DVP bus */
+- reg8_write(client, 0x20, 11);
+- reg8_write(client, 0x21, 10);
+- reg8_write(client, 0x22, 9);
+- reg8_write(client, 0x23, 8);
+- reg8_write(client, 0x24, 7);
+- reg8_write(client, 0x25, 6);
+- reg8_write(client, 0x26, 5);
+- reg8_write(client, 0x27, 4);
+- reg8_write(client, 0x28, 3);
+- reg8_write(client, 0x29, 2);
+- reg8_write(client, 0x2a, 1);
+- reg8_write(client, 0x2b, 0);
++ reg8_write(client, 0x20, priv->cb[11]);
++ reg8_write(client, 0x21, priv->cb[10]);
++ reg8_write(client, 0x22, priv->cb[9]);
++ reg8_write(client, 0x23, priv->cb[8]);
++ reg8_write(client, 0x24, priv->cb[7]);
++ reg8_write(client, 0x25, priv->cb[6]);
++ reg8_write(client, 0x26, priv->cb[5]);
++ reg8_write(client, 0x27, priv->cb[4]);
++ reg8_write(client, 0x28, priv->cb[3]);
++ reg8_write(client, 0x29, priv->cb[2]);
++ reg8_write(client, 0x2a, priv->cb[1]);
++ reg8_write(client, 0x2b, priv->cb[0]);
+
+ /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, 27);
+- reg8_write(client, 0x31, 26);
+- reg8_write(client, 0x32, 25);
+- reg8_write(client, 0x33, 24);
+- reg8_write(client, 0x34, 23);
+- reg8_write(client, 0x35, 22);
+- reg8_write(client, 0x36, 21);
+- reg8_write(client, 0x37, 20);
+- reg8_write(client, 0x38, 19);
+- reg8_write(client, 0x39, 18);
+- reg8_write(client, 0x3a, 17);
+- reg8_write(client, 0x3b, 16);
++ reg8_write(client, 0x30, priv->cb[11] + 16);
++ reg8_write(client, 0x31, priv->cb[10] + 16);
++ reg8_write(client, 0x32, priv->cb[9] + 16);
++ reg8_write(client, 0x33, priv->cb[8] + 16);
++ reg8_write(client, 0x34, priv->cb[7] + 16);
++ reg8_write(client, 0x35, priv->cb[6] + 16);
++ reg8_write(client, 0x36, priv->cb[5] + 16);
++ reg8_write(client, 0x37, priv->cb[4] + 16);
++ reg8_write(client, 0x38, priv->cb[3] + 16);
++ reg8_write(client, 0x39, priv->cb[2] + 16);
++ reg8_write(client, 0x3a, priv->cb[1] + 16);
++ reg8_write(client, 0x3b, priv->cb[0] + 16);
+
+ if (!priv->bws && priv->dbl)
+ dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
+@@ -733,7 +737,6 @@ static int max9286_parse_dt(struct i2c_client *client)
+ if (of_property_read_u32(np, "maxim,switchin", &priv->switchin))
+ priv->switchin = 0;
+
+-
+ /* module params override dts */
+ if (him)
+ priv->him = him;
+@@ -766,6 +769,12 @@ static int max9286_parse_dt(struct i2c_client *client)
+ if (switchin)
+ priv->switchin = switchin;
+
++ /* parse crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = crossbar % 16;
++ crossbar /= 16;
++ }
++
+ for (i = 0; i < priv->links; i++) {
+ endpoint = of_graph_get_next_endpoint(np, endpoint);
+ if (!endpoint)
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch
new file mode 100644
index 00000000..d797cb9f
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch
@@ -0,0 +1,51 @@
+From a2f64f8aadc505509045f2bc5da0be93e302b244 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 00:58:51 +0300
+Subject: [PATCH 01/12] clk: renesas: r8a7795-cpg-mssr: Add RPC clocks
+
+This adds RPC clock support to the R8A7795 CPG MSSR driver.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/clk/renesas/r8a7795-cpg-mssr.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
+index bd5a73f..f20d47d 100644
+--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
+@@ -47,6 +47,7 @@ enum clk_ids {
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_SSPSRC,
++ CLK_RPCSRC,
+ CLK_RINT,
+
+ /* Module Clocks */
+@@ -73,9 +74,15 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
++ DEF_BASE("rpc", R8A7795_CLK_RPC, CLK_TYPE_GEN3_RPC,
++ CLK_RPCSRC),
++ DEF_BASE("rpcd2", R8A7795_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
++ R8A7795_CLK_RPC),
++
+ /* Core Clock Outputs */
+ DEF_GEN3_Z("z", R8A7795_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2),
+ DEF_GEN3_Z("z2", R8A7795_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2, 2),
+@@ -245,6 +252,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
+ DEF_MOD("can-fd", 914, R8A7795_CLK_S3D2),
+ DEF_MOD("can-if1", 915, R8A7795_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4),
++ DEF_MOD("rpc-if", 917, R8A7795_CLK_RPCD2),
+ DEF_MOD("i2c6", 918, R8A7795_CLK_S0D6),
+ DEF_MOD("i2c5", 919, R8A7795_CLK_S0D6),
+ DEF_MOD("adg", 922, R8A7795_CLK_S0D1),
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch
new file mode 100644
index 00000000..d65360f8
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch
@@ -0,0 +1,51 @@
+From ec658a740c059ebc224dcdd3da1461faa2ce71e9 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:00:14 +0300
+Subject: [PATCH 02/12] clk: renesas: r8a7796-cpg-mssr: Add RPC clocks
+
+This adds RPC clock support to the R8A7796 CPG MSSR driver.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/clk/renesas/r8a7796-cpg-mssr.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
+index f4f1350..069a53a 100644
+--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
+@@ -48,6 +48,7 @@ enum clk_ids {
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_SSPSRC,
++ CLK_RPCSRC,
+ CLK_RINT,
+
+ /* Module Clocks */
+@@ -74,9 +75,15 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
++ DEF_BASE("rpc", R8A7796_CLK_RPC, CLK_TYPE_GEN3_RPC,
++ CLK_RPCSRC),
++ DEF_BASE("rpcd2", R8A7796_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
++ R8A7796_CLK_RPC),
++
+ /* Core Clock Outputs */
+ DEF_GEN3_Z("z", R8A7796_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2),
+ DEF_GEN3_Z("z2", R8A7796_CLK_Z2, CLK_TYPE_GEN3_Z2, CLK_PLL2, 2),
+@@ -218,6 +225,7 @@ static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = {
+ DEF_MOD("can-fd", 914, R8A7796_CLK_S3D2),
+ DEF_MOD("can-if1", 915, R8A7796_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A7796_CLK_S3D4),
++ DEF_MOD("rpc-if", 917, R8A7796_CLK_RPCD2),
+ DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6),
+ DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6),
+ DEF_MOD("adg", 922, R8A7796_CLK_S0D1),
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch
new file mode 100644
index 00000000..c51385cc
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch
@@ -0,0 +1,51 @@
+From c76e22071bc721ccd05a7e1acbe9a0e4ea078385 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:00:35 +0300
+Subject: [PATCH 03/12] clk: renesas: r8a77965-cpg-mssr: Add RPC clocks
+
+This adds RPC clock support to the R8A77965 CPG MSSR driver.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/clk/renesas/r8a77965-cpg-mssr.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c
+index 3d4fe53..dbcd320 100644
+--- a/drivers/clk/renesas/r8a77965-cpg-mssr.c
++++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c
+@@ -43,6 +43,7 @@ enum clk_ids {
+ CLK_S3,
+ CLK_SDSRC,
+ CLK_SSPSRC,
++ CLK_RPCSRC,
+ CLK_RINT,
+
+ /* Module Clocks */
+@@ -68,9 +69,15 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = {
+ DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
+ DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
+ DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1),
++ DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
+
+ DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32),
+
++ DEF_BASE("rpc", R8A77965_CLK_RPC, CLK_TYPE_GEN3_RPC,
++ CLK_RPCSRC),
++ DEF_BASE("rpcd2", R8A77965_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
++ R8A77965_CLK_RPC),
++
+ /* Core Clock Outputs */
+ DEF_GEN3_Z("z", R8A77965_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2),
+ DEF_GEN3_Z("zg", R8A77965_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4),
+@@ -215,6 +222,7 @@ static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = {
+ DEF_MOD("can-fd", 914, R8A77965_CLK_S3D2),
+ DEF_MOD("can-if1", 915, R8A77965_CLK_S3D4),
+ DEF_MOD("can-if0", 916, R8A77965_CLK_S3D4),
++ DEF_MOD("rpc-if", 917, R8A77965_CLK_RPCD2),
+ DEF_MOD("i2c6", 918, R8A77965_CLK_S0D6),
+ DEF_MOD("i2c5", 919, R8A77965_CLK_S0D6),
+ DEF_MOD("adg", 922, R8A77965_CLK_S0D1),
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch
new file mode 100644
index 00000000..dcf9de27
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch
@@ -0,0 +1,30 @@
+From 08560a298e3528a510e37f02553d4096445bfc3b Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 02:28:48 +0300
+Subject: [PATCH 04/12] clk: renesas: rcar-gen3-cpg: Allow to set RPCD2 clock
+ parent's rate
+
+This makes RPC clocks adjustable by allowing
+the RPCD2 clock parent's rate changes.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/clk/renesas/rcar-gen3-cpg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
+index 5993dbd..9333d34 100644
+--- a/drivers/clk/renesas/rcar-gen3-cpg.c
++++ b/drivers/clk/renesas/rcar-gen3-cpg.c
+@@ -814,7 +814,7 @@ static struct clk * __init cpg_rpcd2_clk_register(const char *name,
+
+ clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
+ &rpcd2->fixed.hw, &clk_fixed_factor_ops,
+- &rpcd2->gate.hw, &clk_gate_ops, 0);
++ &rpcd2->gate.hw, &clk_gate_ops, CLK_SET_RATE_PARENT);
+ if (IS_ERR(clk))
+ kfree(rpcd2);
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch
new file mode 100644
index 00000000..0b27c085
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0439-mtd-Consolidate-Renesas-RPC-drivers.patch
@@ -0,0 +1,4450 @@
+From 596c2def7a2037f33973c6a064ed54d465a157f0 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:01:19 +0300
+Subject: [PATCH 05/12] mtd: Consolidate Renesas RPC drivers
+
+This consolidates RPC HyperFlash and SPI NOR drivers.
+Flash device detection, and DMA read operation is done
+by the renesas-rpc driver. The operation mode is selected
+based on the child flash device node. If it's "jedec,spi-nor"
+compatible, the "renesas-rpc-qspi" platform device is created.
+If it's "cfi-flash" compatible, the "renesas-rpc-hyperflash"
+device is created instead.
+
+The RPC device compatibility string is adjusted to match U-Boot.
+The following configuration options are available:
+
+ CONFIG_MTD_RENESAS_RPC: enables generic RPC support;
+ CONFIG_MTD_RENESAS_RPC_QSPI: enables SPI NOR support;
+ CONFIG_MTD_RENESAS_RPC_HYPERFLASH: enables HyperFlash support.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/mtd/Kconfig | 6 -
+ drivers/mtd/Makefile | 1 -
+ drivers/mtd/rpc_hyperflash.c | 976 ------------------
+ drivers/mtd/spi-nor/Kconfig | 22 +-
+ drivers/mtd/spi-nor/Makefile | 4 +-
+ drivers/mtd/spi-nor/renesas-rpc-hyperflash.c | 742 ++++++++++++++
+ drivers/mtd/spi-nor/renesas-rpc-qspi.c | 794 +++++++++++++++
+ drivers/mtd/spi-nor/renesas-rpc.c | 1356 ++++----------------------
+ drivers/mtd/spi-nor/renesas-rpc.h | 267 +++++
+ 9 files changed, 1991 insertions(+), 2177 deletions(-)
+ delete mode 100644 drivers/mtd/rpc_hyperflash.c
+ create mode 100644 drivers/mtd/spi-nor/renesas-rpc-hyperflash.c
+ create mode 100644 drivers/mtd/spi-nor/renesas-rpc-qspi.c
+ create mode 100644 drivers/mtd/spi-nor/renesas-rpc.h
+
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 0619e1f..89925b5 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -11,12 +11,6 @@ menuconfig MTD
+ particular hardware and users of MTD devices. If unsure, say N.
+
+ if MTD
+-config MTD_RPC_HYPERFLASH
+- tristate "MTD Renesas R-Car Gen3 RPC HyperFlash"
+- depends on ARCH_R8A7795
+- ---help---
+- This option includes Renesas R-Car Gen3 RPC HyperFlash support.
+-
+ config MTD_TESTS
+ tristate "MTD tests support (DANGEROUS)"
+ depends on m
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index f3fb2b0..d6f8f62 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
+ obj-y += parsers/
+-obj-$(CONFIG_MTD_RPC_HYPERFLASH) += rpc_hyperflash.o
+
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
+diff --git a/drivers/mtd/rpc_hyperflash.c b/drivers/mtd/rpc_hyperflash.c
+deleted file mode 100644
+index cf4d56e..0000000
+--- a/drivers/mtd/rpc_hyperflash.c
++++ /dev/null
+@@ -1,976 +0,0 @@
+-/*
+- * Linux driver for R-Car Gen3 RPC HyperFlash
+- *
+- * Copyright (C) 2016 Renesas Electronics Corporation
+- * Copyright (C) 2016 Cogent Embedded, Inc.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/io.h>
+-#include <linux/module.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/partitions.h>
+-#include <linux/of.h>
+-#include <linux/rwsem.h>
+-#include <linux/slab.h>
+-
+-/* RPC */
+-#define RPC_BASE 0xEE200000
+-#define RPC_SIZE 0x8100
+-#define RPC_FLASH_BASE 0x08000000
+-#define RPC_FLASH_SIZE 0x04000000
+-
+-#define RPC_CMNCR 0x0000 /* R/W */
+-#define RPC_CMNCR_MD (0x1 << 31)
+-#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
+-#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
+-#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
+-#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
+-#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
+- RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
+-#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
+-#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
+-#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
+-#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
+- RPC_CMNCR_IO3FV(3))
+-#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
+-
+-#define RPC_SSLDR 0x0004 /* R/W */
+-#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
+-#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
+-#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
+-
+-#define RPC_DRCR 0x000C /* R/W */
+-#define RPC_DRCR_SSLN (0x1 << 24)
+-#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
+-#define RPC_DRCR_RCF (0x1 << 9)
+-#define RPC_DRCR_RBE (0x1 << 8)
+-#define RPC_DRCR_SSLE (0x1 << 0)
+-
+-#define RPC_DRCMR 0x0010 /* R/W */
+-#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
+-#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
+-
+-#define RPC_DREAR 0x0014 /* R/W */
+-#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
+-#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
+-
+-#define RPC_DROPR 0x0018 /* R/W */
+-#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
+-#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
+-#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
+-#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
+-
+-#define RPC_DRENR 0x001C /* R/W */
+-#define RPC_DRENR_CDB(o) (((o) & 0x3) << 30)
+-#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
+-#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
+-#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
+-#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
+-#define RPC_DRENR_DME (0x1 << 15)
+-#define RPC_DRENR_CDE (0x1 << 14)
+-#define RPC_DRENR_OCDE (0x1 << 12)
+-#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
+-#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
+-
+-#define RPC_SMCR 0x0020 /* R/W */
+-#define RPC_SMCR_SSLKP (0x1 << 8)
+-#define RPC_SMCR_SPIRE (0x1 << 2)
+-#define RPC_SMCR_SPIWE (0x1 << 1)
+-#define RPC_SMCR_SPIE (0x1 << 0)
+-
+-#define RPC_SMCMR 0x0024 /* R/W */
+-#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
+-#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
+-
+-#define RPC_SMADR 0x0028 /* R/W */
+-#define RPC_SMOPR 0x002C /* R/W */
+-#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
+-#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
+-#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
+-#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
+-
+-#define RPC_SMENR 0x0030 /* R/W */
+-#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
+-#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
+-#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
+-#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
+-#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
+-#define RPC_SMENR_DME (0x1 << 15)
+-#define RPC_SMENR_CDE (0x1 << 14)
+-#define RPC_SMENR_OCDE (0x1 << 12)
+-#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
+-#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
+-#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
+-
+-#define RPC_SMRDR0 0x0038 /* R */
+-#define RPC_SMRDR1 0x003C /* R */
+-#define RPC_SMWDR0 0x0040 /* R/W */
+-#define RPC_SMWDR1 0x0044 /* R/W */
+-#define RPC_CMNSR 0x0048 /* R */
+-#define RPC_CMNSR_SSLF (0x1 << 1)
+-#define RPC_CMNSR_TEND (0x1 << 0)
+-
+-#define RPC_DRDMCR 0x0058 /* R/W */
+-#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
+-
+-#define RPC_DRDRENR 0x005C /* R/W */
+-#define RPC_DRDRENR_HYPE (0x5 << 12)
+-#define RPC_DRDRENR_ADDRE (0x1 << 0x8)
+-#define RPC_DRDRENR_OPDRE (0x1 << 0x4)
+-#define RPC_DRDRENR_DRDRE (0x1 << 0x0)
+-
+-#define RPC_SMDMCR 0x0060 /* R/W */
+-#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
+-
+-#define RPC_SMDRENR 0x0064 /* R/W */
+-#define RPC_SMDRENR_HYPE (0x5 << 12)
+-#define RPC_SMDRENR_ADDRE (0x1 << 0x8)
+-#define RPC_SMDRENR_OPDRE (0x1 << 0x4)
+-#define RPC_SMDRENR_SPIDRE (0x1 << 0x0)
+-
+-#define RPC_PHYCNT 0x007C /* R/W */
+-#define RPC_PHYCNT_CAL (0x1 << 31)
+-#define PRC_PHYCNT_OCTA_AA (0x1 << 22)
+-#define PRC_PHYCNT_OCTA_SA (0x2 << 22)
+-#define PRC_PHYCNT_EXDS (0x1 << 21)
+-#define RPC_PHYCNT_OCT (0x1 << 20)
+-#define RPC_PHYCNT_WBUF2 (0x1 << 4)
+-#define RPC_PHYCNT_WBUF (0x1 << 2)
+-#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
+-
+-#define RPC_PHYINT 0x0088 /* R/W */
+-#define RPC_PHYINT_RSTEN (0x1 << 18)
+-#define RPC_PHYINT_WPEN (0x1 << 17)
+-#define RPC_PHYINT_INTEN (0x1 << 16)
+-#define RPC_PHYINT_RST (0x1 << 2)
+-#define RPC_PHYINT_WP (0x1 << 1)
+-#define RPC_PHYINT_INT (0x1 << 0)
+-
+-#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
+-#define RPC_WBUF_SIZE 0x100
+-
+-struct rpc_info {
+- struct rw_semaphore lock;
+- void __iomem *rpc_base;
+- void __iomem *flash_base;
+- struct resource *rpc_res;
+- struct resource *flash_res;
+- u32 flash_id;
+- struct mtd_info mtd;
+-};
+-
+-static inline void __iomem *rpc_addr(struct rpc_info *info, u32 offset)
+-{
+- return info->rpc_base + offset;
+-}
+-
+-static inline u32 rpc_readl(struct rpc_info *info, u32 offset)
+-{
+- u32 val;
+-
+- val = readl(rpc_addr(info, offset));
+- return val;
+-}
+-
+-static inline void rpc_writel(struct rpc_info *info, u32 offset, u32 val)
+-{
+- writel(val, rpc_addr(info, offset));
+-}
+-
+-static inline void rpc_setl(struct rpc_info *info, u32 offset, u32 mask, u32 set)
+-{
+- void __iomem *addr;
+- u32 val;
+-
+- addr = rpc_addr(info, offset);
+- val = readl(addr);
+- val &= mask;
+- val |= set;
+- writel(val, addr);
+-}
+-
+-static void rpc_wait_tend(struct rpc_info *info)
+-{
+- while (!(rpc_readl(info, RPC_CMNSR) & RPC_CMNSR_TEND))
+- cpu_relax();
+-}
+-
+-/* RPC HyperFlash */
+-#define RPC_HF_CMD_CA47 (0x1 << 7) /* Read */
+-#define RPC_HF_CMD_CA46 (0x1 << 6) /* Register space */
+-#define RPC_HF_CMD_CA45 (0x1 << 5) /* Liner burst */
+-
+-#define RPC_HF_CMD_READ_REG (RPC_HF_CMD_CA47 | RPC_HF_CMD_CA46)
+-#define RPC_HF_CMD_READ_MEM RPC_HF_CMD_CA47
+-#define RPC_HF_CMD_WRITE_REG RPC_HF_CMD_CA46
+-#define RPC_HF_CMD_WRITE_MEM 0x0
+-
+-#define RPC_HF_ERASE_SIZE 0x40000
+-
+-#define RPC_CFI_STATUS_DRB (0x1 << 7)
+-#define RPC_CFI_STATUS_ESSB (0x1 << 6)
+-#define RPC_CFI_STATUS_ESB (0x1 << 5)
+-#define RPC_CFI_STATUS_PSB (0x1 << 4)
+-#define RPC_CFI_STATUS_WBASB (0x1 << 3)
+-#define RPC_CFI_STATUS_PSSB (0x1 << 2)
+-#define RPC_CFI_STATUS_SLSB (0x1 << 1)
+-#define RPC_CFI_STATUS_ESTAT (0x1 << 0)
+-
+-#define RPC_CFI_UNLOCK1 (0x555 << 1)
+-#define RPC_CFI_UNLOCK2 (0x2AA << 1)
+-
+-#define RPC_CFI_CMD_UNLOCK_START 0xAA
+-#define RPC_CFI_CMD_UNLOCK_ACK 0x55
+-#define RPC_CFI_CMD_RESET 0xF0
+-#define RPC_CFI_CMD_READ_STATUS 0x70
+-#define RPC_CFI_CMD_READ_ID 0x90
+-#define RPC_CFI_CMD_WRITE 0xA0
+-#define RPC_CFI_CMD_ERASE_START 0x80
+-#define RPC_CFI_CMD_ERASE_SECTOR 0x30
+-
+-#define RPC_CFI_ID_MASK 0x000F
+-#define RPC_CFI_ID_MAN_SPANSION 0x0001
+-#define RPC_CFI_ID_TYPE_HYPERFLASH 0x000E
+-
+-enum rpc_hf_size {
+- RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8),
+- RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC),
+- RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
+-};
+-
+-struct rpc_info *rpc_info;
+-
+-static void rpc_hf_mode_man(struct rpc_info *info)
+-{
+- rpc_wait_tend(info);
+-
+- /*
+- * RPC_PHYCNT = 0x80000263
+- * bit31 CAL = 1 : PHY calibration
+- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
+- */
+- rpc_setl(info, RPC_PHYCNT,
+- ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)),
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+-
+- /*
+- * RPC_CMNCR = 0x81FFF301
+- * bit31 MD = 1 : Manual mode
+- * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash
+- */
+- rpc_setl(info, RPC_CMNCR,
+- ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)),
+- RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+- RPC_CMNCR_MD | RPC_CMNCR_BSZ(1));
+-}
+-
+-static void rpc_hf_mode_ext(struct rpc_info *info)
+-{
+- rpc_wait_tend(info);
+-
+- /*
+- * RPC_PHYCNT = 0x80000263
+- * bit31 CAL = 1 : PHY calibration
+- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
+- */
+- rpc_setl(info, RPC_PHYCNT,
+- ~(RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)),
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+-
+- /*
+- * RPC_CMNCR = 0x81FFF301
+- * bit31 MD = 1 : Manual mode
+- * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash
+- */
+- rpc_setl(info, RPC_CMNCR,
+- ~(RPC_CMNCR_MD | RPC_CMNCR_BSZ(3)),
+- RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
+- RPC_CMNCR_BSZ(1));
+-
+- /*
+- * RPC_DRCR = 0x001F0100
+- * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units
+- * bit9 RCF = 1 : Clear cache
+- * bit8 RBE = 1 : Read burst enable
+- */
+- rpc_writel(info, RPC_DRCR,
+- RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE);
+-
+- rpc_writel(info, RPC_DRCMR, RPC_DRCMR_CMD(0xA0));
+- rpc_writel(info, RPC_DRENR,
+- RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) |
+- RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) |
+- RPC_DRENR_CDE | RPC_DRENR_OCDE | RPC_DRENR_ADE(4));
+- rpc_writel(info, RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE));
+- rpc_writel(info, RPC_DRDRENR,
+- RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE);
+-
+- /* Dummy read */
+- rpc_readl(info, RPC_DRCR);
+-}
+-
+-static void rpc_hf_xfer(struct rpc_info *info, u32 addr, u16 *data,
+- enum rpc_hf_size size, u8 cmd)
+-{
+- u32 val;
+-
+- rpc_hf_mode_man(info);
+-
+- /*
+- * bit23-21 CMD[7:5] : CA47-45
+- * CA47 = 0/1 : Write/Read
+- * CA46 = 0/1 : Memory Space/Register Space
+- * CA45 = 0/1 : Wrapped Burst/Linear Burst
+- */
+- rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(cmd));
+-
+- rpc_writel(info, RPC_SMADR, addr >> 1);
+-
+- rpc_writel(info, RPC_SMOPR, 0x0);
+-
+- /*
+- * RPC_SMDRENR = 0x00005101
+- * bit14-12 HYPE = 101: Hyperflash mode
+- * bit8 ADDRE = 1 : Address DDR transfer
+- * bit0 SPIDRE = 1 : DATA DDR transfer
+- */
+- rpc_writel(info, RPC_SMDRENR,
+- RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE);
+-
+- val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
+- RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
+- RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
+-
+- if (cmd & RPC_HF_CMD_CA47)
+- goto read_transfer;
+-
+- /*
+- * RPC_SMENR = 0xA222540x
+- * bit31-30 CDB[1:0] = 10 : 4bit width command
+- * bit25-24 ADB[1:0] = 10 : 4bit width address
+- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
+- * bit15 DME = 0 : dummy cycle disable
+- * bit14 CDE = 1 : Command enable
+- * bit12 OCDE = 1 : Option Command enable
+- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output
+- * bit7-4 OPDE[3:0] = 0000 : Option data disable
+- * bit3-0 SPIDE[3:0] = xxxx : Transfer size
+- */
+- rpc_writel(info, RPC_SMENR, val);
+-
+- switch (size) {
+- case RPC_HF_SIZE_64BIT:
+- val = cmd & RPC_HF_CMD_CA46 ?
+- cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 :
+- data[0] | data[1] << 16;
+- rpc_writel(info, RPC_SMWDR1, val);
+- val = cmd & RPC_HF_CMD_CA46 ?
+- cpu_to_be16(data[2]) | cpu_to_be16(data[3]) << 16 :
+- data[2] | data[3] << 16;
+- break;
+- case RPC_HF_SIZE_32BIT:
+- val = cmd & RPC_HF_CMD_CA46 ?
+- cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 :
+- data[0] | data[1] << 16;
+- break;
+- default:
+- val = cmd & RPC_HF_CMD_CA46 ?
+- cpu_to_be16(data[0]) << 16 :
+- data[0] << 16;
+- break;
+- }
+-
+- rpc_writel(info, RPC_SMWDR0, val);
+- /*
+- * RPC_SMCR = 0x00000003
+- * bit1 SPIWE = 1 : Data write enable
+- * bit0 SPIE = 1 : SPI transfer start
+- */
+- rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
+- return;
+-
+-read_transfer:
+- rpc_writel(info, RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE));
+- val |= RPC_SMENR_DME;
+-
+- /*
+- * RPC_SMENR = 0xA222D40x
+- * bit31-30 CDB[1:0] = 10 : 4bit width command
+- * bit25-24 ADB[1:0] = 10 : 4bit width address
+- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
+- * bit15 DME = 1 : dummy cycle disable
+- * bit14 CDE = 1 : Command enable
+- * bit12 OCDE = 1 : Option Command enable
+- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address)
+- * bit7-4 OPDE[3:0] = 0000 : Option data disable
+- * bit3-0 SPIDE[3:0] = xxxx : Transfer size
+- */
+- rpc_writel(info, RPC_SMENR, val);
+-
+- /*
+- * RPC_SMCR = 0x00000005
+- * bit2 SPIRE = 1 : Data read disable
+- * bit0 SPIE = 1 : SPI transfer start
+- */
+- rpc_writel(info, RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE);
+-
+- rpc_wait_tend(info);
+- val = rpc_readl(info, RPC_SMRDR0);
+-
+- /*
+- * Read data from either register or memory space.
+- * Register space is always big-endian.
+- */
+- switch (size) {
+- case RPC_HF_SIZE_64BIT:
+- if (cmd & RPC_HF_CMD_CA46) {
+- data[3] = be16_to_cpu((val >> 16) & 0xFFFF);
+- data[2] = be16_to_cpu(val & 0xFFFF);
+- } else {
+- data[3] = (val >> 16) & 0xFFFF;
+- data[2] = val & 0xFFFF;
+- }
+- val = rpc_readl(info, RPC_SMRDR1);
+- if (cmd & RPC_HF_CMD_CA46) {
+- data[1] = be16_to_cpu((val >> 16) & 0xFFFF);
+- data[0] = be16_to_cpu(val & 0xFFFF);
+- } else {
+- data[1] = (val >> 16) & 0xFFFF;
+- data[0] = val & 0xFFFF;
+- }
+- break;
+- case RPC_HF_SIZE_32BIT:
+- if (cmd & RPC_HF_CMD_CA46) {
+- data[1] = be16_to_cpu((val >> 16) & 0xFFFF);
+- data[0] = be16_to_cpu(val & 0xFFFF);
+- } else {
+- data[1] = (val >> 16) & 0xFFFF;
+- data[0] = val & 0xFFFF;
+- }
+- break;
+- default:
+- data[0] = cmd & RPC_HF_CMD_CA46 ?
+- be16_to_cpu((val >> 16) & 0xFFFF) :
+- (val >> 16) & 0xFFFF;
+- break;
+- }
+-}
+-
+-static void rpc_hf_wbuf_enable(struct rpc_info *info)
+-{
+- rpc_wait_tend(info);
+-
+- /*
+- * RPC_PHYCNT = 0x80000277
+- * bit31 CAL = 1 : PHY calibration
+- * bit4 WBUF2 = 1 : Write buffer enable 2
+- * bit2 WBUF = 1 : Write buffer enable
+- * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
+- */
+- rpc_setl(info, RPC_PHYCNT,
+- ~(RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF |
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3)),
+- RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF |
+- RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
+-
+- /*
+- * RPC_DRCR = 0x001F0100
+- * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units
+- * bit9 RCF = 1 : Clear cache
+- * bit8 RBE = 1 : Read burst enable
+- */
+- rpc_writel(info, RPC_DRCR,
+- RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE);
+-
+- rpc_writel(info, RPC_SMCMR, RPC_SMCMR_CMD(RPC_HF_CMD_WRITE_MEM));
+-
+- rpc_writel(info, RPC_SMOPR, 0x0);
+-
+- /*
+- * RPC_SMDRENR = 0x00005101
+- * bit14-12 HYPE = 101:Hyperflash mode
+- * bit8 ADDRE = 1 : Address DDR transfer
+- * bit0 SPIDRE = 1 : DATA DDR transfer
+- */
+- rpc_writel(info, RPC_SMDRENR,
+- RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE);
+-
+- /*
+- * RPC_SMENR = 0xA222540F
+- * bit31-30 CDB[1:0] = 10 : 4bit width command
+- * bit25-24 ADB[1:0] = 10 : 4bit width address
+- * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
+- * bit15 DME = 0 : dummy cycle disable
+- * bit14 CDE = 1 : Command enable
+- * bit12 OCDE = 1 : Option Command enable
+- * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address)
+- * bit7-4 OPDE[3:0] = 0000 : Option data disable
+- * bit3-0 SPIDE[3:0] = 1111 : 64-bit transfer size
+- */
+- rpc_writel(info, RPC_SMENR,
+- RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
+- RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
+- RPC_SMENR_CDE | RPC_SMENR_OCDE |
+- RPC_SMENR_ADE(4) | RPC_HF_SIZE_64BIT);
+-
+- /* Dummy read */
+- rpc_readl(info, RPC_DRCR);
+-}
+-
+-static inline void rpc_hf_write_cmd(struct rpc_info *info, u32 addr, u16 cmd)
+-{
+- rpc_hf_xfer(info, addr, &cmd, RPC_HF_SIZE_16BIT, RPC_HF_CMD_WRITE_REG);
+-}
+-
+-static inline void rpc_hf_read_reg(struct rpc_info *info, u32 addr, u16 *data,
+- enum rpc_hf_size size)
+-{
+- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_REG);
+-}
+-
+-static inline void rpc_hf_write_reg(struct rpc_info *info, u32 addr, u16 *data,
+- enum rpc_hf_size size)
+-{
+- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_REG);
+-}
+-
+-static inline void rpc_hf_read_mem(struct rpc_info *info, u32 addr, u16 *data,
+- enum rpc_hf_size size)
+-{
+- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_READ_MEM);
+-}
+-
+-static inline void rpc_hf_write_mem(struct rpc_info *info, u32 addr, u16 *data,
+- enum rpc_hf_size size)
+-{
+- rpc_hf_xfer(info, addr, data, size, RPC_HF_CMD_WRITE_MEM);
+-}
+-
+-static void rpc_hf_wp(struct rpc_info *info, int enable)
+-{
+- rpc_setl(info, RPC_PHYINT, ~RPC_PHYINT_WP, enable ? RPC_PHYINT_WP : 0);
+-}
+-
+-static void rpc_hf_unlock(struct rpc_info *info, u32 addr)
+-{
+- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1,
+- RPC_CFI_CMD_UNLOCK_START);
+- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK2,
+- RPC_CFI_CMD_UNLOCK_ACK);
+-}
+-
+-static inline int rpc_hf_status(struct rpc_info *info, u32 addr,
+- int iterations, int delay)
+-{
+- int retval;
+- u16 status = 0;
+-
+- while (iterations-- > 0) {
+- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_STATUS);
+- rpc_hf_read_reg(info, addr, &status, RPC_HF_SIZE_16BIT);
+-
+- if (status & RPC_CFI_STATUS_DRB)
+- break;
+-
+- if (delay < 10000)
+- usleep_range(delay, delay * 2);
+- else
+- msleep(delay / 1000);
+- }
+-
+- if (!(status & RPC_CFI_STATUS_DRB)) {
+- retval = -ETIMEDOUT;
+- goto out;
+- }
+-
+- if (status & (RPC_CFI_STATUS_PSB | RPC_CFI_STATUS_ESB)) {
+- retval = -EIO;
+- goto out;
+- }
+-
+- return 0;
+-
+-out:
+- /* Reset the flash */
+- rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET);
+- return retval;
+-}
+-
+-static int rpc_hf_sector_erase(struct rpc_info *info, u32 addr)
+-{
+- rpc_hf_unlock(info, addr);
+- rpc_hf_write_cmd(info, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_ERASE_START);
+- rpc_hf_unlock(info, addr);
+- rpc_hf_write_cmd(info, addr, RPC_CFI_CMD_ERASE_SECTOR);
+-
+- return rpc_hf_status(info, addr, 1000, 10000);
+-}
+-
+-/* Flash read */
+-static int rpc_hf_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+- size_t *retlen, u_char *buf)
+-{
+- struct rpc_info *info = mtd->priv;
+-
+- down_read(&info->lock);
+- memcpy_fromio(buf, info->flash_base + from, len);
+- up_read(&info->lock);
+-
+- *retlen = len;
+- return 0;
+-}
+-
+-/* Flash erase */
+-static int rpc_hf_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+-{
+- struct rpc_info *info = mtd->priv;
+- u32 addr, end;
+- int retval = 0;
+-
+- if (mtd_mod_by_eb(instr->addr, mtd)) {
+- pr_debug("%s: unaligned address\n", __func__);
+- return -EINVAL;
+- }
+-
+- if (mtd_mod_by_eb(instr->len, mtd)) {
+- pr_debug("%s: unaligned length\n", __func__);
+- return -EINVAL;
+- }
+-
+- end = instr->addr + instr->len;
+-
+- down_write(&info->lock);
+- for (addr = instr->addr; addr < end; addr += mtd->erasesize) {
+- retval = rpc_hf_sector_erase(info, addr);
+-
+- if (retval)
+- break;
+- }
+-
+- rpc_hf_mode_ext(info);
+- up_write(&info->lock);
+-
+- instr->state = retval ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+- mtd_erase_callback(instr);
+-
+- return retval;
+-}
+-
+-/* Copy memory to flash */
+-static int rpc_hf_mtd_write(struct mtd_info *mtd, loff_t offset, size_t len,
+- size_t *retlen, const u_char *src)
+-{
+- struct rpc_info *info = mtd->priv;
+- union {
+- u8 b[4];
+- u16 w[2];
+- u32 d;
+- } data;
+- loff_t addr;
+- size_t size, cnt;
+- int retval, idx;
+- u8 last;
+-
+- retval = 0;
+- *retlen = 0;
+- cnt = len;
+- idx = 0;
+-
+- down_write(&info->lock);
+-
+- /* Handle unaligned start */
+- if (offset & 0x1) {
+- offset--;
+- data.b[idx] = readb(info->flash_base + offset);
+- idx++;
+- }
+-
+- /* Handle unaligned end */
+- addr = offset + idx + len;
+- last = addr & 0x1 ? readb(info->flash_base + addr) : 0xFF;
+-
+- addr = offset - mtd_mod_by_eb(offset, mtd);
+- size = mtd->erasesize - (offset - addr);
+-
+- while (cnt) {
+- if (size > cnt)
+- size = cnt;
+-
+- cnt -= size;
+- while (size) {
+- rpc_hf_unlock(info, addr);
+- rpc_hf_write_cmd(info,
+- addr + RPC_CFI_UNLOCK1,
+- RPC_CFI_CMD_WRITE);
+-
+- if (size > 0x7) {
+- u32 wbuf = RPC_WBUF;
+- int block = size >= RPC_WBUF_SIZE ?
+- RPC_WBUF_SIZE : size & ~0x7;
+-
+- rpc_hf_wbuf_enable(info);
+-
+- rpc_writel(info, RPC_SMADR, offset >> 1);
+- offset += block;
+-
+- block >>= 3;
+- while (block--) {
+- while (idx < 4) {
+- data.b[idx++] = *src++;
+- size--;
+- }
+- rpc_writel(info, wbuf, data.d);
+- wbuf += 4;
+-
+- idx = 0;
+- while (idx < 4) {
+- data.b[idx++] = *src++;
+- size--;
+- }
+- rpc_writel(info, wbuf, data.d);
+- wbuf += 4;
+-
+- idx = 0;
+- }
+-
+- rpc_writel(info, RPC_SMCR,
+- RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
+- } else {
+- enum rpc_hf_size bits;
+-
+- while (idx < 4) {
+- data.b[idx++] = *src++;
+- size--;
+-
+- if (!size)
+- break;
+- }
+-
+- if (idx & 0x1)
+- data.b[idx++] = last;
+-
+- switch (idx) {
+- case 2:
+- bits = RPC_HF_SIZE_16BIT;
+- break;
+- default:
+- bits = RPC_HF_SIZE_32BIT;
+- break;
+- }
+-
+- rpc_hf_write_mem(info, offset, data.w, bits);
+- offset += idx;
+- idx = 0;
+- }
+-
+- retval = rpc_hf_status(info, addr, 1000000, 10);
+- if (retval)
+- goto out;
+- }
+-
+- size = mtd->erasesize;
+- addr += size;
+- offset = addr;
+- *retlen = len - cnt;
+- }
+-
+-out:
+- rpc_hf_mode_ext(info);
+- up_write(&info->lock);
+- return retval;
+-}
+-
+-static struct mtd_partition partition_info[]={
+- {
+- .name = "bootparam",
+- .offset = 0,
+- .size = 0x40000,
+- }, {
+- .name = "bl2",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x140000
+- }, {
+- .name = "cert_header",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x40000,
+- }, {
+- .name = "bl31",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x40000,
+- }, {
+- .name = "optee",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x440000,
+- }, {
+- .name = "u-boot",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x80000,
+- }, {
+- .name = "reserved",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x80000,
+- }, {
+- .name = "u-boot-env",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x40000,
+- }, {
+- .name = "dtb",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x80000,
+- }, {
+- .name = "kernel",
+- .offset = MTDPART_OFS_APPEND,
+- .size = 0x1000000,
+- }, {
+- .name = "user",
+- .offset = MTDPART_OFS_APPEND,
+- .size = MTDPART_SIZ_FULL,
+- },
+-};
+-
+-static int rpc_hf_init_mtd(struct rpc_info *info)
+-{
+- struct mtd_info *mtd = &info->mtd;
+- u16 data[2] = { 0, 0 };
+- u32 id, size;
+- int retval;
+-
+- rpc_hf_mode_ext(info);
+-
+- rpc_hf_wp(info, 0);
+-
+- rpc_hf_unlock(info, 0);
+- rpc_hf_write_cmd(info, RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_ID);
+-
+- rpc_hf_read_reg(info, 0x0, data, RPC_HF_SIZE_32BIT);
+- if ((data[0] & RPC_CFI_ID_MASK) != RPC_CFI_ID_MAN_SPANSION ||
+- (data[1] & RPC_CFI_ID_MASK) != RPC_CFI_ID_TYPE_HYPERFLASH) {
+- retval = -ENODEV;
+- goto out;
+- }
+-
+- id = data[0] | data[1] << 16;
+-
+- rpc_hf_read_reg(info, 0x27 << 1, data, RPC_HF_SIZE_16BIT);
+- size = 1 << data[0];
+-
+- if (size > resource_size(info->flash_res))
+- size = resource_size(info->flash_res);
+-
+- if (size & (RPC_HF_ERASE_SIZE - 1)) {
+- retval = -EINVAL;
+- goto out;
+- }
+-
+- init_rwsem(&info->lock);
+- info->flash_id = id;
+- mtd->name = "HyperFlash";
+- mtd->type = MTD_NORFLASH;
+- mtd->flags = MTD_CAP_NORFLASH;
+- mtd->size = size;
+- mtd->writesize = 1;
+- mtd->writebufsize = RPC_WBUF_SIZE;
+- mtd->erasesize = RPC_HF_ERASE_SIZE;
+- mtd->owner = THIS_MODULE;
+- mtd->priv = info;
+- mtd->_erase = rpc_hf_mtd_erase;
+- mtd->_write = rpc_hf_mtd_write;
+- mtd->_read = rpc_hf_mtd_read;
+- retval = mtd_device_register(mtd, partition_info,
+- ARRAY_SIZE(partition_info));
+-out:
+- rpc_hf_write_cmd(info, 0, RPC_CFI_CMD_RESET);
+- rpc_hf_mode_ext(info);
+- return retval;
+-}
+-
+-static int rpc_flash_init(void)
+-{
+- struct rpc_info *info;
+- struct resource *res;
+- void __iomem *base;
+- int retval = -ENODEV;
+-
+- if (!of_machine_is_compatible("renesas,r8a7795"))
+- return -ENODEV;
+-
+- info = kzalloc(sizeof(*info), GFP_KERNEL);
+- if (!info)
+- return -ENOMEM;
+-
+- res = request_mem_region(RPC_BASE, RPC_SIZE, "RPC");
+- if (!res)
+- goto out_info;
+-
+- info->rpc_res = res;
+- base = ioremap(res->start, resource_size(res));
+- if (!base)
+- goto out_rpc_res;
+-
+- info->rpc_base = base;
+- res = request_mem_region(RPC_FLASH_BASE, RPC_FLASH_SIZE, "RPC-ext");
+- if (!res)
+- goto out_rpc_base;
+-
+- info->flash_res = res;
+- base = ioremap(res->start, resource_size(res));
+- if (!base)
+- goto out_flash_res;
+-
+- info->flash_base = base;
+- retval = rpc_hf_init_mtd(info);
+- if (retval)
+- goto out_flash_base;
+-
+- pr_info("HyperFlash Id: %x\n", info->flash_id);
+-
+- rpc_info = info;
+- return 0;
+-
+-out_flash_base:
+- iounmap(info->flash_base);
+-out_flash_res:
+- release_mem_region(info->flash_res->start,
+- resource_size(info->flash_res));
+-out_rpc_base:
+- iounmap(info->rpc_base);
+-out_rpc_res:
+- release_mem_region(info->rpc_res->start,
+- resource_size(info->rpc_res));
+-out_info:
+- kfree(info);
+- return retval;
+-}
+-
+-static void rpc_flash_exit(void)
+-{
+- struct rpc_info *info = rpc_info;
+-
+- if (!info)
+- return;
+-
+- rpc_info = NULL;
+-
+- mtd_device_unregister(&info->mtd);
+-
+- iounmap(info->flash_base);
+- release_mem_region(info->flash_res->start,
+- resource_size(info->flash_res));
+- iounmap(info->rpc_base);
+- release_mem_region(info->rpc_res->start,
+- resource_size(info->rpc_res));
+- kfree(info);
+-}
+-
+-module_init(rpc_flash_init);
+-module_exit(rpc_flash_exit);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_DESCRIPTION("Renesas RPC HyperFlash MTD driver");
+diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
+index 2c73adb..bd316fd 100644
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -8,12 +8,26 @@ menuconfig MTD_SPI_NOR
+ if MTD_SPI_NOR
+
+
+-config SPI_RENESAS_RPC
++config MTD_RENESAS_RPC
+ tristate "Renesas RPC controller"
+- depends on ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77970 || ARCH_R8A77980 || COMPILE_TEST
++ depends on ARCH_RENESAS || COMPILE_TEST
+ help
+- QSPI driver for Renesas SPI Multi I/O Bus controller. This controller
+- supports normal, dual and quad spi for one or two SPI NOR Flashes.
++ Renesas RPC interface driver. This controller support QSPI and HyperFlash
++ devices.
++
++config MTD_RENESAS_RPC_HYPERFLASH
++ tristate "Renesas RPC HyperFlash"
++ depends on ARCH_RENESAS || COMPILE_TEST
++ select MTD_RENESAS_RPC
++ help
++ HyperFlash driver for Renesas RPC Multi I/O Bus controller controller.
++
++config MTD_RENESAS_RPC_QSPI
++ tristate "Renesas RPC QSPI"
++ depends on ARCH_RENESAS || COMPILE_TEST
++ select MTD_RENESAS_RPC
++ help
++ QSPI driver for Renesas RPC Multi I/O Bus controller.
+
+ config MTD_MT81xx_NOR
+ tristate "Mediatek MT81xx SPI NOR flash controller"
+diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
+index 0c46c9c..a10c6ab 100644
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -7,8 +7,10 @@ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
+ obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
+ obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+-obj-$(CONFIG_SPI_RENESAS_RPC) += renesas-rpc.o
+ obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
+ obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o
+ obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
+ obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o
++obj-$(CONFIG_MTD_RENESAS_RPC) += renesas-rpc.o
++obj-$(CONFIG_MTD_RENESAS_RPC_QSPI) += renesas-rpc-qspi.o
++obj-$(CONFIG_MTD_RENESAS_RPC_HYPERFLASH) += renesas-rpc-hyperflash.o
+diff --git a/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c b/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c
+new file mode 100644
+index 0000000..aea42b6
+--- /dev/null
++++ b/drivers/mtd/spi-nor/renesas-rpc-hyperflash.c
+@@ -0,0 +1,742 @@
++/*
++ * Renesas RPC driver
++ *
++ * Copyright (C) 2018, Cogent Embedded Inc.
++ *
++ * 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; version 2 of the License.
++ *
++ * 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.
++ */
++
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/mtd.h>
++
++#include "renesas-rpc.h"
++
++/* RPC HyperFlash */
++#define RPC_HF_CMD_CA47 (0x1 << 7) /* Read */
++#define RPC_HF_CMD_CA46 (0x1 << 6) /* Register space */
++#define RPC_HF_CMD_CA45 (0x1 << 5) /* Liner burst */
++
++#define RPC_HF_CMD_READ_REG (RPC_HF_CMD_CA47 | RPC_HF_CMD_CA46)
++#define RPC_HF_CMD_READ_MEM RPC_HF_CMD_CA47
++#define RPC_HF_CMD_WRITE_REG RPC_HF_CMD_CA46
++#define RPC_HF_CMD_WRITE_MEM 0x0
++
++#define RPC_HF_ERASE_SIZE 0x40000
++
++#define RPC_CFI_STATUS_DRB (0x1 << 7)
++#define RPC_CFI_STATUS_ESSB (0x1 << 6)
++#define RPC_CFI_STATUS_ESB (0x1 << 5)
++#define RPC_CFI_STATUS_PSB (0x1 << 4)
++#define RPC_CFI_STATUS_WBASB (0x1 << 3)
++#define RPC_CFI_STATUS_PSSB (0x1 << 2)
++#define RPC_CFI_STATUS_SLSB (0x1 << 1)
++#define RPC_CFI_STATUS_ESTAT (0x1 << 0)
++
++#define RPC_CFI_UNLOCK1 (0x555 << 1)
++#define RPC_CFI_UNLOCK2 (0x2AA << 1)
++
++#define RPC_CFI_CMD_UNLOCK_START 0xAA
++#define RPC_CFI_CMD_UNLOCK_ACK 0x55
++#define RPC_CFI_CMD_RESET 0xF0
++#define RPC_CFI_CMD_READ_STATUS 0x70
++#define RPC_CFI_CMD_READ_ID 0x90
++#define RPC_CFI_CMD_WRITE 0xA0
++#define RPC_CFI_CMD_ERASE_START 0x80
++#define RPC_CFI_CMD_ERASE_SECTOR 0x30
++
++#define RPC_CFI_ID_MASK 0x000F
++#define RPC_CFI_ID_MAN_SPANSION 0x0001
++#define RPC_CFI_ID_TYPE_HYPERFLASH 0x000E
++
++struct rpc_hf_info {
++ struct mtd_info mtd;
++ struct mutex lock;
++ void *priv;
++};
++
++static void rpc_hf_mode_man(struct rpc_info *rpc)
++{
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ /*
++ * RPC_PHYCNT = 0x80000263
++ * bit31 CAL = 1 : PHY calibration
++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
++ */
++ rpc_clrsetl(rpc, RPC_PHYCNT,
++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
++
++ /*
++ * RPC_CMNCR = 0x81FFF301
++ * bit31 MD = 1 : Manual mode
++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash
++ */
++ rpc_clrsetl(rpc, RPC_CMNCR,
++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(1));
++}
++
++static void rpc_hf_mode_ext(struct rpc_info *rpc)
++{
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ /*
++ * RPC_PHYCNT = 0x80000263
++ * bit31 CAL = 1 : PHY calibration
++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
++ */
++ rpc_clrsetl(rpc, RPC_PHYCNT,
++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
++
++ /*
++ * RPC_CMNCR = 0x81FFF301
++ * bit31 MD = 1 : Manual mode
++ * bit1-0 BSZ[1:0] = 01 : QSPI Flash x 2 or HyperFlash
++ */
++ rpc_clrsetl(rpc, RPC_CMNCR,
++ RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
++ RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
++ RPC_CMNCR_BSZ(1));
++
++ /*
++ * RPC_DRCR = 0x001F0100
++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units
++ * bit9 RCF = 1 : Clear cache
++ * bit8 RBE = 1 : Read burst enable
++ */
++ rpc_writel(rpc, RPC_DRCR,
++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE);
++
++ rpc_writel(rpc, RPC_DRCMR, RPC_DRCMR_CMD(0xA0));
++ rpc_writel(rpc, RPC_DRENR,
++ RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) |
++ RPC_DRENR_ADB(2) | RPC_DRENR_DRDB(2) |
++ RPC_DRENR_CDE | RPC_DRENR_OCDE |
++ RPC_DRENR_DME | RPC_DRENR_ADE(4));
++ rpc_writel(rpc, RPC_DRDMCR, RPC_DRDMCR_DMCYC(0xE));
++ rpc_writel(rpc, RPC_DRDRENR,
++ RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE | RPC_DRDRENR_DRDRE);
++
++ /* Dummy read */
++ rpc_readl(rpc, RPC_DRCR);
++}
++
++static void rpc_hf_xfer(struct rpc_info *rpc, u32 addr, u16 *data,
++ enum rpc_size size, u8 cmd)
++{
++ u32 val;
++
++ rpc_hf_mode_man(rpc);
++
++ /*
++ * bit23-21 CMD[7:5] : CA47-45
++ * CA47 = 0/1 : Write/Read
++ * CA46 = 0/1 : Memory Space/Register Space
++ * CA45 = 0/1 : Wrapped Burst/Linear Burst
++ */
++ rpc_writel(rpc, RPC_SMCMR, RPC_SMCMR_CMD(cmd));
++
++ rpc_writel(rpc, RPC_SMADR, addr >> 1);
++
++ rpc_writel(rpc, RPC_SMOPR, 0x0);
++
++ /*
++ * RPC_SMDRENR = 0x00005101
++ * bit14-12 HYPE = 101: Hyperflash mode
++ * bit8 ADDRE = 1 : Address DDR transfer
++ * bit0 SPIDRE = 1 : DATA DDR transfer
++ */
++ rpc_writel(rpc, RPC_SMDRENR,
++ RPC_SMDRENR_HYPE_HF | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE);
++
++ val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
++ RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
++
++ if (cmd & RPC_HF_CMD_CA47)
++ goto read_transfer;
++
++ /*
++ * RPC_SMENR = 0xA222540x
++ * bit31-30 CDB[1:0] = 10 : 4bit width command
++ * bit25-24 ADB[1:0] = 10 : 4bit width address
++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
++ * bit15 DME = 0 : dummy cycle disable
++ * bit14 CDE = 1 : Command enable
++ * bit12 OCDE = 1 : Option Command enable
++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output
++ * bit7-4 OPDE[3:0] = 0000 : Option data disable
++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size
++ */
++ rpc_writel(rpc, RPC_SMENR, val);
++
++ switch (size) {
++ case RPC_SIZE_DUAL_64BIT:
++ val = cmd & RPC_HF_CMD_CA46 ?
++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 :
++ data[0] | data[1] << 16;
++ rpc_writel(rpc, RPC_SMWDR1, val);
++ val = cmd & RPC_HF_CMD_CA46 ?
++ cpu_to_be16(data[2]) | cpu_to_be16(data[3]) << 16 :
++ data[2] | data[3] << 16;
++ break;
++ case RPC_SIZE_DUAL_32BIT:
++ val = cmd & RPC_HF_CMD_CA46 ?
++ cpu_to_be16(data[0]) | cpu_to_be16(data[1]) << 16 :
++ data[0] | data[1] << 16;
++ break;
++ default:
++ val = cmd & RPC_HF_CMD_CA46 ?
++ cpu_to_be16(data[0]) << 16 :
++ data[0] << 16;
++ break;
++ }
++
++ rpc_writel(rpc, RPC_SMWDR0, val);
++ /*
++ * RPC_SMCR = 0x00000003
++ * bit1 SPIWE = 1 : Data write enable
++ * bit0 SPIE = 1 : SPI transfer start
++ */
++ rpc_writel(rpc, RPC_SMCR, RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
++ return;
++
++read_transfer:
++ rpc_writel(rpc, RPC_SMDMCR, RPC_SMDMCR_DMCYC(0xE));
++ val |= RPC_SMENR_DME;
++
++ /*
++ * RPC_SMENR = 0xA222D40x
++ * bit31-30 CDB[1:0] = 10 : 4bit width command
++ * bit25-24 ADB[1:0] = 10 : 4bit width address
++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
++ * bit15 DME = 1 : dummy cycle disable
++ * bit14 CDE = 1 : Command enable
++ * bit12 OCDE = 1 : Option Command enable
++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address)
++ * bit7-4 OPDE[3:0] = 0000 : Option data disable
++ * bit3-0 SPIDE[3:0] = xxxx : Transfer size
++ */
++ rpc_writel(rpc, RPC_SMENR, val);
++
++ /*
++ * RPC_SMCR = 0x00000005
++ * bit2 SPIRE = 1 : Data read disable
++ * bit0 SPIE = 1 : SPI transfer start
++ */
++ rpc_writel(rpc, RPC_SMCR, RPC_SMCR_SPIRE | RPC_SMCR_SPIE);
++
++ rpc_wait(rpc, RPC_TIMEOUT);
++ val = rpc_readl(rpc, RPC_SMRDR0);
++
++ /*
++ * Read data from either register or memory space.
++ * Register space is always big-endian.
++ */
++ switch (size) {
++ case RPC_SIZE_DUAL_64BIT:
++ if (cmd & RPC_HF_CMD_CA46) {
++ data[3] = be16_to_cpu((val >> 16) & 0xFFFF);
++ data[2] = be16_to_cpu(val & 0xFFFF);
++ } else {
++ data[3] = (val >> 16) & 0xFFFF;
++ data[2] = val & 0xFFFF;
++ }
++ val = rpc_readl(rpc, RPC_SMRDR1);
++ if (cmd & RPC_HF_CMD_CA46) {
++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF);
++ data[0] = be16_to_cpu(val & 0xFFFF);
++ } else {
++ data[1] = (val >> 16) & 0xFFFF;
++ data[0] = val & 0xFFFF;
++ }
++ break;
++ case RPC_SIZE_DUAL_32BIT:
++ if (cmd & RPC_HF_CMD_CA46) {
++ data[1] = be16_to_cpu((val >> 16) & 0xFFFF);
++ data[0] = be16_to_cpu(val & 0xFFFF);
++ } else {
++ data[1] = (val >> 16) & 0xFFFF;
++ data[0] = val & 0xFFFF;
++ }
++ break;
++ default:
++ data[0] = cmd & RPC_HF_CMD_CA46 ?
++ be16_to_cpu((val >> 16) & 0xFFFF) :
++ (val >> 16) & 0xFFFF;
++ break;
++ }
++}
++
++static void rpc_hf_wbuf_enable(struct rpc_info *rpc, u32 addr)
++{
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ /*
++ * RPC_PHYCNT = 0x80000277
++ * bit31 CAL = 1 : PHY calibration
++ * bit4 WBUF2 = 1 : Write buffer enable 2
++ * bit2 WBUF = 1 : Write buffer enable
++ * bit1-0 PHYMEM[1:0] = 11 : HyperFlash
++ */
++ rpc_clrsetl(rpc, RPC_PHYCNT,
++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF |
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF |
++ RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
++
++ /*
++ * RPC_DRCR = 0x001F0100
++ * bit21-16 RBURST[4:0] = 11111 : Read burst 32 64-bit data units
++ * bit9 RCF = 1 : Clear cache
++ * bit8 RBE = 1 : Read burst enable
++ */
++ rpc_writel(rpc, RPC_DRCR,
++ RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF | RPC_DRCR_RBE);
++
++ rpc_writel(rpc, RPC_SMCMR, RPC_SMCMR_CMD(RPC_HF_CMD_WRITE_MEM));
++
++ rpc_writel(rpc, RPC_SMADR, addr >> 1);
++
++ rpc_writel(rpc, RPC_SMOPR, 0x0);
++
++ /*
++ * RPC_SMDRENR = 0x00005101
++ * bit14-12 HYPE = 101:Hyperflash mode
++ * bit8 ADDRE = 1 : Address DDR transfer
++ * bit0 SPIDRE = 1 : DATA DDR transfer
++ */
++ rpc_writel(rpc, RPC_SMDRENR,
++ RPC_SMDRENR_HYPE_HF | RPC_SMDRENR_ADDRE | RPC_SMDRENR_SPIDRE);
++
++ /*
++ * RPC_SMENR = 0xA222540F
++ * bit31-30 CDB[1:0] = 10 : 4bit width command
++ * bit25-24 ADB[1:0] = 10 : 4bit width address
++ * bit17-16 SPIDB[1:0] = 10 : 4bit width transfer data
++ * bit15 DME = 0 : dummy cycle disable
++ * bit14 CDE = 1 : Command enable
++ * bit12 OCDE = 1 : Option Command enable
++ * bit11-8 ADE[3:0] = 0100 : ADR[23:0] output (24 Bit Address)
++ * bit7-4 OPDE[3:0] = 0000 : Option data disable
++ * bit3-0 SPIDE[3:0] = 1111 : 64-bit transfer size
++ */
++ rpc_writel(rpc, RPC_SMENR,
++ RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
++ RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
++ RPC_SMENR_CDE | RPC_SMENR_OCDE |
++ RPC_SMENR_ADE(4) | RPC_SIZE_DUAL_64BIT);
++
++ /* Dummy read */
++ rpc_readl(rpc, RPC_DRCR);
++}
++
++static inline void rpc_hf_write_cmd(struct rpc_info *rpc, u32 addr, u16 cmd)
++{
++ rpc_hf_xfer(rpc, addr, &cmd, RPC_SIZE_DUAL_16BIT, RPC_HF_CMD_WRITE_REG);
++}
++
++static inline void rpc_hf_read_reg(struct rpc_info *rpc, u32 addr, u16 *data,
++ enum rpc_size size)
++{
++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_READ_REG);
++}
++
++static inline void rpc_hf_write_reg(struct rpc_info *rpc, u32 addr, u16 *data,
++ enum rpc_size size)
++{
++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_WRITE_REG);
++}
++
++static inline void rpc_hf_read_mem(struct rpc_info *rpc, u32 addr, u16 *data,
++ enum rpc_size size)
++{
++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_READ_MEM);
++}
++
++static inline void rpc_hf_write_mem(struct rpc_info *rpc, u32 addr, u16 *data,
++ enum rpc_size size)
++{
++ rpc_hf_xfer(rpc, addr, data, size, RPC_HF_CMD_WRITE_MEM);
++}
++
++static void rpc_hf_wp(struct rpc_info *rpc, int enable)
++{
++ rpc_clrsetl(rpc, RPC_PHYINT, RPC_PHYINT_WP, enable ? RPC_PHYINT_WP : 0);
++}
++
++static void rpc_hf_unlock(struct rpc_info *rpc, u32 addr)
++{
++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1,
++ RPC_CFI_CMD_UNLOCK_START);
++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK2,
++ RPC_CFI_CMD_UNLOCK_ACK);
++}
++
++static inline int rpc_hf_status(struct rpc_info *rpc, u32 addr,
++ int iterations, int delay)
++{
++ int ret;
++ u16 status = 0;
++
++ while (iterations-- > 0) {
++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1,
++ RPC_CFI_CMD_READ_STATUS);
++ rpc_hf_read_reg(rpc, addr, &status, RPC_SIZE_DUAL_16BIT);
++
++ if (status & RPC_CFI_STATUS_DRB)
++ break;
++
++ if (delay < 10000)
++ usleep_range(delay, delay * 2);
++ else
++ msleep(delay / 1000);
++ }
++
++ if (!(status & RPC_CFI_STATUS_DRB)) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ if (status & (RPC_CFI_STATUS_PSB | RPC_CFI_STATUS_ESB)) {
++ ret = -EIO;
++ goto out;
++ }
++
++ return 0;
++
++out:
++ /* Reset the flash */
++ rpc_hf_write_cmd(rpc, 0, RPC_CFI_CMD_RESET);
++ return ret;
++}
++
++static int rpc_hf_sector_erase(struct rpc_info *rpc, u32 addr)
++{
++ rpc_hf_unlock(rpc, addr);
++ rpc_hf_write_cmd(rpc, addr + RPC_CFI_UNLOCK1, RPC_CFI_CMD_ERASE_START);
++ rpc_hf_unlock(rpc, addr);
++ rpc_hf_write_cmd(rpc, addr, RPC_CFI_CMD_ERASE_SECTOR);
++
++ return rpc_hf_status(rpc, addr, 1000, 10000);
++}
++
++/* Flash read */
++static int rpc_hf_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
++ size_t *retlen, u_char *buf)
++{
++ struct rpc_hf_info *hf = mtd->priv;
++ struct rpc_info *rpc = hf->priv;
++
++ mutex_lock(&hf->lock);
++ rpc_do_read_flash(rpc, from, len, buf, mtd->size > RPC_READ_ADDR_SIZE);
++ mutex_unlock(&hf->lock);
++
++ *retlen = len;
++ return 0;
++}
++
++/* Flash erase */
++static int rpc_hf_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++ struct rpc_hf_info *hf = mtd->priv;
++ struct rpc_info *rpc = hf->priv;
++ u32 addr, end;
++ int ret = 0;
++
++ if (mtd_mod_by_eb(instr->addr, mtd)) {
++ dev_dbg(mtd->dev.parent, "%s: unaligned address\n", __func__);
++ return -EINVAL;
++ }
++
++ if (mtd_mod_by_eb(instr->len, mtd)) {
++ dev_dbg(mtd->dev.parent, "%s: unaligned length\n", __func__);
++ return -EINVAL;
++ }
++
++ end = instr->addr + instr->len;
++
++ mutex_lock(&hf->lock);
++ for (addr = instr->addr; addr < end; addr += mtd->erasesize) {
++ ret = rpc_hf_sector_erase(rpc, addr);
++
++ if (ret)
++ break;
++ }
++
++ rpc_hf_mode_ext(rpc);
++ mutex_unlock(&hf->lock);
++
++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
++ mtd_erase_callback(instr);
++
++ return ret;
++}
++
++/* Copy memory to flash */
++static int rpc_hf_mtd_write(struct mtd_info *mtd, loff_t offset, size_t len,
++ size_t *retlen, const u_char *src)
++{
++ struct rpc_hf_info *hf = mtd->priv;
++ struct rpc_info *rpc = hf->priv;
++ union {
++ u8 b[4];
++ u16 w[2];
++ u32 d;
++ } data;
++ loff_t addr;
++ size_t size, cnt;
++ int ret, idx;
++ u8 last;
++
++ ret = 0;
++ *retlen = 0;
++ cnt = len;
++ idx = 0;
++
++ mutex_lock(&hf->lock);
++
++ /* Handle unaligned start */
++ if (offset & 0x1) {
++ offset--;
++ data.b[idx] = readb(rpc->read_area + offset);
++ idx++;
++ }
++
++ /* Handle unaligned end */
++ addr = offset + idx + len;
++ last = addr & 0x1 ? readb(rpc->read_area + addr) : 0xFF;
++
++ addr = offset - mtd_mod_by_eb(offset, mtd);
++ size = mtd->erasesize - (offset - addr);
++
++ while (cnt) {
++ if (size > cnt)
++ size = cnt;
++
++ cnt -= size;
++ while (size) {
++ rpc_hf_unlock(rpc, addr);
++ rpc_hf_write_cmd(rpc,
++ addr + RPC_CFI_UNLOCK1,
++ RPC_CFI_CMD_WRITE);
++
++ if (rpc_wbuf_available(rpc) && (size > 0x7)) {
++ u32 wbuf = 0;
++ int block = size >= RPC_WBUF_SIZE ?
++ RPC_WBUF_SIZE : size & ~0x7;
++
++ rpc_hf_wbuf_enable(rpc, offset);
++ offset += block;
++
++ block >>= 3;
++ while (block--) {
++ while (idx < 4) {
++ data.b[idx++] = *src++;
++ size--;
++ }
++ rpc_wbuf_writel(rpc, wbuf, data.d);
++ wbuf += 4;
++
++ idx = 0;
++ while (idx < 4) {
++ data.b[idx++] = *src++;
++ size--;
++ }
++ rpc_wbuf_writel(rpc, wbuf, data.d);
++ wbuf += 4;
++
++ idx = 0;
++ }
++
++ rpc_writel(rpc, RPC_SMCR,
++ RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
++ } else {
++ enum rpc_size bits;
++
++ while (idx < 4) {
++ data.b[idx++] = *src++;
++ size--;
++
++ if (!size)
++ break;
++ }
++
++ if (idx & 0x1)
++ data.b[idx++] = last;
++
++ switch (idx) {
++ case 2:
++ bits = RPC_SIZE_DUAL_16BIT;
++ break;
++ default:
++ bits = RPC_SIZE_DUAL_32BIT;
++ break;
++ }
++
++ rpc_hf_write_mem(rpc, offset, data.w, bits);
++ offset += idx;
++ idx = 0;
++ }
++
++ ret = rpc_hf_status(rpc, addr, 1000000, 10);
++ if (ret)
++ goto out;
++ }
++
++ size = mtd->erasesize;
++ addr += size;
++ offset = addr;
++ *retlen = len - cnt;
++ }
++
++out:
++ rpc_hf_mode_ext(rpc);
++ mutex_unlock(&hf->lock);
++ return ret;
++}
++
++static int rpc_hf_hw_init(struct rpc_info *rpc, u32 *id, u32 *size)
++{
++ u16 data[2] = { 0, 0 };
++ u32 sz;
++ int ret = 0;
++
++ rpc_hf_mode_ext(rpc);
++
++ rpc_hf_wp(rpc, 0);
++
++ rpc_hf_unlock(rpc, 0);
++ rpc_hf_write_cmd(rpc, RPC_CFI_UNLOCK1, RPC_CFI_CMD_READ_ID);
++
++ rpc_hf_read_reg(rpc, 0x0, data, RPC_SIZE_DUAL_32BIT);
++ if ((data[0] & RPC_CFI_ID_MASK) != RPC_CFI_ID_MAN_SPANSION ||
++ (data[1] & RPC_CFI_ID_MASK) != RPC_CFI_ID_TYPE_HYPERFLASH) {
++ ret = -ENXIO;
++ goto out;
++ }
++
++ if (id)
++ *id = data[0] | data[1] << 16;
++
++ rpc_hf_read_reg(rpc, 0x27 << 1, data, RPC_SIZE_DUAL_16BIT);
++ sz = 1 << data[0];
++
++ if (sz & (RPC_HF_ERASE_SIZE - 1)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (size)
++ *size = sz;
++out:
++ rpc_hf_write_cmd(rpc, 0, RPC_CFI_CMD_RESET);
++ rpc_hf_mode_ext(rpc);
++ return ret;
++}
++
++int rpc_hf_probe(struct platform_device *pdev)
++{
++ struct rpc_info *rpc;
++ struct rpc_hf_info *hf;
++ struct mtd_info *mtd;
++ u32 flash_id, flash_size;
++ int ret;
++
++ rpc = dev_get_drvdata(pdev->dev.parent);
++ if (!rpc) {
++ dev_err(&pdev->dev, "invalid data\n");
++ return -EINVAL;
++ }
++
++ hf = devm_kzalloc(&pdev->dev, sizeof(*hf), GFP_KERNEL);
++ if (!hf) {
++ dev_err(&pdev->dev, "allocation failed\n");
++ return -ENOMEM;
++ }
++
++ mutex_init(&hf->lock);
++ mtd_set_of_node(&hf->mtd, rpc->flash);
++ hf->priv = rpc;
++
++ ret = clk_prepare_enable(rpc->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot prepare clock\n");
++ return ret;
++ }
++
++ ret = rpc_hf_hw_init(rpc, &flash_id, &flash_size);
++ if (ret) {
++ dev_err(&pdev->dev, "initialization failed\n");
++ goto error;
++ }
++
++ mtd = &hf->mtd;
++ mtd->name = "HyperFlash";
++ mtd->dev.parent = &pdev->dev;
++ mtd->type = MTD_NORFLASH;
++ mtd->flags = MTD_CAP_NORFLASH;
++ mtd->size = flash_size;
++ mtd->writesize = 1;
++ mtd->writebufsize = RPC_WBUF_SIZE;
++ mtd->erasesize = RPC_HF_ERASE_SIZE;
++ mtd->owner = THIS_MODULE;
++ mtd->priv = hf;
++ mtd->_erase = rpc_hf_mtd_erase;
++ mtd->_write = rpc_hf_mtd_write;
++ mtd->_read = rpc_hf_mtd_read;
++
++ ret = mtd_device_register(mtd, NULL, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "MTD registration failed\n");
++ goto error;
++ }
++
++ platform_set_drvdata(pdev, hf);
++ dev_info(&pdev->dev, "probed flash id:%x\n", flash_id);
++ return 0;
++
++error:
++ clk_disable_unprepare(rpc->clk);
++ return ret;
++}
++
++static int rpc_hf_remove(struct platform_device *pdev)
++{
++ struct rpc_hf_info *hf = platform_get_drvdata(pdev);
++ struct rpc_info *rpc = hf->priv;
++
++ mtd_device_unregister(&hf->mtd);
++ clk_disable_unprepare(rpc->clk);
++ return 0;
++}
++
++/* platform driver interface */
++static struct platform_driver rpc_hf_platform_driver = {
++ .probe = rpc_hf_probe,
++ .remove = rpc_hf_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "renesas-rpc-hyperflash",
++ },
++};
++
++module_platform_driver(rpc_hf_platform_driver);
++
++MODULE_ALIAS("renesas-rpc-hyperflash");
++MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>");
++MODULE_DESCRIPTION("Renesas RPC HyperFlash Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/spi-nor/renesas-rpc-qspi.c b/drivers/mtd/spi-nor/renesas-rpc-qspi.c
+new file mode 100644
+index 0000000..3d2d5db
+--- /dev/null
++++ b/drivers/mtd/spi-nor/renesas-rpc-qspi.c
+@@ -0,0 +1,794 @@
++/*
++ * Renesas RPC QSPI driver
++ *
++ * Copyright (C) 2019, Cogent Embedded Inc.
++ *
++ * 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; version 2 of the License.
++ *
++ * 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.
++ */
++
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/spi-nor.h>
++
++#include "renesas-rpc.h"
++
++static void rpc_endisable_write_buf(struct rpc_info *rpc, bool en)
++{
++ rpc_clrsetl(rpc, RPC_PHYCNT,
++ RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2,
++ en ? RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 : 0);
++}
++
++static int rpc_begin(struct rpc_info *rpc,
++ bool rx, bool tx, bool last)
++{
++ u32 val = RPC_SMCR_SPIE;
++
++ if (rx)
++ val |= RPC_SMCR_SPIRE;
++
++ if (tx)
++ val |= RPC_SMCR_SPIWE;
++
++ if (!last)
++ val |= RPC_SMCR_SSLKP;
++
++ rpc_writel(rpc, RPC_SMCR, val);
++
++ return 0;
++}
++
++static int rpc_setup_reg_mode(struct rpc_info *rpc)
++{
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ rpc_endisable_write_buf(rpc, false);
++
++ /* ...setup manual mode */
++ rpc_clrsetl(rpc, RPC_CMNCR, 0, RPC_CMNCR_MD);
++
++ /* disable ddr */
++ rpc_clrsetl(rpc, RPC_SMDRENR,
++ RPC_SMDRENR_ADDRE | RPC_SMDRENR_OPDRE | RPC_SMDRENR_SPIDRE,
++ 0);
++
++ /* enable 1bit command */
++ rpc_clrsetl(rpc, RPC_SMENR,
++ RPC_SMENR_CDB(3) | RPC_SMENR_OCDB(3) | RPC_SMENR_DME |
++ RPC_SMENR_OCDE | RPC_SMENR_SPIDB(3) |
++ RPC_SMENR_ADE(0xF) | RPC_SMENR_ADB(3) |
++ RPC_SMENR_OPDE(0xF) | RPC_SMENR_SPIDE(0xF),
++ RPC_SMENR_CDB(0) | RPC_SMENR_CDE | RPC_SIZE_SINGLE_32BIT);
++
++ return 0;
++}
++
++static inline void rpc_flush_cache(struct rpc_info *rpc)
++{
++ rpc_clrsetl(rpc, RPC_DRCR, 0, RPC_DRCR_RCF);
++}
++
++static int rpc_setup_ext_mode(struct rpc_info *rpc)
++{
++ u32 val;
++ u32 cmncr;
++
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ rpc_endisable_write_buf(rpc, false);
++
++ /* ...setup ext mode */
++ val = rpc_readl(rpc, RPC_CMNCR);
++ cmncr = val;
++ val &= ~(RPC_CMNCR_MD);
++ rpc_writel(rpc, RPC_CMNCR, val);
++
++ /* ...enable burst and clear cache */
++ val = rpc_readl(rpc, RPC_DRCR);
++ val &= ~(RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RBE | RPC_DRCR_SSLE);
++ val |= RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RBE;
++
++ if (cmncr & RPC_CMNCR_MD)
++ val |= RPC_DRCR_RCF;
++
++ rpc_writel(rpc, RPC_DRCR, val);
++
++ return 0;
++}
++
++static int rpc_setup_data_size(struct rpc_info *rpc, u32 size, bool copy)
++{
++ u32 val;
++
++ val = rpc_readl(rpc, RPC_SMENR);
++ val &= ~(RPC_SMENR_SPIDE(0xF));
++
++ if (rpc->mtdtype == RPC_DUAL && !copy)
++ size >>= 1;
++
++ switch (size) {
++ case 0:
++ break;
++ case 1:
++ val |= RPC_SIZE_SINGLE_8BIT;
++ break;
++ case 2:
++ val |= RPC_SIZE_SINGLE_16BIT;
++ break;
++ case 4:
++ val |= RPC_SIZE_SINGLE_32BIT;
++ break;
++ default:
++ dev_err(&rpc->pdev->dev, "Unsupported data width %d\n", size);
++ return -EINVAL;
++ }
++ rpc_writel(rpc, RPC_SMENR, val);
++
++ return 0;
++}
++
++static inline int rpc_get_read_addr_nbits(u8 opcode)
++{
++ if (opcode == SPINOR_OP_READ_1_4_4_4B)
++ return 4;
++ return 1;
++}
++
++#define RPC_NBITS_TO_VAL(v) ((v >> 1) & 3)
++static void rpc_setup_extmode_nbits(struct rpc_info *rpc,
++ int cnb, int anb, int dnb)
++{
++ rpc_clrsetl(rpc, RPC_DRENR,
++ RPC_DRENR_CDB(3) | RPC_DRENR_ADB(3) | RPC_DRENR_DRDB(3),
++ RPC_DRENR_CDB(RPC_NBITS_TO_VAL(cnb)) |
++ RPC_DRENR_ADB(RPC_NBITS_TO_VAL(anb)) |
++ RPC_DRENR_DRDB(RPC_NBITS_TO_VAL(dnb)));
++}
++
++static void rpc_setup_writemode_nbits(struct rpc_info *rpc,
++ int cnb, int anb, int dnb)
++{
++ rpc_clrsetl(rpc, RPC_SMENR,
++ RPC_SMENR_CDB(3) | RPC_SMENR_ADB(3) | RPC_SMENR_SPIDB(3),
++ RPC_SMENR_CDB(RPC_NBITS_TO_VAL(cnb)) |
++ RPC_SMENR_ADB(RPC_NBITS_TO_VAL(anb)) |
++ RPC_SMENR_SPIDB(RPC_NBITS_TO_VAL(dnb)));
++}
++
++static void rpc_setup_write_mode_command_and_adr(struct rpc_info *rpc,
++ int adr_width, bool ena)
++{
++ u32 val;
++
++ val = rpc_readl(rpc, RPC_SMENR);
++ val &= ~(RPC_SMENR_CDB(3) | RPC_SMENR_CDE | RPC_SMENR_ADE(0xF));
++
++ if (ena) {
++ /* enable 1bit command */
++ val |= RPC_SMENR_CDB(0) | RPC_SMENR_CDE;
++
++ if (adr_width == 4)
++ val |= RPC_SMENR_ADE(0xF); /* bits 31-0 */
++ else
++ val |= RPC_SMENR_ADE(0x7); /* bits 23-0 */
++ }
++ rpc_writel(rpc, RPC_SMENR, val);
++}
++
++static void rpc_setup_write_mode(struct rpc_info *rpc, u8 opcode)
++{
++ rpc_wait(rpc, RPC_TIMEOUT);
++
++ rpc_endisable_write_buf(rpc, true);
++
++ /* ...setup manual mode */
++ rpc_clrsetl(rpc, RPC_CMNCR, 0, RPC_CMNCR_MD);
++
++ /* disable ddr */
++ rpc_clrsetl(rpc, RPC_SMDRENR,
++ RPC_SMDRENR_ADDRE | RPC_SMDRENR_OPDRE | RPC_SMDRENR_SPIDRE,
++ 0);
++
++ rpc_clrsetl(rpc, RPC_SMENR,
++ RPC_SMENR_OCDB(3) | RPC_SMENR_DME | RPC_SMENR_OCDE |
++ RPC_SMENR_SPIDB(3) | RPC_SMENR_ADB(3) |
++ RPC_SMENR_OPDE(0xF) | RPC_SMENR_SPIDE(0xF),
++ opcode != SPINOR_OP_PP ? RPC_SIZE_SINGLE_32BIT :
++ RPC_SIZE_SINGLE_8BIT);
++}
++
++static void rpc_read_manual_data(struct rpc_info *rpc, u32 *pv0, u32 *pv1)
++{
++ u32 val0, val1, rd0, rd1;
++
++ val0 = rpc_readl(rpc, RPC_SMRDR0);
++ val1 = rpc_readl(rpc, RPC_SMRDR1);
++
++ if (rpc->mtdtype == RPC_DUAL) {
++ rd1 = (val0 & 0xFf000000) | ((val0 << 8) & 0xFf0000) |
++ ((val1 >> 16) & 0xff00) | ((val1 >> 8) & 0xff);
++ rd0 = ((val0 & 0xff0000) << 8) | ((val0 << 16) & 0xff0000) |
++ ((val1 >> 8) & 0xff00) | (val1 & 0xff);
++ } else
++ rd0 = val0;
++
++ if (pv0)
++ *pv0 = rd0;
++
++ if (pv1 && rpc->mtdtype == RPC_DUAL)
++ *pv1 = rd1;
++}
++
++static int rpc_datalen2trancfersize(struct rpc_info *rpc, int len, bool copy)
++{
++ int sz = len;
++
++ if (len >= 2)
++ sz = 2;
++
++ if (len >= 4)
++ sz = 4;
++
++ if (rpc->mtdtype == RPC_DUAL && len >= 8 && !copy)
++ sz = 8;
++
++ return sz;
++}
++
++static int __rpc_write_data2reg(struct rpc_info *rpc, int off,
++ const u8 *buf, int sz)
++{
++ const u32 *b32 = (const u32 *)buf;
++ const u16 *b16 = (const u16 *)buf;
++
++ if (sz == 4)
++ rpc_writel(rpc, off, *b32);
++ else if (sz == 2)
++ writew(*b16, rpc->base + off);
++ else if (sz == 1)
++ writeb(*buf, rpc->base + off);
++ else if (sz != 0) {
++ dev_err(&rpc->pdev->dev, "incorrect data size %d\n", sz);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++#define RPC_SETVAL(x) ((((x) & 0xff) << 8) | ((x) & 0xff))
++static int rpc_write_data2reg(struct rpc_info *rpc, const u8 *buf,
++ int sz, bool copy)
++{
++ int i, ret;
++ u32 v = 0;
++
++ if (rpc->mtdtype == RPC_DUAL) {
++ if (copy) {
++ for (i = 0; i < sz && i < 2; i++)
++ v |= (RPC_SETVAL(buf[i]) << 16*i);
++
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? RPC_SMWDR1 : RPC_SMWDR0,
++ (u8 *)&v,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++
++ v = 0;
++ for (; i < sz; i++)
++ v |= (RPC_SETVAL(buf[i]) << 16*i);
++
++
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? RPC_SMWDR0 : RPC_SMWDR1,
++ (u8 *)&v,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++
++ return 0;
++ }
++
++ sz >>= 1;
++ ret = __rpc_write_data2reg(rpc,
++ sz == 4 ? RPC_SMWDR1 : RPC_SMWDR0,
++ buf,
++ sz == 4 ? sz : sz * 2);
++ if (ret)
++ return ret;
++ buf += sz;
++
++ return __rpc_write_data2reg(rpc,
++ sz == 4 ? RPC_SMWDR0 : RPC_SMWDR1,
++ buf, sz == 4 ? sz : sz * 2);
++ }
++
++ return __rpc_write_data2reg(rpc, RPC_SMWDR0, buf, sz);
++}
++
++static ssize_t rpc_write_unaligned(struct spi_nor *nor, loff_t to, size_t len,
++ const u_char *buf, size_t fullen)
++{
++ int ret = len, dsize;
++ struct rpc_info *rpc = nor->priv;
++ bool copy = false, last;
++ loff_t _to;
++
++ rpc_endisable_write_buf(rpc, false);
++
++ while (len > 0) {
++ _to = to;
++ if (rpc->mtdtype == RPC_DUAL)
++ _to >>= 1;
++ rpc_writel(rpc, RPC_SMADR, _to);
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++
++ rpc_write_data2reg(rpc, buf, dsize, copy);
++
++ last = (len <= dsize && fullen <= ret);
++ rpc_begin(rpc, false, true, last);
++ if (rpc_wait(rpc, RPC_TIMEOUT))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ rpc_setup_write_mode_command_and_adr(rpc,
++ nor->addr_width, false);
++
++ buf += dsize;
++ len -= dsize;
++ to += dsize;
++ }
++
++ return ret;
++}
++
++static ssize_t rpc_write_flash(struct spi_nor *nor, loff_t to, size_t len,
++ const u_char *buf)
++{
++ ssize_t res = len, full = len;
++ u32 val;
++ u8 rval[2];
++ struct rpc_info *rpc = nor->priv;
++ loff_t bo;
++ loff_t offset;
++ bool is_rounded = false;
++
++ /* ...len should be rounded to 2 bytes */
++ if (rpc->mtdtype == RPC_DUAL && (len & 1)) {
++ is_rounded = true;
++ len &= ~(1);
++ }
++
++ bo = to & RPC_WBUF_MASK;
++
++ rpc_flush_cache(rpc);
++ rpc_setup_write_mode(rpc, nor->program_opcode);
++ rpc_setup_write_mode_command_and_adr(rpc, nor->addr_width, true);
++ rpc_setup_writemode_nbits(rpc, 1, 1, 1);
++
++ /* ...setup command */
++ val = rpc_readl(rpc, RPC_SMCMR);
++ val &= ~RPC_SMCMR_CMD(0xFF);
++ val |= RPC_SMCMR_CMD(nor->program_opcode);
++ rpc_writel(rpc, RPC_SMCMR, val);
++
++ offset = to & ~RPC_WBUF_MASK;
++
++ /* ...write unaligned first bytes */
++ if (bo) {
++ size_t min = (len < (RPC_WBUF_SIZE - bo)) ? len : (RPC_WBUF_SIZE - bo);
++
++ rpc_write_unaligned(nor, to, min, buf, full);
++ rpc_setup_write_mode(rpc, nor->program_opcode);
++
++ len -= min;
++ buf += min;
++ to += min;
++ full -= min;
++ }
++
++ /*
++ * TODO: Unfortunately RPC does not write properly in write buf mode
++ * without transferring command. Investigate this.
++ */
++
++ if (len) {
++ rpc_write_unaligned(nor, to, len, buf, full);
++ buf += len;
++ to += len;
++ full -= len;
++ len = 0;
++ }
++
++ if (is_rounded) {
++ rval[0] = *buf;
++ rval[1] = 0xFF;
++ rpc_write_unaligned(nor, to, 2, rval, full);
++ }
++
++ rpc_flush_cache(rpc);
++
++ return res;
++}
++
++static inline unsigned int rpc_rx_nbits(struct spi_nor *nor)
++{
++ return spi_nor_get_protocol_data_nbits(nor->read_proto);
++}
++
++static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len,
++ u_char *buf)
++{
++ u32 val;
++ struct rpc_info *rpc = nor->priv;
++ int opcode_nbits = 1;
++ int addr_nbits = rpc_get_read_addr_nbits(nor->read_opcode);
++ int data_nbits = rpc_rx_nbits(nor);
++ int dummy = nor->read_dummy - 1;
++ ssize_t ret = len;
++
++ rpc_setup_ext_mode(rpc);
++ /* ...setup n bits */
++ rpc_setup_extmode_nbits(rpc, opcode_nbits, addr_nbits, data_nbits);
++
++ /* TODO: setup DDR */
++
++ /* ...setup command */
++ val = rpc_readl(rpc, RPC_DRCMR);
++ val &= ~RPC_DRCMR_CMD(0xFF);
++ val |= RPC_DRCMR_CMD(nor->read_opcode);
++ rpc_writel(rpc, RPC_DRCMR, val);
++
++ /* ...setup dummy cycles */
++ val = rpc_readl(rpc, RPC_DRDMCR);
++ val &= ~RPC_DRDMCR_DMCYC(0x1F);
++ val |= RPC_DRDMCR_DMCYC(dummy);
++ rpc_writel(rpc, RPC_DRDMCR, val);
++
++ /* ...setup read sequence */
++ val = rpc_readl(rpc, RPC_DRENR);
++ val |= RPC_DRENR_DME | RPC_DRENR_CDE;
++ rpc_writel(rpc, RPC_DRENR, val);
++
++ rpc_do_read_flash(rpc, from, len, buf, nor->addr_width > 3);
++
++ return ret;
++}
++
++static int __rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ u32 val;
++ u32 val2 = 0;
++ u32 *buf32;
++ int i;
++ u32 mask = 0, type;
++ struct rpc_info *rpc = nor->priv;
++
++ type = rpc->mtdtype;
++
++ rpc_setup_reg_mode(rpc);
++ val = rpc_readl(rpc, RPC_SMCMR);
++ val &= ~RPC_SMCMR_CMD(0xFF);
++ val |= RPC_SMCMR_CMD(opcode);
++ rpc_writel(rpc, RPC_SMCMR, val);
++
++ rpc_begin(rpc, true, false, len <= 4);
++ if (rpc_wait(rpc, RPC_TIMEOUT))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ val = rpc_readl(rpc, RPC_SMENR);
++ val &= ~(RPC_SMENR_CDE);
++ rpc_writel(rpc, RPC_SMENR, val);
++
++ buf32 = (u32 *)buf;
++
++ while (len > 0) {
++ rpc_read_manual_data(rpc, &val, &val2);
++
++ if (mask) {
++ dev_warn(&rpc->pdev->dev,
++ "Using mask workaround (0x%x)\n", mask);
++ val &= ~(mask);
++ val2 &= ~(mask);
++ }
++
++ /* ... spi flashes should be the same */
++ if (type == RPC_DUAL && val != val2) {
++ /* clear cs */
++ rpc_begin(rpc, true, false, true);
++ return -EAGAIN;
++ }
++
++ if (len > 4) {
++ *buf32 = val;
++ buf32++;
++ len -= 4;
++ } else {
++ buf = (u8 *)buf32;
++ for (i = 0; i < len; i++) {
++ *buf = (val >> (8 * i)) & 0x000000ff;
++ buf++;
++ }
++ len = 0;
++ }
++
++ if (!len)
++ break;
++
++ mask = 0xff;
++
++ rpc_begin(rpc, true, false, len <= 4);
++ if (rpc_wait(rpc, RPC_TIMEOUT))
++ return -ETIMEDOUT;
++
++ }
++
++ return 0;
++}
++
++#define RPC_REPEAT_TIMEOUT 200
++static int rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ unsigned long end = jiffies + msecs_to_jiffies(RPC_REPEAT_TIMEOUT);
++
++ /* A few read commands like read status can
++ * generate different answers. We repeat reading
++ * in that case
++ */
++ while (true) {
++ int ret = __rpc_read_reg(nor, opcode, buf, len);
++
++ if (!ret || ret != -EAGAIN)
++ return ret;
++
++ if (time_after(jiffies, end))
++ return -ETIMEDOUT;
++
++ msleep(20);
++ }
++}
++
++static int rpc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ struct rpc_info *rpc = nor->priv;
++ u32 val;
++ int dsize;
++ bool copy = true;
++
++ rpc_setup_reg_mode(rpc);
++
++ val = rpc_readl(rpc, RPC_SMCMR);
++ val &= ~RPC_SMCMR_CMD(0xFF);
++ val |= RPC_SMCMR_CMD(opcode);
++ rpc_writel(rpc, RPC_SMCMR, val);
++
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++
++ if (rpc_write_data2reg(rpc, buf, dsize, copy))
++ return -EINVAL;
++ buf += dsize;
++ len -= dsize;
++ rpc_begin(rpc, false, dsize > 0, len == 0);
++
++ if (rpc_wait(rpc, RPC_TIMEOUT))
++ return -ETIMEDOUT;
++
++ /* ...disable command */
++ val = rpc_readl(rpc, RPC_SMENR);
++ val &= ~(RPC_SMENR_CDE);
++ rpc_writel(rpc, RPC_SMENR, val);
++
++ while (len > 0) {
++ dsize = rpc_datalen2trancfersize(rpc, len, copy);
++ if (rpc_setup_data_size(rpc, dsize, copy))
++ return -EINVAL;
++ rpc_write_data2reg(rpc, buf, dsize, copy);
++ buf += dsize;
++ len -= dsize;
++
++ rpc_begin(rpc, false, dsize, len == 0);
++
++ if (rpc_wait(rpc, RPC_TIMEOUT))
++ return -ETIMEDOUT;
++
++ }
++
++ return 0;
++}
++
++/* hw init for spi-nor flashes */
++static int rpc_spi_hw_init(struct rpc_info *rpc)
++{
++ /* Exec calibration */
++ rpc_clrsetl(rpc, RPC_PHYCNT,
++ RPC_PHYCNT_OCTA(3) | RPC_PHYCNT_EXDS | RPC_PHYCNT_OCT |
++ RPC_PHYCNT_DDRCAL | RPC_PHYCNT_HS | RPC_PHYCNT_STRTIM(7) |
++ RPC_PHYCNT_WBUF2 | RPC_PHYCNT_WBUF | RPC_PHYCNT_MEM(3),
++ RPC_PHYCNT_CAL | RPC_PHYCNT_STRTIM(6));
++
++ /* Disable RPC pins */
++ rpc_clrsetl(rpc, RPC_PHYINT,
++ RPC_PHYINT_INTIE | RPC_PHYINT_RSTEN |
++ RPC_PHYINT_WPEN | RPC_PHYINT_INTEN,
++ 0);
++
++ rpc_clrsetl(rpc, RPC_SMDRENR,
++ RPC_SMDRENR_HYPE(7),
++ RPC_SMDRENR_HYPE_SPI);
++
++ rpc_clrsetl(rpc, RPC_CMNCR,
++ RPC_CMNCR_BSZ(3),
++ rpc->mtdtype != RPC_SINGLE ?
++ RPC_CMNCR_BSZ(1) :
++ RPC_CMNCR_BSZ(0));
++
++ rpc_clrsetl(rpc, RPC_PHYOFFSET1,
++ RPC_PHYOFFSET1_DDRTMG(3),
++ RPC_PHYOFFSET1_DDRTMG_SDR);
++
++ rpc_writel(rpc, RPC_SSLDR,
++ RPC_SSLDR_SPNDL(0) | RPC_SSLDR_SLNDL(4) |
++ RPC_SSLDR_SCKDL(0));
++
++ return 0;
++}
++
++static int rpc_erase_sector(struct spi_nor *nor, loff_t addr)
++{
++ struct rpc_info *rpc = nor->priv;
++ u8 buf[6];
++ int i;
++
++ if (rpc->mtdtype == RPC_DUAL)
++ addr >>= 1;
++
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++int rpc_qspi_probe(struct platform_device *pdev)
++{
++ struct rpc_info *rpc;
++ struct spi_nor *nor;
++ struct spi_nor_hwcaps hwcaps = {
++ .mask = SNOR_HWCAPS_READ |
++ SNOR_HWCAPS_READ_FAST |
++ SNOR_HWCAPS_PP,
++ };
++ u32 property;
++ int ret;
++
++ rpc = dev_get_drvdata(pdev->dev.parent);
++ if (!rpc || !rpc->flash) {
++ dev_err(&pdev->dev, "invalid data\n");
++ return -EINVAL;
++ }
++
++ if (!of_property_read_u32(rpc->flash, "spi-rx-bus-width", &property)) {
++ switch (property) {
++ case 1:
++ break;
++ case 2:
++ hwcaps.mask |= SNOR_HWCAPS_READ_DUAL;
++ break;
++ case 4:
++ hwcaps.mask |= SNOR_HWCAPS_READ_QUAD;
++ break;
++ default:
++ dev_err(&pdev->dev, "unsupported rx-bus-width\n");
++ return -EINVAL;
++ }
++ }
++
++ /* ... setup nor hooks */
++ nor = devm_kzalloc(&pdev->dev, sizeof(*nor), GFP_KERNEL);
++ if (!nor) {
++ dev_err(&pdev->dev, "allocation failed\n");
++ return -ENOMEM;
++ }
++
++ nor->dev = &pdev->dev;
++ spi_nor_set_flash_node(nor, rpc->flash);
++ nor->read = rpc_read_flash;
++ nor->write = rpc_write_flash;
++ nor->read_reg = rpc_read_reg;
++ nor->write_reg = rpc_write_reg;
++ nor->priv = rpc;
++
++ /* ... enable clk */
++ ret = clk_prepare_enable(rpc->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot prepare clock\n");
++ return ret;
++ }
++
++ /* ...init device */
++ ret = rpc_spi_hw_init(rpc);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "rpc_spi_hw_init error.\n");
++ goto error;
++ }
++
++ ret = spi_nor_scan(nor, NULL, &hwcaps);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_nor_scan error.\n");
++ goto error;
++ }
++
++ /* Dual mode support */
++ if (rpc->mtdtype == RPC_DUAL) {
++ nor->page_size <<= 1;
++ nor->mtd.erasesize <<= 1;
++ nor->mtd.size <<= 1;
++ nor->mtd.writebufsize <<= 1;
++ nor->erase = rpc_erase_sector;
++ }
++
++ /* Workaround data size limitation */
++ if (nor->page_size > RPC_WBUF_SIZE) {
++ nor->page_size = RPC_WBUF_SIZE;
++ nor->mtd.writebufsize = RPC_WBUF_SIZE;
++ }
++
++ ret = mtd_device_register(&nor->mtd, NULL, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "MTD registration failed\n");
++ goto error;
++ }
++
++ dev_info(&pdev->dev, "probed as %s\n",
++ rpc->mtdtype == RPC_SINGLE ? "single" : "dual");
++
++ platform_set_drvdata(pdev, nor);
++ return 0;
++
++error:
++ clk_disable_unprepare(rpc->clk);
++ return ret;
++}
++
++static int rpc_qspi_remove(struct platform_device *pdev)
++{
++ struct spi_nor *nor = platform_get_drvdata(pdev);
++ struct rpc_info *rpc = nor->priv;
++
++ mtd_device_unregister(&nor->mtd);
++ clk_disable_unprepare(rpc->clk);
++ return 0;
++}
++
++/* platform driver interface */
++static struct platform_driver rpc_qspi_platform_driver = {
++ .probe = rpc_qspi_probe,
++ .remove = rpc_qspi_remove,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "renesas-rpc-qspi",
++ },
++};
++
++module_platform_driver(rpc_qspi_platform_driver);
++
++MODULE_ALIAS("renesas-rpc-qspi");
++MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>");
++MODULE_DESCRIPTION("Renesas RPC QSPI Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/spi-nor/renesas-rpc.c b/drivers/mtd/spi-nor/renesas-rpc.c
+index 0026b99..3aea0ae 100644
+--- a/drivers/mtd/spi-nor/renesas-rpc.c
++++ b/drivers/mtd/spi-nor/renesas-rpc.c
+@@ -1,7 +1,7 @@
+ /*
+ * Renesas RPC driver
+ *
+- * Copyright (C) 2018, Cogent Embedded Inc.
++ * Copyright (C) 2019, Cogent Embedded Inc.
+ *
+ * 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
+@@ -13,268 +13,28 @@
+ * GNU General Public License for more details.
+ */
+
+-#include <linux/clk.h>
++#include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+-#include <linux/dmaengine.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+ #include <linux/interrupt.h>
+-#include <linux/platform_device.h>
+-#include <linux/delay.h>
+-#include <linux/mtd/spi-nor.h>
+-
+-/* regs offsets */
+-#define CMNCR 0x0000
+-#define SSLDR 0x0004
+-#define DRCR 0x000C
+-#define DRCMR 0x0010
+-#define DREAR 0x0014
+-#define DROPR 0x0018
+-#define DRENR 0x001C
+-#define SMCR 0x0020
+-#define SMCMR 0x0024
+-#define SMADR 0x0028
+-#define SMOPR 0x002C
+-#define SMENR 0x0030
+-#define SMRDR0 0x0038
+-#define SMRDR1 0x003C
+-#define SMWDR0 0x0040
+-#define SMWDR1 0x0044
+-#define CMNSR 0x0048
+-#define DRDMCR 0x0058
+-#define DRDRENR 0x005C
+-#define SMDMCR 0x0060
+-#define SMDRENR 0x0064
+-#define PHYCNT 0x007C
+-#define PHYOFFSET1 0x0080
+-#define PHYOFFSET2 0x0084
+-#define PHYINT 0x0088
+-#define DIV_REG 0x00A8
+-
+-/* CMNCR */
+-#define CMNCR_BSZ_MASK (0x03)
+-#define CMNCR_BSZ_4x1 (0x0)
+-#define CMNCR_BSZ_8x1 (0x1)
+-#define CMNCR_BSZ_4x2 (0x1)
+-#define CMNCR_MD (0x1 << 31)
+-#define CMNCR_MOIIO3_MASK (0x3 << 22)
+-#define CMNCR_MOIIO3_HIZ (0x3 << 22)
+-#define CMNCR_MOIIO2_MASK (0x3 << 20)
+-#define CMNCR_MOIIO2_HIZ (0x3 << 20)
+-#define CMNCR_MOIIO1_MASK (0x3 << 18)
+-#define CMNCR_MOIIO1_HIZ (0x3 << 18)
+-#define CMNCR_MOIIO0_MASK (0x3 << 16)
+-#define CMNCR_MOIIO0_HIZ (0x3 << 16)
+-#define CMNCR_IO0FV_MASK (0x3 << 8)
+-#define CMNCR_IO0FV_HIZ (0x3 << 8)
+-
+-/* DRCR */
+-#define DRCR_RBURST_MASK (0x1f << 16)
+-#define DRCR_RBURST(v) (((v) & 0x1f) << 16)
+-#define DRCR_SSLE (0x1)
+-#define DRCR_RBE (0x1 << 8)
+-#define DRCR_RCF (0x1 << 9)
+-#define DRCR_RBURST_32 (0x1f)
+-
+-/* SMENR */
+-#define SMENR_CDB_MASK (0x03 << 30)
+-#define SMENR_CDB(v) (((v) & 0x03) << 30)
+-#define SMENR_CDB_1B (0)
+-#define SMENR_CDB_2B (0x1 << 30)
+-#define SMENR_CDB_4B (0x2 << 30)
+-#define SMENR_OCDB_MASK (0x03 << 28)
+-#define SMENR_OCDB_1B (0)
+-#define SMENR_OCDB_2B (0x1 << 28)
+-#define SMENR_OCDB_4B (0x2 << 28)
+-#define SMENR_ADB_MASK (0x03 << 24)
+-#define SMENR_ADB(v) (((v) & 0x03) << 24)
+-#define SMENR_ADB_1B (0)
+-#define SMENR_ADB_2B (0x1 << 24)
+-#define SMENR_ADB_4B (0x2 << 24)
+-#define SMENR_OPDB_MASK (0x03 << 20)
+-#define SMENR_OPDB_1B (0)
+-#define SMENR_OPDB_2B (0x1 << 20)
+-#define SMENR_OPDB_4B (0x2 << 20)
+-#define SMENR_SPIDB_MASK (0x03 << 16)
+-#define SMENR_SPIDB(v) (((v) & 0x03) << 16)
+-#define SMENR_SPIDB_1B (0)
+-#define SMENR_SPIDB_2B (0x1 << 16)
+-#define SMENR_SPIDB_4B (0x2 << 16)
+-#define SMENR_OPDE_MASK (0xf << 4)
+-#define SMENR_OPDE_DISABLE (0)
+-#define SMENR_OPDE3 (0x8 << 4)
+-#define SMENR_OPDE32 (0xC << 4)
+-#define SMENR_OPDE321 (0xE << 4)
+-#define SMENR_OPDE3210 (0xF << 4)
+-#define SMENR_SPIDE_MASK (0x0F)
+-#define SMENR_SPIDE_DISABLE (0)
+-#define SMENR_SPIDE_8B (0x08)
+-#define SMENR_SPIDE_16B (0x0C)
+-#define SMENR_SPIDE_32B (0x0F)
+-#define SMENR_DME (1<<15)
+-#define SMENR_CDE (1<<14)
+-#define SMENR_OCDE (1<<12)
+-#define SMENR_ADE_MASK (0xf << 8)
+-#define SMENR_ADE_DISABLE (0)
+-#define SMENR_ADE_23_16 (0x4 << 8)
+-#define SMENR_ADE_23_8 (0x6 << 8)
+-#define SMENR_ADE_23_0 (0x7 << 8)
+-#define SMENR_ADE_31_0 (0xf << 8)
+-
+-/* SMCMR */
+-#define SMCMR_CMD(cmd) (((cmd) & 0xff) << 16)
+-#define SMCMR_CMD_MASK (0xff << 16)
+-#define SMCMR_OCMD(cmd) (((cmd) & 0xff))
+-#define SMCMR_OCMD_MASK (0xff)
+-
+-/* SMDRENR */
+-#define SMDRENR_HYPE_MASK (0x7 << 12)
+-#define SMDRENR_HYPE_SPI_FLASH (0x0)
+-#define SMDRENR_ADDRE (0x1 << 8)
+-#define SMDRENR_OPDRE (0x1 << 4)
+-#define SMDRENR_SPIDRE (0x1)
+-
+-/* PHYCNT */
+-#define PHYCNT_CAL (0x1 << 31)
+-#define PHYCNT_OCTA_MASK (0x3 << 22)
+-#define PHYCNT_EXDS (0x1 << 21)
+-#define PHYCNT_OCT (0x1 << 20)
+-#define PHYCNT_DDRCAL (0x1 << 19)
+-#define PHYCNT_HS (0x1 << 18)
+-#define PHYCNT_STREAM_MASK (0x7 << 15)
+-#define PHYCNT_STREAM(o) (((o) & 0x7) << 15)
+-#define PHYCNT_WBUF2 (0x1 << 4)
+-#define PHYCNT_WBUF (0x1 << 2)
+-#define PHYCNT_PHYMEM_MASK (0x3)
+-
+-/* SMCR */
+-#define SMCR_SSLKP (0x1 << 8)
+-#define SMCR_SPIRE (0x1 << 2)
+-#define SMCR_SPIWE (0x1 << 1)
+-#define SMCR_SPIE (0x1)
+-
+-/* CMNSR */
+-#define CMNSR_TEND (0x1 << 0)
+-
+-/* SSLDR */
+-#define SSLDR_SPNDL(v) (((v) & 0x7) << 16)
+-#define SSLDR_SLNDL(v) ((((v) | 0x4) & 0x7) << 8)
+-#define SSLDR_SCKDL(v) ((v) & 0x7)
+-
+-/* DREAR */
+-#define DREAR_EAV_MASK (0xff << 16)
+-#define DREAR_EAV(v) (((v) & 0xff) << 16)
+-#define DREAR_EAC_MASK (0x7)
+-#define DREAR_24B (0)
+-#define DREAR_25B (1)
+-
+-/* DRENR */
+-#define DRENR_CDB_MASK (0x03 << 30)
+-#define DRENR_CDB(v) (((v) & 0x3) << 30)
+-#define DRENR_CDB_1B (0)
+-#define DRENR_CDB_2B (0x1 << 30)
+-#define DRENR_CDB_4B (0x2 << 30)
+-#define DRENR_OCDB_MASK (0x03 << 28)
+-#define DRENR_OCDB_1B (0)
+-#define DRENR_OCDB_2B (0x1 << 28)
+-#define DRENR_OCDB_4B (0x2 << 28)
+-#define DRENR_ADB_MASK (0x03 << 24)
+-#define DRENR_ADB(v) (((v) & 0x3) << 24)
+-#define DRENR_ADB_1B (0)
+-#define DRENR_ADB_2B (0x1 << 24)
+-#define DRENR_ADB_4B (0x2 << 24)
+-#define DRENR_OPDB_MASK (0x03 << 20)
+-#define DRENR_OPDB_1B (0)
+-#define DRENR_OPDB_2B (0x1 << 20)
+-#define DRENR_OPDB_4B (0x2 << 20)
+-#define DRENR_DRDB_MASK (0x03 << 16)
+-#define DRENR_DRDB(v) (((v) & 0x3) << 16)
+-#define DRENR_DRDB_1B (0)
+-#define DRENR_DRDB_2B (0x1 << 16)
+-#define DRENR_DRDB_4B (0x2 << 16)
+-#define DRENR_OPDE_MASK (0xf << 4)
+-#define DRENR_OPDE_DISABLE (0)
+-#define DRENR_OPDE3 (0x8 << 4)
+-#define DRENR_OPDE32 (0xC << 4)
+-#define DRENR_OPDE321 (0xE << 4)
+-#define DRENR_OPDE3210 (0xF << 4)
+-#define DRENR_DME (1<<15)
+-#define DRENR_CDE (1<<14)
+-#define DRENR_OCDE (1<<12)
+-#define DRENR_ADE_MASK (0xf << 8)
+-#define DRENR_ADE_DISABLE (0)
+-#define DRENR_ADE_23_0 (0x7 << 8)
+-#define DRENR_ADE_31_0 (0xf << 8)
+-
+-/* DRCMR */
+-#define DRCMR_CMD(cmd) (((cmd) & 0xff) << 16)
+-#define DRCMR_CMD_MASK (0xff << 16)
+-#define DRCMR_OCMD(cmd) (((cmd) & 0xff))
+-#define DRCMR_OCMD_MASK (0xff)
+-
+-/* DRCMR */
+-#define DRDMCR_DMCYC(v) ((v) & 0x1f)
+-#define DRDMCR_DMCYC_MASK (0x1f)
+-
+-/* SMDMCR */
+-#define SMDMCR_DMCYC(v) ((v) & 0x0f)
+-#define SMDMCR_DMCYC_MASK (0x0f)
+-
+-/* PHYOFFSET1 */
+-#define PHYOFFSET1_DDRTMG (1 << 28)
+-
+-/* DIVREG */
+-#define DIVREG_RATIO_MASK (0x03)
+-#define DIVREG_RATIO(v) ((v) & 0x03)
+-#define DIVREG_RATIO_MAX (0x2)
+-
+-
+-#define DEFAULT_TO (100)
+-#define WRITE_BUF_SIZE (0x100)
+-#define WRITE_BUF_ADR_MASK (0xff)
+-
+-#define REPEAT_MAX (20)
+-#define REPEAT_TIME (10)
+-
+-struct rpc_spi {
+- struct platform_device *pdev;
+- void __iomem *base;
+- void __iomem *read_area;
+- void __iomem *write_area;
+- dma_addr_t read_area_dma;
+- struct completion comp;
+- struct dma_chan *dma_chan;
+- struct clk *clk;
+- unsigned int irq;
+- struct spi_nor spi_nor;
+-
+-#define MTD_QSPI_1x 0
+-#define MTD_QSPI_2x 1
+-
+- u32 mtdtype;
+-};
+-
+-/* IP block use it's own clock divigion register */
+-#define OWN_CLOCK_DIVIDER BIT(0)
++#include <linux/of_device.h>
+
+-#define RPC_DMA_BURST ((DRCR_RBURST_32 + 1) << 3)
+-#define RPC_DMA_SIZE_MIN (RPC_DMA_BURST << 3)
++#include "renesas-rpc.h"
+
+ static bool use_dma = true;
+ module_param(use_dma, bool, 0);
+ MODULE_PARM_DESC(use_dma, "DMA support. 0 = Disable, 1 = Enable");
+
+-/* debug */
+-static void __maybe_unused regs_dump(struct rpc_spi *rpc)
++/* Debug */
++#ifdef DEBUG
++void rpc_regs_dump(struct rpc_info *rpc)
+ {
+ static u32 regs[] = {
+- CMNCR, SSLDR, DRCR, DRCMR, DREAR,
+- DROPR, DRENR, SMCR, SMCMR, SMADR,
+- SMOPR, SMENR, SMRDR0, SMRDR1, SMWDR0,
+- SMWDR1, CMNSR, DRDMCR, DRDRENR, SMDMCR,
+- SMDRENR, PHYCNT, PHYOFFSET1, PHYOFFSET2,
+- PHYINT
++ RPC_CMNCR, RPC_SSLDR, RPC_DRCR, RPC_DRCMR, RPC_DREAR,
++ RPC_DROPR, RPC_DRENR, RPC_SMCR, RPC_SMCMR, RPC_SMADR,
++ RPC_SMOPR, RPC_SMENR, RPC_SMRDR0, RPC_SMRDR1, RPC_SMWDR0,
++ RPC_SMWDR1, RPC_CMNSR, RPC_DRDMCR, RPC_DRDRENR, RPC_SMDMCR,
++ RPC_SMDRENR, RPC_PHYCNT, RPC_PHYOFFSET1, RPC_PHYOFFSET2,
++ RPC_PHYINT
+ };
+
+ static const char *const names[] = {
+@@ -291,23 +51,43 @@ static void __maybe_unused regs_dump(struct rpc_spi *rpc)
+ dev_dbg(&rpc->pdev->dev, "RPC regs dump:\n");
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ dev_dbg(&rpc->pdev->dev, "%s = 0x%08x\n", names[i],
+- readl(rpc->base + regs[i]));
++ rpc_readl(rpc, regs[i]));
++}
++EXPORT_SYMBOL(rpc_regs_dump);
++#endif
++
++/* Poll operation end */
++int rpc_wait(struct rpc_info *rpc, int timeout)
++{
++ unsigned long end = jiffies + msecs_to_jiffies(timeout);
++
++ while (!(rpc_readl(rpc, RPC_CMNSR) & RPC_CMNSR_TEND)) {
++ if (time_after(jiffies, end)) {
++ dev_err(&rpc->pdev->dev, "timed out\n");
++ return -ETIMEDOUT;
++ }
++
++ cpu_relax();
++ }
++
++ return 0;
+ }
++EXPORT_SYMBOL(rpc_wait);
+
++/* DMA support */
+ static void rpc_dma_complete_func(void *completion)
+ {
+ complete(completion);
+ }
+
+-static int rpc_dma_read(struct rpc_spi *rpc, void *buf,
+- loff_t from, ssize_t *plen)
++int rpc_dma_read(struct rpc_info *rpc, void *buf, loff_t from, ssize_t *plen)
+ {
+ struct dma_device *dma_dev;
+ enum dma_ctrl_flags flags;
+ dma_addr_t dma_dst_addr;
+ struct dma_async_tx_descriptor *tx = NULL;
+ dma_cookie_t cookie;
+- int retval = 0;
++ int ret = 0;
+ ssize_t len;
+
+ len = *plen;
+@@ -322,7 +102,7 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf,
+
+ dma_dst_addr = dma_map_single(dma_dev->dev, buf, len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma_dev->dev, dma_dst_addr)) {
+- dev_err(&rpc->pdev->dev, "Failed to dma_map_single\n");
++ dev_err(&rpc->pdev->dev, "DMA map single failed\n");
+ return -ENXIO;
+ }
+
+@@ -331,8 +111,8 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf,
+ rpc->read_area_dma + from,
+ len, flags);
+ if (!tx) {
+- dev_err(&rpc->pdev->dev, "Failed to prepare DMA memcpy\n");
+- retval = -EIO;
++ dev_err(&rpc->pdev->dev, "DMA prepare memcpy failed\n");
++ ret = -EIO;
+ goto out_dma;
+ }
+
+@@ -341,9 +121,9 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf,
+ tx->callback_param = &rpc->comp;
+
+ cookie = tx->tx_submit(tx);
+- retval = dma_submit_error(cookie);
+- if (retval) {
+- dev_err(&rpc->pdev->dev, "Failed to do DMA tx_submit\n");
++ ret = dma_submit_error(cookie);
++ if (ret) {
++ dev_err(&rpc->pdev->dev, "DMA tx submit failed\n");
+ goto out_dma;
+ }
+
+@@ -355,968 +135,154 @@ static int rpc_dma_read(struct rpc_spi *rpc, void *buf,
+
+ out_dma:
+ dma_unmap_single(dma_dev->dev, dma_dst_addr, len, DMA_FROM_DEVICE);
+- return retval;
+-}
+-
+-/* register acces */
+-static u32 rpc_read(struct rpc_spi *rpc, unsigned int reg)
+-{
+- u32 val;
+-
+- val = readl(rpc->base + reg);
+- return val;
+-}
+-
+-static void rpc_write(struct rpc_spi *rpc, unsigned int reg, u32 val)
+-{
+- writel(val, rpc->base + reg);
+-}
+-
+-static int rpc_wait(struct rpc_spi *rpc, u32 to)
+-{
+- u32 val;
+- int i;
+-
+- for (i = 0; i < to; i++) {
+- val = rpc_read(rpc, CMNSR);
+- val &= CMNSR_TEND;
+- if (val)
+- break;
+-
+- udelay(100);
+- }
+-
+- if (i == to) {
+- dev_err(&rpc->pdev->dev, "timeout waiting for operation end %d\n",
+- rpc_read(rpc, CMNSR));
+- return -ETIMEDOUT;
+- }
+-
+- return 0;
+-}
+-
+-static int rpc_setup_clk_ratio(struct rpc_spi *rpc, u32 max_clk_rate)
+-{
+- unsigned long rate = clk_get_rate(rpc->clk);
+- u32 ratio;
+- u32 val;
+-
+- ratio = DIV_ROUND_UP(rate, max_clk_rate * 2) >> 1;
+- if (ratio > DIVREG_RATIO_MAX)
+- ratio = DIVREG_RATIO_MAX;
+-
+- val = rpc_read(rpc, DIV_REG);
+- val &= DIVREG_RATIO_MASK;
+- val |= DIVREG_RATIO(ratio);
+- rpc_write(rpc, DIV_REG, val);
+-
+- return 0;
+-}
+-
+-static int rpc_endisable_write_buf(struct rpc_spi *rpc, bool en)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, PHYCNT);
+-
+- if (en)
+- val |= PHYCNT_WBUF | PHYCNT_WBUF2;
+- else
+- val &= ~(PHYCNT_WBUF | PHYCNT_WBUF2);
+-
+- rpc_write(rpc, PHYCNT, val);
+-
+- return 0;
+-}
+-
+-static int rpc_begin(struct rpc_spi *rpc,
+- bool rx, bool tx, bool last)
+-{
+- u32 val = SMCR_SPIE;
+-
+- if (rx)
+- val |= SMCR_SPIRE;
+-
+- if (tx)
+- val |= SMCR_SPIWE;
+-
+- if (!last)
+- val |= SMCR_SSLKP;
+-
+- rpc_write(rpc, SMCR, val);
+-
+- return 0;
+-}
+-
+-static int rpc_setup_reg_mode(struct rpc_spi *rpc)
+-{
+- u32 val;
+-
+- rpc_wait(rpc, DEFAULT_TO);
+-
+- rpc_endisable_write_buf(rpc, false);
+-
+- /* ...setup manual mode */
+- val = rpc_read(rpc, CMNCR);
+- val |= CMNCR_MD;
+- rpc_write(rpc, CMNCR, val);
+-
+- /* disable ddr */
+- val = rpc_read(rpc, SMDRENR);
+- val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE);
+- rpc_write(rpc, SMDRENR, val);
+-
+- /* enable 1bit command */
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_CDB_MASK | SMENR_OCDB_MASK | SMENR_DME
+- | SMENR_OCDE | SMENR_SPIDB_MASK
+- | SMENR_ADE_MASK | SMENR_ADB_MASK
+- | SMENR_OPDE_MASK | SMENR_SPIDE_MASK);
+- val |= SMENR_CDB_1B | SMENR_CDE | SMENR_SPIDE_32B;
+- rpc_write(rpc, SMENR, val);
+-
+-
+- return 0;
+-}
+-
+-static void rpc_flush_cache(struct rpc_spi *rpc)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, DRCR);
+- val |= DRCR_RCF;
+- rpc_write(rpc, DRCR, val);
+-}
+-
+-static int rpc_setup_ext_mode(struct rpc_spi *rpc)
+-{
+- u32 val;
+- u32 cmncr;
+-
+- rpc_wait(rpc, DEFAULT_TO);
+-
+- rpc_endisable_write_buf(rpc, false);
+-
+- /* ...setup ext mode */
+- val = rpc_read(rpc, CMNCR);
+- cmncr = val;
+- val &= ~(CMNCR_MD);
+- rpc_write(rpc, CMNCR, val);
+-
+- /* ...enable burst and clear cache */
+- val = rpc_read(rpc, DRCR);
+- val &= ~(DRCR_RBURST_MASK | DRCR_RBE | DRCR_SSLE);
+- val |= DRCR_RBURST(DRCR_RBURST_32) | DRCR_RBE;
+-
+- if (cmncr & CMNCR_MD)
+- val |= DRCR_RCF;
+-
+- rpc_write(rpc, DRCR, val);
+-
+- return 0;
+-}
+-
+-static int rpc_setup_data_size(struct rpc_spi *rpc, u32 size, bool copy)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_SPIDE_MASK);
+-
+- if (rpc->mtdtype == MTD_QSPI_2x && !copy)
+- size >>= 1;
+-
+- switch (size) {
+- case 0:
+- break;
+- case 1:
+- val |= SMENR_SPIDE_8B;
+- break;
+- case 2:
+- val |= SMENR_SPIDE_16B;
+- break;
+- case 4:
+- val |= SMENR_SPIDE_32B;
+- break;
+- default:
+- dev_err(&rpc->pdev->dev, "Unsupported data width %d\n", size);
+- return -EINVAL;
+- }
+- rpc_write(rpc, SMENR, val);
+-
+- return 0;
+-}
+-
+-static int rpc_setup_extmode_read_addr(struct rpc_spi *rpc,
+- int adr_width, loff_t adr)
+-{
+- u32 val;
+- u32 v;
+-
+- val = rpc_read(rpc, DREAR);
+- val &= ~(DREAR_EAV_MASK | DREAR_EAC_MASK);
+-
+- if (adr_width == 4) {
+- v = adr >> 25;
+- val |= DREAR_EAV(v) | DREAR_25B;
+- }
+- rpc_write(rpc, DREAR, val);
+-
+- val = rpc_read(rpc, DRENR);
+- val &= ~(DRENR_ADE_MASK);
+- if (adr_width == 4)
+- val |= DRENR_ADE_31_0;
+- else
+- val |= DRENR_ADE_23_0;
+- rpc_write(rpc, DRENR, val);
+-
+- return 0;
+-}
+-
+-static inline int rpc_get_read_addr_nbits(u8 opcode)
+-{
+- if (opcode == SPINOR_OP_READ_1_4_4_4B)
+- return 4;
+- return 1;
+-}
+-
+-#define NBITS_TO_VAL(v) ((v >> 1) & 3)
+-static int rpc_setup_extmode_nbits(struct rpc_spi *rpc, int cnb,
+- int anb, int dnb)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, DRENR);
+- val &= ~(DRENR_CDB_MASK | DRENR_ADB_MASK | DRENR_DRDB_MASK);
+- val |= DRENR_CDB(NBITS_TO_VAL(cnb))
+- | DRENR_ADB(NBITS_TO_VAL(anb))
+- | DRENR_DRDB(NBITS_TO_VAL(dnb));
+- rpc_write(rpc, DRENR, val);
+-
+- return 0;
+-}
+-
+-static int rpc_setup_writemode_nbits(struct rpc_spi *rpc, int cnb,
+- int anb, int dnb)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_CDB_MASK | SMENR_ADB_MASK | SMENR_SPIDB_MASK);
+- val |= SMENR_CDB(NBITS_TO_VAL(cnb))
+- | SMENR_ADB(NBITS_TO_VAL(anb))
+- | SMENR_SPIDB(NBITS_TO_VAL(dnb));
+- rpc_write(rpc, SMENR, val);
+-
+- return 0;
+-}
+-
+-static void rpc_setup_write_mode_command_and_adr(struct rpc_spi *rpc,
+- int adr_width, bool ena)
+-{
+- u32 val;
+-
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_CDB_MASK | SMENR_CDE | SMENR_ADE_MASK);
+-
+- if (ena) {
+- /* enable 1bit command */
+- val |= SMENR_CDB_1B | SMENR_CDE;
+-
+- if (adr_width == 4)
+- val |= SMENR_ADE_31_0;
+- else
+- val |= SMENR_ADE_23_0;
+- }
+- rpc_write(rpc, SMENR, val);
+-}
+-
+-static int rpc_setup_write_mode(struct rpc_spi *rpc, u8 opcode)
+-{
+- u32 val;
+-
+- rpc_wait(rpc, DEFAULT_TO);
+-
+- rpc_endisable_write_buf(rpc, true);
+-
+- /* ...setup manual mode */
+- val = rpc_read(rpc, CMNCR);
+- val |= CMNCR_MD;
+- rpc_write(rpc, CMNCR, val);
+-
+- /* disable ddr */
+- val = rpc_read(rpc, SMDRENR);
+- val &= ~(SMDRENR_ADDRE | SMDRENR_OPDRE | SMDRENR_SPIDRE);
+- rpc_write(rpc, SMDRENR, val);
+-
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_OCDB_MASK | SMENR_DME | SMENR_OCDE | SMENR_SPIDB_MASK
+- | SMENR_ADB_MASK | SMENR_OPDE_MASK | SMENR_SPIDE_MASK);
+- if (opcode != SPINOR_OP_PP)
+- val |= SMENR_SPIDE_32B;
+- else
+- val |= SMENR_SPIDE_8B;
+-
+- rpc_write(rpc, SMENR, val);
+-
+- return 0;
+-}
+-
+-static void rpc_read_manual_data(struct rpc_spi *rpc, u32 *pv0, u32 *pv1)
+-{
+- u32 val0, val1, rd0, rd1;
+-
+- val0 = rpc_read(rpc, SMRDR0);
+- val1 = rpc_read(rpc, SMRDR1);
+-
+- if (rpc->mtdtype == MTD_QSPI_2x) {
+- rd1 = (val0 & 0xff000000) | ((val0 << 8) & 0xff0000) |
+- ((val1 >> 16) & 0xff00) | ((val1 >> 8) & 0xff);
+- rd0 = ((val0 & 0xff0000) << 8) | ((val0 << 16) & 0xff0000) |
+- ((val1 >> 8) & 0xff00) | (val1 & 0xff);
+- } else
+- rd0 = val0;
+-
+- if (pv0)
+- *pv0 = rd0;
+-
+- if (pv1 && rpc->mtdtype == MTD_QSPI_2x)
+- *pv1 = rd1;
+-}
+-
+-static int rpc_datalen2trancfersize(struct rpc_spi *rpc, int len, bool copy)
+-{
+- int sz = len;
+-
+- if (len >= 2)
+- sz = 2;
+-
+- if (len >= 4)
+- sz = 4;
+-
+- if (rpc->mtdtype == MTD_QSPI_2x && len >= 8 && !copy)
+- sz = 8;
+-
+- return sz;
+-}
+-
+-static int __rpc_write_data2reg(struct rpc_spi *rpc, int off,
+- const u8 *buf, int sz)
+-{
+- const u32 *b32 = (const u32 *)buf;
+- const u16 *b16 = (const u16 *)buf;
+-
+- if (sz == 4)
+- rpc_write(rpc, off, *b32);
+- else if (sz == 2)
+- writew(*b16, rpc->base + off);
+- else if (sz == 1)
+- writeb(*buf, rpc->base + off);
+- else if (sz != 0) {
+- dev_err(&rpc->pdev->dev, "incorrect data size %d\n", sz);
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-#define __SETVAL(x) ((((x) & 0xff) << 8) | ((x) & 0xff))
+-static int rpc_write_data2reg(struct rpc_spi *rpc, const u8 *buf,
+- int sz, bool copy)
+-{
+- int i, ret;
+- u32 v = 0;
+-
+- if (rpc->mtdtype == MTD_QSPI_2x) {
+- if (copy) {
+- for (i = 0; i < sz && i < 2; i++)
+- v |= (__SETVAL(buf[i]) << 16*i);
+-
+- ret = __rpc_write_data2reg(rpc,
+- sz == 4 ? SMWDR1 : SMWDR0,
+- (u8 *)&v,
+- sz == 4 ? sz : sz * 2);
+- if (ret)
+- return ret;
+-
+- v = 0;
+- for (; i < sz; i++)
+- v |= (__SETVAL(buf[i]) << 16*i);
+-
+-
+- ret = __rpc_write_data2reg(rpc,
+- sz == 4 ? SMWDR0 : SMWDR1,
+- (u8 *)&v,
+- sz == 4 ? sz : sz * 2);
+- if (ret)
+- return ret;
+-
+- return 0;
+- }
+-
+- sz >>= 1;
+- ret = __rpc_write_data2reg(rpc,
+- sz == 4 ? SMWDR1 : SMWDR0,
+- buf,
+- sz == 4 ? sz : sz * 2);
+- if (ret)
+- return ret;
+- buf += sz;
+-
+- return __rpc_write_data2reg(rpc,
+- sz == 4 ? SMWDR0 : SMWDR1,
+- buf, sz == 4 ? sz : sz * 2);
+- }
+-
+- return __rpc_write_data2reg(rpc, SMWDR0, buf, sz);
+-}
+-
+-static ssize_t rpc_write_unaligned(struct spi_nor *nor, loff_t to, size_t len,
+- const u_char *buf, size_t fullen)
+-{
+- int ret = len, dsize;
+- struct rpc_spi *rpc = nor->priv;
+- bool copy = false, last;
+- loff_t _to;
+-
+- rpc_endisable_write_buf(rpc, false);
+-
+- while (len > 0) {
+- _to = to;
+- if (rpc->mtdtype == MTD_QSPI_2x)
+- _to >>= 1;
+- rpc_write(rpc, SMADR, _to);
+- dsize = rpc_datalen2trancfersize(rpc, len, copy);
+-
+- if (rpc_setup_data_size(rpc, dsize, copy))
+- return -EINVAL;
+-
+- rpc_write_data2reg(rpc, buf, dsize, copy);
+-
+- last = (len <= dsize && fullen <= ret);
+- rpc_begin(rpc, false, true, last);
+- if (rpc_wait(rpc, DEFAULT_TO))
+- return -ETIMEDOUT;
+-
+- /* ...disable command */
+- rpc_setup_write_mode_command_and_adr(rpc,
+- nor->addr_width, false);
+-
+- buf += dsize;
+- len -= dsize;
+- to += dsize;
+- }
+-
+ return ret;
+ }
++EXPORT_SYMBOL(rpc_dma_read);
+
+-static ssize_t rpc_write_flash(struct spi_nor *nor, loff_t to, size_t len,
+- const u_char *buf)
+-{
+- ssize_t res = len, full = len;
+- u32 val;
+- u8 rval[2];
+- struct rpc_spi *rpc = nor->priv;
+- loff_t bo;
+- loff_t offset;
+- bool is_rounded = false;
+-
+- /* ...len should be rounded to 2 bytes */
+- if (rpc->mtdtype == MTD_QSPI_2x && (len & 1)) {
+- is_rounded = true;
+- len &= ~(1);
+- }
+-
+- bo = to & (WRITE_BUF_ADR_MASK);
+-
+- rpc_flush_cache(rpc);
+- rpc_setup_write_mode(rpc, nor->program_opcode);
+- rpc_setup_write_mode_command_and_adr(rpc, nor->addr_width, true);
+- rpc_setup_writemode_nbits(rpc, 1, 1, 1);
+-
+- /* ...setup command */
+- val = rpc_read(rpc, SMCMR);
+- val &= ~(SMCMR_CMD_MASK);
+- val |= SMCMR_CMD(nor->program_opcode);
+- rpc_write(rpc, SMCMR, val);
+-
+- offset = (to & (~WRITE_BUF_ADR_MASK));
+-
+- /* ...write unaligned first bytes */
+- if (bo) {
+- size_t min = (len < (WRITE_BUF_SIZE - bo)) ? len : (WRITE_BUF_SIZE - bo);
+-
+- rpc_write_unaligned(nor, to, min, buf, full);
+- rpc_setup_write_mode(rpc, nor->program_opcode);
+-
+- len -= min;
+- buf += min;
+- to += min;
+- full -= min;
+- }
+-
+- /*
+- * TODO: Unfortunately RPC does not write properly in write buf mode
+- * without transferring command. Investigate this.
+- */
+-
+- if (len) {
+- rpc_write_unaligned(nor, to, len, buf, full);
+- buf += len;
+- to += len;
+- full -= len;
+- len = 0;
+- }
+-
+- if (is_rounded) {
+- rval[0] = *buf;
+- rval[1] = 0xFF;
+- rpc_write_unaligned(nor, to, 2, rval, full);
+- }
+-
+- rpc_flush_cache(rpc);
+-
+- return res;
+-}
+-
+-static inline unsigned int rpc_rx_nbits(struct spi_nor *nor)
+-{
+- return spi_nor_get_protocol_data_nbits(nor->read_proto);
+-}
+-
+-#define READ_ADR_MASK (BIT(26) - 1)
+-static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len,
+- u_char *buf)
++/* Read */
++void rpc_do_read_flash(struct rpc_info *rpc, loff_t from,
++ size_t len, u_char *buf, bool addr32)
+ {
+- u32 val;
+- struct rpc_spi *rpc = nor->priv;
+- int adr_width = nor->addr_width;
+- int opcode_nbits = 1;
+- int addr_nbits = rpc_get_read_addr_nbits(nor->read_opcode);
+- int data_nbits = rpc_rx_nbits(nor);
+- int dummy = nor->read_dummy - 1;
+- ssize_t ret = len;
+- ssize_t readlen;
+- loff_t _from;
+-
+- rpc_setup_ext_mode(rpc);
+- /* ...setup n bits */
+- rpc_setup_extmode_nbits(rpc, opcode_nbits, addr_nbits, data_nbits);
+-
+- /* TODO: setup DDR */
+-
+- /* ...setup command */
+- val = rpc_read(rpc, DRCMR);
+- val &= ~(DRCMR_CMD_MASK);
+- val |= DRCMR_CMD(nor->read_opcode);
+- rpc_write(rpc, DRCMR, val);
+-
+- /* ...setup dummy cycles */
+- val = rpc_read(rpc, DRDMCR);
+- val &= ~(DRDMCR_DMCYC_MASK);
+- val |= DRDMCR_DMCYC(dummy);
+- rpc_write(rpc, DRDMCR, val);
+-
+- /* ...setup read sequence */
+- val = rpc_read(rpc, DRENR);
+- val |= DRENR_DME | DRENR_CDE;
+- rpc_write(rpc, DRENR, val);
+-
+ while (len > 0) {
+- int retval;
+-
+- /* ...setup address */
+- rpc_setup_extmode_read_addr(rpc, adr_width, from);
+- /* ...use adr [25...0] */
+- _from = from & READ_ADR_MASK;
+-
+- readlen = READ_ADR_MASK - _from + 1;
++ ssize_t readlen;
++ loff_t _from;
++ int ret;
++
++ /* Setup ext mode address */
++ rpc_clrsetl(rpc, RPC_DREAR,
++ RPC_DREAR_EAV(0xFF) | RPC_DREAR_EAC(7),
++ addr32 ?
++ RPC_DREAR_EAV(from >> 25) | RPC_DREAR_EAC(1) :
++ 0);
++
++ rpc_clrsetl(rpc, RPC_DRENR,
++ RPC_DRENR_ADE(0xF),
++ addr32 ?
++ /* bits 31-0 */
++ RPC_DRENR_ADE(0xF) :
++ /* bits 23-0 */
++ RPC_DRENR_ADE(0x7));
++
++ /* Use address bits [25...0] */
++ _from = from & RPC_READ_ADDR_MASK;
++
++ readlen = RPC_READ_ADDR_MASK - _from + 1;
+ readlen = readlen > len ? len : readlen;
+
+- retval = rpc_dma_read(rpc, buf, _from, &readlen);
+- if (retval)
++ ret = rpc_dma_read(rpc, buf, _from, &readlen);
++ if (ret)
+ memcpy_fromio(buf, rpc->read_area + _from, readlen);
+
+ buf += readlen;
+ from += readlen;
+ len -= readlen;
+ }
+-
+- return ret;
+-}
+-
+-static int __rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+-{
+- u32 val;
+- u32 val2 = 0;
+- u32 *buf32;
+- int i;
+- u32 mask = 0, type;
+- struct rpc_spi *rpc = nor->priv;
+-
+- type = rpc->mtdtype;
+-
+- rpc_setup_reg_mode(rpc);
+- val = rpc_read(rpc, SMCMR);
+- val &= ~(SMCMR_CMD_MASK);
+- val |= SMCMR_CMD(opcode);
+- rpc_write(rpc, SMCMR, val);
+-
+- rpc_begin(rpc, true, false, len <= 4);
+- if (rpc_wait(rpc, DEFAULT_TO))
+- return -ETIMEDOUT;
+-
+- /* ...disable command */
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_CDE);
+- rpc_write(rpc, SMENR, val);
+-
+- buf32 = (u32 *)buf;
+-
+- while (len > 0) {
+- rpc_read_manual_data(rpc, &val, &val2);
+-
+- if (mask) {
+- dev_warn(&rpc->pdev->dev,
+- "Using mask workaround (0x%x)\n", mask);
+- val &= ~(mask);
+- val2 &= ~(mask);
+- }
+-
+- /* ... spi flashes should be the same */
+- if (type == MTD_QSPI_2x && val != val2) {
+- /* clear cs */
+- rpc_begin(rpc, true, false, true);
+- return -EAGAIN;
+- }
+-
+- if (len > 4) {
+- *buf32 = val;
+- buf32++;
+- len -= 4;
+- } else {
+- buf = (u8 *)buf32;
+- for (i = 0; i < len; i++) {
+- *buf = (val >> (8 * i)) & 0x000000ff;
+- buf++;
+- }
+- len = 0;
+- }
+-
+- if (!len)
+- break;
+-
+- mask = 0xff;
+-
+- rpc_begin(rpc, true, false, len <= 4);
+- if (rpc_wait(rpc, DEFAULT_TO))
+- return -ETIMEDOUT;
+-
+- }
+-
+- return 0;
+-}
+-
+-static int rpc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+-{
+- int i, ret;
+-
+- /* A few read commands like read status can
+- * generate different answers. We repeat reading
+- * in that case
+- */
+- for (i = 0; i < REPEAT_MAX; i++) {
+- ret = __rpc_read_reg(nor, opcode, buf, len);
+- if (!ret || ret != -EAGAIN)
+- break;
+- mdelay(REPEAT_TIME);
+- }
+-
+- return ret;
+-}
+-
+-static int rpc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+-{
+- struct rpc_spi *rpc = nor->priv;
+- u32 val;
+- int dsize;
+- bool copy = true;
+-
+- rpc_setup_reg_mode(rpc);
+-
+- val = rpc_read(rpc, SMCMR);
+- val &= ~(SMCMR_CMD_MASK);
+- val |= SMCMR_CMD(opcode);
+- rpc_write(rpc, SMCMR, val);
+-
+- dsize = rpc_datalen2trancfersize(rpc, len, copy);
+-
+- if (rpc_setup_data_size(rpc, dsize, copy))
+- return -EINVAL;
+-
+- if (rpc_write_data2reg(rpc, buf, dsize, copy))
+- return -EINVAL;
+- buf += dsize;
+- len -= dsize;
+- rpc_begin(rpc, false, dsize > 0, len == 0);
+-
+- if (rpc_wait(rpc, DEFAULT_TO))
+- return -ETIMEDOUT;
+-
+- /* ...disable command */
+- val = rpc_read(rpc, SMENR);
+- val &= ~(SMENR_CDE);
+- rpc_write(rpc, SMENR, val);
+-
+- while (len > 0) {
+- dsize = rpc_datalen2trancfersize(rpc, len, copy);
+- if (rpc_setup_data_size(rpc, dsize, copy))
+- return -EINVAL;
+- rpc_write_data2reg(rpc, buf, dsize, copy);
+- buf += dsize;
+- len -= dsize;
+-
+- rpc_begin(rpc, false, dsize, len == 0);
+-
+- if (rpc_wait(rpc, DEFAULT_TO))
+- return -ETIMEDOUT;
+-
+- }
+-
+- return 0;
+ }
++EXPORT_SYMBOL(rpc_do_read_flash);
+
+-/* hw init for spi-nor flashes */
+-static int rpc_hw_init_1x2x(struct rpc_spi *rpc)
++/* Own clock setup */
++static int rpc_own_clk_set_rate(struct rpc_info *rpc, u32 max_clk_rate)
+ {
+- u32 val;
+-
+- /* Exec calibration */
+- val = rpc_read(rpc, PHYCNT);
+- val &= ~(PHYCNT_OCTA_MASK | PHYCNT_EXDS | PHYCNT_OCT
+- | PHYCNT_DDRCAL | PHYCNT_HS | PHYCNT_STREAM_MASK
+- | PHYCNT_WBUF2 | PHYCNT_WBUF | PHYCNT_PHYMEM_MASK);
+- val |= (PHYCNT_CAL) | PHYCNT_STREAM(6);
+- rpc_write(rpc, PHYCNT, val);
+-
+- /* disable rpc_* pins */
+- val = rpc_read(rpc, PHYINT);
+- val &= ~((1<<24) | (7<<16));
+- rpc_write(rpc, PHYINT, val);
+-
+- val = rpc_read(rpc, SMDRENR);
+- val &= ~(SMDRENR_HYPE_MASK);
+- val |= SMDRENR_HYPE_SPI_FLASH;
+- rpc_write(rpc, SMDRENR, val);
+-
+- val = rpc_read(rpc, CMNCR);
+- val &= ~(CMNCR_BSZ_MASK);
+- if (rpc->mtdtype != MTD_QSPI_1x)
+- val |= CMNCR_BSZ_4x2;
+- rpc_write(rpc, CMNCR, val);
+-
+- val = rpc_read(rpc, PHYOFFSET1);
+- val |= PHYOFFSET1_DDRTMG;
+- rpc_write(rpc, PHYOFFSET1, val);
++ unsigned long rate = clk_get_rate(rpc->clk);
++ u32 ratio;
+
+- val = SSLDR_SPNDL(0) | SSLDR_SLNDL(4) | SSLDR_SCKDL(0);
+- rpc_write(rpc, SSLDR, val);
++ ratio = DIV_ROUND_UP(rate, max_clk_rate * 2) >> 1;
++ if (ratio > RPC_DIVREG_RATIO_MAX)
++ ratio = RPC_DIVREG_RATIO_MAX;
+
++ rpc_clrsetl(rpc, RPC_DIVREG,
++ RPC_DIVREG_RATIO(0x3),
++ RPC_DIVREG_RATIO(ratio));
+ return 0;
+ }
+
+-static int rpc_hw_init(struct rpc_spi *rpc)
+-{
+- switch (rpc->mtdtype) {
+- case MTD_QSPI_1x:
+- case MTD_QSPI_2x:
+- return rpc_hw_init_1x2x(rpc);
+-
+- default:
+- dev_err(&rpc->pdev->dev, "Unsupported connection mode\n");
+- return -ENODEV;
+- }
+-}
+-
+-static int rpc_erase_sector(struct spi_nor *nor, loff_t addr)
+-{
+- struct rpc_spi *rpc = nor->priv;
+- u8 buf[6];
+- int i;
+-
+- if (rpc->mtdtype == MTD_QSPI_2x)
+- addr >>= 1;
+-
+- for (i = nor->addr_width - 1; i >= 0; i--) {
+- buf[i] = addr & 0xff;
+- addr >>= 8;
+- }
+-
+- return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
+-}
+-
+-static const struct of_device_id rpc_of_match[] = {
+- { .compatible = "renesas,qspi-rpc-r8a77980" },
+- { .compatible = "renesas,qspi-rpc-r8a77970", .data = (void *)OWN_CLOCK_DIVIDER },
+- { },
+-};
+-
+-MODULE_DEVICE_TABLE(of, rpc_of_match);
+-
+-static int rpc_spi_probe(struct platform_device *pdev)
++static int rpc_probe(struct platform_device *pdev)
+ {
+- struct device_node *flash_np;
+- struct spi_nor *nor;
+- struct rpc_spi *rpc;
++ struct rpc_info *rpc;
+ struct resource *res;
+- struct spi_nor_hwcaps hwcaps = {
+- .mask = SNOR_HWCAPS_READ |
+- SNOR_HWCAPS_READ_FAST |
+- SNOR_HWCAPS_PP,
+- };
+- u32 max_clk_rate = 50000000;
+- u32 property;
++ const char *name = NULL;
++ u32 rate = 0;
+ int ret;
+- int own_clk;
+-
+-
+- flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
+- if (!flash_np) {
+- dev_err(&pdev->dev, "no SPI flash device to configure\n");
+- return -ENODEV;
+- }
+-
+- if (!of_property_read_u32(flash_np, "spi-rx-bus-width", &property)) {
+- switch (property) {
+- case 1:
+- break;
+- case 2:
+- hwcaps.mask |= SNOR_HWCAPS_READ_DUAL;
+- break;
+- case 4:
+- hwcaps.mask |= SNOR_HWCAPS_READ_QUAD;
+- break;
+- default:
+- dev_err(&pdev->dev, "unsupported rx-bus-width\n");
+- return -EINVAL;
+- }
+- }
+-
+- of_property_read_u32(flash_np, "spi-max-frequency", &max_clk_rate);
+- own_clk = (of_device_get_match_data(&pdev->dev) == (void *)OWN_CLOCK_DIVIDER);
+
+ rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL);
+- if (!rpc)
++ if (!rpc) {
++ dev_err(&pdev->dev, "allocation failed\n");
+ return -ENOMEM;
+-
+- rpc->pdev = pdev;
+-
+- /* ... setup nor hooks */
+- nor = &rpc->spi_nor;
+- nor->dev = &pdev->dev;
+- spi_nor_set_flash_node(nor, flash_np);
+- nor->read = rpc_read_flash;
+- nor->write = rpc_write_flash;
+- nor->read_reg = rpc_read_reg;
+- nor->write_reg = rpc_write_reg;
+- nor->priv = rpc;
+- rpc->mtdtype = MTD_QSPI_1x;
+-
+- if (of_find_property(pdev->dev.of_node, "dual", NULL)) {
+- rpc->mtdtype = MTD_QSPI_2x;
+- nor->erase = rpc_erase_sector;
+ }
+
+- /* ...get memory */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rpc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rpc->base)) {
+- dev_err(&pdev->dev, "cannot get resources\n");
+- ret = PTR_ERR(rpc->base);
+- goto error;
++ dev_err(&pdev->dev, "cannot get base resource\n");
++ return PTR_ERR(rpc->base);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-
+- rpc->read_area_dma = res->start;
+ rpc->read_area = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(rpc->base)) {
+- dev_err(&pdev->dev, "cannot get resources\n");
+- ret = PTR_ERR(rpc->base);
+- goto error;
++ if (IS_ERR(rpc->read_area)) {
++ dev_err(&pdev->dev, "cannot get read resource\n");
++ return PTR_ERR(rpc->read_area);
++ }
++
++ if (resource_size(res) & RPC_READ_ADDR_MASK) {
++ dev_err(&pdev->dev, "invalid read resource\n");
++ return -EINVAL;
+ }
+
+- /* ...get memory */
++ rpc->read_area_dma = res->start;
++
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ rpc->write_area = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(rpc->base)) {
+- dev_err(&pdev->dev, "cannot get resources\n");
+- ret = PTR_ERR(rpc->base);
+- goto error;
++ if (IS_ERR(rpc->write_area)) {
++ dev_warn(&pdev->dev, "cannot get write resource\n");
++ rpc->write_area = NULL;
+ }
+
+- /* ...get clk */
+ rpc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rpc->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+- ret = PTR_ERR(rpc->clk);
+- goto error;
++ return PTR_ERR(rpc->clk);
+ }
+
+- /* ...set max clk rate */
+- if (!own_clk) {
+- ret = clk_set_rate(rpc->clk, max_clk_rate);
+- if (ret) {
+- dev_err(&pdev->dev, "cannot set clock rate\n");
+- goto error;
+- }
++ rpc->flash = of_get_next_available_child(pdev->dev.of_node, NULL);
++ if (!rpc->flash) {
++ dev_err(&pdev->dev, "no flash device to configure\n");
++ return -ENOTSUPP;
+ }
+
+- /* ... enable clk */
+- ret = clk_prepare_enable(rpc->clk);
+- if (ret) {
+- dev_err(&pdev->dev, "cannot prepare clock\n");
+- goto error;
++ rpc->mtdtype = of_find_property(pdev->dev.of_node, "dual", NULL) ?
++ RPC_DUAL : RPC_SINGLE;
++
++ of_property_read_u32(rpc->flash, "spi-max-frequency", &rate);
++
++ if (of_device_is_compatible(rpc->flash, "jedec,spi-nor")) {
++ name = "renesas-rpc-qspi";
++ if (!rate)
++ rate = 50000000;
++ } else if (of_device_is_compatible(rpc->flash, "cfi-flash")) {
++ rpc->mtdtype = RPC_DUAL;
++ name = "renesas-rpc-hyperflash";
++ if (!rate)
++ rate = 80000000;
+ }
+
+- /* ...init device */
+- ret = rpc_hw_init(rpc);
+- if (ret < 0) {
+- dev_err(&pdev->dev, "rpc_hw_init error.\n");
+- goto error_clk_disable;
++ if (!name) {
++ dev_err(&pdev->dev, "no supported flash device detected\n");
++ ret = -ENODEV;
++ goto error;
+ }
+
+- /* ...set clk ratio */
+- if (own_clk) {
+- ret = rpc_setup_clk_ratio(rpc, max_clk_rate);
++ if (rate) {
++ ret = of_device_is_compatible(pdev->dev.of_node,
++ "renesas,rpc-r8a77970") ?
++ rpc_own_clk_set_rate(rpc, rate) :
++ clk_set_rate(rpc->clk, rate);
+ if (ret) {
+- dev_err(&pdev->dev, "cannot set clock ratio\n");
++ dev_err(&pdev->dev, "clock rate setup failed\n");
+ goto error;
+ }
+ }
+
+- platform_set_drvdata(pdev, rpc);
+-
+- ret = spi_nor_scan(nor, NULL, &hwcaps);
+- if (ret) {
+- dev_err(&pdev->dev, "spi_nor_scan error.\n");
+- goto error_clk_disable;
+- }
+-
+- /* Dual mode support */
+- if (rpc->mtdtype == MTD_QSPI_2x) {
+- nor->page_size <<= 1;
+- nor->mtd.erasesize <<= 1;
+- nor->mtd.size <<= 1;
+- nor->mtd.writebufsize <<= 1;
+- }
+-
+- /* Workaround data size limitation */
+- if (nor->page_size > WRITE_BUF_SIZE) {
+- nor->page_size = WRITE_BUF_SIZE;
+- nor->mtd.writebufsize = WRITE_BUF_SIZE;
+- }
+-
+ if (use_dma) {
+ dma_cap_mask_t mask;
+
+@@ -1324,58 +290,70 @@ static int rpc_spi_probe(struct platform_device *pdev)
+ dma_cap_set(DMA_MEMCPY, mask);
+ rpc->dma_chan = dma_request_channel(mask, NULL, NULL);
+ if (!rpc->dma_chan)
+- dev_warn(&pdev->dev, "Failed to request DMA channel\n");
++ dev_warn(&pdev->dev, "DMA channel request failed\n");
+ else
+- dev_info(&pdev->dev, "Using DMA read (%s)\n",
++ dev_info(&pdev->dev, "using DMA read (%s)\n",
+ dma_chan_name(rpc->dma_chan));
+ }
+
+- ret = mtd_device_register(&nor->mtd, NULL, 0);
+- if (ret) {
+- dev_err(&pdev->dev, "mtd_device_register error.\n");
+- goto error_dma;
++ platform_set_drvdata(pdev, rpc);
++ rpc->pdev = platform_device_register_data(&pdev->dev, name, -1, NULL, 0);
++ if (IS_ERR(rpc->pdev)) {
++ dev_err(&pdev->dev, "%s device registration failed\n", name);
++ ret = PTR_ERR(rpc->pdev);
++ goto error;
+ }
+
+- dev_info(&pdev->dev, "probed as %s\n",
+- rpc->mtdtype == MTD_QSPI_1x ? "single" : "dual");
+-
+ return 0;
+
+-error_dma:
++error:
+ if (rpc->dma_chan)
+ dma_release_channel(rpc->dma_chan);
+-error_clk_disable:
+- clk_disable_unprepare(rpc->clk);
+-error:
++
++ of_node_put(rpc->flash);
+ return ret;
+ }
+
+-static int rpc_spi_remove(struct platform_device *pdev)
++static int rpc_remove(struct platform_device *pdev)
+ {
+- struct rpc_spi *rpc = platform_get_drvdata(pdev);
++ struct rpc_info *rpc = platform_get_drvdata(pdev);
+
+- /* HW shutdown */
+- clk_disable_unprepare(rpc->clk);
+- mtd_device_unregister(&rpc->spi_nor.mtd);
++ if (rpc->pdev)
++ platform_device_unregister(rpc->pdev);
+ if (rpc->dma_chan)
+ dma_release_channel(rpc->dma_chan);
++ if (rpc->flash)
++ of_node_put(rpc->flash);
++
+ return 0;
+ }
+
++static const struct of_device_id rpc_of_match[] = {
++ { .compatible = "renesas,rpc-r8a7795" },
++ { .compatible = "renesas,rpc-r8a7796" },
++ { .compatible = "renesas,rpc-r8a77965" },
++ {
++ .compatible = "renesas,rpc-r8a77970",
++ .data = (void *)RPC_OWN_CLOCK_DIVIDER,
++ },
++ { .compatible = "renesas,rpc-r8a77980" },
++ { },
++};
++
+ /* platform driver interface */
+ static struct platform_driver rpc_platform_driver = {
+- .probe = rpc_spi_probe,
+- .remove = rpc_spi_remove,
++ .probe = rpc_probe,
++ .remove = rpc_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+- .name = "rpc",
++ .name = "renesas-rpc",
+ .of_match_table = of_match_ptr(rpc_of_match),
+ },
+ };
+
+ module_platform_driver(rpc_platform_driver);
+
+-MODULE_ALIAS("rpc");
++MODULE_ALIAS("renesas-rpc");
+ MODULE_AUTHOR("Cogent Embedded Inc. <sources@cogentembedded.com>");
+ MODULE_DESCRIPTION("Renesas RPC Driver");
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/mtd/spi-nor/renesas-rpc.h b/drivers/mtd/spi-nor/renesas-rpc.h
+new file mode 100644
+index 0000000..e500a62
+--- /dev/null
++++ b/drivers/mtd/spi-nor/renesas-rpc.h
+@@ -0,0 +1,267 @@
++/*
++ * Renesas RPC driver
++ *
++ * Copyright (C) 2019, Cogent Embedded Inc.
++ *
++ * 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; version 2 of the License.
++ *
++ * 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.
++ */
++
++#ifndef __RENESAS_RPC_H__
++#define __RENESAS_RPC_H__
++
++#include <linux/clk.h>
++#include <linux/dmaengine.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++
++/* RPC */
++#define RPC_CMNCR 0x0000 /* R/W */
++#define RPC_CMNCR_MD (0x1 << 31)
++#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
++#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
++#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
++#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
++#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
++ RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
++#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
++#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
++#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
++#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
++ RPC_CMNCR_IO3FV(3))
++#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
++
++#define RPC_SSLDR 0x0004 /* R/W */
++#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
++#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
++#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
++
++#define RPC_DRCR 0x000C /* R/W */
++#define RPC_DRCR_SSLN (0x1 << 24)
++#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
++#define RPC_DRCR_RCF (0x1 << 9)
++#define RPC_DRCR_RBE (0x1 << 8)
++#define RPC_DRCR_SSLE (0x1 << 0)
++
++#define RPC_DRCMR 0x0010 /* R/W */
++#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
++#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
++
++#define RPC_DREAR 0x0014 /* R/W */
++#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
++#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
++
++#define RPC_DROPR 0x0018 /* R/W */
++#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
++#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
++#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
++#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
++
++#define RPC_DRENR 0x001C /* R/W */
++#define RPC_DRENR_CDB(o) (((o) & 0x3) << 30)
++#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
++#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
++#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
++#define RPC_DRENR_DRDB(o) (((o) & 0x3) << 16)
++#define RPC_DRENR_DME (0x1 << 15)
++#define RPC_DRENR_CDE (0x1 << 14)
++#define RPC_DRENR_OCDE (0x1 << 12)
++#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
++#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
++
++#define RPC_SMCR 0x0020 /* R/W */
++#define RPC_SMCR_SSLKP (0x1 << 8)
++#define RPC_SMCR_SPIRE (0x1 << 2)
++#define RPC_SMCR_SPIWE (0x1 << 1)
++#define RPC_SMCR_SPIE (0x1 << 0)
++
++#define RPC_SMCMR 0x0024 /* R/W */
++#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
++#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
++
++#define RPC_SMADR 0x0028 /* R/W */
++#define RPC_SMOPR 0x002C /* R/W */
++#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
++#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
++#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
++#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
++
++#define RPC_SMENR 0x0030 /* R/W */
++#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
++#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
++#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
++#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
++#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
++#define RPC_SMENR_DME (0x1 << 15)
++#define RPC_SMENR_CDE (0x1 << 14)
++#define RPC_SMENR_OCDE (0x1 << 12)
++#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
++#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
++#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
++
++#define RPC_SMRDR0 0x0038 /* R */
++#define RPC_SMRDR1 0x003C /* R */
++#define RPC_SMWDR0 0x0040 /* R/W */
++#define RPC_SMWDR1 0x0044 /* R/W */
++#define RPC_CMNSR 0x0048 /* R */
++#define RPC_CMNSR_SSLF (0x1 << 1)
++#define RPC_CMNSR_TEND (0x1 << 0)
++
++#define RPC_DRDMCR 0x0058 /* R/W */
++#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
++
++#define RPC_DRDRENR 0x005C /* R/W */
++#define RPC_DRDRENR_HYPE (0x5 << 12)
++#define RPC_DRDRENR_ADDRE (0x1 << 0x8)
++#define RPC_DRDRENR_OPDRE (0x1 << 0x4)
++#define RPC_DRDRENR_DRDRE (0x1 << 0x0)
++
++#define RPC_SMDMCR 0x0060 /* R/W */
++#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
++
++#define RPC_SMDRENR 0x0064 /* R/W */
++#define RPC_SMDRENR_HYPE(v) (((v) & 0x7) << 12)
++#define RPC_SMDRENR_HYPE_HF RPC_SMDRENR_HYPE(0x5)
++#define RPC_SMDRENR_HYPE_SPI RPC_SMDRENR_HYPE(0)
++#define RPC_SMDRENR_ADDRE (0x1 << 0x8)
++#define RPC_SMDRENR_OPDRE (0x1 << 0x4)
++#define RPC_SMDRENR_SPIDRE (0x1 << 0x0)
++
++#define RPC_PHYCNT 0x007C /* R/W */
++#define RPC_PHYCNT_CAL (0x1 << 31)
++#define RPC_PHYCNT_OCTA(v) (((v) & 0x3) << 22)
++#define RPC_PHYCNT_OCTA_AA (0x1 << 22)
++#define RPC_PHYCNT_OCTA_SA (0x2 << 22)
++#define RPC_PHYCNT_EXDS (0x1 << 21)
++#define RPC_PHYCNT_OCT (0x1 << 20)
++#define RPC_PHYCNT_DDRCAL (0x1 << 19)
++#define RPC_PHYCNT_HS (0x1 << 18)
++#define RPC_PHYCNT_STRTIM(v) (((v) & 0x7) << 15)
++#define RPC_PHYCNT_WBUF2 (0x1 << 4)
++#define RPC_PHYCNT_WBUF (0x1 << 2)
++#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
++
++#define RPC_PHYINT 0x0088 /* R/W */
++#define RPC_PHYINT_INTIE (0x1 << 24)
++#define RPC_PHYINT_RSTEN (0x1 << 18)
++#define RPC_PHYINT_WPEN (0x1 << 17)
++#define RPC_PHYINT_INTEN (0x1 << 16)
++#define RPC_PHYINT_RST (0x1 << 2)
++#define RPC_PHYINT_WP (0x1 << 1)
++#define RPC_PHYINT_INT (0x1 << 0)
++
++#define RPC_PHYOFFSET1 0x0080
++#define RPC_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28)
++#define RPC_PHYOFFSET1_DDRTMG_SDR RPC_PHYOFFSET1_DDRTMG(3)
++#define RPC_PHYOFFSET1_DDRTMG_DDR RPC_PHYOFFSET1_DDRTMG(2)
++
++#define RPC_PHYOFFSET2 0x0084
++#define RPC_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8)
++#define RPC_PHYOFFSET2_OCTAL RPC_PHYOFFSET2_OCTTMG(3)
++#define RPC_PHYOFFSET2_SERIAL RPC_PHYOFFSET2_OCTTMG(4)
++
++#define RPC_DIVREG 0x00A8
++#define RPC_DIVREG_RATIO(v) ((v) & 0x03)
++#define RPC_DIVREG_RATIO_MAX (0x2)
++
++#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
++#define RPC_WBUF_SIZE 0x100
++#define RPC_WBUF_MASK (RPC_WBUF_SIZE - 1)
++
++/* DMA transfer */
++#define RPC_DMA_BURST (0x20 << 3)
++#define RPC_DMA_SIZE_MIN (RPC_DMA_BURST << 3)
++
++#define RPC_READ_ADDR_SIZE BIT(26)
++#define RPC_READ_ADDR_MASK (RPC_READ_ADDR_SIZE - 1)
++
++/* Default timeout in mS */
++#define RPC_TIMEOUT 5000
++
++/* Device flags */
++#define RPC_OWN_CLOCK_DIVIDER BIT(0)
++
++enum rpc_size {
++ /* singe flash: 8 bit; dual flash: 16 bit */
++ RPC_SIZE_SINGLE_8BIT = RPC_SMENR_SPIDE(0x8),
++ RPC_SIZE_DUAL_16BIT = RPC_SMENR_SPIDE(0x8),
++ /* singe flash: 16 bit; dual flash: 32 bit */
++ RPC_SIZE_SINGLE_16BIT = RPC_SMENR_SPIDE(0xC),
++ RPC_SIZE_DUAL_32BIT = RPC_SMENR_SPIDE(0xC),
++ /* singe flash: 32 bit; dual flash: 64 bit */
++ RPC_SIZE_SINGLE_32BIT = RPC_SMENR_SPIDE(0xF),
++ RPC_SIZE_DUAL_64BIT = RPC_SMENR_SPIDE(0xF),
++};
++
++enum rpc_type {
++ RPC_SINGLE = 0,
++ RPC_DUAL,
++};
++
++struct rpc_info {
++ struct platform_device *pdev;
++ struct device_node *flash;
++ void __iomem *base;
++ void __iomem *read_area;
++ void __iomem *write_area;
++ dma_addr_t read_area_dma;
++ struct completion comp;
++ struct dma_chan *dma_chan;
++ struct clk *clk;
++ unsigned int irq;
++ enum rpc_type mtdtype;
++};
++
++/* Register access */
++static inline u32 rpc_readl(struct rpc_info *rpc, u32 offset)
++{
++ return readl(rpc->base + offset);
++}
++
++static inline void rpc_writel(struct rpc_info *rpc, u32 offset, u32 val)
++{
++ writel(val, rpc->base + offset);
++}
++
++static inline void rpc_clrsetl(struct rpc_info *rpc, u32 offset,
++ u32 clr, u32 set)
++{
++ void __iomem *addr = rpc->base + offset;
++ u32 val = readl(addr);
++
++ val &= ~clr;
++ val |= set;
++ writel(val, addr);
++}
++
++static inline void rpc_wbuf_writel(struct rpc_info *rpc, u32 offset, u32 val)
++{
++ writel(val, rpc->write_area + offset);
++}
++
++/* Check whether write buffer should be used */
++static inline bool rpc_wbuf_available(struct rpc_info *rpc)
++{
++ return rpc->write_area;
++}
++
++#ifdef DEBUG
++extern void rpc_regs_dump(struct rpc_info *rpc);
++#else
++static inline void rpc_regs_dump(struct rpc_info *rpc) { }
++#endif
++
++extern int rpc_wait(struct rpc_info *rpc, int timeout);
++extern int rpc_dma_read(struct rpc_info *rpc, void *buf,
++ loff_t from, ssize_t *plen);
++extern void rpc_do_read_flash(struct rpc_info *rpc, loff_t from,
++ size_t len, u_char *buf, bool addr32);
++#endif
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch
new file mode 100644
index 00000000..fba99bf0
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch
@@ -0,0 +1,72 @@
+From 0bfdc760d2cfb3e2c3800310018ac561df458337 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:11:03 +0300
+Subject: [PATCH 06/12] arm64: dts: renesas: r8a77970: Update RPC device nodes
+
+This updates RPC device nodes for the consolidated RPC driver.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77970-eagle.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77970.dtsi | 4 ++--
+ 4 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
+index aa4c65a..5a736aa 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts
+@@ -421,7 +421,7 @@
+ };
+ };
+
+-&qspi0 {
++&rpc0 {
+ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
+ pinctrl-names = "default";
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts
+index d6deffe..fad6654 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts
+@@ -195,7 +195,7 @@
+ };
+ };
+
+-&qspi0 {
++&rpc0 {
+ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
+ pinctrl-names = "default";
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts
+index caecf8c..cabbb0f 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3mzf.dts
+@@ -399,7 +399,7 @@
+ };
+ };
+
+-&qspi0 {
++&rpc0 {
+ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
+ pinctrl-names = "default";
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970.dtsi b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+index 456eeb6..603efeb 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a77970.dtsi
+@@ -767,8 +767,8 @@
+ status = "disabled";
+ };
+
+- qspi0: qspi@ee200000 {
+- compatible = "renesas,qspi-rpc-r8a77970";
++ rpc0: qspi@ee200000 {
++ compatible = "renesas,rpc-r8a77970";
+ reg = <0 0xee200000 0 0x1f0>,
+ <0 0x08000000 0 0x04000000>,
+ <0 0xee208000 0 0x100>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch
new file mode 100644
index 00000000..4268ffa4
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch
@@ -0,0 +1,58 @@
+From a7ac55ef8c0a09f15977a5ea6d7d8558e6d23c93 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:22:47 +0300
+Subject: [PATCH 07/12] arm64: dts: renesas: r8a77980: Update RPC device nodes
+
+This updates RPC device nodes for the consolidated RPC driver.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77980-condor.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77980.dtsi | 4 ++--
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
+index a60482a..1ba48ad 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
+@@ -651,7 +651,7 @@
+ };
+ };
+
+-&qspi0 {
++&rpc0 {
+ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
+ pinctrl-names = "default";
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts
+index 5c8ded5..c8d94e4 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts
+@@ -265,7 +265,7 @@
+ };
+ };
+
+-&qspi0 {
++&rpc0 {
+ pinctrl-0 = <&qspi0_pins &qspi1_pins>;
+ pinctrl-names = "default";
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980.dtsi b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+index 0d25b35..23c39c1 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a77980.dtsi
+@@ -823,8 +823,8 @@
+ status = "disabled";
+ };
+
+- qspi0: qspi@ee200000 {
+- compatible = "renesas,qspi-rpc-r8a77980";
++ rpc0: rpc0@ee200000 {
++ compatible = "renesas,rpc-r8a77980", "renesas,rpc";
+ reg = <0 0xee200000 0 0x1f0>,
+ <0 0x08000000 0 0x04000000>,
+ <0 0xee208000 0 0x100>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch
new file mode 100644
index 00000000..51300f63
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch
@@ -0,0 +1,39 @@
+From 77361fe676437e194091d927125ec3821bfc9eea Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:24:39 +0300
+Subject: [PATCH 08/12] arm64: dts: renesas: r8a7795: Add RPC device node
+
+This adds RPC device node to the r8a7795.dtsi file.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7795.dtsi | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795.dtsi b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+index e1b57e9..cc5844f 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7795.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7795.dtsi
+@@ -1947,6 +1947,19 @@
+ status = "disabled";
+ };
+
++ rpc0: rpc0@ee200000 {
++ compatible = "renesas,rpc-r8a7795", "renesas,rpc";
++ reg = <0 0xee200000 0 0x1f0>,
++ <0 0x08000000 0 0x04000000>,
++ <0 0xee208000 0 0x100>;
++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 917>;
++ power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a7795";
+ reg = <0 0xe6ef0000 0 0x1000>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch
new file mode 100644
index 00000000..6b7e7543
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch
@@ -0,0 +1,39 @@
+From 156743895046cd24f950a3f6790a19b5ba417f92 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:25:40 +0300
+Subject: [PATCH 09/12] arm64: dts: renesas: r8a7796: Add RPC device node
+
+This adds RPC device node to the r8a7796.dtsi file.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a7796.dtsi | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+index 7fcac8f..c50f5e9 100644
+--- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi
+@@ -1853,6 +1853,19 @@
+ status = "disabled";
+ };
+
++ rpc0: rpc0@ee200000 {
++ compatible = "renesas,rpc-r8a7796", "renesas,rpc";
++ reg = <0 0xee200000 0 0x1f0>,
++ <0 0x08000000 0 0x04000000>,
++ <0 0xee208000 0 0x100>;
++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 917>;
++ power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a7796";
+ reg = <0 0xe6ef0000 0 0x1000>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch
new file mode 100644
index 00000000..e683e929
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch
@@ -0,0 +1,39 @@
+From df5a5e4ee2a2059cc4fa06bf17a9e2c547afd540 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:25:58 +0300
+Subject: [PATCH 10/12] arm64: dts: renesas: r8a77965: Add RPC device node
+
+This adds RPC device node to the r8a77965.dtsi file.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77965.dtsi | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77965.dtsi b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
+index b5926ff..0a41a13 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77965.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a77965.dtsi
+@@ -1267,6 +1267,19 @@
+ status = "disabled";
+ };
+
++ rpc0: rpc0@ee200000 {
++ compatible = "renesas,rpc-r8a77965", "renesas,rpc";
++ reg = <0 0xee200000 0 0x1f0>,
++ <0 0x08000000 0 0x04000000>,
++ <0 0xee208000 0 0x100>;
++ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&cpg CPG_MOD 917>;
++ power-domains = <&sysc R8A77965_PD_ALWAYS_ON>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a77965";
+ reg = <0 0xe6ef0000 0 0x1000>;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch
new file mode 100644
index 00000000..52a08ec1
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch
@@ -0,0 +1,77 @@
+From 094c3d4eff875eee4009cac9c2fe0cc748a54394 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Mon, 4 Nov 2019 01:26:23 +0300
+Subject: [PATCH 11/12] arm64: dts: renesas: ulcb: Add RPC HyperFlash device
+ node
+
+This adds RPC HyperFlash device node along with
+its partitions to the ULCB device tree.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/ulcb.dtsi | 49 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+index 7e546d3..924b7a0 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+@@ -422,6 +422,55 @@
+ };
+ };
+
++&rpc0 {
++ status = "okay";
++
++ flash@0 {
++ compatible = "cfi-flash";
++ reg = <0>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ bl2@00040000 {
++ reg = <0x00040000 0x140000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x480000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x0C0000>;
++ read-only;
++ };
++ uboot-env@00700000 {
++ reg = <0x00700000 0x040000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
++};
++
+ &rwdt {
+ timeout-sec = <60>;
+ status = "okay";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch
new file mode 100644
index 00000000..a4a8db97
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch
@@ -0,0 +1,77 @@
+From 02ad9fb42936a698726a824550305ea7e6dd9b14 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Wed, 6 Nov 2019 03:02:20 +0300
+Subject: [PATCH 12/12] arm64: dts: renesas: salvator-common: Add RPC
+ HyperFlash device node
+
+This adds RPC HyperFlash device node along with
+its partitions to the common Salvator device tree.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/salvator-common.dtsi | 49 ++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+index 788d38f..6215545 100644
+--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi
++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+@@ -823,6 +823,55 @@
+ };
+ };
+
++&rpc0 {
++ status = "okay";
++
++ flash@0 {
++ compatible = "cfi-flash";
++ reg = <0>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bootparam@0 {
++ reg = <0x00000000 0x040000>;
++ read-only;
++ };
++ bl2@00040000 {
++ reg = <0x00040000 0x140000>;
++ read-only;
++ };
++ cert_header_sa6@00180000 {
++ reg = <0x00180000 0x040000>;
++ read-only;
++ };
++ bl31@001C0000 {
++ reg = <0x001C0000 0x480000>;
++ read-only;
++ };
++ uboot@00640000 {
++ reg = <0x00640000 0x0C0000>;
++ read-only;
++ };
++ uboot-env@00700000 {
++ reg = <0x00700000 0x040000>;
++ read-only;
++ };
++ dtb@00740000 {
++ reg = <0x00740000 0x080000>;
++ };
++ kernel@007C0000 {
++ reg = <0x007C0000 0x1400000>;
++ };
++ user@01BC0000 {
++ reg = <0x01BC0000 0x2440000>;
++ };
++ };
++ };
++};
++
+ &rwdt {
+ timeout-sec = <60>;
+ status = "okay";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch
new file mode 100644
index 00000000..c6b384e8
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch
@@ -0,0 +1,75 @@
+From b7b603c33d7cc369f1165773a0f3fa14f7f71baf Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Sun, 8 Dec 2019 01:30:38 +0300
+Subject: [PATCH] media: soc_camera: rcar_vin: Fix crash when the module is
+ removed
+
+The kernel may crash when removing rcar_csi2 or re-inserting
+rcar_vin module after having removed it. This happens when
+multiple ports are used. Multiple async clients are created
+in this case. Each client registers a notifier which is added
+to the notifier_list. However, only the last one, referenced
+by the async_client pointer, is removed form the notifier_list
+later when the rcar_vin module is removed.
+
+Fix this issue by using a linked list and removing all the
+async clients in the list when removing rcar_vin device.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/media/platform/soc_camera/rcar_vin.c | 16 +++++++++++-----
+ 1 file changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
+index 501598c..e13a046 100644
+--- a/drivers/media/platform/soc_camera/rcar_vin.c
++++ b/drivers/media/platform/soc_camera/rcar_vin.c
+@@ -922,7 +922,7 @@ struct rcar_vin_priv {
+ bool deser_sync;
+ int lut_updated;
+
+- struct rcar_vin_async_client *async_client;
++ struct list_head async_client;
+ /* Asynchronous CSI2 linking */
+ struct v4l2_subdev *csi2_sd;
+ /* Asynchronous Deserializer linking */
+@@ -3032,7 +3032,7 @@ static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv,
+ sasc->notifier.num_subdevs = 1;
+ sasc->notifier.ops = &rcar_vin_sensor_ops;
+
+- priv->async_client = sasc;
++ list_add(&sasc->list, &priv->async_client);
+
+ client = of_find_i2c_device_by_node(remote);
+
+@@ -3368,6 +3368,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
+
+ spin_lock_init(&priv->lock);
+ INIT_LIST_HEAD(&priv->capture);
++ INIT_LIST_HEAD(&priv->async_client);
+
+ priv->state = STOPPED;
+
+@@ -3417,11 +3418,16 @@ static int rcar_vin_remove(struct platform_device *pdev)
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct rcar_vin_priv *priv = container_of(soc_host,
+ struct rcar_vin_priv, ici);
++ struct rcar_vin_async_client *sasc, *tmp;
+
+- platform_device_del(priv->async_client->pdev);
+- platform_device_put(priv->async_client->pdev);
++ list_for_each_entry_safe(sasc, tmp, &priv->async_client, list) {
++ v4l2_async_notifier_unregister(&sasc->notifier);
++ v4l2_async_notifier_cleanup(&sasc->notifier);
++ list_del(&sasc->list);
+
+- v4l2_async_notifier_unregister(&priv->async_client->notifier);
++ platform_device_del(sasc->pdev);
++ platform_device_put(sasc->pdev);
++ }
+
+ soc_camera_host_unregister(soc_host);
+ pm_runtime_disable(&pdev->dev);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch
new file mode 100644
index 00000000..b2ce7fe9
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch
@@ -0,0 +1,252 @@
+From 294a1931ebc209c2950120c0f2cf24419dd8a1af Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 13 Dec 2019 23:10:27 +0300
+Subject: [PATCH] media: i2c: ar0xxx: append embedded data/stats into frame
+
+This allows to append embedded data/stats into active frame
+after setup via sysfs of valeu emb_enable
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0220_rev2.h | 8 ++--
+ drivers/media/i2c/soc_camera/ar0231_rev7.h | 8 ++--
+ drivers/media/i2c/soc_camera/ar0233.c | 60 +++++++++++++++++++++++++-----
+ drivers/media/i2c/soc_camera/ar0233_rev1.h | 8 ++--
+ drivers/media/i2c/soc_camera/ar0233_rev2.h | 8 ++--
+ drivers/media/i2c/soc_camera/ov106xx.c | 4 +-
+ 6 files changed, 67 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0220_rev2.h b/drivers/media/i2c/soc_camera/ar0220_rev2.h
+index c66872d..12845cd 100644
+--- a/drivers/media/i2c/soc_camera/ar0220_rev2.h
++++ b/drivers/media/i2c/soc_camera/ar0220_rev2.h
+@@ -311,10 +311,10 @@ static const struct ar0xxx_reg ar0220_rev2_hdr_12bit_output[] = {
+
+ static const struct ar0xxx_reg ar0220_rev2_mipi_12bit_4lane[] = {
+ {0x31AE, 0x204}, // serial_format: MIPI 4 lanes
+-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C
++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C
+ //{0x3344, 0x0011}, // default, VC=0
+ //{0x3348, 0x0111}, // default, VC=1
+ //{0x334C, 0x0211}, // default, VC=2
+diff --git a/drivers/media/i2c/soc_camera/ar0231_rev7.h b/drivers/media/i2c/soc_camera/ar0231_rev7.h
+index 704024a..b4c11c3 100644
+--- a/drivers/media/i2c/soc_camera/ar0231_rev7.h
++++ b/drivers/media/i2c/soc_camera/ar0231_rev7.h
+@@ -367,10 +367,10 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = {
+
+ #if 1 /* MIPI 12 bit Settings */
+ {0x31AE, 0x204}, // serial_format: MIPI 4 lanes
+-//{0x3342, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x3346, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334A, 0x122C}, // default, DT=0x12, DT=0x2C
+-//{0x334E, 0x122C}, // default, DT=0x12, DT=0x2C
++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C
+ //{0x3344, 0x0011}, // default, VC=0
+ //{0x3348, 0x0111}, // default, VC=1
+ //{0x334C, 0x0211}, // default, VC=2
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index 312b9fe..b62fb77 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -23,6 +23,7 @@
+ #define AR_DELAY 0xffff
+ static int AR_MAX_WIDTH;
+ static int AR_MAX_HEIGHT;
++#define AR_MAX_HEIGHT_EMB (AR_MAX_HEIGHT + priv->emb_enable * 4) /* embedded data (SOF) and stats (EOF) */
+ static int AR_X_START;
+ static int AR_Y_START;
+ static int AR_X_END;
+@@ -55,6 +56,7 @@ struct ar0233_priv {
+ struct v4l2_rect rect;
+ int init_complete;
+ u8 id[6];
++ bool emb_enable;
+ /* serializers */
+ int ti9x4_addr;
+ int ti9x3_addr;
+@@ -121,7 +123,8 @@ static int ar0233_set_window(struct v4l2_subdev *sd)
+ /* vert crop start */
+ reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START);
+ /* vert crop end */
+- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START);
++ /* limit window for embedded data/stats */
++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START - priv->emb_enable * 4);
+
+ return 0;
+ };
+@@ -207,7 +210,7 @@ static int ar0233_set_selection(struct v4l2_subdev *sd,
+ rect->height = ALIGN(rect->height, 2);
+
+ if ((rect->left + rect->width > AR_MAX_WIDTH) ||
+- (rect->top + rect->height > AR_MAX_HEIGHT))
++ (rect->top + rect->height > AR_MAX_HEIGHT_EMB))
+ *rect = priv->rect;
+
+ priv->rect.left = rect->left;
+@@ -235,13 +238,13 @@ static int ar0233_get_selection(struct v4l2_subdev *sd,
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = AR_MAX_WIDTH;
+- sel->r.height = AR_MAX_HEIGHT;
++ sel->r.height = AR_MAX_HEIGHT_EMB;
+ return 0;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = AR_MAX_WIDTH;
+- sel->r.height = AR_MAX_HEIGHT;
++ sel->r.height = AR_MAX_HEIGHT_EMB;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+@@ -413,7 +416,42 @@ static ssize_t ar0233_otp_id_show(struct device *dev,
+ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ }
+
+-static DEVICE_ATTR(otp_id_ar0233, S_IRUGO, ar0233_otp_id_show, NULL);
++static ssize_t ar0233_emb_enable_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0233_priv *priv = to_ar0233(client);
++ u32 val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ priv->emb_enable = !!val;
++
++ switch (chipid) {
++ case AR0220_PID:
++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802); break;
++ case AR0233_PID:
++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x0180 : 0); break;
++ default:
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static ssize_t ar0233_emb_enable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0233_priv *priv = to_ar0233(client);
++
++ return snprintf(buf, 4, "%d\n", priv->emb_enable);
++}
++
++static DEVICE_ATTR(otp_id, S_IRUGO, ar0233_otp_id_show, NULL);
++static DEVICE_ATTR(emb_enable, S_IRUGO|S_IWUSR, ar0233_emb_enable_show, ar0233_emb_enable_store);
+
+ static int ar0233_initialize(struct i2c_client *client)
+ {
+@@ -454,7 +492,7 @@ static int ar0233_initialize(struct i2c_client *client)
+
+ switch (pid) {
+ case AR0220_PID:
+- chipid = ID_AR0220;
++ chipid = AR0220_PID;
+ strncpy(chip_name, "AR0220", 10);
+ AR_MAX_WIDTH = AR0220_MAX_WIDTH;
+ AR_MAX_HEIGHT = AR0220_MAX_HEIGHT;
+@@ -490,7 +528,7 @@ static int ar0233_initialize(struct i2c_client *client)
+ }
+ break;
+ case AR0233_PID:
+- chipid = ID_AR0233;
++ chipid = AR0233_PID;
+ strncpy(chip_name, "AR0233", 10);
+ AR_MAX_WIDTH = AR0233_MAX_WIDTH;
+ AR_MAX_HEIGHT = AR0233_MAX_HEIGHT;
+@@ -662,8 +700,9 @@ static int ar0233_probe(struct i2c_client *client,
+ if (ret)
+ goto cleanup;
+
+- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0233) != 0) {
+- dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ if (device_create_file(&client->dev, &dev_attr_otp_id) != 0 ||
++ device_create_file(&client->dev, &dev_attr_emb_enable) != 0) {
++ dev_err(&client->dev, "sysfs entry creation failed\n");
+ goto cleanup;
+ }
+
+@@ -686,7 +725,8 @@ static int ar0233_remove(struct i2c_client *client)
+ {
+ struct ar0233_priv *priv = i2c_get_clientdata(client);
+
+- device_remove_file(&client->dev, &dev_attr_otp_id_ar0233);
++ device_remove_file(&client->dev, &dev_attr_otp_id);
++ device_remove_file(&client->dev, &dev_attr_emb_enable);
+ v4l2_async_unregister_subdev(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->hdl);
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+index 0389e51..3ff944f 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+@@ -1138,10 +1138,10 @@ static const struct ar0xxx_reg ar0233_rev1_MIPI_4Lane_12BITS[] = {
+ {0x31B8, 0x4047}, //mipi_timing_2
+ {0x31BA, 0x105}, //mipi_timing_3
+ {0x31BC, 0x704}, //mipi_timing_4
+-{0x3342, 0x122C}, // MIPI_F1_PDT_EDT
+-{0x3346, 0x122C}, // MIPI_F2_PDT_EDT
+-{0x334A, 0x122C}, // MIPI_F3_PDT_EDT
+-{0x334E, 0x122C}, // MIPI_F4_PDT_EDT
++{0x3342, 0x2c2c}, // MIPI_F1_PDT_EDT
++{0x3346, 0x2c2c}, // MIPI_F2_PDT_EDT
++{0x334A, 0x2c2c}, // MIPI_F3_PDT_EDT
++{0x334E, 0x2c2c}, // MIPI_F4_PDT_EDT
+ { }
+ }; /* MIPI_4Lane_12BITS */
+
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+index 7f71056..80572ff 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+@@ -2341,10 +2341,10 @@ static const struct ar0xxx_reg ar0233_rev2_mipi_12bit_4lane[] = {
+ {0x31B8, 0xB04D}, //mipi_timing_2
+ {0x31BA, 0x411}, //mipi_timing_3
+ {0x31BC, 0x940E}, //mipi_timing_4
+-{0x3342, 0x122C}, // MIPI_F1_PDT_EDT
+-{0x3346, 0x122C}, // MIPI_F2_PDT_EDT
+-{0x334A, 0x122C}, // MIPI_F3_PDT_EDT
+-{0x334E, 0x122C}, // MIPI_F4_PDT_EDT
++{0x3342, 0x2c2c}, // MIPI_F1_PDT_EDT
++{0x3346, 0x2c2c}, // MIPI_F2_PDT_EDT
++{0x334A, 0x2c2c}, // MIPI_F3_PDT_EDT
++{0x334E, 0x2c2c}, // MIPI_F4_PDT_EDT
+ { }
+ }; /* mipi_12bit_4lane */
+
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 876b3c1..4d5e084 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -79,10 +79,8 @@ static int ov106xx_probe(struct i2c_client *client,
+ }
+
+ ret = ar0233_probe(client, did);
+- if (!ret) {
+- chip_id = ID_AR0233;
++ if (!ret)
+ goto out;
+- }
+
+ ret = ar0323_probe(client, did);
+ if (!ret) {
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch
new file mode 100644
index 00000000..0c4c5335
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch
@@ -0,0 +1,55 @@
+From 63e509e237f058679dd4a04012f53c8c56aaafb0 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Thu, 19 Dec 2019 15:08:14 +0300
+Subject: [PATCH] media: i2c: soc_camera: ov495_ov2775: Remove early_param
+ parser
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use conf_link variable instead of force_conf_link,
+and remove eaarly_param() parser altogether.
+This fixes the following module compilation error:
+
+ expected declaration specifiers or ‘...’ before ‘ov495_force_conf_link’
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov495_ov2775.c | 13 +------------
+ 1 file changed, 1 insertion(+), 12 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.c b/drivers/media/i2c/soc_camera/ov495_ov2775.c
+index aee8145..c40970c 100644
+--- a/drivers/media/i2c/soc_camera/ov495_ov2775.c
++++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c
+@@ -57,17 +57,6 @@ struct ov495_priv {
+
+ };
+
+-static int force_conf_link;
+-
+-static __init int ov495_force_conf_link(char *str)
+-{
+- /* force configuration link */
+- /* used only if robust firmware flashing required (f.e. recovery) */
+- force_conf_link = 1;
+- return 0;
+-}
+-early_param("force_conf_link", ov495_force_conf_link);
+-
+ static inline struct ov495_priv *to_ov495(const struct i2c_client *client)
+ {
+ return container_of(i2c_get_clientdata(client), struct ov495_priv, sd);
+@@ -429,7 +418,7 @@ static int ov495_initialize(struct i2c_client *client)
+ client->addr = tmp_addr;
+ #endif
+
+- if (unlikely(force_conf_link))
++ if (unlikely(conf_link))
+ goto out;
+
+ #if 0
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch
new file mode 100644
index 00000000..a272501d
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch
@@ -0,0 +1,33 @@
+From c70a41608dfebff4bcc98c5e164dc0bd24ecd37a Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Fri, 20 Dec 2019 00:30:53 +0300
+Subject: [PATCH 1/2] arm64: dts: renesas: ulcb: Add "tee" MTD RPC HyperFlash
+ partition
+
+This reduces "bl31" partition size, and inserts "tee" partition.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/ulcb.dtsi | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+index 924b7a0..4b22551 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+@@ -447,7 +447,11 @@
+ read-only;
+ };
+ bl31@001C0000 {
+- reg = <0x001C0000 0x480000>;
++ reg = <0x001C0000 0x040000>;
++ read-only;
++ };
++ tee@00200000 {
++ reg = <0x00200000 0x440000>;
+ read-only;
+ };
+ uboot@00640000 {
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch
new file mode 100644
index 00000000..bf122dd1
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch
@@ -0,0 +1,33 @@
+From e88ff4d294af995c671760e2a0741a646a52edca Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Fri, 20 Dec 2019 00:34:16 +0300
+Subject: [PATCH 2/2] arm64: dts: renesas: salvator-common: Add "tee" MTD RPC
+ HyperFlash partition
+
+This reduces "bl31" partition size, and inserts "tee" partition.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/salvator-common.dtsi | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+index 6215545..5083d92 100644
+--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi
++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+@@ -848,7 +848,11 @@
+ read-only;
+ };
+ bl31@001C0000 {
+- reg = <0x001C0000 0x480000>;
++ reg = <0x001C0000 0x040000>;
++ read-only;
++ };
++ tee@00200000 {
++ reg = <0x00200000 0x440000>;
+ read-only;
+ };
+ uboot@00640000 {
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch
new file mode 100644
index 00000000..0ff0f918
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch
@@ -0,0 +1,54 @@
+From b45d7c8d45ca94b4e0ac2ad6df8b4f9b56cf3b38 Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Fri, 20 Dec 2019 14:09:00 +0300
+Subject: [PATCH 1/2] arm64: dts: renesas: ulcb: Increase U-Boot partition size
+
+Increase U-Boot partition size according to its actual size.
+This involves moving the "u-boot-env", "kernel", "dtb" and
+"user" partitions further by one sector which is safe
+at this point because they are not used yet. U-Boot
+environment is located on the eMMC flash.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/ulcb.dtsi | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+index 4b22551..f33027c 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi
+@@ -455,21 +455,21 @@
+ read-only;
+ };
+ uboot@00640000 {
+- reg = <0x00640000 0x0C0000>;
++ reg = <0x00640000 0x100000>;
+ read-only;
+ };
+- uboot-env@00700000 {
+- reg = <0x00700000 0x040000>;
++ uboot-env@00740000 {
++ reg = <0x00740000 0x040000>;
+ read-only;
+ };
+- dtb@00740000 {
+- reg = <0x00740000 0x080000>;
++ dtb@00780000 {
++ reg = <0x00780000 0x080000>;
+ };
+- kernel@007C0000 {
+- reg = <0x007C0000 0x1400000>;
++ kernel@00800000 {
++ reg = <0x00800000 0x1400000>;
+ };
+- user@01BC0000 {
+- reg = <0x01BC0000 0x2440000>;
++ user@01C00000 {
++ reg = <0x01C00000 0x2400000>;
+ };
+ };
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch
new file mode 100644
index 00000000..bfed8a06
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch
@@ -0,0 +1,55 @@
+From 4bba9d3777068ee97982c4b6c60a5eb29d06baab Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Fri, 20 Dec 2019 14:05:20 +0300
+Subject: [PATCH 2/2] arm64: dts: renesas: salvator-common: Increase U-Boot
+ partition size
+
+Increase U-Boot partition size according to its actual size.
+This involves moving the "u-boot-env", "kernel", "dtb" and
+"user" partitions further by one sector which is safe
+at this point because they are not used yet. U-Boot
+environment is located on the eMMC flash.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/salvator-common.dtsi | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+index 5083d92..6bc9c6e 100644
+--- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi
++++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi
+@@ -856,21 +856,21 @@
+ read-only;
+ };
+ uboot@00640000 {
+- reg = <0x00640000 0x0C0000>;
++ reg = <0x00640000 0x100000>;
+ read-only;
+ };
+- uboot-env@00700000 {
+- reg = <0x00700000 0x040000>;
++ uboot-env@00740000 {
++ reg = <0x00740000 0x040000>;
+ read-only;
+ };
+- dtb@00740000 {
+- reg = <0x00740000 0x080000>;
++ dtb@00780000 {
++ reg = <0x00780000 0x080000>;
+ };
+- kernel@007C0000 {
+- reg = <0x007C0000 0x1400000>;
++ kernel@00800000 {
++ reg = <0x00800000 0x1400000>;
+ };
+- user@01BC0000 {
+- reg = <0x01BC0000 0x2440000>;
++ user@01C00000 {
++ reg = <0x01C00000 0x2400000>;
+ };
+ };
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch
new file mode 100644
index 00000000..af31b486
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0454-media-i2c-imx390-fix-refclk.patch
@@ -0,0 +1,47 @@
+From 602dbaa9bc1794fe50d522dbef5a2ffde9eea202 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Dec 2019 17:02:13 +0300
+Subject: [PATCH] media: i2c: imx390: fix refclk
+
+The rflck for IMX390 must be ether 24MHz or 27Mhz
+The deserializer on Cogent ECU provides 23Mhz, hence use
+serizlizer PLL to adjust refclk to 24MHz
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imx390.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c
+index b1df1ba..c1e5680 100644
+--- a/drivers/media/i2c/soc_camera/imx390.c
++++ b/drivers/media/i2c/soc_camera/imx390.c
+@@ -428,17 +428,18 @@ static int imx390_initialize(struct i2c_client *client)
+ goto err;
+ }
+
+-#if 0
+- /* setup XCLK */
+ tmp_addr = client->addr;
+ if (priv->ti9x4_addr) {
+- /* CLK_OUT=22.5792*160*M/N/CLKDIV -> CLK_OUT=25MHz: CLKDIV=4, M=7, N=253: 22.5792*160/4*7/253=24.989MHz=CLK_OUT */
+- client->addr = priv->ti9x3_addr; /* Serializer I2C address */
+- reg8_write(client, 0x06, 0x47); /* Set CLKDIV and M */
+- reg8_write(client, 0x07, 0xfd); /* Set N */
++ /* Setup XCLK:
++ CLK_OUT=23MHz*160*M/N/CLKDIV
++ CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230
++ 23*160/4*6/230 = 24MHz = CLK_OUT
++ */
++ client->addr = priv->ti9x3_addr;
++ reg8_write(client, 0x06, 0x46); /* Set CLKDIV and M */
++ reg8_write(client, 0x07, 0xe6); /* Set N */
+ }
+ client->addr = tmp_addr;
+-#endif
+
+ /* Read OTP IDs */
+ imx390_otp_id_read(client);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch
new file mode 100644
index 00000000..3551d572
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0455-media-i2c-ox01d10-add-imager-support.patch
@@ -0,0 +1,1162 @@
+From fc00b90bd8aa659028e73364f6bef6789da95cc6 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Dec 2019 21:03:24 +0300
+Subject: [PATCH] media: i2c: ox01d10: add imager support
+
+This adds OVT OX01D10 imager support
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov106xx.c | 8 +
+ drivers/media/i2c/soc_camera/ox01d10.c | 611 +++++++++++++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ox01d10.h | 487 ++++++++++++++++++++++++++
+ 3 files changed, 1106 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/ox01d10.c
+ create mode 100644 drivers/media/i2c/soc_camera/ox01d10.h
+
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 4d5e084..841861c 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -27,6 +27,7 @@ static enum {
+ ID_GW5200_IMX390,
+ ID_OV2775,
+ ID_IMX390,
++ ID_OX01D10,
+ ID_OX03A,
+ ID_ISX016,
+ ID_ISX019,
+@@ -48,6 +49,7 @@ static enum {
+ #include "gw5200_imx390.c"
+ #include "ov2775.c"
+ #include "imx390.c"
++#include "ox01d10.c"
+ #include "ox03a.c"
+ #include "isx016.c"
+ #include "isx019.c"
+@@ -172,6 +174,12 @@ static int ov106xx_probe(struct i2c_client *client,
+ goto out;
+ }
+
++ ret = ox01d10_probe(client, did);
++ if (!ret) {
++ chip_id = ID_OX01D10;
++ goto out;
++ }
++
+ ret = ox03a_probe(client, did);
+ if (!ret) {
+ chip_id = ID_OX03A;
+diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c
+new file mode 100644
+index 0000000..3ea3fef
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ox01d10.c
+@@ -0,0 +1,611 @@
++/*
++ * OmniVision OX01D10 sensor camera driver
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "ox01d10.h"
++
++#define OX01D10_I2C_ADDR 0x36
++
++#define OX01D10_PID_REGA 0x300A
++#define OX01D10_PID_REGB 0x300B
++#define OX01D10_PID 0x5801
++
++#define OX01D10_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR12_1X12
++
++struct ox01d10_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int again;
++ int autogain;
++ /* serializers */
++ int ti9x4_addr;
++ int ti9x3_addr;
++ int port;
++ int gpio_resetb;
++ int gpio_fsin;
++};
++
++static inline struct ox01d10_priv *to_ox01d10(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ox01d10_priv, sd);
++}
++
++static int ox01d10_set_regs(struct i2c_client *client,
++ const struct ox01d10_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == OX01D10_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static int ox01d10_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ox01d10_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = OX01D10_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ox01d10_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = OX01D10_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ox01d10_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = OX01D10_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ox01d10_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = OX01D10_PID >> 8;
++ edid->edid[9] = OX01D10_PID & 0xff;
++
++ return 0;
++}
++
++static int ox01d10_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > OX01D10_MAX_WIDTH) ||
++ (rect->top + rect->height > OX01D10_MAX_HEIGHT))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int ox01d10_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OX01D10_MAX_WIDTH;
++ sel->r.height = OX01D10_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OX01D10_MAX_WIDTH;
++ sel->r.height = OX01D10_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ox01d10_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ox01d10_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ u8 val = 0;
++
++ ret = reg16_read(client, (u16)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u8);
++
++ return 0;
++}
++
++static int ox01d10_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops ox01d10_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ox01d10_g_register,
++ .s_register = ox01d10_s_register,
++#endif
++};
++
++static int ox01d10_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++ int ret = -EINVAL;
++ u8 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ break;
++ case V4L2_CID_GAIN:
++ /* start recording group3 */
++ ret = reg16_write(client, 0x3208, 0x03);
++ /* HCG digital gain */
++ ret |= reg16_write(client, 0x350a, ctrl->val >> 8);
++ ret |= reg16_write(client, 0x350b, ctrl->val & 0xff);
++ /* LCG digital gain */
++ ret |= reg16_write(client, 0x354a, ctrl->val/8 >> 8);
++ ret |= reg16_write(client, 0x354b, ctrl->val/8 & 0xff);
++ /* VS digital gain */
++ ret |= reg16_write(client, 0x358a, ctrl->val/64 >> 8);
++ ret |= reg16_write(client, 0x358b, ctrl->val/64 & 0xff);
++ /* stop recording and launch group3 */
++ ret |= reg16_write(client, 0x3208, 0x13);
++ ret |= reg16_write(client, 0x3208, 0xe3);
++ break;
++ case V4L2_CID_ANALOGUE_GAIN:
++ /* start recording group3 */
++ ret = reg16_write(client, 0x3208, 0x03);
++ /* HCG real gain */
++ ret |= reg16_write(client, 0x3508, ctrl->val >> 8);
++ ret |= reg16_write(client, 0x3509, ctrl->val & 0xff);
++ /* LCG real gain */
++ ret |= reg16_write(client, 0x3548, ctrl->val/8 >> 8);
++ ret |= reg16_write(client, 0x3549, ctrl->val/8 & 0xff);
++ /* VS real gain */
++ ret |= reg16_write(client, 0x3588, ctrl->val/64 >> 8);
++ ret |= reg16_write(client, 0x3589, ctrl->val/64 & 0xff);
++ /* stop recording and launch group3 */
++ ret |= reg16_write(client, 0x3208, 0x13);
++ ret |= reg16_write(client, 0x3208, 0xe3);
++ break;
++ case V4L2_CID_EXPOSURE:
++ /* start recording group3 */
++ ret = reg16_write(client, 0x3208, 0x03);
++ /* HCG (long) exposure time */
++ ret |= reg16_write(client, 0x3501, ctrl->val >> 8);
++ ret |= reg16_write(client, 0x3502, ctrl->val & 0xff);
++ /* LCG (short) exposure time */
++ ret |= reg16_write(client, 0x3541, ctrl->val/4 >> 8);
++ ret |= reg16_write(client, 0x3542, ctrl->val/4 & 0xff);
++ /* VS exposure time */
++ ret |= reg16_write(client, 0x3581, ctrl->val/16 >> 8);
++ ret |= reg16_write(client, 0x3582, ctrl->val/16 & 0xff);
++ /* stop recording and launch group3 */
++ ret |= reg16_write(client, 0x3208, 0x13);
++ ret |= reg16_write(client, 0x3208, 0xe3);
++ break;
++ case V4L2_CID_HFLIP:
++ /* start recording group3 */
++ ret = reg16_write(client, 0x3208, 0x03);
++ ret = reg16_read(client, 0x3821, &val);
++ if (ctrl->val)
++ val |= 0x04;
++ else
++ val &= ~0x04;
++ ret |= reg16_write(client, 0x3821, val);
++ /* hflip channges CFA, hence compensate it by moving crop window over bayer matrix */
++ ret |= reg16_read(client, 0x3811, &val);
++ if (ctrl->val)
++ val++;
++ else
++ val--;
++ ret |= reg16_write(client, 0x3811, val);
++ /* stop recording and launch group3 */
++ ret |= reg16_write(client, 0x3208, 0x13);
++ ret |= reg16_write(client, 0x3208, 0xe3);
++ break;
++ case V4L2_CID_VFLIP:
++ ret = reg16_read(client, 0x3820, &val);
++ if (ctrl->val)
++ val |= 0x44;
++ else
++ val &= ~0x44;
++ ret |= reg16_write(client, 0x3820, val);
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ox01d10_ctrl_ops = {
++ .s_ctrl = ox01d10_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ox01d10_video_ops = {
++ .s_stream = ox01d10_s_stream,
++ .g_mbus_config = ox01d10_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ox01d10_subdev_pad_ops = {
++ .get_edid = ox01d10_get_edid,
++ .enum_mbus_code = ox01d10_enum_mbus_code,
++ .get_selection = ox01d10_get_selection,
++ .set_selection = ox01d10_set_selection,
++ .get_fmt = ox01d10_get_fmt,
++ .set_fmt = ox01d10_set_fmt,
++};
++
++static struct v4l2_subdev_ops ox01d10_subdev_ops = {
++ .core = &ox01d10_core_ops,
++ .video = &ox01d10_video_ops,
++ .pad = &ox01d10_subdev_pad_ops,
++};
++
++static void ox01d10_otp_id_read(struct i2c_client *client)
++{
++}
++
++static ssize_t ox01d10_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ox01d10_priv *priv = to_ox01d10(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ox01d10, S_IRUGO, ox01d10_otp_id_show, NULL);
++
++static int ox01d10_initialize(struct i2c_client *client)
++{
++ struct ox01d10_priv *priv = to_ox01d10(client);
++ char chip_name[10] = "unknown";
++ u8 val = 0;
++ u16 pid;
++ int ret = 0;
++ int tmp_addr = 0;
++
++ /* check and show model ID */
++ reg16_read(client, OX01D10_PID_REGA, &val);
++ pid = val;
++ reg16_read(client, OX01D10_PID_REGB, &val);
++ pid = (pid << 8) | val;
++
++ if (pid != OX01D10_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ tmp_addr = client->addr;
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x3_addr;
++ reg8_write(client, 0x02, 0x13); /* MIPI 2-lanes */
++
++ /* Setup XCLK: CLK_OUT=23MHz*160*M/N/CLKDIV, CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230, 23*160/4*6/230 = 24MHz = CLK_OUT */
++ reg8_write(client, 0x06, 0x46); /* Set CLKDIV and M */
++ reg8_write(client, 0x07, 0xe6); /* Set N */
++ }
++ client->addr = tmp_addr;
++
++ /* Program wizard registers */
++ ox01d10_set_regs(client, ox01d10_regs_wizard_r1b_hdr3, ARRAY_SIZE(ox01d10_regs_wizard_r1b_hdr3));
++ /* Read OTP IDs */
++ ox01d10_otp_id_read(client);
++
++ dev_info(&client->dev, "ox01d10 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, OX01D10_MAX_WIDTH, OX01D10_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++err:
++ return ret;
++}
++
++static int ox01d10_parse_dt(struct device_node *np, struct ox01d10_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ int i;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ int tmp_addr = 0;
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) &&
++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") &&
++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) &&
++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port))
++ break;
++ }
++
++ of_node_put(endpoint);
++
++ if (!priv->ti9x4_addr) {
++ dev_err(&client->dev, "deserializer does not present\n");
++ return -EINVAL;
++ }
++
++ /* setup I2C translator address */
++ tmp_addr = client->addr;
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */
++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
++ usleep_range(2000, 2500); /* wait 2ms */
++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
++ reg8_write(client, 0x5d, OX01D10_I2C_ADDR << 1); /* Sensor native I2C address */
++ }
++ client->addr = tmp_addr;
++
++ mdelay(10);
++
++ return 0;
++}
++
++static int ox01d10_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ox01d10_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ox01d10_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ priv->exposure = 0x200;
++ priv->gain = 0x200;
++ priv->again = 0x200;
++ priv->autogain = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_GAIN, 1, 0xfff, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 1, 0xfff, 1, priv->again);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_EXPOSURE, 1, 0xffff, 1, priv->exposure);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ox01d10_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 1);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ox01d10_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ox01d10_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = OX01D10_MAX_WIDTH;
++ priv->rect.height = OX01D10_MAX_HEIGHT;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ox01d10) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++#ifdef CONFIG_SOC_CAMERA_OX01D10
++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
++ client->addr, client->adapter->name);
++#endif
++ return ret;
++}
++
++static int ox01d10_remove(struct i2c_client *client)
++{
++ struct ox01d10_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ox01d10);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++#ifdef CONFIG_SOC_CAMERA_OX01D10
++static const struct i2c_device_id ox01d10_id[] = {
++ { "ox01d10", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ox01d10_id);
++
++static const struct of_device_id ox01d10_of_ids[] = {
++ { .compatible = "ovti,ox01d10", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ox01d10_of_ids);
++
++static struct i2c_driver ox01d10_i2c_driver = {
++ .driver = {
++ .name = "ox01d10",
++ .of_match_table = ox01d10_of_ids,
++ },
++ .probe = ox01d10_probe,
++ .remove = ox01d10_remove,
++ .id_table = ox01d10_id,
++};
++
++module_i2c_driver(ox01d10_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for OX01D10");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
++#endif
+diff --git a/drivers/media/i2c/soc_camera/ox01d10.h b/drivers/media/i2c/soc_camera/ox01d10.h
+new file mode 100644
+index 0000000..fd50e55
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ox01d10.h
+@@ -0,0 +1,487 @@
++/*
++ * OmniVision OX01D10 sensor camera wizard 1336x1036@30/RGGB/MIPI
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define OX01D10_DISPLAY_PATTERN_COLOR_BAR
++
++#define OX01D10_MAX_WIDTH 1280
++#define OX01D10_MAX_HEIGHT 960
++
++#define OX01D10_SENSOR_WIDTH 1336
++#define OX01D10_SENSOR_HEIGHT 1036
++
++#define OX01D10_X_START ((OX01D10_SENSOR_WIDTH - OX01D10_MAX_WIDTH) / 2)
++#define OX01D10_Y_START ((OX01D10_SENSOR_HEIGHT - OX01D10_MAX_HEIGHT) / 2)
++#define OX01D10_X_END (OX01D10_X_START + OX01D10_MAX_WIDTH - 1)
++#define OX01D10_Y_END (OX01D10_Y_START + OX01D10_MAX_HEIGHT - 1)
++
++#define OX01D10_DELAY 0xffff
++
++struct ox01d10_reg {
++ u16 reg;
++ u8 val;
++};
++
++/* wizard: MIPI 1280x960 HDR3_COMB RAW 30fps A02 */
++static const struct ox01d10_reg ox01d10_regs_wizard_r1b_hdr3[] = {
++{0x107, 0x01}, // s/w reset
++{OX01D10_DELAY, 100}, // Wait 10ms
++{0x3002, 0x00},
++{0x3009, 0x26},
++{0x3012, 0x21}, // MIPI, 2 lanes
++{0x3016, 0xd0},
++{0x3018, 0x50},
++{0x301a, 0xb0},
++{0x301e, 0x30},
++{0x301f, 0x61},
++{0x3020, 0x01},
++{0x3022, 0x88},
++{0x3023, 0x80},
++{0x3024, 0x80},
++{0x3028, 0x10},
++{0x3600, 0x02},
++{0x3602, 0x42},
++{0x3603, 0x13},
++{0x3604, 0xb3},
++{0x3605, 0xff},
++{0x3606, 0x90},
++{0x3607, 0x59},
++{0x360d, 0x88},
++{0x3611, 0x49},
++{0x3612, 0x49},
++{0x3613, 0xbe},
++{0x3614, 0xa9},
++{0x3615, 0x89},
++{0x3619, 0x00},
++{0x3620, 0x60},
++{0x362a, 0x18},
++{0x362b, 0x18},
++{0x362c, 0x18},
++{0x362d, 0x18},
++{0x3643, 0x12},
++{0x3644, 0x00},
++{0x3645, 0x17},
++{0x3646, 0x1c},
++{0x3647, 0x12},
++{0x3648, 0x00},
++{0x3649, 0x17},
++{0x364a, 0x1c},
++{0x364c, 0x18},
++{0x364d, 0x18},
++{0x364e, 0x18},
++{0x364f, 0x18},
++{0x3652, 0xca},
++{0x3660, 0x43},
++{0x3661, 0x31},
++{0x3662, 0x00},
++{0x3663, 0x00},
++{0x3665, 0x13},
++{0x3668, 0x80},
++{0x366f, 0x00},
++{0x3671, 0xe7},
++{0x3674, 0x80},
++{0x3678, 0x00},
++{0x303, 0x02},
++{0x305, 0x50},
++{0x306, 0x03},
++{0x307, 0x00},
++{0x308, 0x07},
++{0x30a, 0x01},
++{0x316, 0x00},
++{0x317, 0x41},
++{0x323, 0x04},
++{0x325, 0x50},
++{0x326, 0x00},
++{0x327, 0x03},
++{0x328, 0x07},
++{0x329, 0x00},
++{0x32a, 0x00},
++{0x32b, 0x00},
++{0x32c, 0x02},
++{0x3106, 0x10},
++{0x3d8a, 0x03},
++{0x3d8b, 0xff},
++{0x4580, 0xf8},
++{0x4581, 0xc7},
++{0x458f, 0x00},
++{0x4590, 0x20},
++{0x4d0a, 0x68},
++{0x4d0b, 0x78},
++{0x4d0c, 0xa6},
++{0x4d0d, 0x0c},
++{0x4f00, 0xfa},
++{0x4f01, 0x3f},
++{0x3501, 0x00},
++{0x3502, 0x18},
++{0x3504, 0x28},
++{0x3508, 0x01},
++{0x3509, 0x00},
++{0x350a, 0x01},
++{0x350b, 0x00},
++{0x350c, 0x00},
++{0x3541, 0x00},
++{0x3542, 0x14},
++{0x3544, 0x28},
++{0x3548, 0x01},
++{0x3549, 0x00},
++{0x354a, 0x01},
++{0x354b, 0x00},
++{0x354c, 0x00},
++{0x3581, 0x00},
++{0x3582, 0x10},
++{0x3584, 0x28},
++{0x3586, 0x01},
++{0x3587, 0x69},
++{0x3588, 0x01},
++{0x3589, 0x00},
++{0x358a, 0x01},
++{0x358b, 0x00},
++{0x358c, 0x00},
++{0x358d, 0x0c},
++{0x3700, 0x16},
++{0x3701, 0x2c},
++{0x3703, 0x19},
++{0x3705, 0x00},
++{0x3706, 0x35},
++{0x3707, 0x16},
++{0x3709, 0x29},
++{0x370a, 0x00},
++{0x370b, 0x85},
++{0x370d, 0x08},
++{0x3717, 0x03},
++{0x3718, 0x08},
++{0x371a, 0x04},
++{0x371b, 0x14},
++{0x371d, 0x00},
++{0x3720, 0x03},
++{0x372c, 0x10},
++{0x372d, 0x04},
++{0x3738, 0x4f},
++{0x3739, 0x4f},
++{0x373a, 0x2b},
++{0x373b, 0x24},
++{0x373f, 0x49},
++{0x3740, 0x49},
++{0x3741, 0x25},
++{0x3742, 0x20},
++{0x3747, 0x16},
++{0x3748, 0x16},
++{0x374b, 0x03},
++{0x374c, 0x14},
++{0x3752, 0x03},
++{0x3756, 0x10},
++{0x3757, 0x2e},
++{0x3758, 0x00},
++{0x3759, 0x35},
++{0x375a, 0x00},
++{0x375b, 0x85},
++{0x375e, 0x12},
++{0x3760, 0x09},
++{0x376c, 0x01},
++{0x376d, 0x08},
++{0x376e, 0x08},
++{0x376f, 0x08},
++{0x3771, 0x08},
++{0x3773, 0x00},
++{0x3777, 0x00},
++{0x3779, 0x02},
++{0x377a, 0x00},
++{0x377b, 0x00},
++{0x377c, 0xc8},
++{0x3785, 0x08},
++{0x3790, 0x10},
++{0x3797, 0x00},
++{0x3798, 0x00},
++{0x3799, 0x00},
++{0x379c, 0x01},
++{0x379d, 0x00},
++{0x37a2, 0x02},
++{0x37a3, 0x02},
++{0x37a4, 0x02},
++{0x37a5, 0x09},
++{0x37a6, 0x09},
++{0x37a7, 0x09},
++{0x37a8, 0x03},
++{0x37a9, 0x03},
++{0x37ab, 0x03},
++{0x37ad, 0x05},
++{0x37ae, 0x05},
++{0x37b0, 0x05},
++{0x37b2, 0x04},
++{0x37b3, 0x04},
++{0x37b4, 0x04},
++{0x37b5, 0x03},
++{0x37b6, 0x03},
++{0x37b7, 0x03},
++{0x37bd, 0x01},
++{0x37be, 0x36},
++{0x37c0, 0xd0},
++{0x37c4, 0x57},
++{0x37c5, 0x57},
++{0x37c6, 0x33},
++{0x37c7, 0x29},
++{0x37ce, 0x01},
++{0x37d0, 0x00},
++{0x37d1, 0x35},
++{0x37d2, 0x00},
++{0x37d3, 0x85},
++{0x37d4, 0x00},
++{0x37d5, 0x35},
++{0x37d6, 0x00},
++{0x37d7, 0x85},
++{0x37d8, 0x01},
++{0x37da, 0x02},
++{0x37db, 0x00},
++{0x37dc, 0x4c},
++{0x3c00, 0x04},
++{0x3c0b, 0x26},
++{0x3c12, 0x88},
++{0x3c1f, 0x12},
++{0x3c20, 0x04},
++{0x3c24, 0x0f},
++{0x3c25, 0x14},
++{0x3c26, 0x07},
++{0x3c27, 0x10},
++{0x3c28, 0x06},
++{0x3c29, 0x0b},
++{0x3c2b, 0x09},
++{0x3c2c, 0x0e},
++{0x3c2d, 0x07},
++{0x3c2e, 0x0a},
++{0x3c2f, 0x05},
++{0x3c30, 0x0c},
++{0x3c31, 0x08},
++{0x3c32, 0x0f},
++{0x3c33, 0x0a},
++{0x3c34, 0x0d},
++{0x3c3c, 0x00},
++{0x3c3d, 0x0b},
++{0x3c53, 0xe8},
++{0x3c55, 0x28},
++{0x3c5b, 0x20},
++{0x3ce0, 0x02},
++{0x3ce1, 0x3a},
++{0x3ce2, 0x00},
++{0x3ce3, 0x03},
++/* window start */
++{0x3800, 0x00},
++{0x3801, 0x14},
++{0x3802, 0x00},
++{0x3803, 0x22},
++{0x3804, 0x05},
++{0x3805, 0x23},
++{0x3806, 0x03},
++{0x3807, 0xf1},
++{0x3808, OX01D10_MAX_WIDTH >> 8}, //0x508=1288
++{0x3809, OX01D10_MAX_WIDTH & 0xff},
++{0x380a, OX01D10_MAX_HEIGHT >> 8}, //0x3c8=968
++{0x380b, OX01D10_MAX_HEIGHT & 0xff},
++{0x380c, 0x06},
++{0x380d, 0xa0},
++{0x380e, 0x03}, // VTS=0x3f2
++{0x380f, 0xf2}, // VTS
++{0x3810, 0x00},
++{0x3811, 0x04},
++{0x3812, 0x00},
++{0x3813, 0x04},
++/* window end */
++{0x381c, 0x08},
++{0x3820, 0x44}, /* VPLIP on */
++{0x3821, 0x00}, /* HFLIP off */
++{0x3832, 0x00},
++{0x3834, 0x00},
++{0x383c, 0x48},
++{0x383d, 0x20},
++{0x384c, 0x03},
++{0x384d, 0x88},
++{0x3850, 0x00},
++{0x3851, 0x42},
++{0x3852, 0x00},
++{0x3853, 0x40},
++{0x3856, 0x04},
++{0x3857, 0x6b},
++{0x3858, 0x04},
++{0x385b, 0x04},
++{0x385c, 0x6a},
++{0x3861, 0x00},
++{0x3862, 0x40},
++{0x388c, 0x03},
++{0x388d, 0x5c},
++{0x4502, 0x00},
++{0x4504, 0x01},
++{0x4507, 0x10},
++{0x450b, 0x14},
++{0x450c, 0x04},
++{0x3b84, 0x45},
++{0x3b85, 0x00},
++{0x3409, 0x02},
++{0x3304, 0x04},
++{0x3306, 0x03},
++{0x3307, 0x00},
++{0x3308, 0x00},
++{0x3309, 0x00},
++{0x330a, 0x00},
++{0x330b, 0x00},
++{0x330c, 0x00},
++{0x330d, 0x00},
++{0x330e, 0x00},
++{0x330f, 0x00},
++{0x3310, 0x06},
++{0x3311, 0x05},
++{0x3312, 0x55},
++{0x3313, 0x02},
++{0x3314, 0xaa},
++{0x3315, 0x07},
++{0x3316, 0xf0},
++{0x3317, 0x00},
++{0x4001, 0x2b},
++{0x4004, 0x00},
++{0x4005, 0x40},
++{0x4008, 0x02},
++{0x4009, 0x09},
++{0x400a, 0x02},
++{0x400b, 0x00},
++{0x4020, 0x00},
++{0x4021, 0x00},
++{0x4022, 0x00},
++{0x4023, 0x00},
++{0x402e, 0x00},
++{0x402f, 0x40},
++{0x4030, 0x00},
++{0x4031, 0x40},
++{0x405c, 0x20},
++{0x5000, 0x3d},
++{0x5001, 0x05},
++{0x5030, 0x00},
++{0x5038, 0x10},
++{0x5039, 0x04},
++{0x503a, 0x04},
++#ifdef OX01D10_DISPLAY_PATTERN_COLOR_BAR
++{0x5080, 0xc0}, /* Rolling test pattern for HCG */
++{0x5083, 0x0f},
++{0x50c0, 0xc0}, /* Rolling test pattern for LCG */
++{0x50c3, 0x0f},
++{0x5100, 0xc0}, /* Rolling test pattern for VS */
++#else
++{0x5080, 0x00},
++{0x5083, 0x0f},
++{0x50c0, 0x00},
++{0x50c3, 0x0f},
++{0x5100, 0x00},
++#endif
++{0x5103, 0x0f},
++{0x5140, 0x10},
++{0x5142, 0x10},
++{0x5144, 0x10},
++{0x5146, 0x10},
++{0x5147, 0x08},
++{0x5148, 0x08},
++{0x5149, 0x08},
++{0x514a, 0x08},
++{0x514b, 0x10},
++{0x514c, 0x10},
++{0x514d, 0x08},
++{0x514e, 0x00},
++{0x5150, 0x08},
++{0x5154, 0x00},
++{0x5157, 0x10},
++{0x5159, 0x08},
++{0x515b, 0x08},
++{0x515d, 0x10},
++{0x5160, 0x10},
++{0x5162, 0x10},
++{0x5163, 0x10},
++{0x5164, 0xaa},
++{0x5165, 0xaa},
++{0x5166, 0xaa},
++{0x5167, 0xaa},
++{0x5169, 0xaa},
++{0x516c, 0x99},
++{0x516d, 0xaa},
++{0x516e, 0xaa},
++{0x5174, 0x99},
++{0x5176, 0x99},
++{0x5179, 0xaa},
++{0x517a, 0xaa},
++{0x517d, 0x88},
++{0x517e, 0x40},
++{0x517f, 0x20},
++{0x5182, 0x00},
++{0x5183, 0xee},
++{0x5184, 0x01},
++{0x5185, 0x3d},
++{0x5186, 0x01},
++{0x5188, 0x00},
++{0x5189, 0xd3},
++{0x5220, 0x4b},
++{0x5240, 0x4b},
++{0x5260, 0x4b},
++{0x5280, 0x00},
++{0x5281, 0x5e},
++{0x5282, 0x01},
++{0x5283, 0xfd},
++{0x5285, 0x01},
++{0x5422, 0x10},
++{0x54a2, 0x10},
++{0x5522, 0x10},
++{0x559e, 0x03},
++{0x559f, 0x00},
++{0x55a0, 0x40},
++{0x6008, 0xcf},
++{0x6009, 0x00},
++{0x4903, 0x80},
++{0x4601, 0x30},
++{0x4602, 0x02},
++{0x4603, 0x01},
++{0x4605, 0x03},
++{0x460a, 0x36},
++{0x460c, 0x60},
++{0x4800, 0x04},
++{0x480e, 0x04},
++{0x4813, 0x12}, // VC
++{0x481b, 0x50},
++{0x481f, 0x30},
++{0x482b, 0x04},
++{0x482e, 0x34},
++{0x4837, 0x10},
++{0x484b, 0x27},
++{0x4880, 0x00},
++{0x4881, 0x00},
++{0x4885, 0x03},
++{0x4886, 0x00},
++{0x4708, 0x00},
++{0x470b, 0x0f},
++{0x380e, 0x04}, // VTS=0x400
++{0x380f, 0x00}, //
++/* patch start */
++//{0x3208, 0x03}, // start recording group3
++{0x3501, 0x02}, // HCG exposure integration time MSB
++{0x3502, 0x00}, // HCG exposure integration time LSB
++{0x3541, 0x00}, // LCG exposure integration time MSB
++{0x3542, 0x40}, // LCG exposure integration time LSB
++{0x3581, 0x00}, // VS exposure integration time MSB
++{0x3582, 0x08}, // VS exposure integration time LSB
++{0x3508, 0x02}, // HCG real gain MSB
++{0x3509, 0x00}, // HCG real gain LSB
++{0x350a, 0x02}, // HCG digital gain MSB
++{0x350b, 0x00}, // HCG digital gain LSB
++{0x3548, 0x00}, // LCG real gain MSB
++{0x3549, 0x40}, // LCG real gain LSB
++{0x354a, 0x00}, // LCG digital gain MSB
++{0x354b, 0x40}, // LCG digital gain LSB
++{0x3588, 0x00}, // VS real gain MSB
++{0x3589, 0x08}, // VS real gain LSB
++{0x358a, 0x00}, // VS digital gain
++{0x358b, 0x08}, // VS digital gain
++//{0x3208, 0x13}, // stop recording group3
++//{0x3208, 0xe3}, // launch group3
++/* patch2 end */
++{0x100, 0x01},
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch
new file mode 100644
index 00000000..2cffe362
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0456-media-i2c-max9286-fix-resetb-handling.patch
@@ -0,0 +1,36 @@
+From f3e07cec62fb10d0c09d4bb96309ebe01a8f3fae Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 26 Dec 2019 15:26:45 +0300
+Subject: [PATCH] media: i2c: max9286: fix resetb handling
+
+This fixed the RESETB handling for other then GPIOn=1 pins
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9286.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index b185566..f6c6b0a 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -232,10 +232,12 @@ static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_
+ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
+ return;
+
+- /* sensor reset/unreset */
+- client->addr = addr; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
+- ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ if (priv->active_low_resetb)
++ reset_on = !reset_on;
++
++ /* sensor reset/unreset using serializer gpio */
++ client->addr = addr;
++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */
+ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
+ }
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch
new file mode 100644
index 00000000..71c116d2
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch
@@ -0,0 +1,67 @@
+From f35b83dbb68c5c9d01b9c10f8afc95f436a0a40c Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 26 Dec 2019 15:27:34 +0300
+Subject: [PATCH] media: i2c: ov10640: fix dvp order and soft reset
+
+1) the s/w reset must be removed since some comeras have
+serizlizer connected to imager gpio and the address of imager
+may change after soft reset
+
+2) add dvp order
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 6 ++++++
+ drivers/media/i2c/soc_camera/ov10640.h | 6 +++---
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index 89dac1b..6414c6e 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -481,6 +481,8 @@ static int ov10640_initialize(struct i2c_client *client)
+ ov10640_otp_id_read(client);
+ /* Program wizard registers */
+ ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e));
++ /* Set DVP bit swap */
++ reg16_write(client, 0x3124, priv->dvp_order << 4);
+
+ dev_info(&client->dev, "ov10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+@@ -552,6 +554,10 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv)
+ }
+ client->addr = tmp_addr;
+
++ /* module params override dts */
++ if (dvp_order != -1)
++ priv->dvp_order = dvp_order;
++
+ return 0;
+ }
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h
+index dbc6c0b..32cdb2c 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.h
++++ b/drivers/media/i2c/soc_camera/ov10640.h
+@@ -1,7 +1,7 @@
+ /*
+- * OmniVision ov10640 sensor camera wizard 1280x800@30/UYVY/BT601/8bit
++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit
+ *
+- * Copyright (C) 2015-2017 Cogent Embedded, Inc.
++ * Copyright (C) 2015-2019 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -1185,7 +1185,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = {
+ /* DVP_1280x1080_COMB12_raw 30fps */
+ static const struct ov10640_reg ov10640_regs_wizard_r1e[] = {
+ /* ov10640_R1E_setting_3x12_1280x1080_MIPIin_4lane_raw */
+-{0x3013, 0x01},
++//{0x3013, 0x01},
+ {OV10640_DELAY, 10},
+ {0x328a, 0x11},
+ {0x313f, 0x80},
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch
new file mode 100644
index 00000000..3d73bd27
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch
@@ -0,0 +1,866 @@
+From 593e1916da8aa0ff0f4d8d25aa483358d190badb Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Wed, 25 Dec 2019 16:42:09 +0300
+Subject: [PATCH] arm64: dts: renesas: Add V3x VideoBox GMSL 8ch support
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/Makefile | 1 +
+ .../renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts | 834 ++++++++++++++++++
+ 2 files changed, 835 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index 05b164e09f0a..4b2f4fb73bed 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -41,5 +41,6 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb
++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb
+
+ always := $(dtb-y)
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
+new file mode 100644
+index 000000000000..f90951d0e230
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
+@@ -0,0 +1,834 @@
++/*
++ * Device Tree Source for the V3HSK Videobox Mini board on r8a7798
++ *
++ * Copyright (C) 2018 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk.dts"
++#include <dt-bindings/gpio/gpio.h>
++/* FDPLink output */
++//#include "vb-fdplink-output.dtsi"
++
++/ {
++ model = "Renesas V3HSK 8ch GMSL Videobox board based on r8a7798";
++
++ aliases {
++ serial1 = &scif3;
++ ethernet1 = &avb;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led0 {
++ label = "board:status";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "none";
++ };
++ };
++
++ mpcie_1v8: regulator2 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ mpcie_3v3: regulator3 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ common_3v3: regulator4 {
++ compatible = "regulator-fixed";
++ regulator-name = "main 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++};
++
++&canfd {
++ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++&avb {
++ pinctrl-0 = <&avb_pins>;
++ pinctrl-names = "default";
++ renesas,no-ether-link;
++ phy-handle = <&avb_phy0>;
++ status = "okay";
++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>;
++
++ avb_phy0: eavb-phy@0 {
++ rxc-skew-ps = <1500>;
++ rxdv-skew-ps = <420>; /* default */
++ rxd0-skew-ps = <420>; /* default */
++ rxd1-skew-ps = <420>; /* default */
++ rxd2-skew-ps = <420>; /* default */
++ rxd3-skew-ps = <420>; /* default */
++ txc-skew-ps = <900>; /* default */
++ txen-skew-ps = <420>; /* default */
++ txd0-skew-ps = <420>; /* default */
++ txd1-skew-ps = <420>; /* default */
++ txd2-skew-ps = <420>; /* default */
++ txd3-skew-ps = <420>; /* default */
++ reg = <3>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++ max-speed = <1000>;
++ };
++};
++
++&csi40 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi40_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <700>;
++ };
++ };
++};
++
++&csi41 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi41_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <700>;
++ };
++ };
++};
++
++&i2c1 {
++ pinctrl-0 = <&i2c1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ clock-frequency = <400000>;
++
++ i2cswitch1: i2c-switch@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
++
++ /* CTL0_SDA and CTL0_SCL */
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ gpio_exp: gpio_exp@76 {
++ compatible = "nxp,pca9539";
++ reg = <0x76>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ des0_shdn {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Des0SHDN";
++ };
++ des1_shdn {
++ gpio-hog;
++ gpios = <0 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Des1SHDN";
++ };
++ cmr_pwen {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CmrPEN";
++ };
++ };
++
++ dac_vcam: dac_vcam@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ vdd-supply = <&common_3v3>;
++ };
++ };
++
++ /* DS0_SDA and DS0_SCL */
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ /* Deser #0 nodes here */
++ ov106xx@0 {
++ compatible = "ovti,ov106xx";
++ reg = <0x60>;
++
++ port@0 {
++ ov106xx_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des0ep0: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep0>;
++ };
++ };
++ };
++
++ ov106xx@1 {
++ compatible = "ovti,ov106xx";
++ reg = <0x61>;
++
++ port@0 {
++ ov106xx_in1: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin1ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des0ep1: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep1>;
++ };
++ };
++ };
++
++ ov106xx@2 {
++ compatible = "ovti,ov106xx";
++ reg = <0x62>;
++
++ port@0 {
++ ov106xx_in2: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin2ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des0ep2: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep2>;
++ };
++ };
++ };
++
++ ov106xx@3 {
++ compatible = "ovti,ov106xx";
++ reg = <0x63>;
++
++ port@0 {
++ ov106xx_in3: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin3ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des0ep3: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep3>;
++ };
++ };
++ };
++
++ max9286@0 {
++ compatible = "maxim,max9286";
++ reg = <0x2c>;
++ maxim,links = <4>;
++ maxim,lanes = <4>;
++ maxim,resetb-gpio = <1>;
++ maxim,fsync-mode = "automatic";
++ maxim,timeout = <100>;
++
++ POC0-gpios = <&gpio_exp 11 GPIO_ACTIVE_HIGH>;
++ POC1-gpios = <&gpio_exp 10 GPIO_ACTIVE_HIGH>;
++ POC2-gpios = <&gpio_exp 8 GPIO_ACTIVE_HIGH>;
++ POC3-gpios = <&gpio_exp 9 GPIO_ACTIVE_HIGH>;
++
++ port@0 {
++ max9286_des0ep0: endpoint@0 {
++ max9271-addr = <0x50>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in0>;
++ };
++ max9286_des0ep1: endpoint@1 {
++ max9271-addr = <0x51>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in1>;
++ };
++ max9286_des0ep2: endpoint@2 {
++ max9271-addr = <0x52>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in2>;
++ };
++ max9286_des0ep3: endpoint@3 {
++ max9271-addr = <0x53>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in3>;
++ };
++ };
++ port@1 {
++ max9286_csi0ep0: endpoint {
++ csi-rate = <700>;
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ };
++ };
++
++ /* DS1_SDA and DS1_SCL */
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ /* Deser #1 nodes here */
++ ov106xx@4 {
++ compatible = "ovti,ov106xx";
++ reg = <0x60>;
++
++ port@0 {
++ ov106xx_in4: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin4ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des1ep0: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep0>;
++ };
++ };
++ };
++
++ ov106xx@5 {
++ compatible = "ovti,ov106xx";
++ reg = <0x61>;
++
++ port@0 {
++ ov106xx_in5: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin5ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des1ep1: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep1>;
++ };
++ };
++ };
++
++ ov106xx@6 {
++ compatible = "ovti,ov106xx";
++ reg = <0x62>;
++
++ port@0 {
++ ov106xx_in6: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin6ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des1ep2: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep2>;
++ };
++ };
++ };
++
++ ov106xx@7 {
++ compatible = "ovti,ov106xx";
++ reg = <0x63>;
++
++ port@0 {
++ ov106xx_in7: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin7ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des1ep3: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep3>;
++ };
++ };
++ };
++
++ max9286@0 {
++ compatible = "maxim,max9286";
++ reg = <0x2c>;
++ maxim,links = <4>;
++ maxim,lanes = <4>;
++ maxim,resetb-gpio = <1>;
++ maxim,fsync-mode = "automatic";
++ maxim,timeout = <100>;
++
++ POC0-gpios = <&gpio_exp 15 GPIO_ACTIVE_HIGH>;
++ POC1-gpios = <&gpio_exp 14 GPIO_ACTIVE_HIGH>;
++ POC2-gpios = <&gpio_exp 12 GPIO_ACTIVE_HIGH>;
++ POC3-gpios = <&gpio_exp 13 GPIO_ACTIVE_HIGH>;
++
++ port@0 {
++ max9286_des1ep0: endpoint@0 {
++ max9271-addr = <0x50>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in4>;
++ };
++ max9286_des1ep1: endpoint@1 {
++ max9271-addr = <0x51>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in5>;
++ };
++ max9286_des1ep2: endpoint@2 {
++ max9271-addr = <0x52>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in6>;
++ };
++ max9286_des1ep3: endpoint@3 {
++ max9271-addr = <0x53>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in7>;
++ };
++ };
++ port@1 {
++ max9286_csi1ep0: endpoint {
++ csi-rate = <700>;
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ };
++ };
++
++ /* ESDA and ESCL */
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++
++ /* fan node - lm96063 */
++ fan_ctrl: lm96063@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ /* Disp_SDA and Disp_SCL */
++ i2c@6 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <6>;
++
++ /* ext I2C bus nodes */
++ };
++
++ /* RTC_SDA and RTC_SCL */
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++
++ rtc: mcp79411@6f {
++ compatible = "microchip,mcp7941x";
++ reg = <0x6f>;
++ };
++ };
++
++ };
++};
++
++&gpio0 {
++ wake_pin_8 {
++ gpio-hog;
++ gpios = <8 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 8";
++ };
++
++ can0_load {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN0Loff";
++ };
++
++ fpdl_shdn {
++ gpio-hog;
++ gpios = <21 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "FPDL_SHDN";
++ };
++};
++
++&gpio1 {
++ md_buf_en {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CPLD_If_En";
++ };
++};
++
++&gpio2 {
++ m2_rst {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 RST#";
++ };
++
++ rst_vin01 {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CCTRL_RSTn_VIN01";
++ };
++
++ can0_stby {
++ gpio-hog;
++ gpios = <27 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN0STBY";
++ };
++
++ can1_load {
++ gpio-hog;
++ gpios = <29 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1Loff";
++ };
++
++ can1_stby {
++ gpio-hog;
++ gpios = <22 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1STBY";
++ };
++
++ wake_pin_7 {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 7";
++ };
++};
++
++&pcie_bus_clk {
++ clock-frequency = <100000000>;
++ status = "okay";
++};
++
++&pciec {
++ pcie3v3-supply = <&mpcie_3v3>;
++ pcie1v8-supply = <&mpcie_1v8>;
++ status = "okay";
++};
++
++&pcie_phy {
++ status = "okay";
++};
++
++&pfc {
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data_a";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ avb_pins: avb {
++ groups = "avb_mdio", "avb_rgmii";
++ function = "avb";
++ };
++
++ i2c1_pins: i2c1 {
++ groups = "i2c1";
++ function = "i2c1";
++ };
++
++ pwm0_pins: pwm0 {
++ groups = "pwm0_a";
++ function = "pwm0";
++ };
++
++ scif3_pins: scif3 {
++ groups = "scif3_data";
++ function = "scif3";
++ };
++};
++
++&pwm0 {
++ pinctrl-0 = <&pwm0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&scif3 {
++ pinctrl-0 = <&scif3_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&tpu {
++ status = "disabled";
++};
++
++&vin0 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin0ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in0>;
++ };
++ };
++ port@1 {
++ csi0ep0: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin0_max9286_des0ep0: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep0>;
++ };
++ };
++ };
++};
++
++&vin1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin1ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in1>;
++ };
++ };
++ port@1 {
++ csi0ep1: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin1_max9286_des0ep1: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep1>;
++ };
++ };
++ };
++};
++
++&vin2 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin2ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in2>;
++ };
++ };
++ port@1 {
++ csi0ep2: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin6_max9286_des0ep2: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep2>;
++ };
++ };
++ };
++};
++
++&vin3 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin3ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in3>;
++ };
++ };
++ port@1 {
++ csi0ep3: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin7_max9286_des0ep3: endpoint@1 {
++ remote-endpoint = <&max9286_des0ep3>;
++ };
++ };
++ };
++};
++
++&vin4 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin4ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in4>;
++ };
++ };
++ port@1 {
++ csi1ep0: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin4_max9286_des0ep0: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep0>;
++ };
++ };
++ };
++};
++
++&vin5 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin5ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in5>;
++ };
++ };
++ port@1 {
++ csi1ep1: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin5_max9286_des1ep1: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep1>;
++ };
++ };
++ };
++};
++
++&vin6 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin6ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in6>;
++ };
++ };
++ port@1 {
++ csi1ep2: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin6_max9286_des1ep2: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep2>;
++ };
++ };
++ };
++};
++
++&vin7 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin7ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&ov106xx_in7>;
++ };
++ };
++ port@1 {
++ csi1ep3: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin7_max9286_des1ep3: endpoint@1 {
++ remote-endpoint = <&max9286_des1ep3>;
++ };
++ };
++ };
++};
+--
+2.20.1
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch
new file mode 100644
index 00000000..7df38d8c
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0459-media-i2c-ov10640-support-different-revisions.patch
@@ -0,0 +1,6345 @@
+From a5fcfd1f74e05c70308262091be3d9035150bfc6 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Sun, 29 Dec 2019 04:12:59 +0300
+Subject: [PATCH] media: i2c: ov10640: support different revisions
+
+1) support r1d/r1e/r1f revisions
+2) fix exposure/gain, add AEC/AEG
+3) adjust ADV_DEBUG to support u8/u16/u32/u64 access
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 134 +-
+ drivers/media/i2c/soc_camera/ov10640.h | 2378 +---------------------------
+ drivers/media/i2c/soc_camera/ov10640_r1d.h | 1240 +++++++++++++++
+ drivers/media/i2c/soc_camera/ov10640_r1e.h | 1235 +++++++++++++++
+ drivers/media/i2c/soc_camera/ov10640_r1f.h | 1198 ++++++++++++++
+ 5 files changed, 3752 insertions(+), 2433 deletions(-)
+ create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1d.h
+ create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1e.h
+ create mode 100644 drivers/media/i2c/soc_camera/ov10640_r1f.h
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index 6414c6e..40058b7 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -25,9 +25,10 @@
+
+ #define OV10640_I2C_ADDR 0x30
+
+-#define OV10640_PID 0x300a
+-#define OV10640_VER 0x300b
+-#define OV10640_VERSION_REG 0xa640
++#define OV10640_PIDA_REG 0x300a
++#define OV10640_PIDB_REG 0x300b
++#define OV10640_REV_REG 0x300d
++#define OV10640_PID 0xa640
+
+ #define OV10640_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR12_1X12
+
+@@ -190,8 +191,8 @@ static int ov10640_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+
+ edid->edid[6] = 0xff;
+ edid->edid[7] = client->addr;
+- edid->edid[8] = OV10640_VERSION_REG >> 8;
+- edid->edid[9] = OV10640_VERSION_REG & 0xff;
++ edid->edid[8] = OV10640_PID >> 8;
++ edid->edid[9] = OV10640_PID & 0xff;
+
+ return 0;
+ }
+@@ -274,24 +275,36 @@ static int ov10640_g_register(struct v4l2_subdev *sd,
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u8 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ov10640_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ __be64 be_val;
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
++
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++
++ return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
+ }
+ #endif
+
+@@ -309,7 +322,7 @@ static int ov10640_s_ctrl(struct v4l2_ctrl *ctrl)
+ struct ov10640_priv *priv = to_ov10640(client);
+ int ret = -EINVAL;
+ u8 val = 0;
+- u16 val16 = 0;
++ static char again[8] = {0, 1, 4, 2, 5, 3, 6, 7};
+
+ if (!priv->init_complete)
+ return 0;
+@@ -321,38 +334,35 @@ static int ov10640_s_ctrl(struct v4l2_ctrl *ctrl)
+ case V4L2_CID_HUE:
+ case V4L2_CID_GAMMA:
+ break;
++ case V4L2_CID_AUTOGAIN:
++ /* automatic gain/exposure */
++ reg16_read(client, 0x30FA, &val);
++ val &= ~(0x1 << 6);
++ val |= (ctrl->val << 6);
++ ret = reg16_write(client, 0x30FA, val);
++ break;
+ case V4L2_CID_GAIN:
+- reg16_write(client, 0x30EC, ctrl->val); // L
+- reg16_write(client, 0x30EE, ctrl->val); // S
+- ret = reg16_write(client, 0x30F0, ctrl->val); // VS
++ reg16_write(client, 0x30EC, ctrl->val >> 8); // L
++ reg16_write(client, 0x30ED, ctrl->val & 0xff); // L
++ reg16_write(client, 0x30EE, ctrl->val >> 8); // S
++ reg16_write(client, 0x30EF, ctrl->val & 0xff); // S
++ reg16_write(client, 0x30F0, ctrl->val >> 8); // VS
++ ret = reg16_write(client, 0x30F1, ctrl->val & 0xff); // VS
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+- reg16_read(client, 0x30EB, &val);
+- val &= ~(0x3f << 0); // VS, S, L - Gauss curve
+- val |= ((ctrl->val / 2) << 0); // L
+- val |= (ctrl->val << 2); // S
+- val |= ((ctrl->val / 2) << 4); // VS
++ val = again[ctrl->val] & 0x4 ? 0xC0 : 0; // High conversion gain is x2.57, low conversion gain is x1
++ val |= ((again[ctrl->val] & 0x3) << 0); // L
++ val |= ((again[ctrl->val] & 0x3) << 2); // S
++ val |= ((again[ctrl->val] & 0x3) << 4); // VS
+ ret = reg16_write(client, 0x30EB, val);
+ break;
+ case V4L2_CID_EXPOSURE:
+- val16 = 0xfff - ctrl->val;
+-
+- reg16_write(client, 0x30E6, val16 >> 8); // L
+- reg16_write(client, 0x30E7, val16 & 0xff); // L
+-
+- reg16_write(client, 0x30E8, val16 >> 8); // S
+- ret = reg16_write(client, 0x30E9, val16 & 0xff);// S
+-
+-// ret = reg16_write(client, 0x30EA, val >> 8); // VS - fractional ...
++ reg16_write(client, 0x30E6, ctrl->val >> 8); // L
++ reg16_write(client, 0x30E7, ctrl->val & 0xff); // L
++ reg16_write(client, 0x30E8, ctrl->val/16 >> 8); // S
++ reg16_write(client, 0x30E9, ctrl->val/16 & 0xff);// S
++ ret = reg16_write(client, 0x30EA, ctrl->val/256 >> 8); // VS
+ break;
+-#if 0
+- case V4L2_CID_EXPOSURE_AUTO:
+- reg16_read(client, 0x30FA, &val);
+- val &= ~(0x1 << 6);
+- val |= (ctrl->val << 6);
+- ret = reg16_write(client, 0x30FA, val);
+- break;
+-#endif
+ case V4L2_CID_HFLIP:
+ reg16_read(client, 0x3128, &val);
+ val &= ~(0x1 << 0);
+@@ -460,19 +470,21 @@ static int ov10640_initialize(struct i2c_client *client)
+ {
+ struct ov10640_priv *priv = to_ov10640(client);
+ u16 pid;
+- u8 val = 0;
++ u8 val = 0, rev;
+ int ret = 0;
+
+ ov10640_s_port(client, 1);
+
+ /* check and show product ID and manufacturer ID */
+- reg16_read(client, OV10640_PID, &val);
++ reg16_read(client, OV10640_PIDA_REG, &val);
+ pid = val;
+- reg16_read(client, OV10640_VER, &val);
++ reg16_read(client, OV10640_PIDB_REG, &val);
+ pid = (pid << 8) | val;
++ reg16_read(client, OV10640_REV_REG, &val);
++ rev = 0x10 | ((val & 0xf) + 0xa);
+
+- if (pid != OV10640_VERSION_REG) {
+- dev_err(&client->dev, "Product ID error %x\n", pid);
++ if (pid != OV10640_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
+ ret = -ENODEV;
+ goto out;
+ }
+@@ -480,12 +492,25 @@ static int ov10640_initialize(struct i2c_client *client)
+ /* Read OTP IDs */
+ ov10640_otp_id_read(client);
+ /* Program wizard registers */
+- ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e));
++ switch (rev) {
++ case 0x1d:
++ ov10640_set_regs(client, ov10640_regs_wizard_r1d, ARRAY_SIZE(ov10640_regs_wizard_r1d));
++ break;
++ case 0x1e:
++ ov10640_set_regs(client, ov10640_regs_wizard_r1e, ARRAY_SIZE(ov10640_regs_wizard_r1e));
++ break;
++ case 0x1f:
++ ov10640_set_regs(client, ov10640_regs_wizard_r1f, ARRAY_SIZE(ov10640_regs_wizard_r1f));
++ break;
++ default:
++ dev_err(&client->dev, "Unsupported chip revision\n");
++ return -EINVAL;
++ }
+ /* Set DVP bit swap */
+ reg16_write(client, 0x3124, priv->dvp_order << 4);
+
+- dev_info(&client->dev, "ov10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+- pid, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ dev_info(&client->dev, "ov10640 PID %x (r%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, rev, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ out:
+ ov10640_s_port(client, 0);
+
+@@ -535,7 +560,6 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv)
+ tmp_addr = client->addr;
+ if (priv->max9286_addr) {
+ client->addr = priv->max9271_addr; /* Serializer I2C address */
+-
+ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */
+ reg8_write(client, 0x0A, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */
+ usleep_range(2000, 2500); /* wait 2ms */
+@@ -543,14 +567,10 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv)
+
+ if (priv->ti9x4_addr) {
+ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */
+-
+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
+ usleep_range(2000, 2500); /* wait 2ms */
+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
+ reg8_write(client, 0x5d, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */
+-
+-// reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */
+-// udelay(100);
+ }
+ client->addr = tmp_addr;
+
+@@ -592,15 +612,13 @@ static int ov10640_probe(struct i2c_client *client,
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+- V4L2_CID_GAIN, 0, 0x3f, 1, 0x1);
++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+- V4L2_CID_ANALOGUE_GAIN, 0, 3, 1, 1);
++ V4L2_CID_GAIN, 0, 0x3fff, 1, 0x100);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+- V4L2_CID_EXPOSURE, 0, 0xfff, 1, 0x448);
+-#if 0
++ V4L2_CID_ANALOGUE_GAIN, 0, 7, 1, 1);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+- V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 0);
+-#endif
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x400);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h
+index 32cdb2c..3d2de3d 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.h
++++ b/drivers/media/i2c/soc_camera/ov10640.h
+@@ -30,2378 +30,6 @@ struct ov10640_reg {
+ u8 val;
+ };
+
+-/* DVP_1280x1080_COMB12_raw 60fps */
+-static const struct ov10640_reg ov10640_regs_wizard_r1f[] = {
+-{0x3013, 0x01},
+-{OV10640_DELAY, 10},
+-{0x31be, 0x01},
+-{0x3133, 0xb7},
+-{0x3134, 0xca},
+-{0x3135, 0xcc},
+-{0x313f, 0x80},
+-{0x3132, 0x24},
+-{0x3000, 0x03},
+-{0x3001, 0x62},
+-{0x3002, 0x07},
+-//{0x3002, 0x0f}, // for 30fps wizard
+-{0x3004, 0x03},
+-#if 0
+-{0x3005, 0x62},
+-#else
+-{0x3005, 0x48},
+-#endif
+-{0x3006, 0x07},
+-{0x3007, 0x01},
+-{0x3023, 0x05},
+-{0x3032, 0x35},
+-{0x3033, 0x04},
+-{0x3054, 0x00},
+-{0x3055, 0x0f},
+-{0x3056, 0x01},
+-{0x3057, 0xff},
+-{0x3058, 0xaf},
+-{0x3059, 0x44},
+-{0x305a, 0x02},
+-{0x305b, 0x00},
+-{0x305c, 0x30},
+-{0x305d, 0x9e},
+-{0x305e, 0x19},
+-{0x305f, 0x18},
+-{0x3060, 0xf9},
+-{0x3061, 0xf0},
+-#ifdef OV10640_FSIN_ENABLE
+-{0x308c, 0xb2},
+-#else
+-{0x308c, 0x03},
+-#endif
+-{0x308f, 0x10},
+-{0x3090, 0x00},
+-{0x3091, 0x00},
+-{0x30eb, 0x00},
+-{0x30a3, 0x08},
+-{0x30ad, 0x03},
+-{0x30ae, 0x80},
+-{0x30af, 0x80},
+-{0x30b0, 0xff},
+-{0x30b1, 0x3f},
+-{0x30b2, 0x22},
+-{0x30b9, 0x22},
+-{0x30bb, 0x00},
+-{0x30bc, 0x00},
+-{0x30bd, 0x00},
+-{0x30be, 0x00},
+-{0x30bf, 0x00},
+-{0x30c0, 0x00},
+-{0x30c1, 0x00},
+-{0x30c2, 0x00},
+-{0x30c3, 0x00},
+-{0x30c4, 0x80},
+-{0x30c5, 0x00},
+-{0x30c6, 0x80},
+-{0x30c7, 0x00},
+-{0x30c8, 0x80},
+-{0x3119, 0x44},
+-{0x311a, 0x01},
+-{0x311b, 0x4a},
+-{0x3074, 0x00},
+-{0x3075, 0x00},
+-{0x3076, 0x00},
+-{0x3077, 0x02},
+-{0x3078, 0x05},
+-{0x3079, 0x07},
+-{0x307a, 0x04},
+-{0x307b, 0x41},
+-{0x307c, 0x05},
+-{0x307d, 0x00},
+-{0x307e, 0x04},
+-{0x307f, 0x38},
+-#if 0
+-{0x3080, 0x05},
+-{0x3081, 0xbe},
+-#else
+-{0x3080, 0x06}, // minimal VTS for FPDLINK3
+-{0x3081, 0xe0},
+-#endif
+-{0x3082, 0x04},
+-{0x3083, 0x57},
+-{0x3084, 0x00},
+-{0x3085, 0x04},
+-{0x3086, 0x00},
+-{0x3087, 0x04},
+-{0x3088, 0x00},
+-{0x3089, 0x40},
+-{0x308d, 0x92},
+-{0x3094, 0xa5},
+-{0x30e6, 0x04},
+-{0x30e7, 0x48},
+-{0x30e8, 0x04},
+-{0x30e9, 0x48},
+-{0x30ea, 0x11},
+-{0x30ec, 0x01},
+-{0x30fa, 0x06},
+-{0x3120, 0x00},
+-{0x3121, 0x01},
+-{0x3122, 0x00},
+-{0x3127, 0x63},
+-{0x3128, 0xc0},
+-#ifdef OV10640_DISPLAY_PATTERN
+-{0x3129, 0x80},
+-#else
+-{0x3129, 0x00},
+-#endif
+-{0x31be, 0x01},
+-{0x30a5, 0x78},
+-{0x30a6, 0x40},
+-{0x30a7, 0x78},
+-{0x30a8, 0x80},
+-{0x30a9, 0x79},
+-{0x30aa, 0x00},
+-{0x30ab, 0x79},
+-{0x30ac, 0xf8},
+-{0x3440, 0x04},
+-{0x3444, 0x28},
+-{0x344e, 0x2c},
+-{0x3457, 0x33},
+-{0x345e, 0x38},
+-{0x3461, 0xa8},
+-{0x7002, 0xaa},
+-{0x7001, 0xdf},
+-{0x7048, 0x00},
+-{0x7049, 0x02},
+-{0x704a, 0x02},
+-{0x704b, 0x00},
+-{0x704c, 0x01},
+-{0x704d, 0x00},
+-{0x7043, 0x04},
+-{0x7040, 0x3c},
+-{0x7047, 0x00},
+-{0x7044, 0x01},
+-{0x7000, 0x1f},
+-{0x7084, 0x01},
+-{0x7085, 0x03},
+-{0x7086, 0x02},
+-{0x7087, 0x40},
+-{0x7088, 0x01},
+-{0x7089, 0x20},
+-{0x707f, 0x04},
+-{0x707c, 0x3c},
+-{0x7083, 0x00},
+-{0x7080, 0x01},
+-{0x7003, 0xdf},
+-{0x70c0, 0x00},
+-{0x70c1, 0x02},
+-{0x70c2, 0x02},
+-{0x70c3, 0x00},
+-{0x70c4, 0x01},
+-{0x70c5, 0x00},
+-{0x70b8, 0x03},
+-{0x70b9, 0x98},
+-{0x70bc, 0x00},
+-{0x70bd, 0x80},
+-{0x7004, 0x02},
+-{0x7005, 0x00},
+-{0x7006, 0x01},
+-{0x7007, 0x80},
+-{0x7008, 0x02},
+-{0x7009, 0x00},
+-{0x700a, 0x04},
+-{0x700b, 0x00},
+-{0x700e, 0x00},
+-{0x700f, 0x60},
+-{0x701a, 0x02},
+-{0x701b, 0x00},
+-{0x701c, 0x01},
+-{0x701d, 0x80},
+-{0x701e, 0x02},
+-{0x701f, 0x00},
+-{0x7020, 0x04},
+-{0x7021, 0x00},
+-{0x7024, 0x00},
+-{0x7025, 0x60},
+-{0x70e7, 0x00},
+-{0x70e4, 0x10},
+-{0x70e5, 0x00},
+-{0x70e6, 0x00},
+-{0x70eb, 0x00},
+-{0x70e8, 0x10},
+-{0x70e9, 0x00},
+-{0x70ea, 0x00},
+-{0x70ef, 0x00},
+-{0x70ec, 0xfd},
+-{0x70ed, 0x00},
+-{0x70ee, 0x00},
+-{0x70eb, 0x00},
+-{0x70f0, 0xfd},
+-{0x70f1, 0x00},
+-{0x70f2, 0x00},
+-{0x30fb, 0x06},
+-{0x30fc, 0x80},
+-{0x30fd, 0x02},
+-{0x30fe, 0x93},
+-{0x6000, 0xc1},
+-{0x6001, 0xb9},
+-{0x6002, 0xba},
+-{0x6003, 0xa4},
+-{0x6004, 0xa4},
+-{0x6005, 0xb5},
+-{0x6006, 0xa0},
+-{0x6007, 0x82},
+-{0x6008, 0xa7},
+-{0x6009, 0xa7},
+-{0x600a, 0xb7},
+-{0x600b, 0x5c},
+-{0x600c, 0x9e},
+-{0x600d, 0xc0},
+-{0x600e, 0xd2},
+-{0x600f, 0x33},
+-{0x6010, 0xcc},
+-{0x6011, 0xe2},
+-{0x6012, 0xc1},
+-{0x6013, 0xab},
+-{0x6014, 0xab},
+-{0x6015, 0xb7},
+-{0x6016, 0x00},
+-{0x6017, 0x00},
+-{0x6018, 0x00},
+-{0x6019, 0x00},
+-{0x601a, 0x00},
+-{0x601b, 0x00},
+-{0x601c, 0x00},
+-{0x601d, 0x00},
+-{0x601e, 0x00},
+-{0x601f, 0x00},
+-{0x6020, 0x00},
+-{0x6021, 0x00},
+-{0x6022, 0x00},
+-{0x6023, 0x9c},
+-{0x6024, 0x94},
+-{0x6025, 0x90},
+-{0x6026, 0xc5},
+-{0x6027, 0x00},
+-{0x6028, 0x54},
+-{0x6029, 0x2a},
+-{0x602a, 0x61},
+-{0x602b, 0xd2},
+-{0x602c, 0xcc},
+-{0x602d, 0x04},
+-{0x602e, 0x35},
+-{0x602f, 0xb1},
+-{0x6030, 0xb2},
+-{0x6031, 0xb3},
+-{0x6032, 0xd2},
+-{0x6033, 0xd3},
+-{0x6034, 0x11},
+-{0x6035, 0x31},
+-{0x6036, 0xcc},
+-{0x6037, 0x06},
+-{0x6038, 0xd2},
+-{0x6039, 0x00},
+-{0x603a, 0xce},
+-{0x603b, 0x18},
+-{0x603c, 0xcf},
+-{0x603d, 0x1e},
+-{0x603e, 0xd0},
+-{0x603f, 0x24},
+-{0x6040, 0xc5},
+-{0x6041, 0xd2},
+-{0x6042, 0xbc},
+-{0x6043, 0xcc},
+-{0x6044, 0x52},
+-{0x6045, 0x2b},
+-{0x6046, 0xd2},
+-{0x6047, 0xd3},
+-{0x6048, 0x01},
+-{0x6049, 0xcc},
+-{0x604a, 0x0a},
+-{0x604b, 0xd2},
+-{0x604c, 0xd3},
+-{0x604d, 0x0f},
+-{0x604e, 0x1a},
+-{0x604f, 0x2a},
+-{0x6050, 0xd4},
+-{0x6051, 0xe3},
+-{0x6052, 0xba},
+-{0x6053, 0x56},
+-{0x6054, 0xd3},
+-{0x6055, 0x2e},
+-{0x6056, 0x54},
+-{0x6057, 0x26},
+-{0x6058, 0xd2},
+-{0x6059, 0xcc},
+-{0x605a, 0x60},
+-{0x605b, 0xd2},
+-{0x605c, 0xd3},
+-{0x605d, 0x27},
+-{0x605e, 0x27},
+-{0x605f, 0x08},
+-{0x6060, 0x1a},
+-{0x6061, 0xcc},
+-{0x6062, 0x88},
+-{0x6063, 0x00},
+-{0x6064, 0x12},
+-{0x6065, 0x2c},
+-{0x6066, 0x60},
+-{0x6067, 0xc2},
+-{0x6068, 0xb9},
+-{0x6069, 0xa5},
+-{0x606a, 0xa5},
+-{0x606b, 0xb5},
+-{0x606c, 0xa0},
+-{0x606d, 0x82},
+-{0x606e, 0x5c},
+-{0x606f, 0xd4},
+-{0x6070, 0xab},
+-{0x6071, 0xd4},
+-{0x6072, 0xab},
+-{0x6073, 0xd3},
+-{0x6074, 0x01},
+-{0x6075, 0x7c},
+-{0x6076, 0x74},
+-{0x6077, 0x00},
+-{0x6078, 0x61},
+-{0x6079, 0x2a},
+-{0x607a, 0xd2},
+-{0x607b, 0xcc},
+-{0x607c, 0xdf},
+-{0x607d, 0xc6},
+-{0x607e, 0x35},
+-{0x607f, 0xd2},
+-{0x6080, 0xcc},
+-{0x6081, 0x06},
+-{0x6082, 0x31},
+-{0x6083, 0xd2},
+-{0x6084, 0x00},
+-{0x6085, 0xbb},
+-{0x6086, 0xcc},
+-{0x6087, 0x18},
+-{0x6088, 0xc6},
+-{0x6089, 0xd2},
+-{0x608a, 0xbd},
+-{0x608b, 0xcc},
+-{0x608c, 0x52},
+-{0x608d, 0x2b},
+-{0x608e, 0xd2},
+-{0x608f, 0xd3},
+-{0x6090, 0x01},
+-{0x6091, 0xcc},
+-{0x6092, 0x0a},
+-{0x6093, 0xd2},
+-{0x6094, 0xd3},
+-{0x6095, 0x0f},
+-{0x6096, 0x1a},
+-{0x6097, 0x71},
+-{0x6098, 0x2a},
+-{0x6099, 0xd4},
+-{0x609a, 0xe3},
+-{0x609b, 0xd3},
+-{0x609c, 0x22},
+-{0x609d, 0x70},
+-{0x609e, 0xca},
+-{0x609f, 0x26},
+-{0x60a0, 0xd2},
+-{0x60a1, 0xcc},
+-{0x60a2, 0x60},
+-{0x60a3, 0xd2},
+-{0x60a4, 0xd3},
+-{0x60a5, 0x27},
+-{0x60a6, 0x27},
+-{0x60a7, 0x08},
+-{0x60a8, 0x1a},
+-{0x60a9, 0xcc},
+-{0x60aa, 0x88},
+-{0x60ab, 0x00},
+-{0x60ac, 0x12},
+-{0x60ad, 0x2c},
+-{0x60ae, 0x60},
+-{0x60af, 0x00},
+-{0x60b0, 0x00},
+-{0x60b1, 0xc0},
+-{0x60b2, 0xb9},
+-{0x60b3, 0xa3},
+-{0x60b4, 0xa3},
+-{0x60b5, 0xb5},
+-{0x60b6, 0x00},
+-{0x60b7, 0xa0},
+-{0x60b8, 0x82},
+-{0x60b9, 0x5c},
+-{0x60ba, 0xd4},
+-{0x60bb, 0x8b},
+-{0x60bc, 0x9d},
+-{0x60bd, 0xd3},
+-{0x60be, 0x21},
+-{0x60bf, 0xb0},
+-{0x60c0, 0xb0},
+-{0x60c1, 0xb7},
+-{0x60c2, 0x05},
+-{0x60c3, 0xd3},
+-{0x60c4, 0x0a},
+-{0x60c5, 0xd3},
+-{0x60c6, 0x10},
+-{0x60c7, 0x9c},
+-{0x60c8, 0x94},
+-{0x60c9, 0x90},
+-{0x60ca, 0xc8},
+-{0x60cb, 0xba},
+-{0x60cc, 0x7c},
+-{0x60cd, 0x74},
+-{0x60ce, 0x00},
+-{0x60cf, 0x61},
+-{0x60d0, 0x2a},
+-{0x60d1, 0x00},
+-{0x60d2, 0xd2},
+-{0x60d3, 0xcc},
+-{0x60d4, 0xdf},
+-{0x60d5, 0xc4},
+-{0x60d6, 0x35},
+-{0x60d7, 0xd3},
+-{0x60d8, 0x13},
+-{0x60d9, 0xd2},
+-{0x60da, 0xcc},
+-{0x60db, 0x06},
+-{0x60dc, 0x31},
+-{0x60dd, 0xd2},
+-{0x60de, 0xcc},
+-{0x60df, 0x15},
+-{0x60e0, 0xd2},
+-{0x60e1, 0xbb},
+-{0x60e2, 0xcc},
+-{0x60e3, 0x1a},
+-{0x60e4, 0xd2},
+-{0x60e5, 0xbe},
+-{0x60e6, 0xce},
+-{0x60e7, 0x52},
+-{0x60e8, 0xcf},
+-{0x60e9, 0x56},
+-{0x60ea, 0xd0},
+-{0x60eb, 0x5b},
+-{0x60ec, 0x2b},
+-{0x60ed, 0xd2},
+-{0x60ee, 0xd3},
+-{0x60ef, 0x01},
+-{0x60f0, 0xcc},
+-{0x60f1, 0x0a},
+-{0x60f2, 0xd2},
+-{0x60f3, 0xd3},
+-{0x60f4, 0x0f},
+-{0x60f5, 0xd9},
+-{0x60f6, 0xb4},
+-{0x60f7, 0xda},
+-{0x60f8, 0xbb},
+-{0x60f9, 0x1a},
+-{0x60fa, 0xd4},
+-{0x60fb, 0xe3},
+-{0x60fc, 0xd4},
+-{0x60fd, 0x96},
+-{0x60fe, 0x27},
+-{0x60ff, 0x00},
+-{0x6100, 0xd2},
+-{0x6101, 0xcc},
+-{0x6102, 0x60},
+-{0x6103, 0xd2},
+-{0x6104, 0xd3},
+-{0x6105, 0x2d},
+-{0x6106, 0xd9},
+-{0x6107, 0xcc},
+-{0x6108, 0xda},
+-{0x6109, 0xd2},
+-{0x610a, 0x1a},
+-{0x610b, 0x12},
+-{0x610c, 0xcc},
+-{0x610d, 0x88},
+-{0x610e, 0xd6},
+-{0x610f, 0x9e},
+-{0x6110, 0xb9},
+-{0x6111, 0xba},
+-{0x6112, 0xaf},
+-{0x6113, 0xdc},
+-{0x6114, 0x00},
+-{0x6115, 0xd5},
+-{0x6116, 0xba},
+-{0x6117, 0x00},
+-{0x6118, 0x00},
+-{0x6119, 0x00},
+-{0x611a, 0x00},
+-{0x611b, 0x00},
+-{0x611c, 0x00},
+-{0x611d, 0x00},
+-{0x611e, 0x00},
+-{0x611f, 0xaa},
+-{0x6120, 0xaa},
+-{0x6121, 0xb7},
+-{0x6122, 0x00},
+-{0x6123, 0x00},
+-{0x6124, 0x00},
+-{0x6125, 0x00},
+-{0x6126, 0x00},
+-{0x6127, 0xa6},
+-{0x6128, 0xa6},
+-{0x6129, 0xb7},
+-{0x612a, 0x00},
+-{0x612b, 0xd5},
+-{0x612c, 0x71},
+-{0x612d, 0xd3},
+-{0x612e, 0x30},
+-{0x612f, 0xba},
+-{0x6130, 0x00},
+-{0x6131, 0x00},
+-{0x6132, 0x00},
+-{0x6133, 0x00},
+-{0x6134, 0xd3},
+-{0x6135, 0x10},
+-{0x6136, 0x70},
+-{0x6137, 0x00},
+-{0x6138, 0x00},
+-{0x6139, 0x00},
+-{0x613a, 0x00},
+-{0x613b, 0xd5},
+-{0x613c, 0xba},
+-{0x613d, 0xb0},
+-{0x613e, 0xb0},
+-{0x613f, 0xb7},
+-{0x6140, 0x9d},
+-{0x6141, 0x02},
+-{0x6142, 0xd3},
+-{0x6143, 0x0a},
+-{0x6144, 0x9d},
+-{0x6145, 0x9d},
+-{0x6146, 0xd3},
+-{0x6147, 0x10},
+-{0x6148, 0x9c},
+-{0x6149, 0x94},
+-{0x614a, 0x90},
+-{0x614b, 0xc8},
+-{0x614c, 0xba},
+-{0x614d, 0xd2},
+-{0x614e, 0x60},
+-{0x614f, 0x2c},
+-{0x6150, 0x50},
+-{0x6151, 0x11},
+-{0x6152, 0xcc},
+-{0x6153, 0x00},
+-{0x6154, 0x30},
+-{0x6155, 0xd5},
+-{0x6156, 0xba},
+-{0x6157, 0xb0},
+-{0x6158, 0xb0},
+-{0x6159, 0xb7},
+-{0x615a, 0x9d},
+-{0x615b, 0x02},
+-{0x615c, 0xd3},
+-{0x615d, 0x0a},
+-{0x615e, 0x9d},
+-{0x615f, 0x9d},
+-{0x6160, 0xd3},
+-{0x6161, 0x10},
+-{0x6162, 0x9c},
+-{0x6163, 0x94},
+-{0x6164, 0x90},
+-{0x6165, 0xc8},
+-{0x6166, 0xba},
+-{0x6167, 0xd5},
+-{0x6168, 0x01},
+-{0x6169, 0x1a},
+-{0x616a, 0xcc},
+-{0x616b, 0x12},
+-{0x616c, 0x12},
+-{0x616d, 0x00},
+-{0x616e, 0xcc},
+-{0x616f, 0x9c},
+-{0x6170, 0xd2},
+-{0x6171, 0xcc},
+-{0x6172, 0x60},
+-{0x6173, 0xd2},
+-{0x6174, 0x04},
+-{0x6175, 0xd5},
+-{0x6176, 0x1a},
+-{0x6177, 0xcc},
+-{0x6178, 0x12},
+-{0x6179, 0x00},
+-{0x617a, 0x12},
+-{0x617b, 0xcc},
+-{0x617c, 0x9c},
+-{0x617d, 0xd2},
+-{0x617e, 0xcc},
+-{0x617f, 0x60},
+-{0x6180, 0xd2},
+-{0x6181, 0x1a},
+-{0x6182, 0xcc},
+-{0x6183, 0x12},
+-{0x6184, 0x00},
+-{0x6185, 0x12},
+-{0x6186, 0xcc},
+-{0x6187, 0x9c},
+-{0x6188, 0xd2},
+-{0x6189, 0xcc},
+-{0x618a, 0x60},
+-{0x618b, 0xd2},
+-{0x618c, 0x1a},
+-{0x618d, 0xcc},
+-{0x618e, 0x12},
+-{0x618f, 0x00},
+-{0x6190, 0x12},
+-{0x6191, 0xcc},
+-{0x6192, 0x9c},
+-{0x6193, 0xd2},
+-{0x6194, 0xcc},
+-{0x6195, 0x60},
+-{0x6196, 0xd2},
+-{0x6197, 0xd5},
+-{0x6198, 0x1a},
+-{0x6199, 0xcc},
+-{0x619a, 0x12},
+-{0x619b, 0x12},
+-{0x619c, 0x00},
+-{0x619d, 0xcc},
+-{0x619e, 0x8a},
+-{0x619f, 0xd2},
+-{0x61a0, 0xcc},
+-{0x61a1, 0x74},
+-{0x61a2, 0xd2},
+-{0x61a3, 0xd5},
+-{0x61a4, 0x1a},
+-{0x61a5, 0xcc},
+-{0x61a6, 0x12},
+-{0x61a7, 0x00},
+-{0x61a8, 0x12},
+-{0x61a9, 0xcc},
+-{0x61aa, 0x8a},
+-{0x61ab, 0xd2},
+-{0x61ac, 0xcc},
+-{0x61ad, 0x74},
+-{0x61ae, 0xd2},
+-{0x61af, 0x1a},
+-{0x61b0, 0xcc},
+-{0x61b1, 0x12},
+-{0x61b2, 0x00},
+-{0x61b3, 0x12},
+-{0x61b4, 0xcc},
+-{0x61b5, 0x8a},
+-{0x61b6, 0xd2},
+-{0x61b7, 0xcc},
+-{0x61b8, 0x74},
+-{0x61b9, 0xd2},
+-{0x61ba, 0x1a},
+-{0x61bb, 0xcc},
+-{0x61bc, 0x12},
+-{0x61bd, 0x00},
+-{0x61be, 0x12},
+-{0x61bf, 0xcc},
+-{0x61c0, 0x8a},
+-{0x61c1, 0xd2},
+-{0x61c2, 0xcc},
+-{0x61c3, 0x74},
+-{0x61c4, 0xd2},
+-{0x61c5, 0xd5},
+-{0x61c6, 0xcc},
+-{0x61c7, 0x12},
+-{0x61c8, 0x00},
+-{0x61c9, 0x12},
+-{0x61ca, 0xcc},
+-{0x61cb, 0x9c},
+-{0x61cc, 0xd5},
+-{0x6400, 0x04},
+-{0x6401, 0x04},
+-{0x6402, 0x00},
+-{0x6403, 0xff},
+-{0x6404, 0x00},
+-{0x6405, 0x08},
+-{0x6406, 0x00},
+-{0x6407, 0xff},
+-{0x6408, 0x04},
+-{0x6409, 0x70},
+-{0x640a, 0x00},
+-{0x640b, 0xff},
+-{0x640c, 0x05},
+-{0x640d, 0x14},
+-{0x640e, 0x04},
+-{0x640f, 0x71},
+-{0x6410, 0x05},
+-{0x6411, 0x74},
+-{0x6412, 0x00},
+-{0x6413, 0xff},
+-{0x6414, 0x05},
+-{0x6415, 0x54},
+-{0x6416, 0x05},
+-{0x6417, 0x44},
+-{0x6418, 0x04},
+-{0x6419, 0x30},
+-{0x641a, 0x05},
+-{0x641b, 0x46},
+-{0x641c, 0x00},
+-{0x641d, 0xff},
+-{0x641e, 0x04},
+-{0x641f, 0x31},
+-{0x6420, 0x04},
+-{0x6421, 0x30},
+-{0x6422, 0x00},
+-{0x6423, 0xff},
+-{0x6424, 0x04},
+-{0x6425, 0x20},
+-{0x6426, 0x05},
+-{0x6427, 0x06},
+-{0x6428, 0x00},
+-{0x6429, 0xff},
+-{0x642a, 0x08},
+-{0x642b, 0x2a},
+-{0x642c, 0x08},
+-{0x642d, 0x31},
+-{0x642e, 0x00},
+-{0x642f, 0xff},
+-{0x6430, 0x08},
+-{0x6431, 0x2a},
+-{0x6432, 0x08},
+-{0x6433, 0x31},
+-{0x6434, 0x06},
+-{0x6435, 0x20},
+-{0x6436, 0x07},
+-{0x6437, 0x00},
+-{0x6438, 0x08},
+-{0x6439, 0x40},
+-{0x643a, 0x00},
+-{0x643b, 0xff},
+-{0x643c, 0x08},
+-{0x643d, 0x2a},
+-{0x643e, 0x08},
+-{0x643f, 0x36},
+-{0x6440, 0x06},
+-{0x6441, 0x10},
+-{0x6442, 0x07},
+-{0x6443, 0x00},
+-{0x6444, 0x08},
+-{0x6445, 0x40},
+-{0x6446, 0x00},
+-{0x6447, 0xff},
+-{0x6448, 0x08},
+-{0x6449, 0x2a},
+-{0x644a, 0x08},
+-{0x644b, 0x3b},
+-{0x644c, 0x06},
+-{0x644d, 0x00},
+-{0x644e, 0x07},
+-{0x644f, 0x00},
+-{0x6450, 0x08},
+-{0x6451, 0x40},
+-{0x6452, 0x00},
+-{0x6453, 0xff},
+-{0x6454, 0x06},
+-{0x6455, 0x00},
+-{0x6456, 0x07},
+-{0x6457, 0x05},
+-{0x6458, 0x01},
+-{0x6459, 0xaf},
+-{0x645a, 0x01},
+-{0x645b, 0x0f},
+-{0x645c, 0x01},
+-{0x645d, 0x90},
+-{0x645e, 0x01},
+-{0x645f, 0xc8},
+-{0x6460, 0x00},
+-{0x6461, 0xff},
+-{0x6462, 0x01},
+-{0x6463, 0xac},
+-{0x6464, 0x01},
+-{0x6465, 0x0c},
+-{0x6466, 0x01},
+-{0x6467, 0x90},
+-{0x6468, 0x01},
+-{0x6469, 0xe8},
+-{0x646a, 0x00},
+-{0x646b, 0xff},
+-{0x646c, 0x01},
+-{0x646d, 0xad},
+-{0x646e, 0x01},
+-{0x646f, 0x0d},
+-{0x6470, 0x01},
+-{0x6471, 0x90},
+-{0x6472, 0x01},
+-{0x6473, 0xe8},
+-{0x6474, 0x00},
+-{0x6475, 0xff},
+-{0x6476, 0x01},
+-{0x6477, 0xae},
+-{0x6478, 0x01},
+-{0x6479, 0x0e},
+-{0x647a, 0x01},
+-{0x647b, 0x90},
+-{0x647c, 0x01},
+-{0x647d, 0xe8},
+-{0x647e, 0x00},
+-{0x647f, 0xff},
+-{0x6480, 0x01},
+-{0x6481, 0xb0},
+-{0x6482, 0x01},
+-{0x6483, 0xb1},
+-{0x6484, 0x01},
+-{0x6485, 0xb2},
+-{0x6486, 0x01},
+-{0x6487, 0xb3},
+-{0x6488, 0x01},
+-{0x6489, 0xb4},
+-{0x648a, 0x01},
+-{0x648b, 0xb5},
+-{0x648c, 0x01},
+-{0x648d, 0xb6},
+-{0x648e, 0x01},
+-{0x648f, 0xb7},
+-{0x6490, 0x01},
+-{0x6491, 0xb8},
+-{0x6492, 0x01},
+-{0x6493, 0xb9},
+-{0x6494, 0x01},
+-{0x6495, 0xba},
+-{0x6496, 0x01},
+-{0x6497, 0xbb},
+-{0x6498, 0x01},
+-{0x6499, 0xbc},
+-{0x649a, 0x01},
+-{0x649b, 0xbd},
+-{0x649c, 0x01},
+-{0x649d, 0xbe},
+-{0x649e, 0x01},
+-{0x649f, 0xbf},
+-{0x64a0, 0x01},
+-{0x64a1, 0xc0},
+-{0x64a2, 0x00},
+-{0x64a3, 0xff},
+-{0x64a4, 0x06},
+-{0x64a5, 0x00},
+-{0x64a6, 0x01},
+-{0x64a7, 0xf6},
+-{0x64a8, 0x04},
+-{0x64a9, 0x30},
+-{0x64aa, 0x00},
+-{0x64ab, 0xff},
+-{0x64ac, 0x06},
+-{0x64ad, 0x10},
+-{0x64ae, 0x01},
+-{0x64af, 0xf6},
+-{0x64b0, 0x04},
+-{0x64b1, 0x30},
+-{0x64b2, 0x06},
+-{0x64b3, 0x00},
+-{0x64b4, 0x00},
+-{0x64b5, 0xff},
+-{0x64b6, 0x06},
+-{0x64b7, 0x20},
+-{0x64b8, 0x01},
+-{0x64b9, 0xf6},
+-{0x64ba, 0x04},
+-{0x64bb, 0x30},
+-{0x64bc, 0x06},
+-{0x64bd, 0x00},
+-{0x64be, 0x00},
+-{0x64bf, 0xff},
+-{0x64c0, 0x04},
+-{0x64c1, 0x31},
+-{0x64c2, 0x04},
+-{0x64c3, 0x30},
+-{0x64c4, 0x01},
+-{0x64c5, 0x20},
+-{0x64c6, 0x01},
+-{0x64c7, 0x31},
+-{0x64c8, 0x01},
+-{0x64c9, 0x32},
+-{0x64ca, 0x01},
+-{0x64cb, 0x33},
+-{0x64cc, 0x01},
+-{0x64cd, 0x34},
+-{0x64ce, 0x01},
+-{0x64cf, 0x35},
+-{0x64d0, 0x01},
+-{0x64d1, 0x36},
+-{0x64d2, 0x01},
+-{0x64d3, 0x37},
+-{0x64d4, 0x01},
+-{0x64d5, 0x38},
+-{0x64d6, 0x01},
+-{0x64d7, 0x39},
+-{0x64d8, 0x01},
+-{0x64d9, 0x3a},
+-{0x64da, 0x01},
+-{0x64db, 0x3b},
+-{0x64dc, 0x01},
+-{0x64dd, 0x3c},
+-{0x64de, 0x01},
+-{0x64df, 0x3d},
+-{0x64e0, 0x01},
+-{0x64e1, 0x3e},
+-{0x64e2, 0x01},
+-{0x64e3, 0x3f},
+-{0x64e4, 0x02},
+-{0x64e5, 0xa0},
+-{0x64e6, 0x00},
+-{0x64e7, 0xff},
+-{0x64e8, 0x04},
+-{0x64e9, 0x31},
+-{0x64ea, 0x04},
+-{0x64eb, 0x30},
+-{0x64ec, 0x01},
+-{0x64ed, 0x00},
+-{0x64ee, 0x01},
+-{0x64ef, 0x11},
+-{0x64f0, 0x01},
+-{0x64f1, 0x12},
+-{0x64f2, 0x01},
+-{0x64f3, 0x13},
+-{0x64f4, 0x01},
+-{0x64f5, 0x14},
+-{0x64f6, 0x01},
+-{0x64f7, 0x15},
+-{0x64f8, 0x01},
+-{0x64f9, 0x16},
+-{0x64fa, 0x01},
+-{0x64fb, 0x17},
+-{0x64fc, 0x01},
+-{0x64fd, 0x18},
+-{0x64fe, 0x01},
+-{0x64ff, 0x19},
+-{0x6500, 0x01},
+-{0x6501, 0x1a},
+-{0x6502, 0x01},
+-{0x6503, 0x1b},
+-{0x6504, 0x01},
+-{0x6505, 0x1c},
+-{0x6506, 0x01},
+-{0x6507, 0x1d},
+-{0x6508, 0x01},
+-{0x6509, 0x1e},
+-{0x650a, 0x01},
+-{0x650b, 0x1f},
+-{0x650c, 0x02},
+-{0x650d, 0xa0},
+-{0x650e, 0x00},
+-{0x650f, 0xff},
+-{0x6510, 0x04},
+-{0x6511, 0x20},
+-{0x6512, 0x05},
+-{0x6513, 0x86},
+-{0x6514, 0x03},
+-{0x6515, 0x0b},
+-{0x6516, 0x05},
+-{0x6517, 0x86},
+-{0x6518, 0x00},
+-{0x6519, 0x00},
+-{0x651a, 0x05},
+-{0x651b, 0x06},
+-{0x651c, 0x00},
+-{0x651d, 0x04},
+-{0x651e, 0x05},
+-{0x651f, 0x04},
+-{0x6520, 0x00},
+-{0x6521, 0x04},
+-{0x6522, 0x05},
+-{0x6523, 0x00},
+-{0x6524, 0x05},
+-{0x6525, 0x0a},
+-{0x6526, 0x03},
+-{0x6527, 0x9a},
+-{0x6528, 0x05},
+-{0x6529, 0x86},
+-{0x652a, 0x00},
+-{0x652b, 0x00},
+-{0x652c, 0x05},
+-{0x652d, 0x06},
+-{0x652e, 0x00},
+-{0x652f, 0x01},
+-{0x6530, 0x05},
+-{0x6531, 0x04},
+-{0x6532, 0x00},
+-{0x6533, 0x04},
+-{0x6534, 0x05},
+-{0x6535, 0x00},
+-{0x6536, 0x05},
+-{0x6537, 0x0a},
+-{0x6538, 0x03},
+-{0x6539, 0x99},
+-{0x653a, 0x05},
+-{0x653b, 0x06},
+-{0x653c, 0x00},
+-{0x653d, 0x00},
+-{0x653e, 0x05},
+-{0x653f, 0x04},
+-{0x6540, 0x00},
+-{0x6541, 0x04},
+-{0x6542, 0x05},
+-{0x6543, 0x00},
+-{0x6544, 0x05},
+-{0x6545, 0x0a},
+-{0x6546, 0x03},
+-{0x6547, 0x98},
+-{0x6548, 0x05},
+-{0x6549, 0x06},
+-{0x654a, 0x00},
+-{0x654b, 0x00},
+-{0x654c, 0x05},
+-{0x654d, 0x04},
+-{0x654e, 0x00},
+-{0x654f, 0x04},
+-{0x6550, 0x05},
+-{0x6551, 0x00},
+-{0x6552, 0x05},
+-{0x6553, 0x0a},
+-{0x6554, 0x03},
+-{0x6555, 0x97},
+-{0x6556, 0x05},
+-{0x6557, 0x06},
+-{0x6558, 0x05},
+-{0x6559, 0x04},
+-{0x655a, 0x00},
+-{0x655b, 0x04},
+-{0x655c, 0x05},
+-{0x655d, 0x00},
+-{0x655e, 0x05},
+-{0x655f, 0x0a},
+-{0x6560, 0x03},
+-{0x6561, 0x96},
+-{0x6562, 0x05},
+-{0x6563, 0x06},
+-{0x6564, 0x05},
+-{0x6565, 0x04},
+-{0x6566, 0x00},
+-{0x6567, 0x04},
+-{0x6568, 0x05},
+-{0x6569, 0x00},
+-{0x656a, 0x05},
+-{0x656b, 0x0a},
+-{0x656c, 0x03},
+-{0x656d, 0x95},
+-{0x656e, 0x05},
+-{0x656f, 0x06},
+-{0x6570, 0x05},
+-{0x6571, 0x04},
+-{0x6572, 0x00},
+-{0x6573, 0x04},
+-{0x6574, 0x05},
+-{0x6575, 0x00},
+-{0x6576, 0x05},
+-{0x6577, 0x0a},
+-{0x6578, 0x03},
+-{0x6579, 0x94},
+-{0x657a, 0x05},
+-{0x657b, 0x06},
+-{0x657c, 0x00},
+-{0x657d, 0x00},
+-{0x657e, 0x05},
+-{0x657f, 0x04},
+-{0x6580, 0x00},
+-{0x6581, 0x04},
+-{0x6582, 0x05},
+-{0x6583, 0x00},
+-{0x6584, 0x05},
+-{0x6585, 0x0a},
+-{0x6586, 0x03},
+-{0x6587, 0x93},
+-{0x6588, 0x05},
+-{0x6589, 0x06},
+-{0x658a, 0x00},
+-{0x658b, 0x00},
+-{0x658c, 0x05},
+-{0x658d, 0x04},
+-{0x658e, 0x00},
+-{0x658f, 0x04},
+-{0x6590, 0x05},
+-{0x6591, 0x00},
+-{0x6592, 0x05},
+-{0x6593, 0x0a},
+-{0x6594, 0x03},
+-{0x6595, 0x92},
+-{0x6596, 0x05},
+-{0x6597, 0x06},
+-{0x6598, 0x05},
+-{0x6599, 0x04},
+-{0x659a, 0x00},
+-{0x659b, 0x04},
+-{0x659c, 0x05},
+-{0x659d, 0x00},
+-{0x659e, 0x05},
+-{0x659f, 0x0a},
+-{0x65a0, 0x03},
+-{0x65a1, 0x91},
+-{0x65a2, 0x05},
+-{0x65a3, 0x06},
+-{0x65a4, 0x05},
+-{0x65a5, 0x04},
+-{0x65a6, 0x00},
+-{0x65a7, 0x04},
+-{0x65a8, 0x05},
+-{0x65a9, 0x00},
+-{0x65aa, 0x05},
+-{0x65ab, 0x0a},
+-{0x65ac, 0x03},
+-{0x65ad, 0x90},
+-{0x65ae, 0x05},
+-{0x65af, 0x06},
+-{0x65b0, 0x05},
+-{0x65b1, 0x04},
+-{0x65b2, 0x00},
+-{0x65b3, 0x04},
+-{0x65b4, 0x05},
+-{0x65b5, 0x00},
+-{0x65b6, 0x05},
+-{0x65b7, 0x0a},
+-{0x65b8, 0x02},
+-{0x65b9, 0x90},
+-{0x65ba, 0x05},
+-{0x65bb, 0x06},
+-{0x65bc, 0x00},
+-{0x65bd, 0xff},
+-{0x65be, 0x04},
+-{0x65bf, 0x70},
+-{0x65c0, 0x08},
+-{0x65c1, 0x76},
+-{0x65c2, 0x00},
+-{0x65c3, 0xff},
+-{0x65c4, 0x08},
+-{0x65c5, 0x76},
+-{0x65c6, 0x04},
+-{0x65c7, 0x0c},
+-{0x65c8, 0x05},
+-{0x65c9, 0x07},
+-{0x65ca, 0x04},
+-{0x65cb, 0x04},
+-{0x65cc, 0x00},
+-{0x65cd, 0xff},
+-{0x65ce, 0x00},
+-{0x65cf, 0xff},
+-{0x65d0, 0x00},
+-{0x65d1, 0xff},
+-{0x30eb, 0x04},
+-{0x30ed, 0x5a},
+-{0x30ee, 0x01},
+-{0x30ef, 0x80},
+-{0x30f1, 0x5a},
+-{0x303a, 0x04},
+-{0x303b, 0x7f},
+-{0x303c, 0xfe},
+-{0x303d, 0x19},
+-{0x303e, 0xd7},
+-{0x303f, 0x09},
+-{0x3040, 0x78},
+-{0x3042, 0x05},
+-{0x328a, 0x10},
+-{0x3012, 0x01}, // stream on
+-};
+-
+-/* DVP_1280x1080_COMB12_raw 30fps */
+-static const struct ov10640_reg ov10640_regs_wizard_r1e[] = {
+-/* ov10640_R1E_setting_3x12_1280x1080_MIPIin_4lane_raw */
+-//{0x3013, 0x01},
+-{OV10640_DELAY, 10},
+-{0x328a, 0x11},
+-{0x313f, 0x80},
+-{0x3132, 0x24},
+-
+-/* PLL settings */
+-{0x3000, 0x03},
+-{0x3001, 0x60},
+-{0x3002, 0x0f},
+-{0x3004, 0x03},
+-{0x3005, 0x44},
+-{0x3006, 0x07},
+-{0x3007, 0x01},
+-
+-{0x3014, 0x03},
+-{0x3023, 0x05},
+-{0x3032, 0x35},
+-{0x3033, 0x04},
+-{0x3054, 0x00},
+-{0x3055, 0x03},
+-{0x3056, 0x01},
+-{0x3057, 0xff},
+-{0x3058, 0xaf},
+-{0x3059, 0x44},
+-{0x305a, 0x02},
+-{0x305b, 0x00},
+-{0x305c, 0x30},
+-{0x305d, 0x9c},
+-{0x305e, 0x19},
+-{0x305f, 0x18},
+-{0x3060, 0xf9},
+-{0x3061, 0xf0},
+-{0x308a, 0x00},
+-{0x308b, 0x00},
+-#ifdef OV10640_FSIN_ENABLE
+-{0x308c, 0xb2},
+-#else
+-{0x308c, 0x03},
+-#endif
+-{0x308f, 0x10},
+-{0x3090, 0x04}, /* c:enable flip and mirror */
+-{0x3091, 0x00},
+-{0x30eb, 0x00},
+-{0x30a3, 0x08},
+-{0x30ad, 0x03},
+-{0x30ae, 0x80},
+-{0x30af, 0x80},
+-{0x30b0, 0xff},
+-{0x30b1, 0x3f},
+-{0x30b2, 0x22},
+-{0x30b9, 0x22},
+-{0x30bb, 0x00},
+-{0x30bc, 0x00},
+-{0x30bd, 0x00},
+-{0x30be, 0x00},
+-{0x30bf, 0x00},
+-{0x30c0, 0x00},
+-{0x30c1, 0x00},
+-{0x30c2, 0x00},
+-{0x30c3, 0x00},
+-{0x30c4, 0x80},
+-{0x30c5, 0x00},
+-{0x30c6, 0x80},
+-{0x30c7, 0x00},
+-{0x30c8, 0x80},
+-{0x3119, 0x49},
+-{0x311a, 0x01},
+-{0x311b, 0x4a},
+-
+-/* Crop Setting */
+-{0x3074, 0x00}, // crop_h_start
+-{0x3075, 0x00},
+-{0x3076, 0x00}, // crop_v_start
+-{0x3077, 0xf0},
+-{0x3078, 0x05}, // crop_h_end
+-{0x3079, 0x09},
+-{0x307a, 0x04}, // crop_v_end
+-{0x307b, 0x18},
+-{0x307c, 0x05}, // dvp_h_size
+-{0x307d, 0x08},
+-{0x307e, 0x03}, // dvp_v_size
+-{0x307f, 0x28},
+-{0x3080, 0x07}, // hts
+-{0x3081, 0x44},
+-{0x3082, 0x03}, // vts
+-{0x3083, 0x5c},
+-{0x3084, 0x00}, // win_hoffs
+-{0x3085, 0x00},
+-{0x3086, 0x00}, // win_voffs
+-{0x3087, 0x00},
+-
+-{0x3088, 0x00},
+-{0x3089, 0x40},
+-{0x308d, 0x92},
+-{0x3094, 0xa5},
+-{0x30e6, 0x04},
+-{0x30e7, 0x48},
+-{0x30e8, 0x04},
+-{0x30e9, 0x48},
+-{0x30e9, 0x05},
+-{0x30ec, 0x01},
+-{0x30fa, 0x06},
+-{0x3120, 0x00},
+-{0x3121, 0x20}, /* VSYNC delay */
+-{0x3122, 0x00},
+-{0x3127, 0x43}, /* 43 :dpc off, 63 */
+-{0x3128, 0xc0},
+-#ifdef OV10640_DISPLAY_PATTERN
+-{0x3129, 0x80},
+-#else
+-{0x3129, 0x00},
+-#endif
+-{0x31be, 0x00},
+-{0x30a5, 0x78},
+-{0x30a6, 0x40},
+-{0x30a7, 0x78},
+-{0x30a8, 0x80},
+-{0x30a9, 0x78},
+-{0x30aa, 0xe0},
+-{0x30ab, 0xf9},
+-{0x30ac, 0xc0},
+-{0x3440, 0x04},
+-{0x3444, 0x28},
+-{0x344e, 0x2c},
+-{0x3457, 0x33},
+-{0x345e, 0x38},
+-{0x3461, 0xa8},
+-{0x7002, 0xaa},
+-{0x7001, 0xdf},
+-{0x7048, 0x00},
+-{0x7049, 0x02},
+-{0x704a, 0x02},
+-{0x704b, 0x00},
+-{0x704c, 0x01},
+-{0x704d, 0x00},
+-{0x7043, 0x04},
+-{0x7040, 0x3c},
+-{0x7047, 0x00},
+-{0x7044, 0x01},
+-{0x7000, 0x1f},
+-{0x7084, 0x01},
+-{0x7085, 0x03},
+-{0x7086, 0x02},
+-{0x7087, 0x40},
+-{0x7088, 0x01},
+-{0x7089, 0x20},
+-{0x707f, 0x04},
+-{0x707c, 0x3c},
+-{0x7083, 0x00},
+-{0x7080, 0x01},
+-{0x7003, 0xdf},
+-{0x70c0, 0x00},
+-{0x70c1, 0x02},
+-{0x70c2, 0x02},
+-{0x70c3, 0x00},
+-{0x70c4, 0x01},
+-{0x70c5, 0x00},
+-{0x70b8, 0x03},
+-{0x70b9, 0x98},
+-{0x70bc, 0x00},
+-{0x70bd, 0x80},
+-{0x7004, 0x02},
+-{0x7005, 0x00},
+-{0x7006, 0x01},
+-{0x7007, 0x80},
+-{0x7008, 0x02},
+-{0x7009, 0x00},
+-{0x700a, 0x04},
+-{0x700b, 0x00},
+-{0x700e, 0x00},
+-{0x700f, 0x60},
+-{0x701a, 0x02},
+-{0x701b, 0x00},
+-{0x701c, 0x01},
+-{0x701d, 0x80},
+-{0x701e, 0x02},
+-{0x701f, 0x00},
+-{0x7020, 0x04},
+-{0x7021, 0x00},
+-{0x7024, 0x00},
+-{0x7025, 0x60},
+-{0x70e7, 0x00},
+-{0x70e4, 0x10},
+-{0x70e5, 0x00},
+-{0x70e6, 0x00},
+-{0x70eb, 0x00},
+-{0x70e8, 0x10},
+-{0x70e9, 0x00},
+-{0x70ea, 0x00},
+-{0x70ef, 0x00},
+-{0x70ec, 0xfd},
+-{0x70ed, 0x00},
+-{0x70ee, 0x00},
+-{0x70eb, 0x00},
+-{0x70f0, 0xfd},
+-{0x70f1, 0x00},
+-{0x70f2, 0x00},
+-{0x30fb, 0x06},
+-{0x30fc, 0x80},
+-{0x30fd, 0x02},
+-{0x30fe, 0x93},
+-{0x6000, 0xc1},
+-{0x6001, 0xb9},
+-{0x6002, 0xba},
+-{0x6003, 0xa4},
+-{0x6004, 0xb5},
+-{0x6005, 0xa0},
+-{0x6006, 0x82},
+-{0x6007, 0xa7},
+-{0x6008, 0xb7},
+-{0x6009, 0x5c},
+-{0x600a, 0x9e},
+-{0x600b, 0xc0},
+-{0x600c, 0xd2},
+-{0x600d, 0x33},
+-{0x600e, 0xcc},
+-{0x600f, 0xe2},
+-{0x6010, 0xc1},
+-{0x6011, 0xab},
+-{0x6012, 0xb7},
+-{0x6013, 0x00},
+-{0x6014, 0x00},
+-{0x6015, 0x00},
+-{0x6016, 0x00},
+-{0x6017, 0x00},
+-{0x6018, 0x00},
+-{0x6019, 0x00},
+-{0x601a, 0x00},
+-{0x601b, 0x00},
+-{0x601c, 0x00},
+-{0x601d, 0x00},
+-{0x601e, 0x9c},
+-{0x601f, 0x94},
+-{0x6020, 0x90},
+-{0x6021, 0xc5},
+-{0x6022, 0x01},
+-{0x6023, 0x54},
+-{0x6024, 0x2a},
+-{0x6025, 0x61},
+-{0x6026, 0xd2},
+-{0x6027, 0xcc},
+-{0x6028, 0x04},
+-{0x6029, 0x35},
+-{0x602a, 0xb1},
+-{0x602b, 0xb2},
+-{0x602c, 0xb3},
+-{0x602d, 0xd2},
+-{0x602e, 0xd3},
+-{0x602f, 0x12},
+-{0x6030, 0x31},
+-{0x6031, 0xcc},
+-{0x6032, 0x06},
+-{0x6033, 0xd2},
+-{0x6034, 0xc4},
+-{0x6035, 0xce},
+-{0x6036, 0x18},
+-{0x6037, 0xcf},
+-{0x6038, 0x1e},
+-{0x6039, 0xd0},
+-{0x603a, 0x24},
+-{0x603b, 0xc5},
+-{0x603c, 0xd2},
+-{0x603d, 0xbc},
+-{0x603e, 0xcc},
+-{0x603f, 0x52},
+-{0x6040, 0x2b},
+-{0x6041, 0xd2},
+-{0x6042, 0xd3},
+-{0x6043, 0x02},
+-{0x6044, 0xcc},
+-{0x6045, 0x0a},
+-{0x6046, 0xd2},
+-{0x6047, 0xd3},
+-{0x6048, 0x0f},
+-{0x6049, 0x1a},
+-{0x604a, 0x2a},
+-{0x604b, 0xd4},
+-{0x604c, 0xf6},
+-{0x604d, 0xba},
+-{0x604e, 0x56},
+-{0x604f, 0xd3},
+-{0x6050, 0x2e},
+-{0x6051, 0x54},
+-{0x6052, 0x26},
+-{0x6053, 0xd2},
+-{0x6054, 0xcc},
+-{0x6055, 0x60},
+-{0x6056, 0xd2},
+-{0x6057, 0xd3},
+-{0x6058, 0x27},
+-{0x6059, 0x27},
+-{0x605a, 0x08},
+-{0x605b, 0x1a},
+-{0x605c, 0xcc},
+-{0x605d, 0x88},
+-{0x605e, 0x00},
+-{0x605f, 0x12},
+-{0x6060, 0x2c},
+-{0x6061, 0x60},
+-{0x6062, 0xc2},
+-{0x6063, 0xb9},
+-{0x6064, 0xa5},
+-{0x6065, 0xb5},
+-{0x6066, 0xa0},
+-{0x6067, 0x82},
+-{0x6068, 0x5c},
+-{0x6069, 0xd4},
+-{0x606a, 0xbe},
+-{0x606b, 0xd4},
+-{0x606c, 0xbe},
+-{0x606d, 0xd3},
+-{0x606e, 0x01},
+-{0x606f, 0x7c},
+-{0x6070, 0x74},
+-{0x6071, 0x00},
+-{0x6072, 0x61},
+-{0x6073, 0x2a},
+-{0x6074, 0xd2},
+-{0x6075, 0xcc},
+-{0x6076, 0xdf},
+-{0x6077, 0xc6},
+-{0x6078, 0x35},
+-{0x6079, 0xd2},
+-{0x607a, 0xcc},
+-{0x607b, 0x06},
+-{0x607c, 0x31},
+-{0x607d, 0xd2},
+-{0x607e, 0xc5},
+-{0x607f, 0xbb},
+-{0x6080, 0xcc},
+-{0x6081, 0x18},
+-{0x6082, 0xc6},
+-{0x6083, 0xd2},
+-{0x6084, 0xbd},
+-{0x6085, 0xcc},
+-{0x6086, 0x52},
+-{0x6087, 0x2b},
+-{0x6088, 0xd2},
+-{0x6089, 0xd3},
+-{0x608a, 0x01},
+-{0x608b, 0xcc},
+-{0x608c, 0x0a},
+-{0x608d, 0xd2},
+-{0x608e, 0xd3},
+-{0x608f, 0x0f},
+-{0x6090, 0x1a},
+-{0x6091, 0x71},
+-{0x6092, 0x2a},
+-{0x6093, 0xd4},
+-{0x6094, 0xf6},
+-{0x6095, 0xd3},
+-{0x6096, 0x22},
+-{0x6097, 0x70},
+-{0x6098, 0xca},
+-{0x6099, 0x26},
+-{0x609a, 0xd2},
+-{0x609b, 0xcc},
+-{0x609c, 0x60},
+-{0x609d, 0xd2},
+-{0x609e, 0xd3},
+-{0x609f, 0x27},
+-{0x60a0, 0x27},
+-{0x60a1, 0x08},
+-{0x60a2, 0x1a},
+-{0x60a3, 0xcc},
+-{0x60a4, 0x88},
+-{0x60a5, 0x12},
+-{0x60a6, 0x2c},
+-{0x60a7, 0x60},
+-{0x60a8, 0x00},
+-{0x60a9, 0x00},
+-{0x60aa, 0xc0},
+-{0x60ab, 0xb9},
+-{0x60ac, 0xa3},
+-{0x60ad, 0xb5},
+-{0x60ae, 0x00},
+-{0x60af, 0xa0},
+-{0x60b0, 0x82},
+-{0x60b1, 0x5c},
+-{0x60b2, 0xd4},
+-{0x60b3, 0xa0},
+-{0x60b4, 0x9d},
+-{0x60b5, 0xd3},
+-{0x60b6, 0x26},
+-{0x60b7, 0xb0},
+-{0x60b8, 0xb7},
+-{0x60b9, 0x00},
+-{0x60ba, 0xd3},
+-{0x60bb, 0x0a},
+-{0x60bc, 0xd3},
+-{0x60bd, 0x10},
+-{0x60be, 0x9c},
+-{0x60bf, 0x94},
+-{0x60c0, 0x90},
+-{0x60c1, 0xc8},
+-{0x60c2, 0xba},
+-{0x60c3, 0x7c},
+-{0x60c4, 0x74},
+-{0x60c5, 0x00},
+-{0x60c6, 0x61},
+-{0x60c7, 0x2a},
+-{0x60c8, 0x00},
+-{0x60c9, 0xd2},
+-{0x60ca, 0xcc},
+-{0x60cb, 0xdf},
+-{0x60cc, 0xc4},
+-{0x60cd, 0x35},
+-{0x60ce, 0xd2},
+-{0x60cf, 0xcc},
+-{0x60d0, 0x06},
+-{0x60d1, 0x31},
+-{0x60d2, 0xd2},
+-{0x60d3, 0xcc},
+-{0x60d4, 0x15},
+-{0x60d5, 0xd2},
+-{0x60d6, 0xbb},
+-{0x60d7, 0xcc},
+-{0x60d8, 0x1a},
+-{0x60d9, 0xd2},
+-{0x60da, 0xbe},
+-{0x60db, 0xce},
+-{0x60dc, 0x52},
+-{0x60dd, 0xcf},
+-{0x60de, 0x56},
+-{0x60df, 0xd0},
+-{0x60e0, 0x5b},
+-{0x60e1, 0x2b},
+-{0x60e2, 0xd2},
+-{0x60e3, 0xd3},
+-{0x60e4, 0x01},
+-{0x60e5, 0xcc},
+-{0x60e6, 0x0a},
+-{0x60e7, 0xd2},
+-{0x60e8, 0xd3},
+-{0x60e9, 0x0f},
+-{0x60ea, 0xd9},
+-{0x60eb, 0xc7},
+-{0x60ec, 0xda},
+-{0x60ed, 0xce},
+-{0x60ee, 0x1a},
+-{0x60ef, 0xd4},
+-{0x60f0, 0xf6},
+-{0x60f1, 0xd4},
+-{0x60f2, 0xa9},
+-{0x60f3, 0x27},
+-{0x60f4, 0x00},
+-{0x60f5, 0xd2},
+-{0x60f6, 0xcc},
+-{0x60f7, 0x60},
+-{0x60f8, 0xd2},
+-{0x60f9, 0xd3},
+-{0x60fa, 0x2d},
+-{0x60fb, 0xd9},
+-{0x60fc, 0xdf},
+-{0x60fd, 0xda},
+-{0x60fe, 0xe5},
+-{0x60ff, 0x1a},
+-{0x6100, 0x12},
+-{0x6101, 0xcc},
+-{0x6102, 0x88},
+-{0x6103, 0xd6},
+-{0x6104, 0xb1},
+-{0x6105, 0xb9},
+-{0x6106, 0xba},
+-{0x6107, 0xaf},
+-{0x6108, 0xdc},
+-{0x6109, 0x00},
+-{0x610a, 0xcb},
+-{0x610b, 0xc3},
+-{0x610c, 0xb9},
+-{0x610d, 0xa4},
+-{0x610e, 0xb5},
+-{0x610f, 0x5c},
+-{0x6110, 0x12},
+-{0x6111, 0x2a},
+-{0x6112, 0x61},
+-{0x6113, 0xd2},
+-{0x6114, 0xcc},
+-{0x6115, 0xdf},
+-{0x6116, 0xc7},
+-{0x6117, 0x35},
+-{0x6118, 0xd2},
+-{0x6119, 0xcc},
+-{0x611a, 0x06},
+-{0x611b, 0x31},
+-{0x611c, 0xc6},
+-{0x611d, 0xbb},
+-{0x611e, 0xd2},
+-{0x611f, 0xcc},
+-{0x6120, 0x18},
+-{0x6121, 0xd2},
+-{0x6122, 0xbe},
+-{0x6123, 0xcc},
+-{0x6124, 0x52},
+-{0x6125, 0xc7},
+-{0x6126, 0xd2},
+-{0x6127, 0xcc},
+-{0x6128, 0x0a},
+-{0x6129, 0xb4},
+-{0x612a, 0xb7},
+-{0x612b, 0x94},
+-{0x612c, 0xd2},
+-{0x612d, 0x12},
+-{0x612e, 0x26},
+-{0x612f, 0x42},
+-{0x6130, 0x46},
+-{0x6131, 0x42},
+-{0x6132, 0xd3},
+-{0x6133, 0x20},
+-{0x6134, 0x27},
+-{0x6135, 0x00},
+-{0x6136, 0x1a},
+-{0x6137, 0xcc},
+-{0x6138, 0x88},
+-{0x6139, 0x60},
+-{0x613a, 0x2c},
+-{0x613b, 0x12},
+-{0x613c, 0x40},
+-{0x613d, 0xb8},
+-{0x613e, 0x90},
+-{0x613f, 0xd5},
+-{0x6140, 0xba},
+-{0x6141, 0x00},
+-{0x6142, 0x00},
+-{0x6143, 0x00},
+-{0x6144, 0x00},
+-{0x6145, 0x00},
+-{0x6146, 0x00},
+-{0x6147, 0xaa},
+-{0x6148, 0xb7},
+-{0x6149, 0x00},
+-{0x614a, 0x00},
+-{0x614b, 0x00},
+-{0x614c, 0x00},
+-{0x614d, 0xa6},
+-{0x614e, 0xb7},
+-{0x614f, 0x00},
+-{0x6150, 0xd5},
+-{0x6151, 0x00},
+-{0x6152, 0x71},
+-{0x6153, 0xd3},
+-{0x6154, 0x30},
+-{0x6155, 0xba},
+-{0x6156, 0x00},
+-{0x6157, 0x00},
+-{0x6158, 0x00},
+-{0x6159, 0x00},
+-{0x615a, 0xd3},
+-{0x615b, 0x10},
+-{0x615c, 0x70},
+-{0x615d, 0x00},
+-{0x615e, 0x00},
+-{0x615f, 0x00},
+-{0x6160, 0x00},
+-{0x6161, 0xd5},
+-{0x6162, 0xba},
+-{0x6163, 0xb0},
+-{0x6164, 0xb7},
+-{0x6165, 0x00},
+-{0x6166, 0x9d},
+-{0x6167, 0xd3},
+-{0x6168, 0x0a},
+-{0x6169, 0x9d},
+-{0x616a, 0x9d},
+-{0x616b, 0xd3},
+-{0x616c, 0x10},
+-{0x616d, 0x9c},
+-{0x616e, 0x94},
+-{0x616f, 0x90},
+-{0x6170, 0xc8},
+-{0x6171, 0xba},
+-{0x6172, 0xd2},
+-{0x6173, 0x60},
+-{0x6174, 0x2c},
+-{0x6175, 0x50},
+-{0x6176, 0x11},
+-{0x6177, 0xcc},
+-{0x6178, 0x00},
+-{0x6179, 0x30},
+-{0x617a, 0xd5},
+-{0x617b, 0x00},
+-{0x617c, 0xba},
+-{0x617d, 0xb0},
+-{0x617e, 0xb7},
+-{0x617f, 0x00},
+-{0x6180, 0x9d},
+-{0x6181, 0xd3},
+-{0x6182, 0x0a},
+-{0x6183, 0x9d},
+-{0x6184, 0x9d},
+-{0x6185, 0xd3},
+-{0x6186, 0x10},
+-{0x6187, 0x9c},
+-{0x6188, 0x94},
+-{0x6189, 0x90},
+-{0x618a, 0xc8},
+-{0x618b, 0xba},
+-{0x618c, 0xd5},
+-{0x618d, 0x00},
+-{0x618e, 0x01},
+-{0x618f, 0x1a},
+-{0x6190, 0xcc},
+-{0x6191, 0x12},
+-{0x6192, 0x12},
+-{0x6193, 0x00},
+-{0x6194, 0xcc},
+-{0x6195, 0x9c},
+-{0x6196, 0xd2},
+-{0x6197, 0xcc},
+-{0x6198, 0x60},
+-{0x6199, 0xd2},
+-{0x619a, 0x04},
+-{0x619b, 0xd5},
+-{0x619c, 0x1a},
+-{0x619d, 0xcc},
+-{0x619e, 0x12},
+-{0x619f, 0x00},
+-{0x61a0, 0x12},
+-{0x61a1, 0xcc},
+-{0x61a2, 0x9c},
+-{0x61a3, 0xd2},
+-{0x61a4, 0xcc},
+-{0x61a5, 0x60},
+-{0x61a6, 0xd2},
+-{0x61a7, 0x1a},
+-{0x61a8, 0xcc},
+-{0x61a9, 0x12},
+-{0x61aa, 0x00},
+-{0x61ab, 0x12},
+-{0x61ac, 0xcc},
+-{0x61ad, 0x9c},
+-{0x61ae, 0xd2},
+-{0x61af, 0xcc},
+-{0x61b0, 0x60},
+-{0x61b1, 0xd2},
+-{0x61b2, 0x1a},
+-{0x61b3, 0xcc},
+-{0x61b4, 0x12},
+-{0x61b5, 0x00},
+-{0x61b6, 0x12},
+-{0x61b7, 0xcc},
+-{0x61b8, 0x9c},
+-{0x61b9, 0xd2},
+-{0x61ba, 0xcc},
+-{0x61bb, 0x60},
+-{0x61bc, 0xd2},
+-{0x61bd, 0xd5},
+-{0x61be, 0x1a},
+-{0x61bf, 0xcc},
+-{0x61c0, 0x12},
+-{0x61c1, 0x12},
+-{0x61c2, 0x00},
+-{0x61c3, 0xcc},
+-{0x61c4, 0x8a},
+-{0x61c5, 0xd2},
+-{0x61c6, 0xcc},
+-{0x61c7, 0x74},
+-{0x61c8, 0xd2},
+-{0x61c9, 0xd5},
+-{0x61ca, 0x1a},
+-{0x61cb, 0xcc},
+-{0x61cc, 0x12},
+-{0x61cd, 0x00},
+-{0x61ce, 0x12},
+-{0x61cf, 0xcc},
+-{0x61d0, 0x8a},
+-{0x61d1, 0xd2},
+-{0x61d2, 0xcc},
+-{0x61d3, 0x74},
+-{0x61d4, 0xd2},
+-{0x61d5, 0x1a},
+-{0x61d6, 0xcc},
+-{0x61d7, 0x12},
+-{0x61d8, 0x00},
+-{0x61d9, 0x12},
+-{0x61da, 0xcc},
+-{0x61db, 0x8a},
+-{0x61dc, 0xd2},
+-{0x61dd, 0xcc},
+-{0x61de, 0x74},
+-{0x61df, 0xd2},
+-{0x61e0, 0x1a},
+-{0x61e1, 0xcc},
+-{0x61e2, 0x12},
+-{0x61e3, 0x00},
+-{0x61e4, 0x12},
+-{0x61e5, 0xcc},
+-{0x61e6, 0x8a},
+-{0x61e7, 0xd2},
+-{0x61e8, 0xcc},
+-{0x61e9, 0x74},
+-{0x61ea, 0xd2},
+-{0x61eb, 0xd5},
+-{0x61ec, 0xcc},
+-{0x61ed, 0x12},
+-{0x61ee, 0x00},
+-{0x61ef, 0x12},
+-{0x61f0, 0xcc},
+-{0x61f1, 0x9c},
+-{0x61f2, 0xd5},
+-{0x6400, 0x04},
+-{0x6401, 0x04},
+-{0x6402, 0x00},
+-{0x6403, 0xff},
+-{0x6404, 0x00},
+-{0x6405, 0x08},
+-{0x6406, 0x00},
+-{0x6407, 0xff},
+-{0x6408, 0x04},
+-{0x6409, 0x70},
+-{0x640a, 0x00},
+-{0x640b, 0xff},
+-{0x640c, 0x05},
+-{0x640d, 0x14},
+-{0x640e, 0x04},
+-{0x640f, 0x71},
+-{0x6410, 0x05},
+-{0x6411, 0x74},
+-{0x6412, 0x00},
+-{0x6413, 0xff},
+-{0x6414, 0x05},
+-{0x6415, 0x54},
+-{0x6416, 0x05},
+-{0x6417, 0x44},
+-{0x6418, 0x04},
+-{0x6419, 0x30},
+-{0x641a, 0x05},
+-{0x641b, 0x46},
+-{0x641c, 0x00},
+-{0x641d, 0xff},
+-{0x641e, 0x04},
+-{0x641f, 0x31},
+-{0x6420, 0x04},
+-{0x6421, 0x30},
+-{0x6422, 0x00},
+-{0x6423, 0xff},
+-{0x6424, 0x04},
+-{0x6425, 0x20},
+-{0x6426, 0x05},
+-{0x6427, 0x06},
+-{0x6428, 0x00},
+-{0x6429, 0xff},
+-{0x642a, 0x08},
+-{0x642b, 0x2a},
+-{0x642c, 0x08},
+-{0x642d, 0x31},
+-{0x642e, 0x00},
+-{0x642f, 0xff},
+-{0x6430, 0x08},
+-{0x6431, 0x2a},
+-{0x6432, 0x08},
+-{0x6433, 0x31},
+-{0x6434, 0x06},
+-{0x6435, 0x20},
+-{0x6436, 0x07},
+-{0x6437, 0x00},
+-{0x6438, 0x08},
+-{0x6439, 0x40},
+-{0x643a, 0x00},
+-{0x643b, 0xff},
+-{0x643c, 0x08},
+-{0x643d, 0x2a},
+-{0x643e, 0x08},
+-{0x643f, 0x36},
+-{0x6440, 0x06},
+-{0x6441, 0x10},
+-{0x6442, 0x07},
+-{0x6443, 0x00},
+-{0x6444, 0x08},
+-{0x6445, 0x40},
+-{0x6446, 0x00},
+-{0x6447, 0xff},
+-{0x6448, 0x08},
+-{0x6449, 0x2a},
+-{0x644a, 0x08},
+-{0x644b, 0x3b},
+-{0x644c, 0x06},
+-{0x644d, 0x00},
+-{0x644e, 0x07},
+-{0x644f, 0x00},
+-{0x6450, 0x08},
+-{0x6451, 0x40},
+-{0x6452, 0x00},
+-{0x6453, 0xff},
+-{0x6454, 0x06},
+-{0x6455, 0x00},
+-{0x6456, 0x07},
+-{0x6457, 0x05},
+-{0x6458, 0x01},
+-{0x6459, 0xaf},
+-{0x645a, 0x01},
+-{0x645b, 0x0f},
+-{0x645c, 0x01},
+-{0x645d, 0x90},
+-{0x645e, 0x01},
+-{0x645f, 0xc8},
+-{0x6460, 0x00},
+-{0x6461, 0xff},
+-{0x6462, 0x01},
+-{0x6463, 0xac},
+-{0x6464, 0x01},
+-{0x6465, 0x0c},
+-{0x6466, 0x01},
+-{0x6467, 0x90},
+-{0x6468, 0x01},
+-{0x6469, 0xe8},
+-{0x646a, 0x00},
+-{0x646b, 0xff},
+-{0x646c, 0x01},
+-{0x646d, 0xad},
+-{0x646e, 0x01},
+-{0x646f, 0x0d},
+-{0x6470, 0x01},
+-{0x6471, 0x90},
+-{0x6472, 0x01},
+-{0x6473, 0xe8},
+-{0x6474, 0x00},
+-{0x6475, 0xff},
+-{0x6476, 0x01},
+-{0x6477, 0xae},
+-{0x6478, 0x01},
+-{0x6479, 0x0e},
+-{0x647a, 0x01},
+-{0x647b, 0x90},
+-{0x647c, 0x01},
+-{0x647d, 0xe8},
+-{0x647e, 0x00},
+-{0x647f, 0xff},
+-{0x6480, 0x01},
+-{0x6481, 0xb0},
+-{0x6482, 0x01},
+-{0x6483, 0xb1},
+-{0x6484, 0x01},
+-{0x6485, 0xb2},
+-{0x6486, 0x01},
+-{0x6487, 0xb3},
+-{0x6488, 0x01},
+-{0x6489, 0xb4},
+-{0x648a, 0x01},
+-{0x648b, 0xb5},
+-{0x648c, 0x01},
+-{0x648d, 0xb6},
+-{0x648e, 0x01},
+-{0x648f, 0xb7},
+-{0x6490, 0x01},
+-{0x6491, 0xb8},
+-{0x6492, 0x01},
+-{0x6493, 0xb9},
+-{0x6494, 0x01},
+-{0x6495, 0xba},
+-{0x6496, 0x01},
+-{0x6497, 0xbb},
+-{0x6498, 0x01},
+-{0x6499, 0xbc},
+-{0x649a, 0x01},
+-{0x649b, 0xbd},
+-{0x649c, 0x01},
+-{0x649d, 0xbe},
+-{0x649e, 0x01},
+-{0x649f, 0xbf},
+-{0x64a0, 0x01},
+-{0x64a1, 0xc0},
+-{0x64a2, 0x00},
+-{0x64a3, 0xff},
+-{0x64a4, 0x06},
+-{0x64a5, 0x00},
+-{0x64a6, 0x01},
+-{0x64a7, 0xf6},
+-{0x64a8, 0x04},
+-{0x64a9, 0x30},
+-{0x64aa, 0x00},
+-{0x64ab, 0xff},
+-{0x64ac, 0x06},
+-{0x64ad, 0x10},
+-{0x64ae, 0x01},
+-{0x64af, 0xf6},
+-{0x64b0, 0x04},
+-{0x64b1, 0x30},
+-{0x64b2, 0x06},
+-{0x64b3, 0x00},
+-{0x64b4, 0x00},
+-{0x64b5, 0xff},
+-{0x64b6, 0x06},
+-{0x64b7, 0x20},
+-{0x64b8, 0x01},
+-{0x64b9, 0xf6},
+-{0x64ba, 0x04},
+-{0x64bb, 0x30},
+-{0x64bc, 0x06},
+-{0x64bd, 0x00},
+-{0x64be, 0x00},
+-{0x64bf, 0xff},
+-{0x64c0, 0x04},
+-{0x64c1, 0x31},
+-{0x64c2, 0x04},
+-{0x64c3, 0x30},
+-{0x64c4, 0x01},
+-{0x64c5, 0x20},
+-{0x64c6, 0x01},
+-{0x64c7, 0x31},
+-{0x64c8, 0x01},
+-{0x64c9, 0x32},
+-{0x64ca, 0x01},
+-{0x64cb, 0x33},
+-{0x64cc, 0x01},
+-{0x64cd, 0x34},
+-{0x64ce, 0x01},
+-{0x64cf, 0x35},
+-{0x64d0, 0x01},
+-{0x64d1, 0x36},
+-{0x64d2, 0x01},
+-{0x64d3, 0x37},
+-{0x64d4, 0x01},
+-{0x64d5, 0x38},
+-{0x64d6, 0x01},
+-{0x64d7, 0x39},
+-{0x64d8, 0x01},
+-{0x64d9, 0x3a},
+-{0x64da, 0x01},
+-{0x64db, 0x3b},
+-{0x64dc, 0x01},
+-{0x64dd, 0x3c},
+-{0x64de, 0x01},
+-{0x64df, 0x3d},
+-{0x64e0, 0x01},
+-{0x64e1, 0x3e},
+-{0x64e2, 0x01},
+-{0x64e3, 0x3f},
+-{0x64e4, 0x02},
+-{0x64e5, 0xa0},
+-{0x64e6, 0x00},
+-{0x64e7, 0xff},
+-{0x64e8, 0x04},
+-{0x64e9, 0x31},
+-{0x64ea, 0x04},
+-{0x64eb, 0x30},
+-{0x64ec, 0x01},
+-{0x64ed, 0x00},
+-{0x64ee, 0x01},
+-{0x64ef, 0x11},
+-{0x64f0, 0x01},
+-{0x64f1, 0x12},
+-{0x64f2, 0x01},
+-{0x64f3, 0x13},
+-{0x64f4, 0x01},
+-{0x64f5, 0x14},
+-{0x64f6, 0x01},
+-{0x64f7, 0x15},
+-{0x64f8, 0x01},
+-{0x64f9, 0x16},
+-{0x64fa, 0x01},
+-{0x64fb, 0x17},
+-{0x64fc, 0x01},
+-{0x64fd, 0x18},
+-{0x64fe, 0x01},
+-{0x64ff, 0x19},
+-{0x6500, 0x01},
+-{0x6501, 0x1a},
+-{0x6502, 0x01},
+-{0x6503, 0x1b},
+-{0x6504, 0x01},
+-{0x6505, 0x1c},
+-{0x6506, 0x01},
+-{0x6507, 0x1d},
+-{0x6508, 0x01},
+-{0x6509, 0x1e},
+-{0x650a, 0x01},
+-{0x650b, 0x1f},
+-{0x650c, 0x02},
+-{0x650d, 0xa0},
+-{0x650e, 0x00},
+-{0x650f, 0xff},
+-{0x6510, 0x04},
+-{0x6511, 0x20},
+-{0x6512, 0x05},
+-{0x6513, 0x86},
+-{0x6514, 0x03},
+-{0x6515, 0x0b},
+-{0x6516, 0x05},
+-{0x6517, 0x86},
+-{0x6518, 0x00},
+-{0x6519, 0x00},
+-{0x651a, 0x05},
+-{0x651b, 0x06},
+-{0x651c, 0x00},
+-{0x651d, 0x04},
+-{0x651e, 0x05},
+-{0x651f, 0x04},
+-{0x6520, 0x00},
+-{0x6521, 0x04},
+-{0x6522, 0x05},
+-{0x6523, 0x00},
+-{0x6524, 0x05},
+-{0x6525, 0x0a},
+-{0x6526, 0x03},
+-{0x6527, 0x9a},
+-{0x6528, 0x05},
+-{0x6529, 0x86},
+-{0x652a, 0x00},
+-{0x652b, 0x00},
+-{0x652c, 0x05},
+-{0x652d, 0x06},
+-{0x652e, 0x00},
+-{0x652f, 0x01},
+-{0x6530, 0x05},
+-{0x6531, 0x04},
+-{0x6532, 0x00},
+-{0x6533, 0x04},
+-{0x6534, 0x05},
+-{0x6535, 0x00},
+-{0x6536, 0x05},
+-{0x6537, 0x0a},
+-{0x6538, 0x03},
+-{0x6539, 0x99},
+-{0x653a, 0x05},
+-{0x653b, 0x06},
+-{0x653c, 0x00},
+-{0x653d, 0x00},
+-{0x653e, 0x05},
+-{0x653f, 0x04},
+-{0x6540, 0x00},
+-{0x6541, 0x04},
+-{0x6542, 0x05},
+-{0x6543, 0x00},
+-{0x6544, 0x05},
+-{0x6545, 0x0a},
+-{0x6546, 0x03},
+-{0x6547, 0x98},
+-{0x6548, 0x05},
+-{0x6549, 0x06},
+-{0x654a, 0x00},
+-{0x654b, 0x00},
+-{0x654c, 0x05},
+-{0x654d, 0x04},
+-{0x654e, 0x00},
+-{0x654f, 0x04},
+-{0x6550, 0x05},
+-{0x6551, 0x00},
+-{0x6552, 0x05},
+-{0x6553, 0x0a},
+-{0x6554, 0x03},
+-{0x6555, 0x97},
+-{0x6556, 0x05},
+-{0x6557, 0x06},
+-{0x6558, 0x05},
+-{0x6559, 0x04},
+-{0x655a, 0x00},
+-{0x655b, 0x04},
+-{0x655c, 0x05},
+-{0x655d, 0x00},
+-{0x655e, 0x05},
+-{0x655f, 0x0a},
+-{0x6560, 0x03},
+-{0x6561, 0x96},
+-{0x6562, 0x05},
+-{0x6563, 0x06},
+-{0x6564, 0x05},
+-{0x6565, 0x04},
+-{0x6566, 0x00},
+-{0x6567, 0x04},
+-{0x6568, 0x05},
+-{0x6569, 0x00},
+-{0x656a, 0x05},
+-{0x656b, 0x0a},
+-{0x656c, 0x03},
+-{0x656d, 0x95},
+-{0x656e, 0x05},
+-{0x656f, 0x06},
+-{0x6570, 0x05},
+-{0x6571, 0x04},
+-{0x6572, 0x00},
+-{0x6573, 0x04},
+-{0x6574, 0x05},
+-{0x6575, 0x00},
+-{0x6576, 0x05},
+-{0x6577, 0x0a},
+-{0x6578, 0x03},
+-{0x6579, 0x94},
+-{0x657a, 0x05},
+-{0x657b, 0x06},
+-{0x657c, 0x00},
+-{0x657d, 0x00},
+-{0x657e, 0x05},
+-{0x657f, 0x04},
+-{0x6580, 0x00},
+-{0x6581, 0x04},
+-{0x6582, 0x05},
+-{0x6583, 0x00},
+-{0x6584, 0x05},
+-{0x6585, 0x0a},
+-{0x6586, 0x03},
+-{0x6587, 0x93},
+-{0x6588, 0x05},
+-{0x6589, 0x06},
+-{0x658a, 0x00},
+-{0x658b, 0x00},
+-{0x658c, 0x05},
+-{0x658d, 0x04},
+-{0x658e, 0x00},
+-{0x658f, 0x04},
+-{0x6590, 0x05},
+-{0x6591, 0x00},
+-{0x6592, 0x05},
+-{0x6593, 0x0a},
+-{0x6594, 0x03},
+-{0x6595, 0x92},
+-{0x6596, 0x05},
+-{0x6597, 0x06},
+-{0x6598, 0x05},
+-{0x6599, 0x04},
+-{0x659a, 0x00},
+-{0x659b, 0x04},
+-{0x659c, 0x05},
+-{0x659d, 0x00},
+-{0x659e, 0x05},
+-{0x659f, 0x0a},
+-{0x65a0, 0x03},
+-{0x65a1, 0x91},
+-{0x65a2, 0x05},
+-{0x65a3, 0x06},
+-{0x65a4, 0x05},
+-{0x65a5, 0x04},
+-{0x65a6, 0x00},
+-{0x65a7, 0x04},
+-{0x65a8, 0x05},
+-{0x65a9, 0x00},
+-{0x65aa, 0x05},
+-{0x65ab, 0x0a},
+-{0x65ac, 0x03},
+-{0x65ad, 0x90},
+-{0x65ae, 0x05},
+-{0x65af, 0x06},
+-{0x65b0, 0x05},
+-{0x65b1, 0x04},
+-{0x65b2, 0x00},
+-{0x65b3, 0x04},
+-{0x65b4, 0x05},
+-{0x65b5, 0x00},
+-{0x65b6, 0x05},
+-{0x65b7, 0x0a},
+-{0x65b8, 0x02},
+-{0x65b9, 0x90},
+-{0x65ba, 0x05},
+-{0x65bb, 0x06},
+-{0x65bc, 0x00},
+-{0x65bd, 0xff},
+-{0x65be, 0x04},
+-{0x65bf, 0x70},
+-{0x65c0, 0x08},
+-{0x65c1, 0x76},
+-{0x65c2, 0x00},
+-{0x65c3, 0xff},
+-{0x65c4, 0x08},
+-{0x65c5, 0x76},
+-{0x65c6, 0x04},
+-{0x65c7, 0x0c},
+-{0x65c8, 0x05},
+-{0x65c9, 0x07},
+-{0x65ca, 0x04},
+-{0x65cb, 0x04},
+-{0x65cc, 0x00},
+-{0x65cd, 0xff},
+-{0x65ce, 0x00},
+-{0x65cf, 0xff},
+-{0x65d0, 0x00},
+-{0x65d1, 0xff},
+-{0x30eb, 0x04},
+-{0x30ed, 0x5a},
+-{0x30ee, 0x01},
+-{0x30ef, 0x80},
+-{0x30f1, 0x5a},
+-{0x303a, 0x04},
+-{0x303b, 0x7f},
+-{0x303c, 0xfe},
+-{0x303d, 0x19},
+-{0x303e, 0xd7},
+-{0x303f, 0x09},
+-{0x3040, 0x78},
+-{0x3042, 0x05},
+-{0x328a, 0x10},
+-
+-{0x3291, 0x03}, /* 7:enable flip and mirror offset may on 20150330 */
+-
+-/* change settings to 1280x1080 COMB12 30 fps, 96MHz */
+-{0x3012, 0x0},
+-{0x3000, 0x3},
+-{0x3001, 0x50},
+-{0x3002, 0x0a},
+-{0x3004, 0x3},
+-{0x3005, 0x48},
+-{0x3006, 0x7},
+-{0x308f, 0x10},
+-{0x3127, 0x63},
+-{0x3074, OV10640_X_START >> 8},
+-{0x3075, OV10640_X_START & 0xff},
+-{0x3076, OV10640_Y_START >> 8},
+-{0x3077, OV10640_Y_START & 0xff},
+-{0x3078, OV10640_X_END >> 8},
+-{0x3079, OV10640_X_END & 0xff},
+-{0x307a, OV10640_Y_END >> 8},
+-{0x307b, OV10640_Y_END & 0xff},
+-{0x307c, OV10640_MAX_WIDTH >> 8},
+-{0x307d, OV10640_MAX_WIDTH & 0xff},
+-{0x307e, OV10640_MAX_HEIGHT >> 8},
+-{0x307f, OV10640_MAX_HEIGHT & 0xff},
+-{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
+-{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
+-{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
+-{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff},
+-{0x3084, 0x0},
+-{0x3085, 0x0},
+-{0x3086, 0x0},
+-{0x3087, 0x0},
+-{0x346d, 0x14},
+-{0x3444, 0x28},
+-{0x3091, 0x0},
+-{0x3119, 0x44}, // COMB12
+-{0x3012, 0x1},
+-};
++#include "ov10640_r1d.h"
++#include "ov10640_r1e.h"
++#include "ov10640_r1f.h"
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1d.h b/drivers/media/i2c/soc_camera/ov10640_r1d.h
+new file mode 100644
+index 0000000..374b6d1
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ov10640_r1d.h
+@@ -0,0 +1,1240 @@
++/*
++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit
++ *
++ * Copyright (C) 2015-2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++/* DVP_1280x960_COMB12_raw 30fps */
++static const struct ov10640_reg ov10640_regs_wizard_r1d[] = {
++//{0x3013, 0x01},
++//{OV10640_DELAY, 10},
++{0x328a, 0x01},
++{0x313f, 0x80},
++{0x3132, 0x24},
++{0x3000, 0x03},
++{0x3001, 0x38},
++{0x3002, 0x07},
++{0x3004, 0x03},
++{0x3005, 0x38},
++{0x3006, 0x07},
++{0x3007, 0x01},
++{0x3014, 0x03},
++{0x3023, 0x05},
++{0x3032, 0x34},
++{0x3033, 0xfb},
++{0x3054, 0x00},
++{0x3055, 0x0f},
++{0x3056, 0x01},
++{0x3057, 0xff},
++{0x3058, 0xbf},
++{0x3059, 0x44},
++{0x305a, 0x02},
++{0x305b, 0x00},
++{0x305c, 0x30},
++{0x305d, 0x1d},
++{0x305e, 0x16},
++{0x305f, 0x18},
++{0x3060, 0xf9},
++{0x3061, 0xf0},
++#ifdef OV10640_FSIN_ENABLE
++{0x308c, 0xb2},
++#else
++{0x308c, 0x03},
++#endif
++{0x308f, 0x20},
++{0x3090, 0x00},
++{0x3091, 0x00},
++{0x30eb, 0x00},
++{0x30a3, 0x08},
++{0x30ad, 0x03},
++{0x30ae, 0x80},
++{0x30af, 0x80},
++{0x30b0, 0xff},
++{0x30b1, 0x3f},
++{0x30b2, 0x22},
++{0x30b9, 0x22},
++{0x30bb, 0x00},
++{0x30bc, 0x00},
++{0x30bd, 0x00},
++{0x30be, 0x00},
++{0x30bf, 0x00},
++{0x30c0, 0x00},
++{0x30c1, 0x00},
++{0x30c2, 0x00},
++{0x30c3, 0x00},
++{0x30c4, 0x80},
++{0x30c5, 0x00},
++{0x30c6, 0x80},
++{0x30c7, 0x00},
++{0x30c8, 0x80},
++{0x3119, 0x45},
++{0x311a, 0x01},
++{0x311b, 0x4a},
++{0x3074, 0x00},
++{0x3075, 0x00},
++{0x3076, 0x00},
++{0x3077, 0x3e},
++{0x3078, 0x05},
++{0x3079, 0x07},
++{0x307a, 0x04},
++{0x307b, 0x05},
++{0x307c, 0x05},
++{0x307d, 0x00},
++{0x307e, 0x03},
++{0x307f, 0xc0},
++{0x3080, 0x07},
++{0x3081, 0x43},
++{0x3082, 0x03},
++{0x3083, 0xec},
++{0x3084, 0x00},
++{0x3085, 0x02},
++{0x3086, 0x00},
++{0x3087, 0x04},
++{0x3088, 0x00},
++{0x3089, 0x40},
++{0x308d, 0x92},
++{0x3094, 0xa5},
++{0x30e6, 0x03},
++{0x30e7, 0xe8},
++{0x30e8, 0x03},
++{0x30e9, 0xe8},
++{0x30e9, 0x05},
++{0x30ec, 0x01},
++{0x30fa, 0x06},
++{0x3120, 0x00},
++{0x3121, 0x01},
++{0x3122, 0x00},
++{0x3127, 0x63},
++{0x3128, 0xc0},
++#ifdef OV10640_DISPLAY_PATTERN
++{0x3129, 0x80},
++#else
++{0x3129, 0x00},
++#endif
++{0x31be, 0x00},
++{0x30a5, 0x78},
++{0x30a6, 0x40},
++{0x30a7, 0x78},
++{0x30a8, 0x80},
++{0x30a9, 0x78},
++{0x30aa, 0xe0},
++{0x30ab, 0x79},
++{0x30ac, 0xc0},
++{0x3440, 0x04},
++{0x3444, 0x28},
++{0x344e, 0x2c},
++{0x3457, 0x33},
++{0x345e, 0x38},
++{0x3461, 0xa8},
++{0x7002, 0xaa},
++{0x7001, 0xdf},
++{0x7048, 0x00},
++{0x7049, 0x02},
++{0x704a, 0x02},
++{0x704b, 0x00},
++{0x704c, 0x01},
++{0x704d, 0x00},
++{0x7043, 0x04},
++{0x7040, 0x3c},
++{0x7047, 0x00},
++{0x7044, 0x01},
++{0x7000, 0x1f},
++{0x7084, 0x01},
++{0x7085, 0x03},
++{0x7086, 0x02},
++{0x7087, 0x40},
++{0x7088, 0x01},
++{0x7089, 0x20},
++{0x707f, 0x04},
++{0x707c, 0x3c},
++{0x7083, 0x00},
++{0x7080, 0x01},
++{0x7003, 0xdf},
++{0x70c0, 0x00},
++{0x70c1, 0x02},
++{0x70c2, 0x02},
++{0x70c3, 0x00},
++{0x70c4, 0x01},
++{0x70c5, 0x00},
++{0x70b8, 0x03},
++{0x70b9, 0x98},
++{0x70bc, 0x00},
++{0x70bd, 0x80},
++{0x7004, 0x02},
++{0x7005, 0x00},
++{0x7006, 0x01},
++{0x7007, 0x80},
++{0x7008, 0x02},
++{0x7009, 0x00},
++{0x700a, 0x04},
++{0x700b, 0x00},
++{0x700e, 0x00},
++{0x700f, 0x60},
++{0x701a, 0x02},
++{0x701b, 0x00},
++{0x701c, 0x01},
++{0x701d, 0x80},
++{0x701e, 0x02},
++{0x701f, 0x00},
++{0x7020, 0x04},
++{0x7021, 0x00},
++{0x7024, 0x00},
++{0x7025, 0x60},
++{0x70e7, 0x00},
++{0x70e4, 0x10},
++{0x70e5, 0x00},
++{0x70e6, 0x00},
++{0x70eb, 0x00},
++{0x70e8, 0x10},
++{0x70e9, 0x00},
++{0x70ea, 0x00},
++{0x70ef, 0x00},
++{0x70ec, 0xfd},
++{0x70ed, 0x00},
++{0x70ee, 0x00},
++{0x70eb, 0x00},
++{0x70f0, 0xfd},
++{0x70f1, 0x00},
++{0x70f2, 0x00},
++{0x30fb, 0x06},
++{0x30fc, 0x80},
++{0x30fd, 0x02},
++{0x30fe, 0x93},
++{0x6000, 0xc1},
++{0x6001, 0xb9},
++{0x6002, 0xba},
++{0x6003, 0xa4},
++{0x6004, 0xb5},
++{0x6005, 0xa0},
++{0x6006, 0x82},
++{0x6007, 0xa7},
++{0x6008, 0xb7},
++{0x6009, 0x5c},
++{0x600a, 0x9e},
++{0x600b, 0xc0},
++{0x600c, 0xd2},
++{0x600d, 0x33},
++{0x600e, 0xcc},
++{0x600f, 0xde},
++{0x6010, 0xc1},
++{0x6011, 0xab},
++{0x6012, 0xb7},
++{0x6013, 0x00},
++{0x6014, 0x00},
++{0x6015, 0x00},
++{0x6016, 0x00},
++{0x6017, 0x00},
++{0x6018, 0x00},
++{0x6019, 0x00},
++{0x601a, 0x00},
++{0x601b, 0x00},
++{0x601c, 0x00},
++{0x601d, 0xc5},
++{0x601e, 0x54},
++{0x601f, 0x9c},
++{0x6020, 0x94},
++{0x6021, 0x90},
++{0x6022, 0x2a},
++{0x6023, 0x61},
++{0x6024, 0xd2},
++{0x6025, 0xcc},
++{0x6026, 0x02},
++{0x6027, 0x35},
++{0x6028, 0xb1},
++{0x6029, 0xb2},
++{0x602a, 0xb3},
++{0x602b, 0xd2},
++{0x602c, 0xd3},
++{0x602d, 0x0a},
++{0x602e, 0x31},
++{0x602f, 0xcc},
++{0x6030, 0x05},
++{0x6031, 0xc4},
++{0x6032, 0xd2},
++{0x6033, 0xce},
++{0x6034, 0x17},
++{0x6035, 0xcf},
++{0x6036, 0x1d},
++{0x6037, 0xd0},
++{0x6038, 0x23},
++{0x6039, 0xd2},
++{0x603a, 0xbc},
++{0x603b, 0xcc},
++{0x603c, 0x51},
++{0x603d, 0xc5},
++{0x603e, 0xd2},
++{0x603f, 0x00},
++{0x6040, 0x2b},
++{0x6041, 0xcc},
++{0x6042, 0x09},
++{0x6043, 0xd2},
++{0x6044, 0x1a},
++{0x6045, 0xcc},
++{0x6046, 0xeb},
++{0x6047, 0x12},
++{0x6048, 0x2a},
++{0x6049, 0xba},
++{0x604a, 0x56},
++{0x604b, 0xd3},
++{0x604c, 0x27},
++{0x604d, 0x54},
++{0x604e, 0xd4},
++{0x604f, 0xc1},
++{0x6050, 0x26},
++{0x6051, 0xd2},
++{0x6052, 0x01},
++{0x6053, 0xd3},
++{0x6054, 0x2f},
++{0x6055, 0x27},
++{0x6056, 0x08},
++{0x6057, 0x1a},
++{0x6058, 0xcc},
++{0x6059, 0xd9},
++{0x605a, 0x12},
++{0x605b, 0x2c},
++{0x605c, 0x11},
++{0x605d, 0x60},
++{0x605e, 0x50},
++{0x605f, 0xc2},
++{0x6060, 0xb9},
++{0x6061, 0xa5},
++{0x6062, 0xb5},
++{0x6063, 0xa0},
++{0x6064, 0x82},
++{0x6065, 0x5c},
++{0x6066, 0xd4},
++{0x6067, 0xc1},
++{0x6068, 0xd4},
++{0x6069, 0xc1},
++{0x606a, 0xd3},
++{0x606b, 0x01},
++{0x606c, 0x7c},
++{0x606d, 0x74},
++{0x606e, 0x00},
++{0x606f, 0x2a},
++{0x6070, 0x61},
++{0x6071, 0xd2},
++{0x6072, 0xcc},
++{0x6073, 0xde},
++{0x6074, 0xc6},
++{0x6075, 0xd2},
++{0x6076, 0xcc},
++{0x6077, 0x02},
++{0x6078, 0x35},
++{0x6079, 0xd3},
++{0x607a, 0x0f},
++{0x607b, 0x31},
++{0x607c, 0xcc},
++{0x607d, 0x05},
++{0x607e, 0xc5},
++{0x607f, 0xd2},
++{0x6080, 0xbb},
++{0x6081, 0xcc},
++{0x6082, 0x17},
++{0x6083, 0xd2},
++{0x6084, 0xbd},
++{0x6085, 0xcc},
++{0x6086, 0x51},
++{0x6087, 0xc6},
++{0x6088, 0xd2},
++{0x6089, 0x2b},
++{0x608a, 0xcc},
++{0x608b, 0x09},
++{0x608c, 0xd2},
++{0x608d, 0x1a},
++{0x608e, 0xcc},
++{0x608f, 0xeb},
++{0x6090, 0x71},
++{0x6091, 0x12},
++{0x6092, 0x2a},
++{0x6093, 0xd3},
++{0x6094, 0x24},
++{0x6095, 0x00},
++{0x6096, 0x00},
++{0x6097, 0x70},
++{0x6098, 0xca},
++{0x6099, 0x26},
++{0x609a, 0xd2},
++{0x609b, 0x01},
++{0x609c, 0xd3},
++{0x609d, 0x2f},
++{0x609e, 0x27},
++{0x609f, 0x08},
++{0x60a0, 0x1a},
++{0x60a1, 0x12},
++{0x60a2, 0xcc},
++{0x60a3, 0xd9},
++{0x60a4, 0x60},
++{0x60a5, 0x2c},
++{0x60a6, 0x11},
++{0x60a7, 0x50},
++{0x60a8, 0x00},
++{0x60a9, 0x00},
++{0x60aa, 0xc0},
++{0x60ab, 0xb9},
++{0x60ac, 0xa3},
++{0x60ad, 0xb5},
++{0x60ae, 0xb5},
++{0x60af, 0x00},
++{0x60b0, 0xa0},
++{0x60b1, 0x82},
++{0x60b2, 0x5c},
++{0x60b3, 0xd4},
++{0x60b4, 0xa6},
++{0x60b5, 0x9d},
++{0x60b6, 0xd3},
++{0x60b7, 0x34},
++{0x60b8, 0xb0},
++{0x60b9, 0xb7},
++{0x60ba, 0x00},
++{0x60bb, 0xd3},
++{0x60bc, 0x0a},
++{0x60bd, 0xd3},
++{0x60be, 0x10},
++{0x60bf, 0x9c},
++{0x60c0, 0x94},
++{0x60c1, 0x90},
++{0x60c2, 0xc8},
++{0x60c3, 0xba},
++{0x60c4, 0x7c},
++{0x60c5, 0x74},
++{0x60c6, 0x00},
++{0x60c7, 0x2a},
++{0x60c8, 0x61},
++{0x60c9, 0x00},
++{0x60ca, 0xd2},
++{0x60cb, 0xcc},
++{0x60cc, 0xde},
++{0x60cd, 0xc4},
++{0x60ce, 0xd2},
++{0x60cf, 0xcc},
++{0x60d0, 0x02},
++{0x60d1, 0x35},
++{0x60d2, 0xd2},
++{0x60d3, 0xcc},
++{0x60d4, 0x14},
++{0x60d5, 0xd3},
++{0x60d6, 0x09},
++{0x60d7, 0x31},
++{0x60d8, 0xd2},
++{0x60d9, 0xcc},
++{0x60da, 0x05},
++{0x60db, 0xd2},
++{0x60dc, 0xbb},
++{0x60dd, 0xcc},
++{0x60de, 0x19},
++{0x60df, 0xd2},
++{0x60e0, 0xbe},
++{0x60e1, 0xce},
++{0x60e2, 0x51},
++{0x60e3, 0xcf},
++{0x60e4, 0x54},
++{0x60e5, 0xd0},
++{0x60e6, 0x58},
++{0x60e7, 0xd3},
++{0x60e8, 0x01},
++{0x60e9, 0x2b},
++{0x60ea, 0xcc},
++{0x60eb, 0x09},
++{0x60ec, 0xd2},
++{0x60ed, 0xd9},
++{0x60ee, 0xd3},
++{0x60ef, 0xda},
++{0x60f0, 0xd7},
++{0x60f1, 0x1a},
++{0x60f2, 0xcc},
++{0x60f3, 0xeb},
++{0x60f4, 0x12},
++{0x60f5, 0xd4},
++{0x60f6, 0xaf},
++{0x60f7, 0x27},
++{0x60f8, 0x00},
++{0x60f9, 0xd2},
++{0x60fa, 0xd3},
++{0x60fb, 0x3b},
++{0x60fc, 0xd9},
++{0x60fd, 0xe0},
++{0x60fe, 0xda},
++{0x60ff, 0xe4},
++{0x6100, 0x1a},
++{0x6101, 0x12},
++{0x6102, 0xcc},
++{0x6103, 0xd9},
++{0x6104, 0x60},
++{0x6105, 0x10},
++{0x6106, 0x2c},
++{0x6107, 0x5d},
++{0x6108, 0xd3},
++{0x6109, 0x0a},
++{0x610a, 0x5c},
++{0x610b, 0x01},
++{0x610c, 0x50},
++{0x610d, 0x11},
++{0x610e, 0xd6},
++{0x610f, 0xb7},
++{0x6110, 0xb9},
++{0x6111, 0xba},
++{0x6112, 0xaf},
++{0x6113, 0xdc},
++{0x6114, 0xcb},
++{0x6115, 0xc3},
++{0x6116, 0xb9},
++{0x6117, 0xa4},
++{0x6118, 0xb5},
++{0x6119, 0x5c},
++{0x611a, 0x12},
++{0x611b, 0x2a},
++{0x611c, 0x61},
++{0x611d, 0xd2},
++{0x611e, 0xcc},
++{0x611f, 0xe2},
++{0x6120, 0x35},
++{0x6121, 0xc7},
++{0x6122, 0xd2},
++{0x6123, 0x31},
++{0x6124, 0xcc},
++{0x6125, 0x05},
++{0x6126, 0xc6},
++{0x6127, 0xbb},
++{0x6128, 0xd2},
++{0x6129, 0xcc},
++{0x612a, 0x17},
++{0x612b, 0xd2},
++{0x612c, 0xbe},
++{0x612d, 0xcc},
++{0x612e, 0x51},
++{0x612f, 0xc7},
++{0x6130, 0xd2},
++{0x6131, 0xcc},
++{0x6132, 0x09},
++{0x6133, 0xb4},
++{0x6134, 0xb7},
++{0x6135, 0x94},
++{0x6136, 0xd2},
++{0x6137, 0x12},
++{0x6138, 0x26},
++{0x6139, 0x42},
++{0x613a, 0x46},
++{0x613b, 0x42},
++{0x613c, 0xd3},
++{0x613d, 0x20},
++{0x613e, 0x27},
++{0x613f, 0x00},
++{0x6140, 0x1a},
++{0x6141, 0xcc},
++{0x6142, 0xd9},
++{0x6143, 0x60},
++{0x6144, 0x2c},
++{0x6145, 0x11},
++{0x6146, 0x40},
++{0x6147, 0x50},
++{0x6148, 0xb8},
++{0x6149, 0x90},
++{0x614a, 0xd5},
++{0x614b, 0x00},
++{0x614c, 0xba},
++{0x614d, 0x00},
++{0x614e, 0x00},
++{0x614f, 0x00},
++{0x6150, 0x00},
++{0x6151, 0x00},
++{0x6152, 0x00},
++{0x6153, 0xaa},
++{0x6154, 0xb7},
++{0x6155, 0x00},
++{0x6156, 0x00},
++{0x6157, 0x00},
++{0x6158, 0x00},
++{0x6159, 0xa6},
++{0x615a, 0xb7},
++{0x615b, 0x00},
++{0x615c, 0xd5},
++{0x615d, 0x00},
++{0x615e, 0x71},
++{0x615f, 0xd3},
++{0x6160, 0x3e},
++{0x6161, 0xba},
++{0x6162, 0x00},
++{0x6163, 0x00},
++{0x6164, 0x00},
++{0x6165, 0x00},
++{0x6166, 0xd3},
++{0x6167, 0x10},
++{0x6168, 0x70},
++{0x6169, 0x00},
++{0x616a, 0x00},
++{0x616b, 0x00},
++{0x616c, 0x00},
++{0x616d, 0xd5},
++{0x616e, 0xba},
++{0x616f, 0xb0},
++{0x6170, 0xb7},
++{0x6171, 0x00},
++{0x6172, 0x9d},
++{0x6173, 0xd3},
++{0x6174, 0x0a},
++{0x6175, 0x9d},
++{0x6176, 0x9d},
++{0x6177, 0xd3},
++{0x6178, 0x10},
++{0x6179, 0x9c},
++{0x617a, 0x94},
++{0x617b, 0x90},
++{0x617c, 0xc8},
++{0x617d, 0xba},
++{0x617e, 0xd2},
++{0x617f, 0x30},
++{0x6180, 0xd5},
++{0x6181, 0x00},
++{0x6182, 0xba},
++{0x6183, 0xb0},
++{0x6184, 0xb7},
++{0x6185, 0x00},
++{0x6186, 0x9d},
++{0x6187, 0xd3},
++{0x6188, 0x0a},
++{0x6189, 0x9d},
++{0x618a, 0x9d},
++{0x618b, 0xd3},
++{0x618c, 0x10},
++{0x618d, 0x9c},
++{0x618e, 0x94},
++{0x618f, 0x90},
++{0x6190, 0xc8},
++{0x6191, 0xba},
++{0x6192, 0xd5},
++{0x6193, 0x00},
++{0x6194, 0xba},
++{0x6195, 0xb0},
++{0x6196, 0xb7},
++{0x6197, 0x00},
++{0x6198, 0x9d},
++{0x6199, 0xd3},
++{0x619a, 0x0a},
++{0x619b, 0x9d},
++{0x619c, 0x9d},
++{0x619d, 0xd3},
++{0x619e, 0x10},
++{0x619f, 0x9c},
++{0x61a0, 0x94},
++{0x61a1, 0x90},
++{0x61a2, 0xc9},
++{0x61a3, 0xba},
++{0x61a4, 0xd5},
++{0x61a5, 0x00},
++{0x61a6, 0x00},
++{0x61a7, 0x1a},
++{0x61a8, 0x12},
++{0x61a9, 0xcc},
++{0x61aa, 0xeb},
++{0x61ab, 0xd2},
++{0x61ac, 0xd5},
++{0x61ad, 0x00},
++{0x61ae, 0x00},
++{0x61af, 0x1a},
++{0x61b0, 0x12},
++{0x61b1, 0xcc},
++{0x61b2, 0xeb},
++{0x61b3, 0xd2},
++{0x61b4, 0x1a},
++{0x61b5, 0x12},
++{0x61b6, 0xcc},
++{0x61b7, 0xeb},
++{0x61b8, 0xd2},
++{0x61b9, 0x1a},
++{0x61ba, 0x12},
++{0x61bb, 0xcc},
++{0x61bc, 0xeb},
++{0x61bd, 0xd2},
++{0x61be, 0xd5},
++{0x61bf, 0x00},
++{0x61c0, 0x00},
++{0x61c1, 0x1a},
++{0x61c2, 0xcc},
++{0x61c3, 0xf0},
++{0x61c4, 0x12},
++{0x61c5, 0xd2},
++{0x61c6, 0xd5},
++{0x61c7, 0x00},
++{0x61c8, 0x00},
++{0x61c9, 0x1a},
++{0x61ca, 0xcc},
++{0x61cb, 0xf0},
++{0x61cc, 0x12},
++{0x61cd, 0xd2},
++{0x61ce, 0x1a},
++{0x61cf, 0xcc},
++{0x61d0, 0xf0},
++{0x61d1, 0x12},
++{0x61d2, 0xd2},
++{0x61d3, 0x1a},
++{0x61d4, 0xcc},
++{0x61d5, 0xf0},
++{0x61d6, 0x12},
++{0x61d7, 0xd2},
++{0x61d8, 0xd5},
++{0x6400, 0x00},
++{0x6401, 0x08},
++{0x6402, 0x00},
++{0x6403, 0xff},
++{0x6404, 0x04},
++{0x6405, 0x61},
++{0x6406, 0x04},
++{0x6407, 0x70},
++{0x6408, 0x00},
++{0x6409, 0xff},
++{0x640a, 0x05},
++{0x640b, 0x14},
++{0x640c, 0x04},
++{0x640d, 0x70},
++{0x640e, 0x05},
++{0x640f, 0x74},
++{0x6410, 0x00},
++{0x6411, 0xff},
++{0x6412, 0x05},
++{0x6413, 0x54},
++{0x6414, 0x04},
++{0x6415, 0x30},
++{0x6416, 0x05},
++{0x6417, 0x44},
++{0x6418, 0x05},
++{0x6419, 0x47},
++{0x641a, 0x00},
++{0x641b, 0xff},
++{0x641c, 0x04},
++{0x641d, 0x31},
++{0x641e, 0x04},
++{0x641f, 0x30},
++{0x6420, 0x00},
++{0x6421, 0xff},
++{0x6422, 0x04},
++{0x6423, 0x20},
++{0x6424, 0x05},
++{0x6425, 0x06},
++{0x6426, 0x00},
++{0x6427, 0xff},
++{0x6428, 0x08},
++{0x6429, 0x29},
++{0x642a, 0x08},
++{0x642b, 0x30},
++{0x642c, 0x00},
++{0x642d, 0xff},
++{0x642e, 0x08},
++{0x642f, 0x29},
++{0x6430, 0x08},
++{0x6431, 0x30},
++{0x6432, 0x06},
++{0x6433, 0x20},
++{0x6434, 0x07},
++{0x6435, 0x00},
++{0x6436, 0x08},
++{0x6437, 0x3f},
++{0x6438, 0x00},
++{0x6439, 0xff},
++{0x643a, 0x08},
++{0x643b, 0x29},
++{0x643c, 0x08},
++{0x643d, 0x35},
++{0x643e, 0x06},
++{0x643f, 0x10},
++{0x6440, 0x07},
++{0x6441, 0x00},
++{0x6442, 0x08},
++{0x6443, 0x3f},
++{0x6444, 0x00},
++{0x6445, 0xff},
++{0x6446, 0x08},
++{0x6447, 0x29},
++{0x6448, 0x08},
++{0x6449, 0x3a},
++{0x644a, 0x06},
++{0x644b, 0x00},
++{0x644c, 0x07},
++{0x644d, 0x00},
++{0x644e, 0x08},
++{0x644f, 0x3f},
++{0x6450, 0x00},
++{0x6451, 0xff},
++{0x6452, 0x06},
++{0x6453, 0x00},
++{0x6454, 0x07},
++{0x6455, 0x05},
++{0x6456, 0x01},
++{0x6457, 0xaf},
++{0x6458, 0x01},
++{0x6459, 0x0f},
++{0x645a, 0x01},
++{0x645b, 0x90},
++{0x645c, 0x01},
++{0x645d, 0xc8},
++{0x645e, 0x00},
++{0x645f, 0xff},
++{0x6460, 0x01},
++{0x6461, 0xac},
++{0x6462, 0x01},
++{0x6463, 0x0c},
++{0x6464, 0x01},
++{0x6465, 0x90},
++{0x6466, 0x01},
++{0x6467, 0xe8},
++{0x6468, 0x00},
++{0x6469, 0xff},
++{0x646a, 0x01},
++{0x646b, 0xad},
++{0x646c, 0x01},
++{0x646d, 0x0d},
++{0x646e, 0x01},
++{0x646f, 0x90},
++{0x6470, 0x01},
++{0x6471, 0xe8},
++{0x6472, 0x00},
++{0x6473, 0xff},
++{0x6474, 0x01},
++{0x6475, 0xae},
++{0x6476, 0x01},
++{0x6477, 0x0e},
++{0x6478, 0x01},
++{0x6479, 0x90},
++{0x647a, 0x01},
++{0x647b, 0xe8},
++{0x647c, 0x00},
++{0x647d, 0xff},
++{0x647e, 0x01},
++{0x647f, 0xb0},
++{0x6480, 0x01},
++{0x6481, 0xb1},
++{0x6482, 0x01},
++{0x6483, 0xb2},
++{0x6484, 0x01},
++{0x6485, 0xb3},
++{0x6486, 0x01},
++{0x6487, 0xb4},
++{0x6488, 0x01},
++{0x6489, 0xb5},
++{0x648a, 0x01},
++{0x648b, 0xb6},
++{0x648c, 0x01},
++{0x648d, 0xb7},
++{0x648e, 0x01},
++{0x648f, 0xb8},
++{0x6490, 0x01},
++{0x6491, 0xb9},
++{0x6492, 0x01},
++{0x6493, 0xba},
++{0x6494, 0x01},
++{0x6495, 0xbb},
++{0x6496, 0x01},
++{0x6497, 0xbc},
++{0x6498, 0x01},
++{0x6499, 0xbd},
++{0x649a, 0x01},
++{0x649b, 0xbe},
++{0x649c, 0x01},
++{0x649d, 0xbf},
++{0x649e, 0x01},
++{0x649f, 0xc0},
++{0x64a0, 0x00},
++{0x64a1, 0xff},
++{0x64a2, 0x06},
++{0x64a3, 0x00},
++{0x64a4, 0x01},
++{0x64a5, 0xf6},
++{0x64a6, 0x00},
++{0x64a7, 0xff},
++{0x64a8, 0x06},
++{0x64a9, 0x10},
++{0x64aa, 0x01},
++{0x64ab, 0xf6},
++{0x64ac, 0x06},
++{0x64ad, 0x00},
++{0x64ae, 0x00},
++{0x64af, 0xff},
++{0x64b0, 0x06},
++{0x64b1, 0x20},
++{0x64b2, 0x01},
++{0x64b3, 0xf6},
++{0x64b4, 0x06},
++{0x64b5, 0x00},
++{0x64b6, 0x00},
++{0x64b7, 0xff},
++{0x64b8, 0x04},
++{0x64b9, 0x31},
++{0x64ba, 0x04},
++{0x64bb, 0x30},
++{0x64bc, 0x01},
++{0x64bd, 0x20},
++{0x64be, 0x01},
++{0x64bf, 0x31},
++{0x64c0, 0x01},
++{0x64c1, 0x32},
++{0x64c2, 0x01},
++{0x64c3, 0x33},
++{0x64c4, 0x01},
++{0x64c5, 0x34},
++{0x64c6, 0x01},
++{0x64c7, 0x35},
++{0x64c8, 0x01},
++{0x64c9, 0x36},
++{0x64ca, 0x01},
++{0x64cb, 0x37},
++{0x64cc, 0x01},
++{0x64cd, 0x38},
++{0x64ce, 0x01},
++{0x64cf, 0x39},
++{0x64d0, 0x01},
++{0x64d1, 0x3a},
++{0x64d2, 0x01},
++{0x64d3, 0x3b},
++{0x64d4, 0x01},
++{0x64d5, 0x3c},
++{0x64d6, 0x01},
++{0x64d7, 0x3d},
++{0x64d8, 0x01},
++{0x64d9, 0x3e},
++{0x64da, 0x01},
++{0x64db, 0x3f},
++{0x64dc, 0x02},
++{0x64dd, 0xa0},
++{0x64de, 0x00},
++{0x64df, 0xff},
++{0x64e0, 0x04},
++{0x64e1, 0x31},
++{0x64e2, 0x04},
++{0x64e3, 0x30},
++{0x64e4, 0x01},
++{0x64e5, 0x00},
++{0x64e6, 0x01},
++{0x64e7, 0x11},
++{0x64e8, 0x01},
++{0x64e9, 0x12},
++{0x64ea, 0x01},
++{0x64eb, 0x13},
++{0x64ec, 0x01},
++{0x64ed, 0x14},
++{0x64ee, 0x01},
++{0x64ef, 0x15},
++{0x64f0, 0x01},
++{0x64f1, 0x16},
++{0x64f2, 0x01},
++{0x64f3, 0x17},
++{0x64f4, 0x01},
++{0x64f5, 0x18},
++{0x64f6, 0x01},
++{0x64f7, 0x19},
++{0x64f8, 0x01},
++{0x64f9, 0x1a},
++{0x64fa, 0x01},
++{0x64fb, 0x1b},
++{0x64fc, 0x01},
++{0x64fd, 0x1c},
++{0x64fe, 0x01},
++{0x64ff, 0x1d},
++{0x6500, 0x01},
++{0x6501, 0x1e},
++{0x6502, 0x01},
++{0x6503, 0x1f},
++{0x6504, 0x02},
++{0x6505, 0xa0},
++{0x6506, 0x00},
++{0x6507, 0xff},
++{0x6508, 0x03},
++{0x6509, 0x0b},
++{0x650a, 0x05},
++{0x650b, 0x86},
++{0x650c, 0x00},
++{0x650d, 0x00},
++{0x650e, 0x05},
++{0x650f, 0x06},
++{0x6510, 0x00},
++{0x6511, 0x04},
++{0x6512, 0x05},
++{0x6513, 0x04},
++{0x6514, 0x00},
++{0x6515, 0x04},
++{0x6516, 0x05},
++{0x6517, 0x00},
++{0x6518, 0x05},
++{0x6519, 0x08},
++{0x651a, 0x03},
++{0x651b, 0x9a},
++{0x651c, 0x05},
++{0x651d, 0x86},
++{0x651e, 0x00},
++{0x651f, 0x00},
++{0x6520, 0x05},
++{0x6521, 0x06},
++{0x6522, 0x00},
++{0x6523, 0x01},
++{0x6524, 0x05},
++{0x6525, 0x04},
++{0x6526, 0x00},
++{0x6527, 0x04},
++{0x6528, 0x05},
++{0x6529, 0x00},
++{0x652a, 0x05},
++{0x652b, 0x08},
++{0x652c, 0x03},
++{0x652d, 0x99},
++{0x652e, 0x05},
++{0x652f, 0x06},
++{0x6530, 0x00},
++{0x6531, 0x00},
++{0x6532, 0x05},
++{0x6533, 0x04},
++{0x6534, 0x00},
++{0x6535, 0x04},
++{0x6536, 0x05},
++{0x6537, 0x00},
++{0x6538, 0x05},
++{0x6539, 0x08},
++{0x653a, 0x03},
++{0x653b, 0x98},
++{0x653c, 0x05},
++{0x653d, 0x06},
++{0x653e, 0x00},
++{0x653f, 0x00},
++{0x6540, 0x05},
++{0x6541, 0x04},
++{0x6542, 0x00},
++{0x6543, 0x04},
++{0x6544, 0x05},
++{0x6545, 0x00},
++{0x6546, 0x05},
++{0x6547, 0x08},
++{0x6548, 0x03},
++{0x6549, 0x97},
++{0x654a, 0x05},
++{0x654b, 0x06},
++{0x654c, 0x05},
++{0x654d, 0x04},
++{0x654e, 0x00},
++{0x654f, 0x04},
++{0x6550, 0x05},
++{0x6551, 0x00},
++{0x6552, 0x05},
++{0x6553, 0x08},
++{0x6554, 0x03},
++{0x6555, 0x96},
++{0x6556, 0x05},
++{0x6557, 0x06},
++{0x6558, 0x05},
++{0x6559, 0x04},
++{0x655a, 0x00},
++{0x655b, 0x04},
++{0x655c, 0x05},
++{0x655d, 0x00},
++{0x655e, 0x05},
++{0x655f, 0x08},
++{0x6560, 0x03},
++{0x6561, 0x95},
++{0x6562, 0x05},
++{0x6563, 0x06},
++{0x6564, 0x05},
++{0x6565, 0x04},
++{0x6566, 0x00},
++{0x6567, 0x04},
++{0x6568, 0x05},
++{0x6569, 0x00},
++{0x656a, 0x05},
++{0x656b, 0x08},
++{0x656c, 0x03},
++{0x656d, 0x94},
++{0x656e, 0x05},
++{0x656f, 0x06},
++{0x6570, 0x00},
++{0x6571, 0x00},
++{0x6572, 0x05},
++{0x6573, 0x04},
++{0x6574, 0x00},
++{0x6575, 0x04},
++{0x6576, 0x05},
++{0x6577, 0x00},
++{0x6578, 0x05},
++{0x6579, 0x08},
++{0x657a, 0x03},
++{0x657b, 0x93},
++{0x657c, 0x05},
++{0x657d, 0x06},
++{0x657e, 0x00},
++{0x657f, 0x00},
++{0x6580, 0x05},
++{0x6581, 0x04},
++{0x6582, 0x00},
++{0x6583, 0x04},
++{0x6584, 0x05},
++{0x6585, 0x00},
++{0x6586, 0x05},
++{0x6587, 0x08},
++{0x6588, 0x03},
++{0x6589, 0x92},
++{0x658a, 0x05},
++{0x658b, 0x06},
++{0x658c, 0x05},
++{0x658d, 0x04},
++{0x658e, 0x00},
++{0x658f, 0x04},
++{0x6590, 0x05},
++{0x6591, 0x00},
++{0x6592, 0x05},
++{0x6593, 0x08},
++{0x6594, 0x03},
++{0x6595, 0x91},
++{0x6596, 0x05},
++{0x6597, 0x06},
++{0x6598, 0x05},
++{0x6599, 0x04},
++{0x659a, 0x00},
++{0x659b, 0x04},
++{0x659c, 0x05},
++{0x659d, 0x00},
++{0x659e, 0x05},
++{0x659f, 0x08},
++{0x65a0, 0x03},
++{0x65a1, 0x90},
++{0x65a2, 0x05},
++{0x65a3, 0x06},
++{0x65a4, 0x05},
++{0x65a5, 0x04},
++{0x65a6, 0x00},
++{0x65a7, 0x04},
++{0x65a8, 0x05},
++{0x65a9, 0x00},
++{0x65aa, 0x05},
++{0x65ab, 0x08},
++{0x65ac, 0x02},
++{0x65ad, 0x90},
++{0x65ae, 0x05},
++{0x65af, 0x06},
++{0x65b0, 0x00},
++{0x65b1, 0xff},
++{0x65b2, 0x04},
++{0x65b3, 0x20},
++{0x65b4, 0x05},
++{0x65b5, 0x06},
++{0x65b6, 0x08},
++{0x65b7, 0x84},
++{0x65b8, 0x04},
++{0x65b9, 0x04},
++{0x65ba, 0x00},
++{0x65bb, 0xff},
++{0x65bc, 0x08},
++{0x65bd, 0x72},
++{0x65be, 0x04},
++{0x65bf, 0x0c},
++{0x65c0, 0x04},
++{0x65c1, 0x04},
++{0x65c2, 0x00},
++{0x65c3, 0xff},
++{0x65c4, 0x04},
++{0x65c5, 0x45},
++{0x65c6, 0x04},
++{0x65c7, 0x54},
++{0x65c8, 0x08},
++{0x65c9, 0x72},
++{0x65ca, 0x00},
++{0x65cb, 0xff},
++{0x65cc, 0x04},
++{0x65cd, 0x20},
++{0x65ce, 0x05},
++{0x65cf, 0x06},
++{0x65d0, 0x08},
++{0x65d1, 0x96},
++{0x65d2, 0x08},
++{0x65d3, 0x5e},
++{0x65d4, 0x00},
++{0x65d5, 0xff},
++{0x65d6, 0x04},
++{0x65d7, 0x20},
++{0x65d8, 0x05},
++{0x65d9, 0x06},
++{0x65da, 0x08},
++{0x65db, 0x96},
++{0x65dc, 0x08},
++{0x65dd, 0x5c},
++{0x65de, 0x00},
++{0x65df, 0xff},
++{0x65e0, 0x04},
++{0x65e1, 0x20},
++{0x65e2, 0x05},
++{0x65e3, 0x06},
++{0x65e4, 0x08},
++{0x65e5, 0x84},
++{0x65e6, 0x08},
++{0x65e7, 0x70},
++{0x65e8, 0x00},
++{0x65e9, 0xff},
++{0x65ea, 0x00},
++{0x65eb, 0xff},
++{0x65ec, 0x00},
++{0x65ed, 0xff},
++{0x30eb, 0x04},
++{0x30ed, 0x5a},
++{0x30ee, 0x01},
++{0x30ef, 0x80},
++{0x30f1, 0x5a},
++{0x303a, 0x04},
++{0x303b, 0x7f},
++{0x303c, 0xfe},
++{0x303d, 0x19},
++{0x303e, 0xd7},
++{0x303f, 0x09},
++{0x3040, 0x78},
++{0x3042, 0x05},
++{0x328a, 0x00},
++{0x31bf, 0x9f},
++{0x31c0, 0xff},
++#if 0
++{0x3012, 0x01},
++{0x3012, 0x00},
++{0x3119, 0x44},
++//;{0x3132, 0x24},
++//;{0x3128, 0xc0},
++//;{0x328a, 0x02},
++{0x3012, 0x01},
++#else
++/* HFLIP=1, VFLIP=0 */
++{0x3128, 0xc0 | 0x1},
++{0x3291, 0x01 | 0x2},
++{0x3090, 0x4},
++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */
++{0x3012, 0x0},
++{0x3000, 0x3},
++{0x3001, 0x50},
++{0x3002, 0x0a},
++{0x3004, 0x3},
++{0x3005, 0x48},
++{0x3006, 0x7},
++{0x308f, 0x10},
++{0x3127, 0x63},
++{0x3074, OV10640_X_START >> 8},
++{0x3075, OV10640_X_START & 0xff},
++{0x3076, OV10640_Y_START >> 8},
++{0x3077, OV10640_Y_START & 0xff},
++{0x3078, OV10640_X_END >> 8},
++{0x3079, OV10640_X_END & 0xff},
++{0x307a, OV10640_Y_END >> 8},
++{0x307b, OV10640_Y_END & 0xff},
++{0x307c, OV10640_MAX_WIDTH >> 8},
++{0x307d, OV10640_MAX_WIDTH & 0xff},
++{0x307e, OV10640_MAX_HEIGHT >> 8},
++{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff},
++{0x3084, 0x0},
++{0x3085, 0x0},
++{0x3086, 0x0},
++{0x3087, 0x0},
++{0x346d, 0x14},
++{0x3444, 0x28},
++{0x3091, 0x0},
++{0x3119, 0x44}, // COMB12
++{0x3012, 0x1},
++#endif
++};
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1e.h b/drivers/media/i2c/soc_camera/ov10640_r1e.h
+new file mode 100644
+index 0000000..eeff330
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ov10640_r1e.h
+@@ -0,0 +1,1235 @@
++/*
++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit
++ *
++ * Copyright (C) 2015-2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++/* DVP_1280x1080_COMB12_raw 60fps */
++static const struct ov10640_reg ov10640_regs_wizard_r1e[] = {
++//{0x3013, 0x01},
++//{OV10640_DELAY, 10},
++{0x328a, 0x11},
++{0x313f, 0x80},
++{0x3132, 0x24},
++{0x3000, 0x03},
++{0x3001, 0x62},
++{0x3002, 0x07},
++{0x3004, 0x03},
++{0x3005, 0x62},
++{0x3006, 0x07},
++{0x3007, 0x01},
++{0x3014, 0x03},
++{0x3023, 0x05},
++{0x3032, 0x35},
++{0x3033, 0x04},
++{0x3054, 0x00},
++{0x3055, 0x08},
++{0x3056, 0x01},
++{0x3057, 0xff},
++{0x3058, 0xaf},
++{0x3059, 0x44},
++{0x305a, 0x02},
++{0x305b, 0x00},
++{0x305c, 0x30},
++{0x305d, 0x9e},
++{0x305e, 0x19},
++{0x305f, 0x18},
++{0x3060, 0xf9},
++{0x3061, 0xf0},
++#ifdef OV10640_FSIN_ENABLE
++{0x308c, 0xb2},
++#else
++{0x308c, 0x03},
++#endif
++{0x308f, 0x10},
++{0x3090, 0x00},
++{0x3091, 0x00},
++{0x30eb, 0x00},
++{0x30a3, 0x08},
++{0x30ad, 0x03},
++{0x30ae, 0x80},
++{0x30af, 0x80},
++{0x30b0, 0xff},
++{0x30b1, 0x3f},
++{0x30b2, 0x22},
++{0x30b9, 0x22},
++{0x30bb, 0x00},
++{0x30bc, 0x00},
++{0x30bd, 0x00},
++{0x30be, 0x00},
++{0x30bf, 0x00},
++{0x30c0, 0x00},
++{0x30c1, 0x00},
++{0x30c2, 0x00},
++{0x30c3, 0x00},
++{0x30c4, 0x80},
++{0x30c5, 0x00},
++{0x30c6, 0x80},
++{0x30c7, 0x00},
++{0x30c8, 0x80},
++{0x3119, 0x45},
++{0x311a, 0x01},
++{0x311b, 0x4a},
++{0x3074, 0x00},
++{0x3075, 0x00},
++{0x3076, 0x00},
++{0x3077, 0x02},
++{0x3078, 0x05},
++{0x3079, 0x07},
++{0x307a, 0x04},
++{0x307b, 0x41},
++{0x307c, 0x05},
++{0x307d, 0x00},
++{0x307e, 0x04},
++{0x307f, 0x38},
++{0x3080, 0x05},
++{0x3081, 0xbe},
++{0x3082, 0x04},
++{0x3083, 0x57},
++{0x3084, 0x00},
++{0x3085, 0x04},
++{0x3086, 0x00},
++{0x3087, 0x04},
++{0x3088, 0x00},
++{0x3089, 0x40},
++{0x308d, 0x92},
++{0x3094, 0xa5},
++{0x30e6, 0x04},
++{0x30e7, 0x48},
++{0x30e8, 0x04},
++{0x30e9, 0x48},
++{0x30e9, 0x05},
++{0x30ec, 0x01},
++{0x30fa, 0x06},
++{0x3120, 0x00},
++{0x3121, 0x01},
++{0x3122, 0x00},
++{0x3127, 0x63},
++{0x3128, 0xc0},
++#ifdef OV10640_DISPLAY_PATTERN
++{0x3129, 0x80},
++#else
++{0x3129, 0x00},
++#endif
++{0x31be, 0x00},
++{0x30a5, 0x78},
++{0x30a6, 0x40},
++{0x30a7, 0x78},
++{0x30a8, 0x80},
++{0x30a9, 0x78},
++{0x30aa, 0xe0},
++{0x30ab, 0xf9},
++{0x30ac, 0xc0},
++{0x3440, 0x04},
++{0x3444, 0x28},
++{0x344e, 0x2c},
++{0x3457, 0x33},
++{0x345e, 0x38},
++{0x3461, 0xa8},
++{0x7002, 0xaa},
++{0x7001, 0xdf},
++{0x7048, 0x00},
++{0x7049, 0x02},
++{0x704a, 0x02},
++{0x704b, 0x00},
++{0x704c, 0x01},
++{0x704d, 0x00},
++{0x7043, 0x04},
++{0x7040, 0x3c},
++{0x7047, 0x00},
++{0x7044, 0x01},
++{0x7000, 0x1f},
++{0x7084, 0x01},
++{0x7085, 0x03},
++{0x7086, 0x02},
++{0x7087, 0x40},
++{0x7088, 0x01},
++{0x7089, 0x20},
++{0x707f, 0x04},
++{0x707c, 0x3c},
++{0x7083, 0x00},
++{0x7080, 0x01},
++{0x7003, 0xdf},
++{0x70c0, 0x00},
++{0x70c1, 0x02},
++{0x70c2, 0x02},
++{0x70c3, 0x00},
++{0x70c4, 0x01},
++{0x70c5, 0x00},
++{0x70b8, 0x03},
++{0x70b9, 0x98},
++{0x70bc, 0x00},
++{0x70bd, 0x80},
++{0x7004, 0x02},
++{0x7005, 0x00},
++{0x7006, 0x01},
++{0x7007, 0x80},
++{0x7008, 0x02},
++{0x7009, 0x00},
++{0x700a, 0x04},
++{0x700b, 0x00},
++{0x700e, 0x00},
++{0x700f, 0x60},
++{0x701a, 0x02},
++{0x701b, 0x00},
++{0x701c, 0x01},
++{0x701d, 0x80},
++{0x701e, 0x02},
++{0x701f, 0x00},
++{0x7020, 0x04},
++{0x7021, 0x00},
++{0x7024, 0x00},
++{0x7025, 0x60},
++{0x70e7, 0x00},
++{0x70e4, 0x10},
++{0x70e5, 0x00},
++{0x70e6, 0x00},
++{0x70eb, 0x00},
++{0x70e8, 0x10},
++{0x70e9, 0x00},
++{0x70ea, 0x00},
++{0x70ef, 0x00},
++{0x70ec, 0xfd},
++{0x70ed, 0x00},
++{0x70ee, 0x00},
++{0x70eb, 0x00},
++{0x70f0, 0xfd},
++{0x70f1, 0x00},
++{0x70f2, 0x00},
++{0x30fb, 0x06},
++{0x30fc, 0x80},
++{0x30fd, 0x02},
++{0x30fe, 0x93},
++{0x6000, 0xc1},
++{0x6001, 0xb9},
++{0x6002, 0xba},
++{0x6003, 0xa4},
++{0x6004, 0xb5},
++{0x6005, 0xa0},
++{0x6006, 0x82},
++{0x6007, 0xa7},
++{0x6008, 0xb7},
++{0x6009, 0x5c},
++{0x600a, 0x9e},
++{0x600b, 0xc0},
++{0x600c, 0xd2},
++{0x600d, 0x33},
++{0x600e, 0xcc},
++{0x600f, 0xe2},
++{0x6010, 0xc1},
++{0x6011, 0xab},
++{0x6012, 0xb7},
++{0x6013, 0x00},
++{0x6014, 0x00},
++{0x6015, 0x00},
++{0x6016, 0x00},
++{0x6017, 0x00},
++{0x6018, 0x00},
++{0x6019, 0x00},
++{0x601a, 0x00},
++{0x601b, 0x00},
++{0x601c, 0x00},
++{0x601d, 0x00},
++{0x601e, 0x9c},
++{0x601f, 0x94},
++{0x6020, 0x90},
++{0x6021, 0xc5},
++{0x6022, 0x01},
++{0x6023, 0x54},
++{0x6024, 0x2a},
++{0x6025, 0x61},
++{0x6026, 0xd2},
++{0x6027, 0xcc},
++{0x6028, 0x04},
++{0x6029, 0x35},
++{0x602a, 0xb1},
++{0x602b, 0xb2},
++{0x602c, 0xb3},
++{0x602d, 0xd2},
++{0x602e, 0xd3},
++{0x602f, 0x12},
++{0x6030, 0x31},
++{0x6031, 0xcc},
++{0x6032, 0x06},
++{0x6033, 0xd2},
++{0x6034, 0xc4},
++{0x6035, 0xce},
++{0x6036, 0x18},
++{0x6037, 0xcf},
++{0x6038, 0x1e},
++{0x6039, 0xd0},
++{0x603a, 0x24},
++{0x603b, 0xc5},
++{0x603c, 0xd2},
++{0x603d, 0xbc},
++{0x603e, 0xcc},
++{0x603f, 0x52},
++{0x6040, 0x2b},
++{0x6041, 0xd2},
++{0x6042, 0xd3},
++{0x6043, 0x02},
++{0x6044, 0xcc},
++{0x6045, 0x0a},
++{0x6046, 0xd2},
++{0x6047, 0xd3},
++{0x6048, 0x0f},
++{0x6049, 0x1a},
++{0x604a, 0x2a},
++{0x604b, 0xd4},
++{0x604c, 0xf6},
++{0x604d, 0xba},
++{0x604e, 0x56},
++{0x604f, 0xd3},
++{0x6050, 0x2e},
++{0x6051, 0x54},
++{0x6052, 0x26},
++{0x6053, 0xd2},
++{0x6054, 0xcc},
++{0x6055, 0x60},
++{0x6056, 0xd2},
++{0x6057, 0xd3},
++{0x6058, 0x27},
++{0x6059, 0x27},
++{0x605a, 0x08},
++{0x605b, 0x1a},
++{0x605c, 0xcc},
++{0x605d, 0x88},
++{0x605e, 0x00},
++{0x605f, 0x12},
++{0x6060, 0x2c},
++{0x6061, 0x60},
++{0x6062, 0xc2},
++{0x6063, 0xb9},
++{0x6064, 0xa5},
++{0x6065, 0xb5},
++{0x6066, 0xa0},
++{0x6067, 0x82},
++{0x6068, 0x5c},
++{0x6069, 0xd4},
++{0x606a, 0xbe},
++{0x606b, 0xd4},
++{0x606c, 0xbe},
++{0x606d, 0xd3},
++{0x606e, 0x01},
++{0x606f, 0x7c},
++{0x6070, 0x74},
++{0x6071, 0x00},
++{0x6072, 0x61},
++{0x6073, 0x2a},
++{0x6074, 0xd2},
++{0x6075, 0xcc},
++{0x6076, 0xdf},
++{0x6077, 0xc6},
++{0x6078, 0x35},
++{0x6079, 0xd2},
++{0x607a, 0xcc},
++{0x607b, 0x06},
++{0x607c, 0x31},
++{0x607d, 0xd2},
++{0x607e, 0xc5},
++{0x607f, 0xbb},
++{0x6080, 0xcc},
++{0x6081, 0x18},
++{0x6082, 0xc6},
++{0x6083, 0xd2},
++{0x6084, 0xbd},
++{0x6085, 0xcc},
++{0x6086, 0x52},
++{0x6087, 0x2b},
++{0x6088, 0xd2},
++{0x6089, 0xd3},
++{0x608a, 0x01},
++{0x608b, 0xcc},
++{0x608c, 0x0a},
++{0x608d, 0xd2},
++{0x608e, 0xd3},
++{0x608f, 0x0f},
++{0x6090, 0x1a},
++{0x6091, 0x71},
++{0x6092, 0x2a},
++{0x6093, 0xd4},
++{0x6094, 0xf6},
++{0x6095, 0xd3},
++{0x6096, 0x22},
++{0x6097, 0x70},
++{0x6098, 0xca},
++{0x6099, 0x26},
++{0x609a, 0xd2},
++{0x609b, 0xcc},
++{0x609c, 0x60},
++{0x609d, 0xd2},
++{0x609e, 0xd3},
++{0x609f, 0x27},
++{0x60a0, 0x27},
++{0x60a1, 0x08},
++{0x60a2, 0x1a},
++{0x60a3, 0xcc},
++{0x60a4, 0x88},
++{0x60a5, 0x12},
++{0x60a6, 0x2c},
++{0x60a7, 0x60},
++{0x60a8, 0x00},
++{0x60a9, 0x00},
++{0x60aa, 0xc0},
++{0x60ab, 0xb9},
++{0x60ac, 0xa3},
++{0x60ad, 0xb5},
++{0x60ae, 0x00},
++{0x60af, 0xa0},
++{0x60b0, 0x82},
++{0x60b1, 0x5c},
++{0x60b2, 0xd4},
++{0x60b3, 0xa0},
++{0x60b4, 0x9d},
++{0x60b5, 0xd3},
++{0x60b6, 0x26},
++{0x60b7, 0xb0},
++{0x60b8, 0xb7},
++{0x60b9, 0x00},
++{0x60ba, 0xd3},
++{0x60bb, 0x0a},
++{0x60bc, 0xd3},
++{0x60bd, 0x10},
++{0x60be, 0x9c},
++{0x60bf, 0x94},
++{0x60c0, 0x90},
++{0x60c1, 0xc8},
++{0x60c2, 0xba},
++{0x60c3, 0x7c},
++{0x60c4, 0x74},
++{0x60c5, 0x00},
++{0x60c6, 0x61},
++{0x60c7, 0x2a},
++{0x60c8, 0x00},
++{0x60c9, 0xd2},
++{0x60ca, 0xcc},
++{0x60cb, 0xdf},
++{0x60cc, 0xc4},
++{0x60cd, 0x35},
++{0x60ce, 0xd2},
++{0x60cf, 0xcc},
++{0x60d0, 0x06},
++{0x60d1, 0x31},
++{0x60d2, 0xd2},
++{0x60d3, 0xcc},
++{0x60d4, 0x15},
++{0x60d5, 0xd2},
++{0x60d6, 0xbb},
++{0x60d7, 0xcc},
++{0x60d8, 0x1a},
++{0x60d9, 0xd2},
++{0x60da, 0xbe},
++{0x60db, 0xce},
++{0x60dc, 0x52},
++{0x60dd, 0xcf},
++{0x60de, 0x56},
++{0x60df, 0xd0},
++{0x60e0, 0x5b},
++{0x60e1, 0x2b},
++{0x60e2, 0xd2},
++{0x60e3, 0xd3},
++{0x60e4, 0x01},
++{0x60e5, 0xcc},
++{0x60e6, 0x0a},
++{0x60e7, 0xd2},
++{0x60e8, 0xd3},
++{0x60e9, 0x0f},
++{0x60ea, 0xd9},
++{0x60eb, 0xc7},
++{0x60ec, 0xda},
++{0x60ed, 0xce},
++{0x60ee, 0x1a},
++{0x60ef, 0xd4},
++{0x60f0, 0xf6},
++{0x60f1, 0xd4},
++{0x60f2, 0xa9},
++{0x60f3, 0x27},
++{0x60f4, 0x00},
++{0x60f5, 0xd2},
++{0x60f6, 0xcc},
++{0x60f7, 0x60},
++{0x60f8, 0xd2},
++{0x60f9, 0xd3},
++{0x60fa, 0x2d},
++{0x60fb, 0xd9},
++{0x60fc, 0xdf},
++{0x60fd, 0xda},
++{0x60fe, 0xe5},
++{0x60ff, 0x1a},
++{0x6100, 0x12},
++{0x6101, 0xcc},
++{0x6102, 0x88},
++{0x6103, 0xd6},
++{0x6104, 0xb1},
++{0x6105, 0xb9},
++{0x6106, 0xba},
++{0x6107, 0xaf},
++{0x6108, 0xdc},
++{0x6109, 0x00},
++{0x610a, 0xcb},
++{0x610b, 0xc3},
++{0x610c, 0xb9},
++{0x610d, 0xa4},
++{0x610e, 0xb5},
++{0x610f, 0x5c},
++{0x6110, 0x12},
++{0x6111, 0x2a},
++{0x6112, 0x61},
++{0x6113, 0xd2},
++{0x6114, 0xcc},
++{0x6115, 0xdf},
++{0x6116, 0xc7},
++{0x6117, 0x35},
++{0x6118, 0xd2},
++{0x6119, 0xcc},
++{0x611a, 0x06},
++{0x611b, 0x31},
++{0x611c, 0xc6},
++{0x611d, 0xbb},
++{0x611e, 0xd2},
++{0x611f, 0xcc},
++{0x6120, 0x18},
++{0x6121, 0xd2},
++{0x6122, 0xbe},
++{0x6123, 0xcc},
++{0x6124, 0x52},
++{0x6125, 0xc7},
++{0x6126, 0xd2},
++{0x6127, 0xcc},
++{0x6128, 0x0a},
++{0x6129, 0xb4},
++{0x612a, 0xb7},
++{0x612b, 0x94},
++{0x612c, 0xd2},
++{0x612d, 0x12},
++{0x612e, 0x26},
++{0x612f, 0x42},
++{0x6130, 0x46},
++{0x6131, 0x42},
++{0x6132, 0xd3},
++{0x6133, 0x20},
++{0x6134, 0x27},
++{0x6135, 0x00},
++{0x6136, 0x1a},
++{0x6137, 0xcc},
++{0x6138, 0x88},
++{0x6139, 0x60},
++{0x613a, 0x2c},
++{0x613b, 0x12},
++{0x613c, 0x40},
++{0x613d, 0xb8},
++{0x613e, 0x90},
++{0x613f, 0xd5},
++{0x6140, 0xba},
++{0x6141, 0x00},
++{0x6142, 0x00},
++{0x6143, 0x00},
++{0x6144, 0x00},
++{0x6145, 0x00},
++{0x6146, 0x00},
++{0x6147, 0xaa},
++{0x6148, 0xb7},
++{0x6149, 0x00},
++{0x614a, 0x00},
++{0x614b, 0x00},
++{0x614c, 0x00},
++{0x614d, 0xa6},
++{0x614e, 0xb7},
++{0x614f, 0x00},
++{0x6150, 0xd5},
++{0x6151, 0x00},
++{0x6152, 0x71},
++{0x6153, 0xd3},
++{0x6154, 0x30},
++{0x6155, 0xba},
++{0x6156, 0x00},
++{0x6157, 0x00},
++{0x6158, 0x00},
++{0x6159, 0x00},
++{0x615a, 0xd3},
++{0x615b, 0x10},
++{0x615c, 0x70},
++{0x615d, 0x00},
++{0x615e, 0x00},
++{0x615f, 0x00},
++{0x6160, 0x00},
++{0x6161, 0xd5},
++{0x6162, 0xba},
++{0x6163, 0xb0},
++{0x6164, 0xb7},
++{0x6165, 0x00},
++{0x6166, 0x9d},
++{0x6167, 0xd3},
++{0x6168, 0x0a},
++{0x6169, 0x9d},
++{0x616a, 0x9d},
++{0x616b, 0xd3},
++{0x616c, 0x10},
++{0x616d, 0x9c},
++{0x616e, 0x94},
++{0x616f, 0x90},
++{0x6170, 0xc8},
++{0x6171, 0xba},
++{0x6172, 0xd2},
++{0x6173, 0x60},
++{0x6174, 0x2c},
++{0x6175, 0x50},
++{0x6176, 0x11},
++{0x6177, 0xcc},
++{0x6178, 0x00},
++{0x6179, 0x30},
++{0x617a, 0xd5},
++{0x617b, 0x00},
++{0x617c, 0xba},
++{0x617d, 0xb0},
++{0x617e, 0xb7},
++{0x617f, 0x00},
++{0x6180, 0x9d},
++{0x6181, 0xd3},
++{0x6182, 0x0a},
++{0x6183, 0x9d},
++{0x6184, 0x9d},
++{0x6185, 0xd3},
++{0x6186, 0x10},
++{0x6187, 0x9c},
++{0x6188, 0x94},
++{0x6189, 0x90},
++{0x618a, 0xc8},
++{0x618b, 0xba},
++{0x618c, 0xd5},
++{0x618d, 0x00},
++{0x618e, 0x01},
++{0x618f, 0x1a},
++{0x6190, 0xcc},
++{0x6191, 0x12},
++{0x6192, 0x12},
++{0x6193, 0x00},
++{0x6194, 0xcc},
++{0x6195, 0x9c},
++{0x6196, 0xd2},
++{0x6197, 0xcc},
++{0x6198, 0x60},
++{0x6199, 0xd2},
++{0x619a, 0x04},
++{0x619b, 0xd5},
++{0x619c, 0x1a},
++{0x619d, 0xcc},
++{0x619e, 0x12},
++{0x619f, 0x00},
++{0x61a0, 0x12},
++{0x61a1, 0xcc},
++{0x61a2, 0x9c},
++{0x61a3, 0xd2},
++{0x61a4, 0xcc},
++{0x61a5, 0x60},
++{0x61a6, 0xd2},
++{0x61a7, 0x1a},
++{0x61a8, 0xcc},
++{0x61a9, 0x12},
++{0x61aa, 0x00},
++{0x61ab, 0x12},
++{0x61ac, 0xcc},
++{0x61ad, 0x9c},
++{0x61ae, 0xd2},
++{0x61af, 0xcc},
++{0x61b0, 0x60},
++{0x61b1, 0xd2},
++{0x61b2, 0x1a},
++{0x61b3, 0xcc},
++{0x61b4, 0x12},
++{0x61b5, 0x00},
++{0x61b6, 0x12},
++{0x61b7, 0xcc},
++{0x61b8, 0x9c},
++{0x61b9, 0xd2},
++{0x61ba, 0xcc},
++{0x61bb, 0x60},
++{0x61bc, 0xd2},
++{0x61bd, 0xd5},
++{0x61be, 0x1a},
++{0x61bf, 0xcc},
++{0x61c0, 0x12},
++{0x61c1, 0x12},
++{0x61c2, 0x00},
++{0x61c3, 0xcc},
++{0x61c4, 0x8a},
++{0x61c5, 0xd2},
++{0x61c6, 0xcc},
++{0x61c7, 0x74},
++{0x61c8, 0xd2},
++{0x61c9, 0xd5},
++{0x61ca, 0x1a},
++{0x61cb, 0xcc},
++{0x61cc, 0x12},
++{0x61cd, 0x00},
++{0x61ce, 0x12},
++{0x61cf, 0xcc},
++{0x61d0, 0x8a},
++{0x61d1, 0xd2},
++{0x61d2, 0xcc},
++{0x61d3, 0x74},
++{0x61d4, 0xd2},
++{0x61d5, 0x1a},
++{0x61d6, 0xcc},
++{0x61d7, 0x12},
++{0x61d8, 0x00},
++{0x61d9, 0x12},
++{0x61da, 0xcc},
++{0x61db, 0x8a},
++{0x61dc, 0xd2},
++{0x61dd, 0xcc},
++{0x61de, 0x74},
++{0x61df, 0xd2},
++{0x61e0, 0x1a},
++{0x61e1, 0xcc},
++{0x61e2, 0x12},
++{0x61e3, 0x00},
++{0x61e4, 0x12},
++{0x61e5, 0xcc},
++{0x61e6, 0x8a},
++{0x61e7, 0xd2},
++{0x61e8, 0xcc},
++{0x61e9, 0x74},
++{0x61ea, 0xd2},
++{0x61eb, 0xd5},
++{0x61ec, 0xcc},
++{0x61ed, 0x12},
++{0x61ee, 0x00},
++{0x61ef, 0x12},
++{0x61f0, 0xcc},
++{0x61f1, 0x9c},
++{0x61f2, 0xd5},
++{0x6400, 0x04},
++{0x6401, 0x04},
++{0x6402, 0x00},
++{0x6403, 0xff},
++{0x6404, 0x00},
++{0x6405, 0x08},
++{0x6406, 0x00},
++{0x6407, 0xff},
++{0x6408, 0x04},
++{0x6409, 0x70},
++{0x640a, 0x00},
++{0x640b, 0xff},
++{0x640c, 0x05},
++{0x640d, 0x14},
++{0x640e, 0x04},
++{0x640f, 0x71},
++{0x6410, 0x05},
++{0x6411, 0x74},
++{0x6412, 0x00},
++{0x6413, 0xff},
++{0x6414, 0x05},
++{0x6415, 0x54},
++{0x6416, 0x05},
++{0x6417, 0x44},
++{0x6418, 0x04},
++{0x6419, 0x30},
++{0x641a, 0x05},
++{0x641b, 0x46},
++{0x641c, 0x00},
++{0x641d, 0xff},
++{0x641e, 0x04},
++{0x641f, 0x31},
++{0x6420, 0x04},
++{0x6421, 0x30},
++{0x6422, 0x00},
++{0x6423, 0xff},
++{0x6424, 0x04},
++{0x6425, 0x20},
++{0x6426, 0x05},
++{0x6427, 0x06},
++{0x6428, 0x00},
++{0x6429, 0xff},
++{0x642a, 0x08},
++{0x642b, 0x2a},
++{0x642c, 0x08},
++{0x642d, 0x31},
++{0x642e, 0x00},
++{0x642f, 0xff},
++{0x6430, 0x08},
++{0x6431, 0x2a},
++{0x6432, 0x08},
++{0x6433, 0x31},
++{0x6434, 0x06},
++{0x6435, 0x20},
++{0x6436, 0x07},
++{0x6437, 0x00},
++{0x6438, 0x08},
++{0x6439, 0x40},
++{0x643a, 0x00},
++{0x643b, 0xff},
++{0x643c, 0x08},
++{0x643d, 0x2a},
++{0x643e, 0x08},
++{0x643f, 0x36},
++{0x6440, 0x06},
++{0x6441, 0x10},
++{0x6442, 0x07},
++{0x6443, 0x00},
++{0x6444, 0x08},
++{0x6445, 0x40},
++{0x6446, 0x00},
++{0x6447, 0xff},
++{0x6448, 0x08},
++{0x6449, 0x2a},
++{0x644a, 0x08},
++{0x644b, 0x3b},
++{0x644c, 0x06},
++{0x644d, 0x00},
++{0x644e, 0x07},
++{0x644f, 0x00},
++{0x6450, 0x08},
++{0x6451, 0x40},
++{0x6452, 0x00},
++{0x6453, 0xff},
++{0x6454, 0x06},
++{0x6455, 0x00},
++{0x6456, 0x07},
++{0x6457, 0x05},
++{0x6458, 0x01},
++{0x6459, 0xaf},
++{0x645a, 0x01},
++{0x645b, 0x0f},
++{0x645c, 0x01},
++{0x645d, 0x90},
++{0x645e, 0x01},
++{0x645f, 0xc8},
++{0x6460, 0x00},
++{0x6461, 0xff},
++{0x6462, 0x01},
++{0x6463, 0xac},
++{0x6464, 0x01},
++{0x6465, 0x0c},
++{0x6466, 0x01},
++{0x6467, 0x90},
++{0x6468, 0x01},
++{0x6469, 0xe8},
++{0x646a, 0x00},
++{0x646b, 0xff},
++{0x646c, 0x01},
++{0x646d, 0xad},
++{0x646e, 0x01},
++{0x646f, 0x0d},
++{0x6470, 0x01},
++{0x6471, 0x90},
++{0x6472, 0x01},
++{0x6473, 0xe8},
++{0x6474, 0x00},
++{0x6475, 0xff},
++{0x6476, 0x01},
++{0x6477, 0xae},
++{0x6478, 0x01},
++{0x6479, 0x0e},
++{0x647a, 0x01},
++{0x647b, 0x90},
++{0x647c, 0x01},
++{0x647d, 0xe8},
++{0x647e, 0x00},
++{0x647f, 0xff},
++{0x6480, 0x01},
++{0x6481, 0xb0},
++{0x6482, 0x01},
++{0x6483, 0xb1},
++{0x6484, 0x01},
++{0x6485, 0xb2},
++{0x6486, 0x01},
++{0x6487, 0xb3},
++{0x6488, 0x01},
++{0x6489, 0xb4},
++{0x648a, 0x01},
++{0x648b, 0xb5},
++{0x648c, 0x01},
++{0x648d, 0xb6},
++{0x648e, 0x01},
++{0x648f, 0xb7},
++{0x6490, 0x01},
++{0x6491, 0xb8},
++{0x6492, 0x01},
++{0x6493, 0xb9},
++{0x6494, 0x01},
++{0x6495, 0xba},
++{0x6496, 0x01},
++{0x6497, 0xbb},
++{0x6498, 0x01},
++{0x6499, 0xbc},
++{0x649a, 0x01},
++{0x649b, 0xbd},
++{0x649c, 0x01},
++{0x649d, 0xbe},
++{0x649e, 0x01},
++{0x649f, 0xbf},
++{0x64a0, 0x01},
++{0x64a1, 0xc0},
++{0x64a2, 0x00},
++{0x64a3, 0xff},
++{0x64a4, 0x06},
++{0x64a5, 0x00},
++{0x64a6, 0x01},
++{0x64a7, 0xf6},
++{0x64a8, 0x04},
++{0x64a9, 0x30},
++{0x64aa, 0x00},
++{0x64ab, 0xff},
++{0x64ac, 0x06},
++{0x64ad, 0x10},
++{0x64ae, 0x01},
++{0x64af, 0xf6},
++{0x64b0, 0x04},
++{0x64b1, 0x30},
++{0x64b2, 0x06},
++{0x64b3, 0x00},
++{0x64b4, 0x00},
++{0x64b5, 0xff},
++{0x64b6, 0x06},
++{0x64b7, 0x20},
++{0x64b8, 0x01},
++{0x64b9, 0xf6},
++{0x64ba, 0x04},
++{0x64bb, 0x30},
++{0x64bc, 0x06},
++{0x64bd, 0x00},
++{0x64be, 0x00},
++{0x64bf, 0xff},
++{0x64c0, 0x04},
++{0x64c1, 0x31},
++{0x64c2, 0x04},
++{0x64c3, 0x30},
++{0x64c4, 0x01},
++{0x64c5, 0x20},
++{0x64c6, 0x01},
++{0x64c7, 0x31},
++{0x64c8, 0x01},
++{0x64c9, 0x32},
++{0x64ca, 0x01},
++{0x64cb, 0x33},
++{0x64cc, 0x01},
++{0x64cd, 0x34},
++{0x64ce, 0x01},
++{0x64cf, 0x35},
++{0x64d0, 0x01},
++{0x64d1, 0x36},
++{0x64d2, 0x01},
++{0x64d3, 0x37},
++{0x64d4, 0x01},
++{0x64d5, 0x38},
++{0x64d6, 0x01},
++{0x64d7, 0x39},
++{0x64d8, 0x01},
++{0x64d9, 0x3a},
++{0x64da, 0x01},
++{0x64db, 0x3b},
++{0x64dc, 0x01},
++{0x64dd, 0x3c},
++{0x64de, 0x01},
++{0x64df, 0x3d},
++{0x64e0, 0x01},
++{0x64e1, 0x3e},
++{0x64e2, 0x01},
++{0x64e3, 0x3f},
++{0x64e4, 0x02},
++{0x64e5, 0xa0},
++{0x64e6, 0x00},
++{0x64e7, 0xff},
++{0x64e8, 0x04},
++{0x64e9, 0x31},
++{0x64ea, 0x04},
++{0x64eb, 0x30},
++{0x64ec, 0x01},
++{0x64ed, 0x00},
++{0x64ee, 0x01},
++{0x64ef, 0x11},
++{0x64f0, 0x01},
++{0x64f1, 0x12},
++{0x64f2, 0x01},
++{0x64f3, 0x13},
++{0x64f4, 0x01},
++{0x64f5, 0x14},
++{0x64f6, 0x01},
++{0x64f7, 0x15},
++{0x64f8, 0x01},
++{0x64f9, 0x16},
++{0x64fa, 0x01},
++{0x64fb, 0x17},
++{0x64fc, 0x01},
++{0x64fd, 0x18},
++{0x64fe, 0x01},
++{0x64ff, 0x19},
++{0x6500, 0x01},
++{0x6501, 0x1a},
++{0x6502, 0x01},
++{0x6503, 0x1b},
++{0x6504, 0x01},
++{0x6505, 0x1c},
++{0x6506, 0x01},
++{0x6507, 0x1d},
++{0x6508, 0x01},
++{0x6509, 0x1e},
++{0x650a, 0x01},
++{0x650b, 0x1f},
++{0x650c, 0x02},
++{0x650d, 0xa0},
++{0x650e, 0x00},
++{0x650f, 0xff},
++{0x6510, 0x04},
++{0x6511, 0x20},
++{0x6512, 0x05},
++{0x6513, 0x86},
++{0x6514, 0x03},
++{0x6515, 0x0b},
++{0x6516, 0x05},
++{0x6517, 0x86},
++{0x6518, 0x00},
++{0x6519, 0x00},
++{0x651a, 0x05},
++{0x651b, 0x06},
++{0x651c, 0x00},
++{0x651d, 0x04},
++{0x651e, 0x05},
++{0x651f, 0x04},
++{0x6520, 0x00},
++{0x6521, 0x04},
++{0x6522, 0x05},
++{0x6523, 0x00},
++{0x6524, 0x05},
++{0x6525, 0x0a},
++{0x6526, 0x03},
++{0x6527, 0x9a},
++{0x6528, 0x05},
++{0x6529, 0x86},
++{0x652a, 0x00},
++{0x652b, 0x00},
++{0x652c, 0x05},
++{0x652d, 0x06},
++{0x652e, 0x00},
++{0x652f, 0x01},
++{0x6530, 0x05},
++{0x6531, 0x04},
++{0x6532, 0x00},
++{0x6533, 0x04},
++{0x6534, 0x05},
++{0x6535, 0x00},
++{0x6536, 0x05},
++{0x6537, 0x0a},
++{0x6538, 0x03},
++{0x6539, 0x99},
++{0x653a, 0x05},
++{0x653b, 0x06},
++{0x653c, 0x00},
++{0x653d, 0x00},
++{0x653e, 0x05},
++{0x653f, 0x04},
++{0x6540, 0x00},
++{0x6541, 0x04},
++{0x6542, 0x05},
++{0x6543, 0x00},
++{0x6544, 0x05},
++{0x6545, 0x0a},
++{0x6546, 0x03},
++{0x6547, 0x98},
++{0x6548, 0x05},
++{0x6549, 0x06},
++{0x654a, 0x00},
++{0x654b, 0x00},
++{0x654c, 0x05},
++{0x654d, 0x04},
++{0x654e, 0x00},
++{0x654f, 0x04},
++{0x6550, 0x05},
++{0x6551, 0x00},
++{0x6552, 0x05},
++{0x6553, 0x0a},
++{0x6554, 0x03},
++{0x6555, 0x97},
++{0x6556, 0x05},
++{0x6557, 0x06},
++{0x6558, 0x05},
++{0x6559, 0x04},
++{0x655a, 0x00},
++{0x655b, 0x04},
++{0x655c, 0x05},
++{0x655d, 0x00},
++{0x655e, 0x05},
++{0x655f, 0x0a},
++{0x6560, 0x03},
++{0x6561, 0x96},
++{0x6562, 0x05},
++{0x6563, 0x06},
++{0x6564, 0x05},
++{0x6565, 0x04},
++{0x6566, 0x00},
++{0x6567, 0x04},
++{0x6568, 0x05},
++{0x6569, 0x00},
++{0x656a, 0x05},
++{0x656b, 0x0a},
++{0x656c, 0x03},
++{0x656d, 0x95},
++{0x656e, 0x05},
++{0x656f, 0x06},
++{0x6570, 0x05},
++{0x6571, 0x04},
++{0x6572, 0x00},
++{0x6573, 0x04},
++{0x6574, 0x05},
++{0x6575, 0x00},
++{0x6576, 0x05},
++{0x6577, 0x0a},
++{0x6578, 0x03},
++{0x6579, 0x94},
++{0x657a, 0x05},
++{0x657b, 0x06},
++{0x657c, 0x00},
++{0x657d, 0x00},
++{0x657e, 0x05},
++{0x657f, 0x04},
++{0x6580, 0x00},
++{0x6581, 0x04},
++{0x6582, 0x05},
++{0x6583, 0x00},
++{0x6584, 0x05},
++{0x6585, 0x0a},
++{0x6586, 0x03},
++{0x6587, 0x93},
++{0x6588, 0x05},
++{0x6589, 0x06},
++{0x658a, 0x00},
++{0x658b, 0x00},
++{0x658c, 0x05},
++{0x658d, 0x04},
++{0x658e, 0x00},
++{0x658f, 0x04},
++{0x6590, 0x05},
++{0x6591, 0x00},
++{0x6592, 0x05},
++{0x6593, 0x0a},
++{0x6594, 0x03},
++{0x6595, 0x92},
++{0x6596, 0x05},
++{0x6597, 0x06},
++{0x6598, 0x05},
++{0x6599, 0x04},
++{0x659a, 0x00},
++{0x659b, 0x04},
++{0x659c, 0x05},
++{0x659d, 0x00},
++{0x659e, 0x05},
++{0x659f, 0x0a},
++{0x65a0, 0x03},
++{0x65a1, 0x91},
++{0x65a2, 0x05},
++{0x65a3, 0x06},
++{0x65a4, 0x05},
++{0x65a5, 0x04},
++{0x65a6, 0x00},
++{0x65a7, 0x04},
++{0x65a8, 0x05},
++{0x65a9, 0x00},
++{0x65aa, 0x05},
++{0x65ab, 0x0a},
++{0x65ac, 0x03},
++{0x65ad, 0x90},
++{0x65ae, 0x05},
++{0x65af, 0x06},
++{0x65b0, 0x05},
++{0x65b1, 0x04},
++{0x65b2, 0x00},
++{0x65b3, 0x04},
++{0x65b4, 0x05},
++{0x65b5, 0x00},
++{0x65b6, 0x05},
++{0x65b7, 0x0a},
++{0x65b8, 0x02},
++{0x65b9, 0x90},
++{0x65ba, 0x05},
++{0x65bb, 0x06},
++{0x65bc, 0x00},
++{0x65bd, 0xff},
++{0x65be, 0x04},
++{0x65bf, 0x70},
++{0x65c0, 0x08},
++{0x65c1, 0x76},
++{0x65c2, 0x00},
++{0x65c3, 0xff},
++{0x65c4, 0x08},
++{0x65c5, 0x76},
++{0x65c6, 0x04},
++{0x65c7, 0x0c},
++{0x65c8, 0x05},
++{0x65c9, 0x07},
++{0x65ca, 0x04},
++{0x65cb, 0x04},
++{0x65cc, 0x00},
++{0x65cd, 0xff},
++{0x65ce, 0x00},
++{0x65cf, 0xff},
++{0x65d0, 0x00},
++{0x65d1, 0xff},
++{0x30eb, 0x04},
++{0x30ed, 0x5a},
++{0x30ee, 0x01},
++{0x30ef, 0x80},
++{0x30f1, 0x5a},
++{0x303a, 0x04},
++{0x303b, 0x7f},
++{0x303c, 0xfe},
++{0x303d, 0x19},
++{0x303e, 0xd7},
++{0x303f, 0x09},
++{0x3040, 0x78},
++{0x3042, 0x05},
++{0x328a, 0x10},
++#if 0
++{0x3012, 0x01},
++{0x3012, 0x00},
++{0x3119, 0x44},
++{0x328a, 0x10},
++{0x3012, 0x01},
++#else
++{0x328a, 0x10},
++/* HFLIP=1, VFLIP=0 */
++{0x3128, 0xc0 | 0x1},
++{0x3291, 0x01 | 0x2},
++{0x3090, 0x4},
++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */
++{0x3012, 0x0},
++{0x3000, 0x3},
++{0x3001, 0x50},
++{0x3002, 0x0a},
++{0x3004, 0x3},
++{0x3005, 0x48},
++{0x3006, 0x7},
++{0x308f, 0x10},
++{0x3127, 0x63},
++{0x3074, OV10640_X_START >> 8},
++{0x3075, OV10640_X_START & 0xff},
++{0x3076, OV10640_Y_START >> 8},
++{0x3077, OV10640_Y_START & 0xff},
++{0x3078, OV10640_X_END >> 8},
++{0x3079, OV10640_X_END & 0xff},
++{0x307a, OV10640_Y_END >> 8},
++{0x307b, OV10640_Y_END & 0xff},
++{0x307c, OV10640_MAX_WIDTH >> 8},
++{0x307d, OV10640_MAX_WIDTH & 0xff},
++{0x307e, OV10640_MAX_HEIGHT >> 8},
++{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff},
++{0x3084, 0x0},
++{0x3085, 0x0},
++{0x3086, 0x0},
++{0x3087, 0x0},
++{0x346d, 0x14},
++{0x3444, 0x28},
++{0x3091, 0x0},
++{0x3119, 0x44}, // COMB12
++{0x3012, 0x1},
++#endif
++};
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1f.h b/drivers/media/i2c/soc_camera/ov10640_r1f.h
+new file mode 100644
+index 0000000..ef866fa
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ov10640_r1f.h
+@@ -0,0 +1,1198 @@
++/*
++ * OmniVision ov10640 sensor camera wizard 1280x1080@30/BGGR/BT601/12bit
++ *
++ * Copyright (C) 2015-2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++/* DVP_1280x1080_COMB12_raw 60fps */
++static const struct ov10640_reg ov10640_regs_wizard_r1f[] = {
++//{0x3013, 0x01},
++//{OV10640_DELAY, 10},
++{0x31be, 0x01},
++{0x3133, 0xb7},
++{0x3134, 0xca},
++{0x3135, 0xcc},
++{0x313f, 0x80},
++{0x3132, 0x24},
++{0x3000, 0x03},
++{0x3001, 0x62},
++{0x3002, 0x07},
++{0x3004, 0x03},
++{0x3005, 0x62},
++{0x3006, 0x07},
++{0x3007, 0x01},
++{0x3023, 0x05},
++{0x3032, 0x35},
++{0x3033, 0x04},
++{0x3054, 0x00},
++{0x3055, 0x0f},
++{0x3056, 0x01},
++{0x3057, 0xff},
++{0x3058, 0xaf},
++{0x3059, 0x44},
++{0x305a, 0x02},
++{0x305b, 0x00},
++{0x305c, 0x30},
++{0x305d, 0x9e},
++{0x305e, 0x19},
++{0x305f, 0x18},
++{0x3060, 0xf9},
++{0x3061, 0xf0},
++#ifdef OV10640_FSIN_ENABLE
++{0x308c, 0xb2},
++#else
++{0x308c, 0x03},
++#endif
++{0x308f, 0x10},
++{0x3090, 0x00},
++{0x3091, 0x00},
++{0x30eb, 0x00},
++{0x30a3, 0x08},
++{0x30ad, 0x03},
++{0x30ae, 0x80},
++{0x30af, 0x80},
++{0x30b0, 0xff},
++{0x30b1, 0x3f},
++{0x30b2, 0x22},
++{0x30b9, 0x22},
++{0x30bb, 0x00},
++{0x30bc, 0x00},
++{0x30bd, 0x00},
++{0x30be, 0x00},
++{0x30bf, 0x00},
++{0x30c0, 0x00},
++{0x30c1, 0x00},
++{0x30c2, 0x00},
++{0x30c3, 0x00},
++{0x30c4, 0x80},
++{0x30c5, 0x00},
++{0x30c6, 0x80},
++{0x30c7, 0x00},
++{0x30c8, 0x80},
++{0x3119, 0x44},
++{0x311a, 0x01},
++{0x311b, 0x4a},
++{0x3074, 0x00},
++{0x3075, 0x00},
++{0x3076, 0x00},
++{0x3077, 0x02},
++{0x3078, 0x05},
++{0x3079, 0x07},
++{0x307a, 0x04},
++{0x307b, 0x41},
++{0x307c, 0x05},
++{0x307d, 0x00},
++{0x307e, 0x04},
++{0x307f, 0x38},
++{0x3080, 0x05},
++{0x3081, 0xbe},
++{0x3082, 0x04},
++{0x3083, 0x57},
++{0x3084, 0x00},
++{0x3085, 0x04},
++{0x3086, 0x00},
++{0x3087, 0x04},
++{0x3088, 0x00},
++{0x3089, 0x40},
++{0x308d, 0x92},
++{0x3094, 0xa5},
++{0x30e6, 0x04},
++{0x30e7, 0x48},
++{0x30e8, 0x04},
++{0x30e9, 0x48},
++{0x30ea, 0x11},
++{0x30ec, 0x01},
++{0x30fa, 0x06},
++{0x3120, 0x00},
++{0x3121, 0x01},
++{0x3122, 0x00},
++{0x3127, 0x63},
++{0x3128, 0xc0},
++#ifdef OV10640_DISPLAY_PATTERN
++{0x3129, 0x80},
++#else
++{0x3129, 0x00},
++#endif
++{0x31be, 0x01},
++{0x30a5, 0x78},
++{0x30a6, 0x40},
++{0x30a7, 0x78},
++{0x30a8, 0x80},
++{0x30a9, 0x79},
++{0x30aa, 0x00},
++{0x30ab, 0x79},
++{0x30ac, 0xf8},
++{0x3440, 0x04},
++{0x3444, 0x28},
++{0x344e, 0x2c},
++{0x3457, 0x33},
++{0x345e, 0x38},
++{0x3461, 0xa8},
++{0x7002, 0xaa},
++{0x7001, 0xdf},
++{0x7048, 0x00},
++{0x7049, 0x02},
++{0x704a, 0x02},
++{0x704b, 0x00},
++{0x704c, 0x01},
++{0x704d, 0x00},
++{0x7043, 0x04},
++{0x7040, 0x3c},
++{0x7047, 0x00},
++{0x7044, 0x01},
++{0x7000, 0x1f},
++{0x7084, 0x01},
++{0x7085, 0x03},
++{0x7086, 0x02},
++{0x7087, 0x40},
++{0x7088, 0x01},
++{0x7089, 0x20},
++{0x707f, 0x04},
++{0x707c, 0x3c},
++{0x7083, 0x00},
++{0x7080, 0x01},
++{0x7003, 0xdf},
++{0x70c0, 0x00},
++{0x70c1, 0x02},
++{0x70c2, 0x02},
++{0x70c3, 0x00},
++{0x70c4, 0x01},
++{0x70c5, 0x00},
++{0x70b8, 0x03},
++{0x70b9, 0x98},
++{0x70bc, 0x00},
++{0x70bd, 0x80},
++{0x7004, 0x02},
++{0x7005, 0x00},
++{0x7006, 0x01},
++{0x7007, 0x80},
++{0x7008, 0x02},
++{0x7009, 0x00},
++{0x700a, 0x04},
++{0x700b, 0x00},
++{0x700e, 0x00},
++{0x700f, 0x60},
++{0x701a, 0x02},
++{0x701b, 0x00},
++{0x701c, 0x01},
++{0x701d, 0x80},
++{0x701e, 0x02},
++{0x701f, 0x00},
++{0x7020, 0x04},
++{0x7021, 0x00},
++{0x7024, 0x00},
++{0x7025, 0x60},
++{0x70e7, 0x00},
++{0x70e4, 0x10},
++{0x70e5, 0x00},
++{0x70e6, 0x00},
++{0x70eb, 0x00},
++{0x70e8, 0x10},
++{0x70e9, 0x00},
++{0x70ea, 0x00},
++{0x70ef, 0x00},
++{0x70ec, 0xfd},
++{0x70ed, 0x00},
++{0x70ee, 0x00},
++{0x70eb, 0x00},
++{0x70f0, 0xfd},
++{0x70f1, 0x00},
++{0x70f2, 0x00},
++{0x30fb, 0x06},
++{0x30fc, 0x80},
++{0x30fd, 0x02},
++{0x30fe, 0x93},
++{0x6000, 0xc1},
++{0x6001, 0xb9},
++{0x6002, 0xba},
++{0x6003, 0xa4},
++{0x6004, 0xa4},
++{0x6005, 0xb5},
++{0x6006, 0xa0},
++{0x6007, 0x82},
++{0x6008, 0xa7},
++{0x6009, 0xa7},
++{0x600a, 0xb7},
++{0x600b, 0x5c},
++{0x600c, 0x9e},
++{0x600d, 0xc0},
++{0x600e, 0xd2},
++{0x600f, 0x33},
++{0x6010, 0xcc},
++{0x6011, 0xe2},
++{0x6012, 0xc1},
++{0x6013, 0xab},
++{0x6014, 0xab},
++{0x6015, 0xb7},
++{0x6016, 0x00},
++{0x6017, 0x00},
++{0x6018, 0x00},
++{0x6019, 0x00},
++{0x601a, 0x00},
++{0x601b, 0x00},
++{0x601c, 0x00},
++{0x601d, 0x00},
++{0x601e, 0x00},
++{0x601f, 0x00},
++{0x6020, 0x00},
++{0x6021, 0x00},
++{0x6022, 0x00},
++{0x6023, 0x9c},
++{0x6024, 0x94},
++{0x6025, 0x90},
++{0x6026, 0xc5},
++{0x6027, 0x00},
++{0x6028, 0x54},
++{0x6029, 0x2a},
++{0x602a, 0x61},
++{0x602b, 0xd2},
++{0x602c, 0xcc},
++{0x602d, 0x04},
++{0x602e, 0x35},
++{0x602f, 0xb1},
++{0x6030, 0xb2},
++{0x6031, 0xb3},
++{0x6032, 0xd2},
++{0x6033, 0xd3},
++{0x6034, 0x11},
++{0x6035, 0x31},
++{0x6036, 0xcc},
++{0x6037, 0x06},
++{0x6038, 0xd2},
++{0x6039, 0x00},
++{0x603a, 0xce},
++{0x603b, 0x18},
++{0x603c, 0xcf},
++{0x603d, 0x1e},
++{0x603e, 0xd0},
++{0x603f, 0x24},
++{0x6040, 0xc5},
++{0x6041, 0xd2},
++{0x6042, 0xbc},
++{0x6043, 0xcc},
++{0x6044, 0x52},
++{0x6045, 0x2b},
++{0x6046, 0xd2},
++{0x6047, 0xd3},
++{0x6048, 0x01},
++{0x6049, 0xcc},
++{0x604a, 0x0a},
++{0x604b, 0xd2},
++{0x604c, 0xd3},
++{0x604d, 0x0f},
++{0x604e, 0x1a},
++{0x604f, 0x2a},
++{0x6050, 0xd4},
++{0x6051, 0xe3},
++{0x6052, 0xba},
++{0x6053, 0x56},
++{0x6054, 0xd3},
++{0x6055, 0x2e},
++{0x6056, 0x54},
++{0x6057, 0x26},
++{0x6058, 0xd2},
++{0x6059, 0xcc},
++{0x605a, 0x60},
++{0x605b, 0xd2},
++{0x605c, 0xd3},
++{0x605d, 0x27},
++{0x605e, 0x27},
++{0x605f, 0x08},
++{0x6060, 0x1a},
++{0x6061, 0xcc},
++{0x6062, 0x88},
++{0x6063, 0x00},
++{0x6064, 0x12},
++{0x6065, 0x2c},
++{0x6066, 0x60},
++{0x6067, 0xc2},
++{0x6068, 0xb9},
++{0x6069, 0xa5},
++{0x606a, 0xa5},
++{0x606b, 0xb5},
++{0x606c, 0xa0},
++{0x606d, 0x82},
++{0x606e, 0x5c},
++{0x606f, 0xd4},
++{0x6070, 0xab},
++{0x6071, 0xd4},
++{0x6072, 0xab},
++{0x6073, 0xd3},
++{0x6074, 0x01},
++{0x6075, 0x7c},
++{0x6076, 0x74},
++{0x6077, 0x00},
++{0x6078, 0x61},
++{0x6079, 0x2a},
++{0x607a, 0xd2},
++{0x607b, 0xcc},
++{0x607c, 0xdf},
++{0x607d, 0xc6},
++{0x607e, 0x35},
++{0x607f, 0xd2},
++{0x6080, 0xcc},
++{0x6081, 0x06},
++{0x6082, 0x31},
++{0x6083, 0xd2},
++{0x6084, 0x00},
++{0x6085, 0xbb},
++{0x6086, 0xcc},
++{0x6087, 0x18},
++{0x6088, 0xc6},
++{0x6089, 0xd2},
++{0x608a, 0xbd},
++{0x608b, 0xcc},
++{0x608c, 0x52},
++{0x608d, 0x2b},
++{0x608e, 0xd2},
++{0x608f, 0xd3},
++{0x6090, 0x01},
++{0x6091, 0xcc},
++{0x6092, 0x0a},
++{0x6093, 0xd2},
++{0x6094, 0xd3},
++{0x6095, 0x0f},
++{0x6096, 0x1a},
++{0x6097, 0x71},
++{0x6098, 0x2a},
++{0x6099, 0xd4},
++{0x609a, 0xe3},
++{0x609b, 0xd3},
++{0x609c, 0x22},
++{0x609d, 0x70},
++{0x609e, 0xca},
++{0x609f, 0x26},
++{0x60a0, 0xd2},
++{0x60a1, 0xcc},
++{0x60a2, 0x60},
++{0x60a3, 0xd2},
++{0x60a4, 0xd3},
++{0x60a5, 0x27},
++{0x60a6, 0x27},
++{0x60a7, 0x08},
++{0x60a8, 0x1a},
++{0x60a9, 0xcc},
++{0x60aa, 0x88},
++{0x60ab, 0x00},
++{0x60ac, 0x12},
++{0x60ad, 0x2c},
++{0x60ae, 0x60},
++{0x60af, 0x00},
++{0x60b0, 0x00},
++{0x60b1, 0xc0},
++{0x60b2, 0xb9},
++{0x60b3, 0xa3},
++{0x60b4, 0xa3},
++{0x60b5, 0xb5},
++{0x60b6, 0x00},
++{0x60b7, 0xa0},
++{0x60b8, 0x82},
++{0x60b9, 0x5c},
++{0x60ba, 0xd4},
++{0x60bb, 0x8b},
++{0x60bc, 0x9d},
++{0x60bd, 0xd3},
++{0x60be, 0x21},
++{0x60bf, 0xb0},
++{0x60c0, 0xb0},
++{0x60c1, 0xb7},
++{0x60c2, 0x05},
++{0x60c3, 0xd3},
++{0x60c4, 0x0a},
++{0x60c5, 0xd3},
++{0x60c6, 0x10},
++{0x60c7, 0x9c},
++{0x60c8, 0x94},
++{0x60c9, 0x90},
++{0x60ca, 0xc8},
++{0x60cb, 0xba},
++{0x60cc, 0x7c},
++{0x60cd, 0x74},
++{0x60ce, 0x00},
++{0x60cf, 0x61},
++{0x60d0, 0x2a},
++{0x60d1, 0x00},
++{0x60d2, 0xd2},
++{0x60d3, 0xcc},
++{0x60d4, 0xdf},
++{0x60d5, 0xc4},
++{0x60d6, 0x35},
++{0x60d7, 0xd3},
++{0x60d8, 0x13},
++{0x60d9, 0xd2},
++{0x60da, 0xcc},
++{0x60db, 0x06},
++{0x60dc, 0x31},
++{0x60dd, 0xd2},
++{0x60de, 0xcc},
++{0x60df, 0x15},
++{0x60e0, 0xd2},
++{0x60e1, 0xbb},
++{0x60e2, 0xcc},
++{0x60e3, 0x1a},
++{0x60e4, 0xd2},
++{0x60e5, 0xbe},
++{0x60e6, 0xce},
++{0x60e7, 0x52},
++{0x60e8, 0xcf},
++{0x60e9, 0x56},
++{0x60ea, 0xd0},
++{0x60eb, 0x5b},
++{0x60ec, 0x2b},
++{0x60ed, 0xd2},
++{0x60ee, 0xd3},
++{0x60ef, 0x01},
++{0x60f0, 0xcc},
++{0x60f1, 0x0a},
++{0x60f2, 0xd2},
++{0x60f3, 0xd3},
++{0x60f4, 0x0f},
++{0x60f5, 0xd9},
++{0x60f6, 0xb4},
++{0x60f7, 0xda},
++{0x60f8, 0xbb},
++{0x60f9, 0x1a},
++{0x60fa, 0xd4},
++{0x60fb, 0xe3},
++{0x60fc, 0xd4},
++{0x60fd, 0x96},
++{0x60fe, 0x27},
++{0x60ff, 0x00},
++{0x6100, 0xd2},
++{0x6101, 0xcc},
++{0x6102, 0x60},
++{0x6103, 0xd2},
++{0x6104, 0xd3},
++{0x6105, 0x2d},
++{0x6106, 0xd9},
++{0x6107, 0xcc},
++{0x6108, 0xda},
++{0x6109, 0xd2},
++{0x610a, 0x1a},
++{0x610b, 0x12},
++{0x610c, 0xcc},
++{0x610d, 0x88},
++{0x610e, 0xd6},
++{0x610f, 0x9e},
++{0x6110, 0xb9},
++{0x6111, 0xba},
++{0x6112, 0xaf},
++{0x6113, 0xdc},
++{0x6114, 0x00},
++{0x6115, 0xd5},
++{0x6116, 0xba},
++{0x6117, 0x00},
++{0x6118, 0x00},
++{0x6119, 0x00},
++{0x611a, 0x00},
++{0x611b, 0x00},
++{0x611c, 0x00},
++{0x611d, 0x00},
++{0x611e, 0x00},
++{0x611f, 0xaa},
++{0x6120, 0xaa},
++{0x6121, 0xb7},
++{0x6122, 0x00},
++{0x6123, 0x00},
++{0x6124, 0x00},
++{0x6125, 0x00},
++{0x6126, 0x00},
++{0x6127, 0xa6},
++{0x6128, 0xa6},
++{0x6129, 0xb7},
++{0x612a, 0x00},
++{0x612b, 0xd5},
++{0x612c, 0x71},
++{0x612d, 0xd3},
++{0x612e, 0x30},
++{0x612f, 0xba},
++{0x6130, 0x00},
++{0x6131, 0x00},
++{0x6132, 0x00},
++{0x6133, 0x00},
++{0x6134, 0xd3},
++{0x6135, 0x10},
++{0x6136, 0x70},
++{0x6137, 0x00},
++{0x6138, 0x00},
++{0x6139, 0x00},
++{0x613a, 0x00},
++{0x613b, 0xd5},
++{0x613c, 0xba},
++{0x613d, 0xb0},
++{0x613e, 0xb0},
++{0x613f, 0xb7},
++{0x6140, 0x9d},
++{0x6141, 0x02},
++{0x6142, 0xd3},
++{0x6143, 0x0a},
++{0x6144, 0x9d},
++{0x6145, 0x9d},
++{0x6146, 0xd3},
++{0x6147, 0x10},
++{0x6148, 0x9c},
++{0x6149, 0x94},
++{0x614a, 0x90},
++{0x614b, 0xc8},
++{0x614c, 0xba},
++{0x614d, 0xd2},
++{0x614e, 0x60},
++{0x614f, 0x2c},
++{0x6150, 0x50},
++{0x6151, 0x11},
++{0x6152, 0xcc},
++{0x6153, 0x00},
++{0x6154, 0x30},
++{0x6155, 0xd5},
++{0x6156, 0xba},
++{0x6157, 0xb0},
++{0x6158, 0xb0},
++{0x6159, 0xb7},
++{0x615a, 0x9d},
++{0x615b, 0x02},
++{0x615c, 0xd3},
++{0x615d, 0x0a},
++{0x615e, 0x9d},
++{0x615f, 0x9d},
++{0x6160, 0xd3},
++{0x6161, 0x10},
++{0x6162, 0x9c},
++{0x6163, 0x94},
++{0x6164, 0x90},
++{0x6165, 0xc8},
++{0x6166, 0xba},
++{0x6167, 0xd5},
++{0x6168, 0x01},
++{0x6169, 0x1a},
++{0x616a, 0xcc},
++{0x616b, 0x12},
++{0x616c, 0x12},
++{0x616d, 0x00},
++{0x616e, 0xcc},
++{0x616f, 0x9c},
++{0x6170, 0xd2},
++{0x6171, 0xcc},
++{0x6172, 0x60},
++{0x6173, 0xd2},
++{0x6174, 0x04},
++{0x6175, 0xd5},
++{0x6176, 0x1a},
++{0x6177, 0xcc},
++{0x6178, 0x12},
++{0x6179, 0x00},
++{0x617a, 0x12},
++{0x617b, 0xcc},
++{0x617c, 0x9c},
++{0x617d, 0xd2},
++{0x617e, 0xcc},
++{0x617f, 0x60},
++{0x6180, 0xd2},
++{0x6181, 0x1a},
++{0x6182, 0xcc},
++{0x6183, 0x12},
++{0x6184, 0x00},
++{0x6185, 0x12},
++{0x6186, 0xcc},
++{0x6187, 0x9c},
++{0x6188, 0xd2},
++{0x6189, 0xcc},
++{0x618a, 0x60},
++{0x618b, 0xd2},
++{0x618c, 0x1a},
++{0x618d, 0xcc},
++{0x618e, 0x12},
++{0x618f, 0x00},
++{0x6190, 0x12},
++{0x6191, 0xcc},
++{0x6192, 0x9c},
++{0x6193, 0xd2},
++{0x6194, 0xcc},
++{0x6195, 0x60},
++{0x6196, 0xd2},
++{0x6197, 0xd5},
++{0x6198, 0x1a},
++{0x6199, 0xcc},
++{0x619a, 0x12},
++{0x619b, 0x12},
++{0x619c, 0x00},
++{0x619d, 0xcc},
++{0x619e, 0x8a},
++{0x619f, 0xd2},
++{0x61a0, 0xcc},
++{0x61a1, 0x74},
++{0x61a2, 0xd2},
++{0x61a3, 0xd5},
++{0x61a4, 0x1a},
++{0x61a5, 0xcc},
++{0x61a6, 0x12},
++{0x61a7, 0x00},
++{0x61a8, 0x12},
++{0x61a9, 0xcc},
++{0x61aa, 0x8a},
++{0x61ab, 0xd2},
++{0x61ac, 0xcc},
++{0x61ad, 0x74},
++{0x61ae, 0xd2},
++{0x61af, 0x1a},
++{0x61b0, 0xcc},
++{0x61b1, 0x12},
++{0x61b2, 0x00},
++{0x61b3, 0x12},
++{0x61b4, 0xcc},
++{0x61b5, 0x8a},
++{0x61b6, 0xd2},
++{0x61b7, 0xcc},
++{0x61b8, 0x74},
++{0x61b9, 0xd2},
++{0x61ba, 0x1a},
++{0x61bb, 0xcc},
++{0x61bc, 0x12},
++{0x61bd, 0x00},
++{0x61be, 0x12},
++{0x61bf, 0xcc},
++{0x61c0, 0x8a},
++{0x61c1, 0xd2},
++{0x61c2, 0xcc},
++{0x61c3, 0x74},
++{0x61c4, 0xd2},
++{0x61c5, 0xd5},
++{0x61c6, 0xcc},
++{0x61c7, 0x12},
++{0x61c8, 0x00},
++{0x61c9, 0x12},
++{0x61ca, 0xcc},
++{0x61cb, 0x9c},
++{0x61cc, 0xd5},
++{0x6400, 0x04},
++{0x6401, 0x04},
++{0x6402, 0x00},
++{0x6403, 0xff},
++{0x6404, 0x00},
++{0x6405, 0x08},
++{0x6406, 0x00},
++{0x6407, 0xff},
++{0x6408, 0x04},
++{0x6409, 0x70},
++{0x640a, 0x00},
++{0x640b, 0xff},
++{0x640c, 0x05},
++{0x640d, 0x14},
++{0x640e, 0x04},
++{0x640f, 0x71},
++{0x6410, 0x05},
++{0x6411, 0x74},
++{0x6412, 0x00},
++{0x6413, 0xff},
++{0x6414, 0x05},
++{0x6415, 0x54},
++{0x6416, 0x05},
++{0x6417, 0x44},
++{0x6418, 0x04},
++{0x6419, 0x30},
++{0x641a, 0x05},
++{0x641b, 0x46},
++{0x641c, 0x00},
++{0x641d, 0xff},
++{0x641e, 0x04},
++{0x641f, 0x31},
++{0x6420, 0x04},
++{0x6421, 0x30},
++{0x6422, 0x00},
++{0x6423, 0xff},
++{0x6424, 0x04},
++{0x6425, 0x20},
++{0x6426, 0x05},
++{0x6427, 0x06},
++{0x6428, 0x00},
++{0x6429, 0xff},
++{0x642a, 0x08},
++{0x642b, 0x2a},
++{0x642c, 0x08},
++{0x642d, 0x31},
++{0x642e, 0x00},
++{0x642f, 0xff},
++{0x6430, 0x08},
++{0x6431, 0x2a},
++{0x6432, 0x08},
++{0x6433, 0x31},
++{0x6434, 0x06},
++{0x6435, 0x20},
++{0x6436, 0x07},
++{0x6437, 0x00},
++{0x6438, 0x08},
++{0x6439, 0x40},
++{0x643a, 0x00},
++{0x643b, 0xff},
++{0x643c, 0x08},
++{0x643d, 0x2a},
++{0x643e, 0x08},
++{0x643f, 0x36},
++{0x6440, 0x06},
++{0x6441, 0x10},
++{0x6442, 0x07},
++{0x6443, 0x00},
++{0x6444, 0x08},
++{0x6445, 0x40},
++{0x6446, 0x00},
++{0x6447, 0xff},
++{0x6448, 0x08},
++{0x6449, 0x2a},
++{0x644a, 0x08},
++{0x644b, 0x3b},
++{0x644c, 0x06},
++{0x644d, 0x00},
++{0x644e, 0x07},
++{0x644f, 0x00},
++{0x6450, 0x08},
++{0x6451, 0x40},
++{0x6452, 0x00},
++{0x6453, 0xff},
++{0x6454, 0x06},
++{0x6455, 0x00},
++{0x6456, 0x07},
++{0x6457, 0x05},
++{0x6458, 0x01},
++{0x6459, 0xaf},
++{0x645a, 0x01},
++{0x645b, 0x0f},
++{0x645c, 0x01},
++{0x645d, 0x90},
++{0x645e, 0x01},
++{0x645f, 0xc8},
++{0x6460, 0x00},
++{0x6461, 0xff},
++{0x6462, 0x01},
++{0x6463, 0xac},
++{0x6464, 0x01},
++{0x6465, 0x0c},
++{0x6466, 0x01},
++{0x6467, 0x90},
++{0x6468, 0x01},
++{0x6469, 0xe8},
++{0x646a, 0x00},
++{0x646b, 0xff},
++{0x646c, 0x01},
++{0x646d, 0xad},
++{0x646e, 0x01},
++{0x646f, 0x0d},
++{0x6470, 0x01},
++{0x6471, 0x90},
++{0x6472, 0x01},
++{0x6473, 0xe8},
++{0x6474, 0x00},
++{0x6475, 0xff},
++{0x6476, 0x01},
++{0x6477, 0xae},
++{0x6478, 0x01},
++{0x6479, 0x0e},
++{0x647a, 0x01},
++{0x647b, 0x90},
++{0x647c, 0x01},
++{0x647d, 0xe8},
++{0x647e, 0x00},
++{0x647f, 0xff},
++{0x6480, 0x01},
++{0x6481, 0xb0},
++{0x6482, 0x01},
++{0x6483, 0xb1},
++{0x6484, 0x01},
++{0x6485, 0xb2},
++{0x6486, 0x01},
++{0x6487, 0xb3},
++{0x6488, 0x01},
++{0x6489, 0xb4},
++{0x648a, 0x01},
++{0x648b, 0xb5},
++{0x648c, 0x01},
++{0x648d, 0xb6},
++{0x648e, 0x01},
++{0x648f, 0xb7},
++{0x6490, 0x01},
++{0x6491, 0xb8},
++{0x6492, 0x01},
++{0x6493, 0xb9},
++{0x6494, 0x01},
++{0x6495, 0xba},
++{0x6496, 0x01},
++{0x6497, 0xbb},
++{0x6498, 0x01},
++{0x6499, 0xbc},
++{0x649a, 0x01},
++{0x649b, 0xbd},
++{0x649c, 0x01},
++{0x649d, 0xbe},
++{0x649e, 0x01},
++{0x649f, 0xbf},
++{0x64a0, 0x01},
++{0x64a1, 0xc0},
++{0x64a2, 0x00},
++{0x64a3, 0xff},
++{0x64a4, 0x06},
++{0x64a5, 0x00},
++{0x64a6, 0x01},
++{0x64a7, 0xf6},
++{0x64a8, 0x04},
++{0x64a9, 0x30},
++{0x64aa, 0x00},
++{0x64ab, 0xff},
++{0x64ac, 0x06},
++{0x64ad, 0x10},
++{0x64ae, 0x01},
++{0x64af, 0xf6},
++{0x64b0, 0x04},
++{0x64b1, 0x30},
++{0x64b2, 0x06},
++{0x64b3, 0x00},
++{0x64b4, 0x00},
++{0x64b5, 0xff},
++{0x64b6, 0x06},
++{0x64b7, 0x20},
++{0x64b8, 0x01},
++{0x64b9, 0xf6},
++{0x64ba, 0x04},
++{0x64bb, 0x30},
++{0x64bc, 0x06},
++{0x64bd, 0x00},
++{0x64be, 0x00},
++{0x64bf, 0xff},
++{0x64c0, 0x04},
++{0x64c1, 0x31},
++{0x64c2, 0x04},
++{0x64c3, 0x30},
++{0x64c4, 0x01},
++{0x64c5, 0x20},
++{0x64c6, 0x01},
++{0x64c7, 0x31},
++{0x64c8, 0x01},
++{0x64c9, 0x32},
++{0x64ca, 0x01},
++{0x64cb, 0x33},
++{0x64cc, 0x01},
++{0x64cd, 0x34},
++{0x64ce, 0x01},
++{0x64cf, 0x35},
++{0x64d0, 0x01},
++{0x64d1, 0x36},
++{0x64d2, 0x01},
++{0x64d3, 0x37},
++{0x64d4, 0x01},
++{0x64d5, 0x38},
++{0x64d6, 0x01},
++{0x64d7, 0x39},
++{0x64d8, 0x01},
++{0x64d9, 0x3a},
++{0x64da, 0x01},
++{0x64db, 0x3b},
++{0x64dc, 0x01},
++{0x64dd, 0x3c},
++{0x64de, 0x01},
++{0x64df, 0x3d},
++{0x64e0, 0x01},
++{0x64e1, 0x3e},
++{0x64e2, 0x01},
++{0x64e3, 0x3f},
++{0x64e4, 0x02},
++{0x64e5, 0xa0},
++{0x64e6, 0x00},
++{0x64e7, 0xff},
++{0x64e8, 0x04},
++{0x64e9, 0x31},
++{0x64ea, 0x04},
++{0x64eb, 0x30},
++{0x64ec, 0x01},
++{0x64ed, 0x00},
++{0x64ee, 0x01},
++{0x64ef, 0x11},
++{0x64f0, 0x01},
++{0x64f1, 0x12},
++{0x64f2, 0x01},
++{0x64f3, 0x13},
++{0x64f4, 0x01},
++{0x64f5, 0x14},
++{0x64f6, 0x01},
++{0x64f7, 0x15},
++{0x64f8, 0x01},
++{0x64f9, 0x16},
++{0x64fa, 0x01},
++{0x64fb, 0x17},
++{0x64fc, 0x01},
++{0x64fd, 0x18},
++{0x64fe, 0x01},
++{0x64ff, 0x19},
++{0x6500, 0x01},
++{0x6501, 0x1a},
++{0x6502, 0x01},
++{0x6503, 0x1b},
++{0x6504, 0x01},
++{0x6505, 0x1c},
++{0x6506, 0x01},
++{0x6507, 0x1d},
++{0x6508, 0x01},
++{0x6509, 0x1e},
++{0x650a, 0x01},
++{0x650b, 0x1f},
++{0x650c, 0x02},
++{0x650d, 0xa0},
++{0x650e, 0x00},
++{0x650f, 0xff},
++{0x6510, 0x04},
++{0x6511, 0x20},
++{0x6512, 0x05},
++{0x6513, 0x86},
++{0x6514, 0x03},
++{0x6515, 0x0b},
++{0x6516, 0x05},
++{0x6517, 0x86},
++{0x6518, 0x00},
++{0x6519, 0x00},
++{0x651a, 0x05},
++{0x651b, 0x06},
++{0x651c, 0x00},
++{0x651d, 0x04},
++{0x651e, 0x05},
++{0x651f, 0x04},
++{0x6520, 0x00},
++{0x6521, 0x04},
++{0x6522, 0x05},
++{0x6523, 0x00},
++{0x6524, 0x05},
++{0x6525, 0x0a},
++{0x6526, 0x03},
++{0x6527, 0x9a},
++{0x6528, 0x05},
++{0x6529, 0x86},
++{0x652a, 0x00},
++{0x652b, 0x00},
++{0x652c, 0x05},
++{0x652d, 0x06},
++{0x652e, 0x00},
++{0x652f, 0x01},
++{0x6530, 0x05},
++{0x6531, 0x04},
++{0x6532, 0x00},
++{0x6533, 0x04},
++{0x6534, 0x05},
++{0x6535, 0x00},
++{0x6536, 0x05},
++{0x6537, 0x0a},
++{0x6538, 0x03},
++{0x6539, 0x99},
++{0x653a, 0x05},
++{0x653b, 0x06},
++{0x653c, 0x00},
++{0x653d, 0x00},
++{0x653e, 0x05},
++{0x653f, 0x04},
++{0x6540, 0x00},
++{0x6541, 0x04},
++{0x6542, 0x05},
++{0x6543, 0x00},
++{0x6544, 0x05},
++{0x6545, 0x0a},
++{0x6546, 0x03},
++{0x6547, 0x98},
++{0x6548, 0x05},
++{0x6549, 0x06},
++{0x654a, 0x00},
++{0x654b, 0x00},
++{0x654c, 0x05},
++{0x654d, 0x04},
++{0x654e, 0x00},
++{0x654f, 0x04},
++{0x6550, 0x05},
++{0x6551, 0x00},
++{0x6552, 0x05},
++{0x6553, 0x0a},
++{0x6554, 0x03},
++{0x6555, 0x97},
++{0x6556, 0x05},
++{0x6557, 0x06},
++{0x6558, 0x05},
++{0x6559, 0x04},
++{0x655a, 0x00},
++{0x655b, 0x04},
++{0x655c, 0x05},
++{0x655d, 0x00},
++{0x655e, 0x05},
++{0x655f, 0x0a},
++{0x6560, 0x03},
++{0x6561, 0x96},
++{0x6562, 0x05},
++{0x6563, 0x06},
++{0x6564, 0x05},
++{0x6565, 0x04},
++{0x6566, 0x00},
++{0x6567, 0x04},
++{0x6568, 0x05},
++{0x6569, 0x00},
++{0x656a, 0x05},
++{0x656b, 0x0a},
++{0x656c, 0x03},
++{0x656d, 0x95},
++{0x656e, 0x05},
++{0x656f, 0x06},
++{0x6570, 0x05},
++{0x6571, 0x04},
++{0x6572, 0x00},
++{0x6573, 0x04},
++{0x6574, 0x05},
++{0x6575, 0x00},
++{0x6576, 0x05},
++{0x6577, 0x0a},
++{0x6578, 0x03},
++{0x6579, 0x94},
++{0x657a, 0x05},
++{0x657b, 0x06},
++{0x657c, 0x00},
++{0x657d, 0x00},
++{0x657e, 0x05},
++{0x657f, 0x04},
++{0x6580, 0x00},
++{0x6581, 0x04},
++{0x6582, 0x05},
++{0x6583, 0x00},
++{0x6584, 0x05},
++{0x6585, 0x0a},
++{0x6586, 0x03},
++{0x6587, 0x93},
++{0x6588, 0x05},
++{0x6589, 0x06},
++{0x658a, 0x00},
++{0x658b, 0x00},
++{0x658c, 0x05},
++{0x658d, 0x04},
++{0x658e, 0x00},
++{0x658f, 0x04},
++{0x6590, 0x05},
++{0x6591, 0x00},
++{0x6592, 0x05},
++{0x6593, 0x0a},
++{0x6594, 0x03},
++{0x6595, 0x92},
++{0x6596, 0x05},
++{0x6597, 0x06},
++{0x6598, 0x05},
++{0x6599, 0x04},
++{0x659a, 0x00},
++{0x659b, 0x04},
++{0x659c, 0x05},
++{0x659d, 0x00},
++{0x659e, 0x05},
++{0x659f, 0x0a},
++{0x65a0, 0x03},
++{0x65a1, 0x91},
++{0x65a2, 0x05},
++{0x65a3, 0x06},
++{0x65a4, 0x05},
++{0x65a5, 0x04},
++{0x65a6, 0x00},
++{0x65a7, 0x04},
++{0x65a8, 0x05},
++{0x65a9, 0x00},
++{0x65aa, 0x05},
++{0x65ab, 0x0a},
++{0x65ac, 0x03},
++{0x65ad, 0x90},
++{0x65ae, 0x05},
++{0x65af, 0x06},
++{0x65b0, 0x05},
++{0x65b1, 0x04},
++{0x65b2, 0x00},
++{0x65b3, 0x04},
++{0x65b4, 0x05},
++{0x65b5, 0x00},
++{0x65b6, 0x05},
++{0x65b7, 0x0a},
++{0x65b8, 0x02},
++{0x65b9, 0x90},
++{0x65ba, 0x05},
++{0x65bb, 0x06},
++{0x65bc, 0x00},
++{0x65bd, 0xff},
++{0x65be, 0x04},
++{0x65bf, 0x70},
++{0x65c0, 0x08},
++{0x65c1, 0x76},
++{0x65c2, 0x00},
++{0x65c3, 0xff},
++{0x65c4, 0x08},
++{0x65c5, 0x76},
++{0x65c6, 0x04},
++{0x65c7, 0x0c},
++{0x65c8, 0x05},
++{0x65c9, 0x07},
++{0x65ca, 0x04},
++{0x65cb, 0x04},
++{0x65cc, 0x00},
++{0x65cd, 0xff},
++{0x65ce, 0x00},
++{0x65cf, 0xff},
++{0x65d0, 0x00},
++{0x65d1, 0xff},
++{0x30eb, 0x04},
++{0x30ed, 0x5a},
++{0x30ee, 0x01},
++{0x30ef, 0x80},
++{0x30f1, 0x5a},
++{0x303a, 0x04},
++{0x303b, 0x7f},
++{0x303c, 0xfe},
++{0x303d, 0x19},
++{0x303e, 0xd7},
++{0x303f, 0x09},
++{0x3040, 0x78},
++{0x3042, 0x05},
++#if 0
++{0x3012, 0x01},
++{0x3012, 0x00},
++{0x3119, 0x44},
++{0x328a, 0x10},
++{0x3012, 0x01},
++#else
++{0x328a, 0x10},
++/* HFLIP=1, VFLIP=0 */
++{0x3128, 0xc0 | 0x1},
++{0x3291, 0x01 | 0x2},
++{0x3090, 0x4},
++/* change settings to 1280x1080 COMB12 30 fps, 96MHz */
++{0x3012, 0x0},
++{0x3000, 0x3},
++{0x3001, 0x50},
++{0x3002, 0x0a},
++{0x3004, 0x3},
++{0x3005, 0x48},
++{0x3006, 0x7},
++{0x308f, 0x10},
++{0x3127, 0x63},
++{0x3074, OV10640_X_START >> 8},
++{0x3075, OV10640_X_START & 0xff},
++{0x3076, OV10640_Y_START >> 8},
++{0x3077, OV10640_Y_START & 0xff},
++{0x3078, OV10640_X_END >> 8},
++{0x3079, OV10640_X_END & 0xff},
++{0x307a, OV10640_Y_END >> 8},
++{0x307b, OV10640_Y_END & 0xff},
++{0x307c, OV10640_MAX_WIDTH >> 8},
++{0x307d, OV10640_MAX_WIDTH & 0xff},
++{0x307e, OV10640_MAX_HEIGHT >> 8},
++{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
++{0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
++{0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
++{0x3083, (OV10640_SENSOR_HEIGHT + 208) & 0xff},
++{0x3084, 0x0},
++{0x3085, 0x0},
++{0x3086, 0x0},
++{0x3087, 0x0},
++{0x346d, 0x14},
++{0x3444, 0x28},
++{0x3091, 0x0},
++{0x3119, 0x44}, // COMB12
++{0x3012, 0x1},
++#endif
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch
new file mode 100644
index 00000000..67dfa466
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0460-media-ar0xxx-add-embedded-line-into-frame.patch
@@ -0,0 +1,534 @@
+From 093694680d2fc99df1dc5118b78f80f34a0e3f4b Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 30 Dec 2019 19:48:34 +0300
+Subject: [PATCH] media: ar0xxx: add embedded line into frame
+
+This adds embedded line into frame for further parsing in ISP
+
+Signed-off-by: Petr Nechaev <petr.nechaev@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0140.c | 49 +++++++++++++++++++++----
+ drivers/media/i2c/soc_camera/ar0140.h | 21 ++++++-----
+ drivers/media/i2c/soc_camera/ar0143.c | 53 +++++++++++++++++++++++++---
+ drivers/media/i2c/soc_camera/ar0143.h | 17 +++++----
+ drivers/media/i2c/soc_camera/ar0143_custom.h | 6 +---
+ drivers/media/i2c/soc_camera/ar0143_rev1.h | 8 +----
+ drivers/media/i2c/soc_camera/ar0220.h | 12 ++++---
+ drivers/media/i2c/soc_camera/ar0233.c | 31 ++++++++++------
+ drivers/media/i2c/soc_camera/ar0233.h | 12 ++++---
+ drivers/media/i2c/soc_camera/ar0233_rev1.h | 2 +-
+ drivers/media/i2c/soc_camera/ar0233_rev2.h | 2 +-
+ 11 files changed, 150 insertions(+), 63 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c
+index ec2b2e5..ceb2c31 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.c
++++ b/drivers/media/i2c/soc_camera/ar0140.c
+@@ -36,6 +36,7 @@ struct ar0140_priv {
+ struct v4l2_rect rect;
+ int init_complete;
+ u8 id[6];
++ bool emb_enable;
+ /* serializers */
+ int max9286_addr;
+ int max9271_addr;
+@@ -115,7 +116,7 @@ static int ar0140_set_window(struct v4l2_subdev *sd)
+ reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0140_X_START);
+ /* vert crop start */
+ reg16_write16(client, 0x3002, priv->rect.top + AR0140_Y_START);
+- /* vert crop end */
++ /* limit window for embedded data/stats */
+ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0140_Y_START);
+
+ return 0;
+@@ -235,12 +236,18 @@ static int ar0140_get_selection(struct v4l2_subdev *sd,
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = AR0140_MAX_WIDTH;
+- sel->r.height = AR0140_MAX_HEIGHT;
++ sel->r.width = AR0140_DEFAULT_WIDTH;
++ sel->r.height = AR0140_DEFAULT_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+ return 0;
++ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = AR0140_EMB_PADDED;
++ sel->r.width = priv->rect.width;
++ sel->r.height = priv->rect.height;
++ return 0;
+ default:
+ return -EINVAL;
+ }
+@@ -402,7 +409,35 @@ static ssize_t ar0140_otp_id_show(struct device *dev,
+ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ }
+
++static ssize_t ar0140_emb_enable_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0140_priv *priv = to_ar0140(client);
++ u32 val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ priv->emb_enable = !!val;
++
++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802);
++
++ return count;
++}
++
++static ssize_t ar0140_emb_enable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0140_priv *priv = to_ar0140(client);
++
++ return snprintf(buf, 4, "%d\n", priv->emb_enable);
++}
++
+ static DEVICE_ATTR(otp_id_ar0140, S_IRUGO, ar0140_otp_id_show, NULL);
++static DEVICE_ATTR(emb_enable_ar0140, S_IRUGO|S_IWUSR, ar0140_emb_enable_show, ar0140_emb_enable_store);
+
+ static int ar0140_initialize(struct i2c_client *client)
+ {
+@@ -589,14 +624,15 @@ static int ar0140_probe(struct i2c_client *client,
+
+ priv->rect.left = 0;
+ priv->rect.top = 0;
+- priv->rect.width = AR0140_MAX_WIDTH;
+- priv->rect.height = AR0140_MAX_HEIGHT;
++ priv->rect.width = AR0140_DEFAULT_WIDTH;
++ priv->rect.height = AR0140_DEFAULT_HEIGHT;
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret)
+ goto cleanup;
+
+- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0140) != 0) {
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0140) != 0 ||
++ device_create_file(&client->dev, &dev_attr_emb_enable_ar0140) != 0) {
+ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
+ goto cleanup;
+ }
+@@ -620,6 +656,7 @@ static int ar0140_remove(struct i2c_client *client)
+ {
+ struct ar0140_priv *priv = i2c_get_clientdata(client);
+
++ device_remove_file(&client->dev, &dev_attr_emb_enable_ar0140);
+ device_remove_file(&client->dev, &dev_attr_otp_id_ar0140);
+ v4l2_async_unregister_subdev(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+diff --git a/drivers/media/i2c/soc_camera/ar0140.h b/drivers/media/i2c/soc_camera/ar0140.h
+index 2993478..08ce1ca 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.h
++++ b/drivers/media/i2c/soc_camera/ar0140.h
+@@ -12,20 +12,23 @@
+ //#define AR0140_DISPLAY_PATTERN_FIXED
+ //#define AR0140_DISPLAY_PATTERN_COLOR_BAR
+
+-//#define AR0140_EMBEDDED_LINE
++#define AR0140_DEFAULT_WIDTH 1280
++#define AR0140_DEFAULT_HEIGHT 800
+
+-#define AR0140_MAX_WIDTH 1280
+-#define AR0140_MAX_HEIGHT 800
++#define AR0140_EMB_LINES 4
++#define AR0140_EMB_PADDED (priv->emb_enable ? AR0140_EMB_LINES + 30 : 0) /* embedded data (SOF) and stats (EOF) + post padding */
+
+ #define AR0140_DELAY 0xffff
+
++#define AR0140_MAX_WIDTH 1280
++#define AR0140_MAX_HEIGHT 800
+ #define AR0140_SENSOR_WIDTH 1280
+ #define AR0140_SENSOR_HEIGHT 800
+
+-#define AR0140_X_START ((AR0140_SENSOR_WIDTH - AR0140_MAX_WIDTH) / 2)
+-#define AR0140_Y_START ((AR0140_SENSOR_HEIGHT - AR0140_MAX_HEIGHT) / 2)
+-#define AR0140_X_END (AR0140_X_START + AR0140_MAX_WIDTH - 1)
+-#define AR0140_Y_END (AR0140_Y_START + AR0140_MAX_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */
++#define AR0140_X_START ((AR0140_SENSOR_WIDTH - AR0140_DEFAULT_WIDTH) / 2)
++#define AR0140_Y_START ((AR0140_SENSOR_HEIGHT - AR0140_DEFAULT_HEIGHT) / 2)
++#define AR0140_X_END (AR0140_X_START + AR0140_DEFAULT_WIDTH - 1)
++#define AR0140_Y_END (AR0140_Y_START + AR0140_DEFAULT_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */
+
+ struct ar0140_reg {
+ u16 reg;
+@@ -395,11 +398,7 @@ static const struct ar0140_reg ar0140_regs_wizard[] = {
+ {0x3086, 0x2C2C},
+ {0x3086, 0x2C00},
+ /* End Sequencer */
+-#ifdef AR0140_EMBEDDED_LINE
+-{0x3064, 0x1982}, // SMIA_TEST
+-#else
+ {0x3064, 0x1802}, // SMIA_TEST
+-#endif
+ /* PCLK=27Mhz/0x2 *0x30 /1/0x10 - TI serializers */
+ {0x302A, 0x0010}, // vt_pix_clk_div
+ {0x302E, 0x0002}, // pre_pll_clk_div
+diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c
+index 0c4b970..bf8d717 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.c
++++ b/drivers/media/i2c/soc_camera/ar0143.c
+@@ -38,6 +38,7 @@ struct ar0143_priv {
+ int init_complete;
+ u8 id[6];
+ int setup;
++ bool emb_enable;
+ /* serializers */
+ int max9286_addr;
+ int max9271_addr;
+@@ -265,12 +270,18 @@ static int ar0143_get_selection(struct v4l2_subdev *sd,
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = AR0143_MAX_WIDTH;
+- sel->r.height = AR0143_MAX_HEIGHT;
++ sel->r.width = AR0143_DEFAULT_WIDTH;
++ sel->r.height = AR0143_DEFAULT_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+ return 0;
++ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = AR0143_EMB_PADDED;
++ sel->r.width = priv->rect.width;
++ sel->r.height = priv->rect.height;
++ return 0;
+ default:
+ return -EINVAL;
+ }
+@@ -436,7 +449,35 @@ static ssize_t ar0143_otp_id_show(struct device *dev,
+ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ }
+
++static ssize_t ar0143_emb_enable_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0143_priv *priv = to_ar0143(client);
++ u32 val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ priv->emb_enable = !!val;
++
++ reg16_write16(client, 0x3064, priv->emb_enable ? 0x1982 : 0x1802);
++
++ return count;
++}
++
++static ssize_t ar0143_emb_enable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0143_priv *priv = to_ar0143(client);
++
++ return snprintf(buf, 4, "%d\n", priv->emb_enable);
++}
++
+ static DEVICE_ATTR(otp_id_ar0143, S_IRUGO, ar0143_otp_id_show, NULL);
++static DEVICE_ATTR(emb_enable_ar0143, S_IRUGO|S_IWUSR, ar0143_emb_enable_show, ar0143_emb_enable_store);
+
+ static int ar0143_initialize(struct i2c_client *client)
+ {
+@@ -632,14 +673,15 @@ static int ar0143_probe(struct i2c_client *client,
+
+ priv->rect.left = 0;
+ priv->rect.top = 0;
+- priv->rect.width = AR0143_MAX_WIDTH;
+- priv->rect.height = AR0143_MAX_HEIGHT;
++ priv->rect.width = AR0143_DEFAULT_WIDTH;
++ priv->rect.height = AR0143_DEFAULT_HEIGHT;
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret)
+ goto cleanup;
+
+- if (device_create_file(&client->dev, &dev_attr_otp_id_ar0143) != 0) {
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0143) != 0||
++ device_create_file(&client->dev, &dev_attr_emb_enable_ar0143) != 0) {
+ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
+ goto cleanup;
+ }
+@@ -664,6 +706,7 @@ static int ar0143_remove(struct i2c_client *client)
+ struct ar0143_priv *priv = i2c_get_clientdata(client);
+
+ device_remove_file(&client->dev, &dev_attr_otp_id_ar0143);
++ device_remove_file(&client->dev, &dev_attr_emb_enable_ar0143);
+ v4l2_async_unregister_subdev(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->hdl);
+diff --git a/drivers/media/i2c/soc_camera/ar0143.h b/drivers/media/i2c/soc_camera/ar0143.h
+index 14d8175..d14ecae 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.h
++++ b/drivers/media/i2c/soc_camera/ar0143.h
+@@ -12,20 +12,23 @@
+ //#define AR0143_DISPLAY_PATTERN_FIXED
+ //#define AR0143_DISPLAY_PATTERN_COLOR_BAR
+
+-//#define AR0143_EMBEDDED_LINE
++#define AR0143_DEFAULT_WIDTH 1280
++#define AR0143_DEFAULT_HEIGHT 960
+
+-#define AR0143_MAX_WIDTH 1344
+-#define AR0143_MAX_HEIGHT 968
++#define AR0143_EMB_LINES 8
++#define AR0143_EMB_PADDED (priv->emb_enable ? AR0143_EMB_LINES + 30 : 0) /* embedded data (SOF) and stats (EOF) + post padding */
+
+ #define AR0143_DELAY 0xffff
+
++#define AR0143_MAX_WIDTH 1344
++#define AR0143_MAX_HEIGHT 968
+ #define AR0143_SENSOR_WIDTH 1344
+ #define AR0143_SENSOR_HEIGHT 968
+
+-#define AR0143_X_START ((AR0143_SENSOR_WIDTH - AR0143_MAX_WIDTH) / 2)
+-#define AR0143_Y_START ((AR0143_SENSOR_HEIGHT - AR0143_MAX_HEIGHT) / 2)
+-#define AR0143_X_END (AR0143_X_START + AR0143_MAX_WIDTH - 1)
+-#define AR0143_Y_END (AR0143_Y_START + AR0143_MAX_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */
++#define AR0143_X_START ((AR0143_SENSOR_WIDTH - AR0143_DEFAULT_WIDTH) / 2)
++#define AR0143_Y_START ((AR0143_SENSOR_HEIGHT - AR0143_DEFAULT_HEIGHT) / 2)
++#define AR0143_X_END (AR0143_X_START + AR0143_DEFAULT_WIDTH - 1)
++#define AR0143_Y_END (AR0143_Y_START + AR0143_DEFAULT_HEIGHT + 1) /* must be +1 and not -1 or 2 lines missed - bug in imager? */
+
+ struct ar0143_reg {
+ u16 reg;
+diff --git a/drivers/media/i2c/soc_camera/ar0143_custom.h b/drivers/media/i2c/soc_camera/ar0143_custom.h
+index e5bc37a..8e21416 100644
+--- a/drivers/media/i2c/soc_camera/ar0143_custom.h
++++ b/drivers/media/i2c/soc_camera/ar0143_custom.h
+@@ -368,11 +368,7 @@ static const struct ar0143_reg ar0143_regs_wizard_custom[] = {
+ {0x3180, 0x0080}, // RESERVED_MFR_3180
+ {0x33E4, 0x0080}, // RESERVED_MFR_33E4
+ {0x33E0, 0x0880}, // TEST_ASIL_ROWS
+-#ifdef AR0143_EMBEDDED_LINE
+-{0x3064, 0x1982}, // SMIA_TEST
+-#else
+ {0x3064, 0x1802}, // SMIA_TEST
+-#endif
+ {0x3004, 0x0000}, // X_ADDR_START_
+ {0x3008, 0x053F}, // X_ADDR_END_
+ {0x3002, 0x0000}, // Y_ADDR_START_
+@@ -455,7 +451,7 @@ static const struct ar0143_reg ar0143_regs_wizard_custom[] = {
+ {0x31B8, 0x404B}, // RESERVED_MFR_31B8
+ {0x31BA, 0x020A}, // RESERVED_MFR_31BA
+ {0x31BC, 0x0C08}, // RESERVED_MFR_31BC
+-{0x3040, 0x0000}, // READ_MODE
++{0x3040, 0x0005}, // READ_MODE
+ {0x30BA, 0x01E2}, // DIGITAL_CTRL
+ {0x3082, 0x0008}, // OPERATION_MODE_CTRL
+ {0x3044, 0x0400}, // DARK_CONTROL
+diff --git a/drivers/media/i2c/soc_camera/ar0143_rev1.h b/drivers/media/i2c/soc_camera/ar0143_rev1.h
+index ec941d8..21cb4bf 100644
+--- a/drivers/media/i2c/soc_camera/ar0143_rev1.h
++++ b/drivers/media/i2c/soc_camera/ar0143_rev1.h
+@@ -390,7 +390,7 @@ static const struct ar0143_reg ar0143_regs_wizard_rev1[] = {
+ #ifdef AR0143_Readout_Mode_Configuration
+ {0x30A2, 0x0001}, // X_ODD_INC_
+ {0x30A6, 0x0001}, // Y_ODD_INC_
+-{0x3040, 0x0000}, // READ_MODE
++{0x3040, 0x0005}, // READ_MODE
+ {0x3082, 0x0008}, // OPERATION_MODE_CTRL: 3exp
+ {0x30BA, 0x01E2}, // DIGITAL_CTRL: 3exp max
+ {0x3044, 0x0400}, // DARK_CONTROL
+@@ -400,12 +400,6 @@ static const struct ar0143_reg ar0143_regs_wizard_rev1[] = {
+ {0x33E4, 0x0080}, // RESERVED_MFR_33E4
+ #endif /* AR0143_Readout_Mode_Configuration */
+
+-#ifdef AR0143_HDR_Readout_Mode_Configuration
+-#ifdef AR0143_EMBEDDED_LINE
+-{0x3064, 0x1982}, // SMIA_TEST: enable emb data and stats
+-#endif
+-#endif /* AR0143_HDR_Readout_Mode_Configuration */
+-
+ #ifdef AR0143_Full_Res_FOV
+ {0x31B0, 0x0006}, // FRAME_PREAMBLE
+ {0x31B2, 0x0045}, // LINE_PREAMBLE
+diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h
+index 59a949e..f90deae 100644
+--- a/drivers/media/i2c/soc_camera/ar0220.h
++++ b/drivers/media/i2c/soc_camera/ar0220.h
+@@ -12,16 +12,18 @@
+ //#define AR0220_DISPLAY_PATTERN_FIXED
+ //#define AR0220_DISPLAY_PATTERN_COLOR_BAR
+
++#define AR0220_DEFAULT_WIDTH 1792
++#define AR0220_DEFAULT_HEIGHT 944
++
+ #define AR0220_MAX_WIDTH 1828
+ #define AR0220_MAX_HEIGHT 948
+-
+ #define AR0220_SENSOR_WIDTH 1828
+ #define AR0220_SENSOR_HEIGHT 948
+
+-#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_MAX_WIDTH) / 2)
+-#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_MAX_HEIGHT) / 2)
+-#define AR0220_X_END (AR0220_X_START + AR0220_MAX_WIDTH - 1)
+-#define AR0220_Y_END (AR0220_Y_START + AR0220_MAX_HEIGHT - 1)
++#define AR0220_X_START ((AR0220_SENSOR_WIDTH - AR0220_DEFAULT_WIDTH) / 2)
++#define AR0220_Y_START ((AR0220_SENSOR_HEIGHT - AR0220_DEFAULT_HEIGHT) / 2)
++#define AR0220_X_END (AR0220_X_START + AR0220_DEFAULT_WIDTH - 1)
++#define AR0220_Y_END (AR0220_Y_START + AR0220_DEFAULT_HEIGHT - 1)
+
+ #include "ar0220_rev2.h"
+ #include "ar0220_rev3.h"
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index b62fb77..cdd2d8a 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -21,9 +21,10 @@
+ #include <media/v4l2-ctrls.h>
+
+ #define AR_DELAY 0xffff
+-static int AR_MAX_WIDTH;
+-static int AR_MAX_HEIGHT;
+-#define AR_MAX_HEIGHT_EMB (AR_MAX_HEIGHT + priv->emb_enable * 4) /* embedded data (SOF) and stats (EOF) */
++static int AR_MAX_WIDTH, AR_DEFAULT_WIDTH;
++static int AR_MAX_HEIGHT, AR_DEFAULT_HEIGHT;
++#define AR_EMB_LINES 8
++#define AR_EMB_PADDED (priv->emb_enable ? AR_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */
+ static int AR_X_START;
+ static int AR_Y_START;
+ static int AR_X_END;
+@@ -124,7 +125,7 @@ static int ar0233_set_window(struct v4l2_subdev *sd)
+ reg16_write16(client, 0x3002, priv->rect.top + AR_Y_START);
+ /* vert crop end */
+ /* limit window for embedded data/stats */
+- reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START - priv->emb_enable * 4);
++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR_Y_START);
+
+ return 0;
+ };
+@@ -210,7 +211,7 @@ static int ar0233_set_selection(struct v4l2_subdev *sd,
+ rect->height = ALIGN(rect->height, 2);
+
+ if ((rect->left + rect->width > AR_MAX_WIDTH) ||
+- (rect->top + rect->height > AR_MAX_HEIGHT_EMB))
++ (rect->top + rect->height > AR_MAX_HEIGHT))
+ *rect = priv->rect;
+
+ priv->rect.left = rect->left;
+@@ -238,17 +239,23 @@ static int ar0233_get_selection(struct v4l2_subdev *sd,
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = AR_MAX_WIDTH;
+- sel->r.height = AR_MAX_HEIGHT_EMB;
++ sel->r.height = AR_MAX_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = AR_MAX_WIDTH;
+- sel->r.height = AR_MAX_HEIGHT_EMB;
++ sel->r.width = AR_DEFAULT_WIDTH;
++ sel->r.height = AR_DEFAULT_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+ return 0;
++ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = AR_EMB_PADDED;
++ sel->r.width = priv->rect.width;
++ sel->r.height = priv->rect.height;
++ return 0;
+ default:
+ return -EINVAL;
+ }
+@@ -496,6 +503,8 @@ static int ar0233_initialize(struct i2c_client *client)
+ strncpy(chip_name, "AR0220", 10);
+ AR_MAX_WIDTH = AR0220_MAX_WIDTH;
+ AR_MAX_HEIGHT = AR0220_MAX_HEIGHT;
++ AR_DEFAULT_WIDTH = AR0220_DEFAULT_WIDTH;
++ AR_DEFAULT_HEIGHT = AR0220_DEFAULT_HEIGHT;
+ AR_X_START = AR0220_X_START;
+ AR_Y_START = AR0220_Y_START;
+ AR_X_END = AR0220_X_END;
+@@ -532,6 +541,8 @@ static int ar0233_initialize(struct i2c_client *client)
+ strncpy(chip_name, "AR0233", 10);
+ AR_MAX_WIDTH = AR0233_MAX_WIDTH;
+ AR_MAX_HEIGHT = AR0233_MAX_HEIGHT;
++ AR_DEFAULT_WIDTH = AR0233_DEFAULT_WIDTH;
++ AR_DEFAULT_HEIGHT = AR0233_DEFAULT_HEIGHT;
+ AR_X_START = AR0233_X_START;
+ AR_Y_START = AR0233_Y_START;
+ AR_X_END = AR0233_X_END;
+@@ -693,8 +704,8 @@ static int ar0233_probe(struct i2c_client *client,
+
+ priv->rect.left = 0;
+ priv->rect.top = 0;
+- priv->rect.width = AR_MAX_WIDTH;
+- priv->rect.height = AR_MAX_HEIGHT;
++ priv->rect.width = AR_DEFAULT_WIDTH;
++ priv->rect.height = AR_DEFAULT_HEIGHT;
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret)
+diff --git a/drivers/media/i2c/soc_camera/ar0233.h b/drivers/media/i2c/soc_camera/ar0233.h
+index 33b661a..cb79421 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.h
++++ b/drivers/media/i2c/soc_camera/ar0233.h
+@@ -12,16 +12,18 @@
+ //#define AR0233_DISPLAY_PATTERN_FIXED
+ //#define AR0233_DISPLAY_PATTERN_COLOR_BAR
+
++#define AR0233_DEFAULT_WIDTH 2048
++#define AR0233_DEFAULT_HEIGHT 1280
++
+ #define AR0233_MAX_WIDTH 2048
+ #define AR0233_MAX_HEIGHT 1280
+-
+ #define AR0233_SENSOR_WIDTH 2072
+ #define AR0233_SENSOR_HEIGHT 1296
+
+-#define AR0233_X_START ((AR0233_SENSOR_WIDTH - AR0233_MAX_WIDTH) / 2)
+-#define AR0233_Y_START ((AR0233_SENSOR_HEIGHT - AR0233_MAX_HEIGHT) / 2)
+-#define AR0233_X_END (AR0233_X_START + AR0233_MAX_WIDTH - 1)
+-#define AR0233_Y_END (AR0233_Y_START + AR0233_MAX_HEIGHT - 1)
++#define AR0233_X_START ((AR0233_SENSOR_WIDTH - AR0233_DEFAULT_WIDTH) / 2)
++#define AR0233_Y_START ((AR0233_SENSOR_HEIGHT - AR0233_DEFAULT_HEIGHT) / 2)
++#define AR0233_X_END (AR0233_X_START + AR0233_DEFAULT_WIDTH - 1)
++#define AR0233_Y_END (AR0233_Y_START + AR0233_DEFAULT_HEIGHT - 1)
+
+ #include "ar0233_rev1.h"
+ #include "ar0233_rev2.h"
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev1.h b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+index 3ff944f..8b9638b 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev1.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev1.h
+@@ -1156,7 +1156,7 @@ static const struct ar0xxx_reg ar0233_rev1_Full_resolution[] = {
+ }; /* Full_resolution */
+
+ static const struct ar0xxx_reg ar0233_rev1_disable_embed_data_stat[] = {
+-{0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1
++{0x3040, 0xC005}, //Embedded stat4 and data4 rows, hflip/vflip=1
+ #ifdef AR0233_EMBEDDED_LINE
+ {0x3064, 0x0180}, //Enable embedded data and stat
+ #else
+diff --git a/drivers/media/i2c/soc_camera/ar0233_rev2.h b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+index 80572ff..bd508f0 100644
+--- a/drivers/media/i2c/soc_camera/ar0233_rev2.h
++++ b/drivers/media/i2c/soc_camera/ar0233_rev2.h
+@@ -2265,7 +2265,7 @@ static const struct ar0xxx_reg ar0233_rev2_O1_Recommended_Defaults_SE_T1_LIN_T2[
+ }; /* O1_Recommended_Defaults_SE_T1_LIN_T2 */
+
+ static const struct ar0xxx_reg ar0233_rev2_disable_embed_data_stat[] = {
+-{0x3040, 0xC000}, //Embedded stat2 and data2 rows, hflip/vflip=1
++{0x3040, 0xC005}, //Embedded stat4 and data4 rows, hflip/vflip=1
+ {0x350e, 0x2089}, // bit0 must be set for vflip=1
+ #ifdef AR0233_EMBEDDED_LINE
+ {0x3064, 0x0180}, // SMIA_TEST: enable emb data and stats
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch
new file mode 100644
index 00000000..a34231f6
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch
@@ -0,0 +1,132 @@
+From 193b183e75deb047c60196e987b3112e134abe17 Mon Sep 17 00:00:00 2001
+From: Petr Nechaev <petr.nechaev@cogentembedded.com>
+Date: Thu, 13 Jun 2019 21:20:25 -0400
+Subject: [PATCH] v3hsk: Add separate dts for dummy camera 1920x1080
+
+To be used as LVDS -> HDMI converter.
+---
+ arch/arm64/boot/dts/renesas/Makefile | 1 +
+ .../renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts | 46 +++++++++++++++++++
+ .../renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts | 46 +++++++++++++++++++
+ 3 files changed, 93 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index 4b2f4fb73bed..89da50cbfbdb 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -42,5 +42,6 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb
++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb
+
+ always := $(dtb-y)
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts
+new file mode 100644
+index 000000000000..f5931c5d3ef6
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch-hdmi.dts
+@@ -0,0 +1,46 @@
++/*
++ * Device Tree Source for the V3HSK VideoBox 4-channel board on r8a7798 with dummy LVDS input
++ *
++ * Copyright (C) 2018 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk-vb-4ch.dts"
++
++&i2cswitch1 {
++ i2c@2 {
++ /delete-node/ ov106xx@0;
++
++ dummy-camera@0 {
++ compatible = "dummy-camera";
++ reg = <0x60>;
++
++ dummy,width = <1920>;
++ dummy,height = <1080>;
++
++ port@0 {
++ dummy_camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ dummy_camera_ti9x4_des0ep0: endpoint@1 {
++ remote-endpoint = <&ti9x4_des0ep0>;
++ };
++ };
++ };
++ };
++};
++
++&ti9x4_des0ep0 {
++ remote-endpoint = <&dummy_camera_in0>;
++};
++
++&vin0ep0 {
++ remote-endpoint = <&dummy_camera_in0>;
++};
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts
+new file mode 100644
+index 000000000000..5aecc0e80cde
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch-hdmi.dts
+@@ -0,0 +1,46 @@
++/*
++ * Device Tree Source for the V3HSK VideoBox 8-channel board on r8a7798 with dummy LVDS input
++ *
++ * Copyright (C) 2018 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk-vb-8ch.dts"
++
++&i2cswitch1 {
++ i2c@2 {
++ /delete-node/ ov106xx@0;
++
++ dummy-camera@0 {
++ compatible = "dummy-camera";
++ reg = <0x60>;
++
++ dummy,width = <1920>;
++ dummy,height = <1080>;
++
++ port@0 {
++ dummy_camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ dummy_camera_ti9x4_des0ep0: endpoint@1 {
++ remote-endpoint = <&ti9x4_des0ep0>;
++ };
++ };
++ };
++ };
++};
++
++&ti9x4_des0ep0 {
++ remote-endpoint = <&dummy_camera_in0>;
++};
++
++&vin0ep0 {
++ remote-endpoint = <&dummy_camera_in0>;
++};
+--
+2.20.1
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch
new file mode 100644
index 00000000..683ee130
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch
@@ -0,0 +1,289 @@
+From 0f0c2244b6ed65807d40b8cf730d297e1218600e Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 13 Jan 2020 19:01:29 +0300
+Subject: [PATCH] media: i2c: ov10640: add embedded data, fix crop
+
+This addes embedded line and stats for furhter parsing inside ISP
+This also fixes the crop.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 79 ++++++++++++++++++++++++------
+ drivers/media/i2c/soc_camera/ov10640.h | 17 ++++---
+ drivers/media/i2c/soc_camera/ov10640_r1d.h | 10 ++--
+ drivers/media/i2c/soc_camera/ov10640_r1e.h | 10 ++--
+ drivers/media/i2c/soc_camera/ov10640_r1f.h | 10 ++--
+ 5 files changed, 89 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index 40058b7..fab2c0d 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -42,6 +42,7 @@ struct ov10640_priv {
+ int init_complete;
+ u8 id[6];
+ int dvp_order;
++ bool emb_enable;
+ /* serializers */
+ int max9286_addr;
+ int max9271_addr;
+@@ -113,23 +114,23 @@ static int ov10640_set_window(struct v4l2_subdev *sd)
+ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height);
+
+ /* horiz crop start (reverse) */
+- reg16_write(client, 0x3074, (OV10640_MAX_WIDTH - priv->rect.width - priv->rect.left) >> 8);
+- reg16_write(client, 0x3075, (OV10640_MAX_WIDTH - priv->rect.width - priv->rect.left) & 0xff);
++ reg16_write(client, 0x3074, (OV10640_X_END - priv->rect.left - priv->rect.width + 1) >> 8);
++ reg16_write(client, 0x3075, (OV10640_X_END - priv->rect.left - priv->rect.width + 1) & 0xff);
+ /* horiz crop end (reverse) */
+- reg16_write(client, 0x3078, (OV10640_MAX_WIDTH - priv->rect.left - 1) >> 8);
+- reg16_write(client, 0x3079, (OV10640_MAX_WIDTH - priv->rect.left - 1) & 0xff);
++ reg16_write(client, 0x3078, (OV10640_X_END - priv->rect.left) >> 8);
++ reg16_write(client, 0x3079, (OV10640_X_END - priv->rect.left) & 0xff);
+ /* vert crop start */
+- reg16_write(client, 0x3076, priv->rect.top >> 8);
+- reg16_write(client, 0x3077, priv->rect.top & 0xff);
++ reg16_write(client, 0x3076, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) >> 8);
++ reg16_write(client, 0x3077, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) & 0xff);
+ /* vert crop end */
+- reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height + 1) >> 8);
+- reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height + 1) & 0xff);
++ reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height + OV10640_Y_START - 1 + OV10640_EMB_PADDED / 2) >> 8);
++ reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height + OV10640_Y_START - 1 + OV10640_EMB_PADDED / 2) & 0xff);
+ /* horiz output */
+ reg16_write(client, 0x307c, priv->rect.width >> 8);
+ reg16_write(client, 0x307d, priv->rect.width & 0xff);
+ /* vert output */
+- reg16_write(client, 0x307e, priv->rect.height >> 8);
+- reg16_write(client, 0x307f, priv->rect.height & 0xff);
++ reg16_write(client, 0x307e, (priv->rect.height + OV10640_EMB_PADDED) >> 8);
++ reg16_write(client, 0x307f, (priv->rect.height + OV10640_EMB_PADDED) & 0xff);
+
+ return 0;
+ };
+@@ -248,12 +249,18 @@ static int ov10640_get_selection(struct v4l2_subdev *sd,
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+- sel->r.width = OV10640_MAX_WIDTH;
+- sel->r.height = OV10640_MAX_HEIGHT;
++ sel->r.width = OV10640_DEFAULT_WIDTH;
++ sel->r.height = OV10640_DEFAULT_HEIGHT;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = priv->rect;
+ return 0;
++ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = OV10640_EMB_PADDED / 2;
++ sel->r.width = priv->rect.width;
++ sel->r.height = priv->rect.height;
++ return 0;
+ default:
+ return -EINVAL;
+ }
+@@ -464,7 +471,45 @@ static ssize_t ov10640_otp_id_show(struct device *dev,
+ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ }
+
++static ssize_t ov10640_emb_enable_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
++ u32 val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ priv->emb_enable = !!val;
++
++ /* vert crop start */
++ reg16_write(client, 0x3076, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) >> 8);
++ reg16_write(client, 0x3077, (priv->rect.top + OV10640_Y_START - OV10640_EMB_PADDED / 2) & 0xff);
++ /* vert crop end */
++ reg16_write(client, 0x307a, (priv->rect.top + priv->rect.height - 1 + OV10640_Y_START + OV10640_EMB_PADDED / 2) >> 8);
++ reg16_write(client, 0x307b, (priv->rect.top + priv->rect.height - 1 + OV10640_Y_START + OV10640_EMB_PADDED / 2) & 0xff);
++ /* vert output */
++ reg16_write(client, 0x307e, (priv->rect.height + OV10640_EMB_PADDED) >> 8);
++ reg16_write(client, 0x307f, (priv->rect.height + OV10640_EMB_PADDED) & 0xff);
++
++ reg16_write(client, 0x3091, priv->emb_enable ? 0x0C : 0x00);
++
++ return count;
++}
++
++static ssize_t ov10640_emb_enable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
++
++ return snprintf(buf, 4, "%d\n", priv->emb_enable);
++}
++
+ static DEVICE_ATTR(otp_id_ov10640, S_IRUGO, ov10640_otp_id_show, NULL);
++static DEVICE_ATTR(emb_enable_ov10640, S_IRUGO|S_IWUSR, ov10640_emb_enable_show, ov10640_emb_enable_store);
+
+ static int ov10640_initialize(struct i2c_client *client)
+ {
+@@ -510,7 +555,7 @@ static int ov10640_initialize(struct i2c_client *client)
+ reg16_write(client, 0x3124, priv->dvp_order << 4);
+
+ dev_info(&client->dev, "ov10640 PID %x (r%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+- pid, rev, OV10640_MAX_WIDTH, OV10640_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ pid, rev, OV10640_DEFAULT_WIDTH, OV10640_DEFAULT_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ out:
+ ov10640_s_port(client, 0);
+
+@@ -596,8 +641,8 @@ static int ov10640_probe(struct i2c_client *client,
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ priv->rect.left = 0;
+ priv->rect.top = 0;
+- priv->rect.width = OV10640_MAX_WIDTH;
+- priv->rect.height = OV10640_MAX_HEIGHT;
++ priv->rect.width = OV10640_DEFAULT_WIDTH;
++ priv->rect.height = OV10640_DEFAULT_HEIGHT;
+ priv->fps_denominator = 30;
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+@@ -653,7 +698,8 @@ static int ov10640_probe(struct i2c_client *client,
+ if (ret)
+ goto cleanup;
+
+- if (device_create_file(&client->dev, &dev_attr_otp_id_ov10640) != 0) {
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10640) != 0||
++ device_create_file(&client->dev, &dev_attr_emb_enable_ov10640) != 0) {
+ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
+ goto cleanup;
+ }
+@@ -678,6 +724,7 @@ static int ov10640_remove(struct i2c_client *client)
+ struct ov10640_priv *priv = i2c_get_clientdata(client);
+
+ device_remove_file(&client->dev, &dev_attr_otp_id_ov10640);
++ device_remove_file(&client->dev, &dev_attr_emb_enable_ov10640);
+ v4l2_async_unregister_subdev(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->hdl);
+diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h
+index 3d2de3d..04ff326 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.h
++++ b/drivers/media/i2c/soc_camera/ov10640.h
+@@ -12,18 +12,23 @@
+ //#define OV10640_DISPLAY_PATTERN
+ #define OV10640_FSIN_ENABLE
+
+-#define OV10640_MAX_WIDTH 1280
+-#define OV10640_MAX_HEIGHT 1080
++#define OV10640_DEFAULT_WIDTH 1280
++#define OV10640_DEFAULT_HEIGHT 1080
++
++#define OV10640_EMB_LINES 4 /* 2 emb lines at top and 2 stat lines at bottom */
++#define OV10640_EMB_PADDED (priv->emb_enable ? OV10640_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */
+
+ #define OV10640_DELAY 0xffff
+
++#define OV10640_MAX_WIDTH 1280
++#define OV10640_MAX_HEIGHT 1080
+ #define OV10640_SENSOR_WIDTH 1292
+ #define OV10640_SENSOR_HEIGHT 1092
+
+-#define OV10640_X_START ((OV10640_SENSOR_WIDTH - OV10640_MAX_WIDTH) / 2)
+-#define OV10640_Y_START ((OV10640_SENSOR_HEIGHT - OV10640_MAX_HEIGHT) / 2)
+-#define OV10640_X_END (OV10640_X_START + OV10640_MAX_WIDTH - 1)
+-#define OV10640_Y_END (OV10640_Y_START + OV10640_MAX_HEIGHT - 1)
++#define OV10640_X_START ((OV10640_SENSOR_WIDTH - OV10640_DEFAULT_WIDTH) / 2)
++#define OV10640_Y_START ((OV10640_SENSOR_HEIGHT - OV10640_DEFAULT_HEIGHT) / 2)
++#define OV10640_X_END (OV10640_X_START + OV10640_DEFAULT_WIDTH - 1)
++#define OV10640_Y_END (OV10640_Y_START + OV10640_DEFAULT_HEIGHT - 1)
+
+ struct ov10640_reg {
+ u16 reg;
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1d.h b/drivers/media/i2c/soc_camera/ov10640_r1d.h
+index 374b6d1..6f29b01 100644
+--- a/drivers/media/i2c/soc_camera/ov10640_r1d.h
++++ b/drivers/media/i2c/soc_camera/ov10640_r1d.h
+@@ -1219,10 +1219,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1d[] = {
+ {0x3079, OV10640_X_END & 0xff},
+ {0x307a, OV10640_Y_END >> 8},
+ {0x307b, OV10640_Y_END & 0xff},
+-{0x307c, OV10640_MAX_WIDTH >> 8},
+-{0x307d, OV10640_MAX_WIDTH & 0xff},
+-{0x307e, OV10640_MAX_HEIGHT >> 8},
+-{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x307c, OV10640_DEFAULT_WIDTH >> 8},
++{0x307d, OV10640_DEFAULT_WIDTH & 0xff},
++{0x307e, OV10640_DEFAULT_HEIGHT >> 8},
++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff},
+ {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
+ {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
+ {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
+@@ -1233,7 +1233,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1d[] = {
+ {0x3087, 0x0},
+ {0x346d, 0x14},
+ {0x3444, 0x28},
+-{0x3091, 0x0},
++{0x3091, 0x00}, // embedded data, embedded stats
+ {0x3119, 0x44}, // COMB12
+ {0x3012, 0x1},
+ #endif
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1e.h b/drivers/media/i2c/soc_camera/ov10640_r1e.h
+index eeff330..ba3c636 100644
+--- a/drivers/media/i2c/soc_camera/ov10640_r1e.h
++++ b/drivers/media/i2c/soc_camera/ov10640_r1e.h
+@@ -1214,10 +1214,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1e[] = {
+ {0x3079, OV10640_X_END & 0xff},
+ {0x307a, OV10640_Y_END >> 8},
+ {0x307b, OV10640_Y_END & 0xff},
+-{0x307c, OV10640_MAX_WIDTH >> 8},
+-{0x307d, OV10640_MAX_WIDTH & 0xff},
+-{0x307e, OV10640_MAX_HEIGHT >> 8},
+-{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x307c, OV10640_DEFAULT_WIDTH >> 8},
++{0x307d, OV10640_DEFAULT_WIDTH & 0xff},
++{0x307e, OV10640_DEFAULT_HEIGHT >> 8},
++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff},
+ {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
+ {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
+ {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
+@@ -1228,7 +1228,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1e[] = {
+ {0x3087, 0x0},
+ {0x346d, 0x14},
+ {0x3444, 0x28},
+-{0x3091, 0x0},
++{0x3091, 0x00}, // embedded data, embedded stats
+ {0x3119, 0x44}, // COMB12
+ {0x3012, 0x1},
+ #endif
+diff --git a/drivers/media/i2c/soc_camera/ov10640_r1f.h b/drivers/media/i2c/soc_camera/ov10640_r1f.h
+index ef866fa..3f9b3f5 100644
+--- a/drivers/media/i2c/soc_camera/ov10640_r1f.h
++++ b/drivers/media/i2c/soc_camera/ov10640_r1f.h
+@@ -1177,10 +1177,10 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = {
+ {0x3079, OV10640_X_END & 0xff},
+ {0x307a, OV10640_Y_END >> 8},
+ {0x307b, OV10640_Y_END & 0xff},
+-{0x307c, OV10640_MAX_WIDTH >> 8},
+-{0x307d, OV10640_MAX_WIDTH & 0xff},
+-{0x307e, OV10640_MAX_HEIGHT >> 8},
+-{0x307f, OV10640_MAX_HEIGHT & 0xff},
++{0x307c, OV10640_DEFAULT_WIDTH >> 8},
++{0x307d, OV10640_DEFAULT_WIDTH & 0xff},
++{0x307e, OV10640_DEFAULT_HEIGHT >> 8},
++{0x307f, OV10640_DEFAULT_HEIGHT & 0xff},
+ {0x3080, (OV10640_SENSOR_WIDTH + 200) >> 8}, // HTS
+ {0x3081, (OV10640_SENSOR_WIDTH + 200) & 0xff},
+ {0x3082, (OV10640_SENSOR_HEIGHT + 208) >> 8}, //VTS
+@@ -1191,7 +1191,7 @@ static const struct ov10640_reg ov10640_regs_wizard_r1f[] = {
+ {0x3087, 0x0},
+ {0x346d, 0x14},
+ {0x3444, 0x28},
+-{0x3091, 0x0},
++{0x3091, 0x00}, // embedded data, embedded stats
+ {0x3119, 0x44}, // COMB12
+ {0x3012, 0x1},
+ #endif
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch
new file mode 100644
index 00000000..8fffdc42
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch
@@ -0,0 +1,62 @@
+From f64aaea45c16fd3f34e4130b62a14389fb174b13 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Jan 2020 13:17:42 +0300
+Subject: [PATCH] net: can: rcar_can: fix possible IRQ storm on high load
+
+We have observed rcar_canfd driver entering IRQ storm under high load,
+with following scenario:
+- rcar_canfd_global_interrupt() in entered due to Rx available,
+- napi_schedule_prep() is called, and sets NAPIF_STATE_SCHED in state
+- Rx fifo interrupts are masked,
+- rcar_canfd_global_interrupt() is entered again, this time due to
+ error interrupt (e.g. due to overflow),
+- since scheduled napi poller has not yet executed, condition for calling
+ napi_schedule_prep() from rcar_canfd_global_interrupt() remains true,
+ thus napi_schedule_prep() gets called and sets NAPIF_STATE_MISSED flag
+ in state,
+- later, napi poller function rcar_canfd_rx_poll() gets executed, and
+ calls napi_complete_done(),
+- due to NAPIF_STATE_MISSED flag in state, this call does not clear
+ NAPIF_STATE_SCHED flag from state,
+- on return from napi_complete_done(), rcar_canfd_rx_poll() unmasks Rx
+ interrutps,
+- Rx interrupt happens, rcar_canfd_global_interrupt() gets called
+ and calls napi_schedule_prep(),
+- since NAPIF_STATE_SCHED is set in state at this time, this call
+ returns false,
+- due to that false return, rcar_canfd_global_interrupt() returns
+ without masking Rx interrupt
+- and this results into IRQ storm: unmasked Rx interrupt happens again
+ and again is misprocessed in the same way.
+
+This patch fixes that scenario by unmasking Rx interrupts only when
+napi_complete_done() returns true, which means it has cleared
+NAPIF_STATE_SCHED in state.
+
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/net/can/rcar/rcar_can.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c
+index 8d2c709..b06bfc2 100644
+--- a/drivers/net/can/rcar/rcar_can.c
++++ b/drivers/net/can/rcar/rcar_can.c
+@@ -705,9 +705,10 @@ static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
+ }
+ /* All packets processed */
+ if (num_pkts < quota) {
+- napi_complete_done(napi, num_pkts);
+- priv->ier |= RCAR_CAN_IER_RXFIE;
+- writeb(priv->ier, &priv->regs->ier);
++ if (napi_complete_done(napi, num_pkts)) {
++ priv->ier |= RCAR_CAN_IER_RXFIE;
++ writeb(priv->ier, &priv->regs->ier);
++ }
+ }
+ return num_pkts;
+ }
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch
new file mode 100644
index 00000000..5d8b49e0
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch
@@ -0,0 +1,48 @@
+From 233ca8eeba0564b0754a31afd4535f35362479cf Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Jan 2020 16:28:12 +0300
+Subject: [PATCH] arm64: dts: renesas: ulcb-v2: use CANFD instead CAN
+
+Replace replace CAN with CANFD
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
+index 89bc8c1..1b4e6c3 100644
+--- a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi
+@@ -1584,25 +1584,19 @@
+ &can0 {
+ pinctrl-0 = <&can0_pins>;
+ pinctrl-names = "default";
+- status = "okay";
+-
+- renesas,can-clock-select = <0x0>;
++ status = "disabled";
+ };
+
+ &can1 {
+ pinctrl-0 = <&can1_pins>;
+ pinctrl-names = "default";
+- status = "okay";
+-
+- renesas,can-clock-select = <0x0>;
++ status = "disabled";
+ };
+
+ &canfd {
+ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
+ pinctrl-names = "default";
+- status = "disabled";
+-
+- renesas,can-clock-select = <0x0>;
++ status = "okay";
+
+ channel0 {
+ status = "okay";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch
new file mode 100644
index 00000000..12d71ec1
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch
@@ -0,0 +1,481 @@
+From 13310cdf96f0f4cf63c2b374267fce6794573500 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 28 Jan 2020 21:13:56 +0300
+Subject: [PATCH] arm64: dts: renesas: add cn12 support on VB2.1
+
+This adds CN12 (SLOT C) on VB2.1
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi | 459 +++++++++++++++++++++++++
+ 1 file changed, 459 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi
+
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi
+new file mode 100644
+index 0000000..7ce48d90
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2-cn12.dtsi
+@@ -0,0 +1,459 @@
++/*
++ * Device Tree Source for the H3ULCB Videobox board V2:
++ * this adding conflicting resource on VIN4/VIN5/VIN6/VIN7 for CN12
++ *
++ * Copyright (C) 2020 Renesas Electronics Corp.
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++&i2cswitch2 {
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++ /* Slot C (CN12) */
++
++ ov106xx@8 {
++ compatible = "ovti,ov106xx";
++ reg = <0x68>;
++
++ port@0 {
++ ov106xx_in8: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ remote-endpoint = <&vin4ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des2ep0: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep0>;
++ };
++ ov106xx_ti9x4_des2ep0: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep0>;
++ };
++ };
++ };
++
++ ov106xx@9 {
++ compatible = "ovti,ov106xx";
++ reg = <0x69>;
++
++ port@0 {
++ ov106xx_in9: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ remote-endpoint = <&vin5ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des2ep1: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep1>;
++ };
++ ov106xx_ti9x4_des2ep1: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep1>;
++ };
++ };
++ };
++
++ ov106xx@10 {
++ compatible = "ovti,ov106xx";
++ reg = <0x6a>;
++
++ port@0 {
++ ov106xx_in10: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ remote-endpoint = <&vin6ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des2ep2: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep2>;
++ };
++ ov106xx_ti9x4_des2ep2: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep2>;
++ };
++ };
++ };
++
++ ov106xx@11 {
++ compatible = "ovti,ov106xx";
++ reg = <0x6b>;
++
++ port@0 {
++ ov106xx_in11: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ remote-endpoint = <&vin7ep0>;
++ };
++ };
++ port@1 {
++ ov106xx_max9286_des2ep3: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep3>;
++ };
++ ov106xx_ti9x4_des2ep3: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep3>;
++ };
++ };
++ };
++
++ /* DS90UB9x4 @ 0x3a */
++ ti9x4@2 {
++ compatible = "ti,ti9x4";
++ reg = <0x3a>;
++ ti,sensor_delay = <350>;
++ ti,links = <4>;
++ ti,lanes = <2>;
++ ti,forwarding-mode = "round-robin";
++ ti,cable-mode = "coax";
++
++ POC0-gpios = <&gpio_exp_c_5c 8 GPIO_ACTIVE_HIGH>;
++ POC1-gpios = <&gpio_exp_c_5c 9 GPIO_ACTIVE_HIGH>;
++ POC2-gpios = <&gpio_exp_c_5c 10 GPIO_ACTIVE_HIGH>;
++ POC3-gpios = <&gpio_exp_c_5c 11 GPIO_ACTIVE_HIGH>;
++
++ port@0 {
++ ti9x4_des2ep0: endpoint@0 {
++ ti9x3-addr = <0x0c>;
++ dvp-order = <0>;
++ remote-endpoint = <&ov106xx_in8>;
++ };
++ ti9x4_des2ep1: endpoint@1 {
++ ti9x3-addr = <0x0d>;
++ dvp-order = <0>;
++ remote-endpoint = <&ov106xx_in9>;
++ };
++ ti9x4_des2ep2: endpoint@2 {
++ ti9x3-addr = <0x0e>;
++ dvp-order = <0>;
++ remote-endpoint = <&ov106xx_in10>;
++ };
++ ti9x4_des2ep3: endpoint@3 {
++ ti9x3-addr = <0x0f>;
++ dvp-order = <0>;
++ remote-endpoint = <&ov106xx_in11>;
++ };
++ };
++ port@1 {
++ ti9x4_csi1ep0: endpoint {
++ csi-rate = <1450>;
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ };
++
++ /* MAX9286 @ 0x2c */
++ max9286@2 {
++ compatible = "maxim,max9286";
++ reg = <0x2c>;
++ maxim,sensor_delay = <350>;
++ maxim,links = <4>;
++ maxim,lanes = <2>;
++ maxim,resetb-gpio = <1>;
++ maxim,fsync-mode = "automatic";
++ maxim,timeout = <100>;
++
++ POC0-gpios = <&gpio_exp_c_5c 9 GPIO_ACTIVE_HIGH>;
++ POC1-gpios = <&gpio_exp_c_5c 8 GPIO_ACTIVE_HIGH>;
++ POC2-gpios = <&gpio_exp_c_5c 11 GPIO_ACTIVE_HIGH>;
++ POC3-gpios = <&gpio_exp_c_5c 10 GPIO_ACTIVE_HIGH>;
++
++ port@0 {
++ max9286_des2ep0: endpoint@0 {
++ max9271-addr = <0x50>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in8>;
++ };
++ max9286_des2ep1: endpoint@1 {
++ max9271-addr = <0x51>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in9>;
++ };
++ max9286_des2ep2: endpoint@2 {
++ max9271-addr = <0x52>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in10>;
++ };
++ max9286_des2ep3: endpoint@3 {
++ max9271-addr = <0x53>;
++ dvp-order = <1>;
++ remote-endpoint = <&ov106xx_in11>;
++ };
++ };
++ port@1 {
++ max9286_csi1ep0: endpoint {
++ csi-rate = <700>;
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ };
++ };
++
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++ /* Slot C (CN12) */
++
++ /* PCA9535 is a redundand/deprecated card */
++ gpio_exp_c_27: gpio@27 {
++ compatible = "nxp,pca9535";
++ reg = <0x26>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_c_des_cfg1 {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg1";
++ };
++ video_c_des_cfg0 {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg0";
++ };
++ video_c_pwr_shdn {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR_SHDN";
++ };
++ video_c_cam_pwr0 {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR0";
++ };
++ video_c_cam_pwr1 {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR1";
++ };
++ video_c_cam_pwr2 {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR2";
++ };
++ video_c_cam_pwr3 {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR3";
++ };
++ video_c_des_shdn {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C DES_SHDN";
++ };
++ video_c_des_led {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-C led";
++ };
++ };
++
++ gpio_exp_c_5c: gpio@5c {
++ compatible = "maxim,max7325";
++ reg = <0x5c>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_c_des_cfg2 {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg2";
++ };
++ video_c_des_cfg1 {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg1";
++ };
++ video_c_des_cfg0 {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg0";
++ };
++ video_c_pwr_shdn {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR_SHDN";
++ };
++ video_c_des_shdn {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C DES_SHDN";
++ };
++ video_c_led {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-C LED";
++ };
++ };
++ };
++};
++
++&vin4 {
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin4ep0: endpoint {
++ csi,select = "csi20";
++ virtual,channel = <0>;
++ remote-endpoint = <&ov106xx_in8>;
++ data-lanes = <1 2>;
++ };
++ };
++ port@1 {
++ csi2ep0: endpoint {
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ port@2 {
++ vin4_max9286_des2ep0: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep0>;
++ };
++ vin4_ti9x4_des2ep0: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep0>;
++ };
++ };
++ };
++};
++
++&vin5 {
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin5ep0: endpoint@0 {
++ csi,select = "csi20";
++ virtual,channel = <1>;
++ remote-endpoint = <&ov106xx_in9>;
++ data-lanes = <1 2>;
++ };
++ };
++ port@1 {
++ csi2ep1: endpoint {
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ port@2 {
++ vin5_max9286_des2ep1: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep1>;
++ };
++ vin5_ti9x4_des2ep1: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep1>;
++ };
++ };
++ };
++};
++
++&vin6 {
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin6ep0: endpoint@0 {
++ csi,select = "csi20";
++ virtual,channel = <2>;
++ remote-endpoint = <&ov106xx_in10>;
++ data-lanes = <1 2>;
++ };
++ };
++ port@1 {
++ csi2ep2: endpoint {
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ port@2 {
++ vin6_max9286_des2ep2: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep2>;
++ };
++ vin6_ti9x4_des2ep2: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep2>;
++ };
++ };
++ };
++};
++
++&vin7 {
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin7ep0: endpoint@0 {
++ csi,select = "csi20";
++ virtual,channel = <3>;
++ remote-endpoint = <&ov106xx_in11>;
++ data-lanes = <1 2>;
++ };
++ };
++ port@1 {
++ csi2ep3: endpoint {
++ remote-endpoint = <&csi20_ep>;
++ };
++ };
++ port@2 {
++ vin7_max9286_des2ep3: endpoint@0 {
++ remote-endpoint = <&max9286_des2ep3>;
++ };
++ vin7_ti9x4_des2ep3: endpoint@1 {
++ remote-endpoint = <&ti9x4_des2ep3>;
++ };
++ };
++ };
++};
++
++&csi20 {
++ status = "okay";
++
++ virtual,channel {
++ csi2_vc0 {
++ data,type = "ycbcr422";
++ receive,vc = <0>;
++ };
++ csi2_vc1 {
++ data,type = "ycbcr422";
++ receive,vc = <1>;
++ };
++ csi2_vc2 {
++ data,type = "ycbcr422";
++ receive,vc = <2>;
++ };
++ csi2_vc3 {
++ data,type = "ycbcr422";
++ receive,vc = <3>;
++ };
++ };
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi20_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2>;
++ csi-rate = <300>;
++ };
++ };
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch
new file mode 100644
index 00000000..f96696d6
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0466-media-i2c-max9286-parse-crossbar-from-dt.patch
@@ -0,0 +1,58 @@
+From 0220ffebe645d66242aca68d7a374140dea9e6a3 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Jan 2020 16:38:19 +0300
+Subject: [PATCH] media: i2c: max9286: parse crossbar from dt
+
+This allows to parse crossbar from device tree
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9286.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index f6c6b0a..0a1732a 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -56,6 +56,7 @@ struct max9286_priv {
+ int dbl;
+ int dt;
+ int hsgen;
++ u64 crossbar;
+ char cb[16];
+ int hts;
+ int vts;
+@@ -141,8 +142,8 @@ static int switchin = 0;
+ module_param(switchin, int, 0644);
+ MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)");
+
+-static long crossbar = 0xba9876543210;
+-module_param(crossbar, long, 0644);
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
+ MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)");
+
+ enum {
+@@ -738,6 +739,8 @@ static int max9286_parse_dt(struct i2c_client *client)
+ priv->pclk = pclk;
+ if (of_property_read_u32(np, "maxim,switchin", &priv->switchin))
+ priv->switchin = 0;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
+
+ /* module params override dts */
+ if (him)
+@@ -773,8 +776,8 @@ static int max9286_parse_dt(struct i2c_client *client)
+
+ /* parse crossbar setup */
+ for (i = 0; i < 16; i++) {
+- priv->cb[i] = crossbar % 16;
+- crossbar /= 16;
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
+ }
+
+ for (i = 0; i < priv->links; i++) {
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch
new file mode 100644
index 00000000..359e1903
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0467-media-i2c-isx016-add-fixed-sensor.patch
@@ -0,0 +1,94 @@
+From 43b01937acf76c4d057fd6681ff66f945634f5c4 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Jan 2020 16:41:59 +0300
+Subject: [PATCH] media: i2c: isx016: add fixed sensor
+
+This add possibility to enable camera if the imager is not
+accessible in i2c line for ID detection
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/isx016.c | 41 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+diff --git a/drivers/media/i2c/soc_camera/isx016.c b/drivers/media/i2c/soc_camera/isx016.c
+index 9465c8f..a9f137c 100644
+--- a/drivers/media/i2c/soc_camera/isx016.c
++++ b/drivers/media/i2c/soc_camera/isx016.c
+@@ -51,8 +51,21 @@ struct isx016_priv {
+ int port;
+ int gpio_resetb;
+ int gpio_fsin;
++ int fixed_sensor;
+ };
+
++static int isx016_fixed = 0;
++module_param(isx016_fixed, int, 0644);
++MODULE_PARM_DESC(isx016_fixed, " isx016 fixed detect (0 - imager disabled)");
++
++static int isx016_width = ISX016_MAX_WIDTH;
++module_param(isx016_width, int, 0644);
++MODULE_PARM_DESC(isx016_width, " isx016 fixed width");
++
++static int isx016_height = ISX016_MAX_HEIGHT;
++module_param(isx016_height, int, 0644);
++MODULE_PARM_DESC(isx016_height, " isx016 fixed height");
++
+ static inline struct isx016_priv *to_isx016(const struct i2c_client *client)
+ {
+ return container_of(i2c_get_clientdata(client), struct isx016_priv, sd);
+@@ -371,9 +384,27 @@ static int isx016_initialize(struct i2c_client *client)
+ int ret = 0;
+ int tmp_addr;
+ int i;
++ u8 ser_pid = 0;
+
+ isx016_s_port(client, 1);
+
++ if (priv->fixed_sensor) {
++ tmp_addr = client->addr;
++ if (priv->max9286_addr) {
++ client->addr = priv->max9271_addr;
++ /* check serizlizer ID */
++ reg8_read(client, 0x1e, &ser_pid);
++ }
++ client->addr = tmp_addr;
++
++ if (ser_pid != MAX9271_ID && ser_pid != MAX96705_ID && ser_pid != MAX96707_ID) {
++ ret = -ENODEV;
++ goto err;
++ }
++
++ goto out;
++ }
++
+ for (i = 0; i < ARRAY_SIZE(isx016_i2c_addr); i++) {
+ tmp_addr = client->addr;
+ if (priv->max9286_addr) {
+@@ -409,6 +440,7 @@ static int isx016_initialize(struct i2c_client *client)
+ /* Program wizard registers */
+ isx016_set_regs(client, isx016_regs_wizard, ARRAY_SIZE(isx016_regs_wizard));
+
++out:
+ dev_info(&client->dev, "isx016 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ err:
+@@ -471,6 +503,15 @@ static int isx016_parse_dt(struct device_node *np, struct isx016_priv *priv)
+ }
+ client->addr = tmp_addr;
+
++ if (of_property_read_u32(np, "isx016,fixed", &priv->fixed_sensor))
++ priv->fixed_sensor = isx016_fixed;
++ if (priv->fixed_sensor) {
++ if (of_property_read_u32(np, "width", &priv->max_width))
++ priv->max_width = ISX016_MAX_WIDTH;
++ if (of_property_read_u32(np, "height", &priv->max_height))
++ priv->max_height = ISX016_MAX_HEIGHT;
++ }
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch
new file mode 100644
index 00000000..50658706
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0468-imx390-Read-1-byte-registers-by-default.patch
@@ -0,0 +1,37 @@
+From 0dc45a01a271f56aedeb7cfc72f8550243d0b3b0 Mon Sep 17 00:00:00 2001
+From: Petr Nechaev <petr.nechaev@cogentembedded.com>
+Date: Fri, 27 Dec 2019 22:07:20 +0300
+Subject: [PATCH] imx390: Read 1 byte registers by default
+
+This patch switches to 1-byte default register size for imx390 image sensor.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imx390.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c
+index c1e568055e54..9d970b16697d 100644
+--- a/drivers/media/i2c/soc_camera/imx390.c
++++ b/drivers/media/i2c/soc_camera/imx390.c
+@@ -217,7 +217,7 @@ static int imx390_g_register(struct v4l2_subdev *sd,
+ int ret;
+
+ if (!s)
+- s = 4;
++ s = 1;
+ if (s > sizeof(reg->val))
+ s = sizeof(reg->val);
+
+@@ -235,7 +235,7 @@ static int imx390_s_register(struct v4l2_subdev *sd,
+ u32 s = reg->size;
+
+ if (!s)
+- s = 4;
++ s = 1;
+ if (s > sizeof(reg->val))
+ s = sizeof(reg->val);
+
+--
+2.20.1
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch
new file mode 100644
index 00000000..506ff276
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch
@@ -0,0 +1,67 @@
+From bfdc3bf828002a0550b8183a67879fc3a9246795 Mon Sep 17 00:00:00 2001
+From: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Date: Thu, 6 Feb 2020 23:13:19 +0300
+Subject: [PATCH] rcar_canfd: fix one more interrupt storm window
+
+When more than one rcar_canfd channel works simultaneously, same irq and
+same irq handler, rcar_canfd_global_interrupt(), is shared between them
+all. Entry into this handler while Rx interrupt for one channel is masked
+per NAPI, becomes a very frequent event.
+
+Code makes an attempt to alter interrupt mask only when NAPI suggests to
+do so. However that code is racy, and with frequent call to handler with
+masked interrupt, this race actually happens.
+
+The race window is:
+- after code in napi_complete_done() clears NAPIF_STATE_SCHED flag inside
+ NAPI state, but before napi_complete_done() returns true, side-called
+ interrupt handler detects pending (although masked) Rx, calls
+ napi_schedule_prep(), and NAPIF_STATE_SCHED flag is re-set,
+- then napi_complete_done() returns true and Rx interrupt gets unmasked,
+- then unmasked interrupt fires, but this time NAPIF_STATE_SCHED flag
+ is already set, so napi_schedule_prep() returns false,
+- which causes return from interrupt handler without touching interrupt,
+ and IRQ storm is entered.
+
+To fix it, active Rx interrupt must be UNCONDITIONALLY masked inside the
+handler. Failing to mask active interrupt immediately results into IRQ
+storm, regardless of NAPI state or whatever other conditions.
+
+Once napi_schedule_prep() is called after this unconditional masking, future
+call to NAPI poller and evential interrupt unmask is guaranteed.
+
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+---
+ drivers/net/can/rcar/rcar_canfd.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
+index 0017ab9..056a5f6 100644
+--- a/drivers/net/can/rcar/rcar_canfd.c
++++ b/drivers/net/can/rcar/rcar_canfd.c
+@@ -1101,13 +1101,16 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
+ /* Handle Rx interrupts */
+ sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx));
+ if (likely(sts & RCANFD_RFSTS_RFIF)) {
+- if (napi_schedule_prep(&priv->napi)) {
+- /* Disable Rx FIFO interrupts */
+- rcar_canfd_clear_bit(priv->base,
+- RCANFD_RFCC(ridx),
+- RCANFD_RFCC_RFIE);
++ /* If Rx FIFO interrupt is there, it must be masked
++ * UNCONDITIONALLY, otherwise IRQ storm will start */
++ rcar_canfd_clear_bit(priv->base,
++ RCANFD_RFCC(ridx),
++ RCANFD_RFCC_RFIE);
++ /* The above calls ensure that napi polling will be
++ * called sometime AFTER the above call, which
++ * eventually ensures interrupt re-enable */
++ if (napi_schedule_prep(&priv->napi))
+ __napi_schedule(&priv->napi);
+- }
+ }
+ }
+ return IRQ_HANDLED;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch
new file mode 100644
index 00000000..70fac592
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0470-media-i2c-add-fps-setup.patch
@@ -0,0 +1,429 @@
+From 07c0308d3c5991ff67c32329d56f14e375e3e981 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 10 Feb 2020 18:46:46 +0300
+Subject: [PATCH] media: i2c: add fps setup
+
+This adds FPS setup for max9286/ti9x4 with ar0143/147 imagers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0143.c | 66 ++++++++++++++++++++++++++++++++--
+ drivers/media/i2c/soc_camera/ar0147.c | 64 +++++++++++++++++++++++++++++++--
+ drivers/media/i2c/soc_camera/max9286.c | 42 ++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ti9x4.c | 54 ++++++++++++++++++++++++----
+ 4 files changed, 215 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c
+index d81871b..de4ca3c 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.c
++++ b/drivers/media/i2c/soc_camera/ar0143.c
+@@ -35,6 +35,8 @@ struct ar0143_priv {
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct v4l2_rect rect;
++ int fps_numerator;
++ int fps_denominator;
+ int init_complete;
+ u8 id[6];
+ int setup;
+@@ -297,6 +299,61 @@ static int ar0143_g_mbus_config(struct v4l2_subdev *sd,
+ return 0;
+ }
+
++static int ar0143_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0143_priv *priv = to_ar0143(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0143_priv *priv = to_ar0143(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0;
++ int tmp_addr;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ if (priv->ti9x4_addr)
++ priv->vts = (AR0143_SENSOR_HEIGHT + 157) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++ else
++ priv->vts = (AR0143_SENSOR_HEIGHT + 142) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++
++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */
++
++ tmp_addr = client->addr;
++ if (priv->max9271_addr) {
++ client->addr = priv->max9271_addr; /* Serializer I2C address */
++ reg8_write(client, 0x58, priv->vts >> 8); /* HS count */
++ reg8_write(client, 0x59, priv->vts & 0xff);
++ }
++ client->addr = tmp_addr;
++
++ priv->fps_denominator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++out:
++ return ret;
++}
++
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0143_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -361,7 +418,8 @@ static int ar0143_s_ctrl(struct v4l2_ctrl *ctrl)
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* T1 exposure */
+- ret = reg16_write16(client, 0x3012, ctrl->val);
++ if (ctrl->val < 0x400 * 30 * priv->fps_numerator / priv->fps_denominator)
++ ret = reg16_write16(client, 0x3012, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = reg16_read16(client, 0x3040, &val);
+@@ -394,6 +452,8 @@ static const struct v4l2_ctrl_ops ar0143_ctrl_ops = {
+ static struct v4l2_subdev_video_ops ar0143_video_ops = {
+ .s_stream = ar0143_s_stream,
+ .g_mbus_config = ar0143_g_mbus_config,
++ .g_parm = ar0143_g_parm,
++ .s_parm = ar0143_s_parm,
+ };
+
+ static const struct v4l2_subdev_pad_ops ar0143_subdev_pad_ops = {
+@@ -617,6 +677,8 @@ static int ar0143_probe(struct i2c_client *client,
+
+ v4l2_i2c_subdev_init(&priv->sd, client, &ar0143_subdev_ops);
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops,
+@@ -638,7 +700,7 @@ static int ar0143_probe(struct i2c_client *client,
+ v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0x7);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops,
+- V4L2_CID_EXPOSURE, 1, 0x400, 1, 0x300);
++ V4L2_CID_EXPOSURE, 1, 0x400 * 30, 1, 0x300);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0143_ctrl_ops,
+diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c
+index fc2a09e..e3ecec2 100644
+--- a/drivers/media/i2c/soc_camera/ar0147.c
++++ b/drivers/media/i2c/soc_camera/ar0147.c
+@@ -36,6 +36,8 @@ struct ar0147_priv {
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct v4l2_rect rect;
++ int fps_denominator;
++ int fps_numerator;
+ int init_complete;
+ u8 id[6];
+ /* serializers */
+@@ -146,7 +148,7 @@ static int ar0147_set_regs(struct i2c_client *client, const struct ar0147_reg **
+ reg16_write16(client, regs[i].reg, 1); // OP_SYS_CLK_DIV
+ continue;
+ case 0x300A:
+- reg16_write16(client, regs[i].reg, AR0147_SENSOR_HEIGHT + 142); // FRAME_LENGTH_LINES_
++ reg16_write16(client, regs[i].reg, AR0147_SENSOR_HEIGHT + 226); // FRAME_LENGTH_LINES_
+ continue;
+ }
+ }
+@@ -317,6 +319,57 @@ static int ar0147_g_mbus_config(struct v4l2_subdev *sd,
+ return 0;
+ }
+
++static int ar0147_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0147_priv *priv = to_ar0147(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0147_priv *priv = to_ar0147(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0;
++ int tmp_addr;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ priv->vts = (AR0147_SENSOR_HEIGHT + 226) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++
++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */
++
++ tmp_addr = client->addr;
++ if (priv->max9271_addr) {
++ client->addr = priv->max9271_addr; /* Serializer I2C address */
++ reg8_write(client, 0x58, priv->vts >> 8); /* HS count */
++ reg8_write(client, 0x59, priv->vts & 0xff);
++ }
++ client->addr = tmp_addr;
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++out:
++ return ret;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0147_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -381,7 +434,8 @@ static int ar0147_s_ctrl(struct v4l2_ctrl *ctrl)
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* T1 exposure */
+- ret = reg16_write16(client, 0x3012, ctrl->val);
++ if (ctrl->val < 0x400 * 30 * priv->fps_numerator / priv->fps_denominator)
++ ret = reg16_write16(client, 0x3012, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = reg16_read16(client, 0x3040, &val);
+@@ -414,6 +468,8 @@ static const struct v4l2_ctrl_ops ar0147_ctrl_ops = {
+ static struct v4l2_subdev_video_ops ar0147_video_ops = {
+ .s_stream = ar0147_s_stream,
+ .g_mbus_config = ar0147_g_mbus_config,
++ .g_parm = ar0147_g_parm,
++ .s_parm = ar0147_s_parm,
+ };
+
+ static const struct v4l2_subdev_pad_ops ar0147_subdev_pad_ops = {
+@@ -648,6 +704,8 @@ static int ar0147_probe(struct i2c_client *client,
+
+ v4l2_i2c_subdev_init(&priv->sd, client, &ar0147_subdev_ops);
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops,
+@@ -669,7 +727,7 @@ static int ar0147_probe(struct i2c_client *client,
+ v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0x7);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops,
+- V4L2_CID_EXPOSURE, 1, 0x400, 1, 0x300);
++ V4L2_CID_EXPOSURE, 1, 0x400 * 30, 1, 0x300);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0147_ctrl_ops,
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index 0a1732a..343b8ab 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -43,6 +43,8 @@ struct max9286_priv {
+ int csi_rate;
+ const char *fsync_mode;
+ int fsync_period;
++ int fps_numerator;
++ int fps_denominator;
+ int pclk;
+ char pclk_rising_edge;
+ int gpio_resetb;
+@@ -650,8 +652,46 @@ static struct v4l2_subdev_core_ops max9286_subdev_core_ops = {
+ .registered_async = max9286_registered_async,
+ };
+
++static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ return 0;
++}
++
++static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ int f_period;
++
++ f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++ reg8_write(client, 0x06, f_period & 0xff);
++ reg8_write(client, 0x07, (f_period >> 8) & 0xff);
++ reg8_write(client, 0x08, f_period >> 16);
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return 0;
++}
++
++static struct v4l2_subdev_video_ops max9286_video_ops = {
++ .g_parm = max9286_g_parm,
++ .s_parm = max9286_s_parm,
++};
++
+ static struct v4l2_subdev_ops max9286_subdev_ops = {
+ .core = &max9286_subdev_core_ops,
++ .video = &max9286_video_ops,
+ };
+
+ static int max9286_parse_dt(struct i2c_client *client)
+@@ -926,6 +966,8 @@ static int max9286_probe(struct i2c_client *client,
+ priv->client = client;
+ atomic_set(&priv->use_count, 0);
+ priv->csi2_outord = 0xff;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ err = max9286_parse_dt(client);
+ if (err)
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+index aa85d92..b671736 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -32,6 +32,9 @@ struct ti9x4_priv {
+ int lanes;
+ int csi_rate;
+ const char *forwarding_mode;
++ int fs_time;
++ int fps_numerator;
++ int fps_denominator;
+ int is_coax;
+ int dvp_bus;
+ int dvp_lsb;
+@@ -139,7 +142,6 @@ static void ti9x4_read_chipid(struct i2c_client *client)
+ static void ti9x4_initial_setup(struct i2c_client *client)
+ {
+ struct ti9x4_priv *priv = i2c_get_clientdata(client);
+- int fs_time = 0;
+
+ /* Initial setup */
+ client->addr = priv->des_addr; /* TI9x4 I2C */
+@@ -175,20 +177,21 @@ static void ti9x4_initial_setup(struct i2c_client *client)
+ case 800:
+ case 400:
+ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */
+- fs_time = 2790;
++ priv->fs_time = 2790;
+ break;
+ case 1500:
+ /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */
+- fs_time = 2570;
++ priv->fs_time = 2570;
+ break;
+ case 1450:
+ case 1100:
+ case 700:
+ case 350:
+ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */
+- fs_time = 2513;
++ priv->fs_time = 2513;
+ break;
+ default:
++ priv->fs_time = 0;
+ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
+ }
+
+@@ -213,8 +216,8 @@ static void ti9x4_initial_setup(struct i2c_client *client)
+ #else
+ reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */
+ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */
+- reg8_write(client, 0x1b, fs_time >> 8); /* FrameSync low time MSB */
+- reg8_write(client, 0x1c, fs_time & 0xff); /* FrameSync low time LSB */
++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
++ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */
+ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
+ // reg8_write(client, 0x18, 0x80); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
+ #endif
+@@ -425,8 +428,45 @@ static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = {
+ .registered_async = ti9x4_registered_async,
+ };
+
++static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ return 0;
++}
++
++static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ int f_time;
++
++ f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++ reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */
++ reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */
++
++ priv->fps_denominator = cp->timeperframe.denominator;
++ priv->fps_numerator = cp->timeperframe.numerator;
++ }
++
++ return 0;
++}
++
++static struct v4l2_subdev_video_ops ti9x4_video_ops = {
++ .g_parm = ti9x4_g_parm,
++ .s_parm = ti9x4_s_parm,
++};
++
+ static struct v4l2_subdev_ops ti9x4_subdev_ops = {
+ .core = &ti9x4_subdev_core_ops,
++ .video = &ti9x4_video_ops,
+ };
+
+ static int ti9x4_parse_dt(struct i2c_client *client)
+@@ -607,6 +647,8 @@ static int ti9x4_probe(struct i2c_client *client,
+ priv->des_addr = client->addr;
+ priv->client = client;
+ atomic_set(&priv->use_count, 0);
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ err = ti9x4_parse_dt(client);
+ if (err)
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch
new file mode 100644
index 00000000..cf009e51
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0471-media-i2c-ov10640-add-fps-setup.patch
@@ -0,0 +1,104 @@
+From 969dff5e0dbd9ad6b289073410dbd3013ccd5e31 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 10 Feb 2020 21:09:29 +0300
+Subject: [PATCH] media: i2c: ov10640: add fps setup
+
+This adds framerate change support for OV10640 imager
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 50 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index fab2c0d..0af091e 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -38,6 +38,7 @@ struct ov10640_priv {
+ struct media_pad pad;
+ struct v4l2_rect rect;
+ int subsampling;
++ int fps_numerator;
+ int fps_denominator;
+ int init_complete;
+ u8 id[6];
+@@ -51,6 +52,7 @@ struct ov10640_priv {
+ int port;
+ int gpio_resetb;
+ int gpio_fsin;
++ int vts;
+ };
+
+ static inline struct ov10640_priv *to_ov10640(const struct i2c_client *client)
+@@ -276,6 +278,51 @@ static int ov10640_g_mbus_config(struct v4l2_subdev *sd,
+ return 0;
+ }
+
++static int ov10640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int ov10640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ priv->vts = (OV10640_SENSOR_HEIGHT + 208) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++
++ reg16_write(client, 0x3012, 0);
++ reg16_write(client, 0x3082, priv->vts >> 8);
++ reg16_write(client, 0x3083, priv->vts & 0xff);
++ ret = reg16_write(client, 0x3012, 1);
++
++ priv->fps_denominator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return ret;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ov10640_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -417,6 +464,8 @@ static const struct v4l2_ctrl_ops ov10640_ctrl_ops = {
+ static struct v4l2_subdev_video_ops ov10640_video_ops = {
+ .s_stream = ov10640_s_stream,
+ .g_mbus_config = ov10640_g_mbus_config,
++ .g_parm = ov10640_g_parm,
++ .s_parm = ov10640_s_parm,
+ };
+
+ static const struct v4l2_subdev_pad_ops ov10640_subdev_pad_ops = {
+@@ -643,6 +692,7 @@ static int ov10640_probe(struct i2c_client *client,
+ priv->rect.top = 0;
+ priv->rect.width = OV10640_DEFAULT_WIDTH;
+ priv->rect.height = OV10640_DEFAULT_HEIGHT;
++ priv->fps_numerator = 1;
+ priv->fps_denominator = 30;
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch
new file mode 100644
index 00000000..396c78f8
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0472-media-i2c-soc_camera-fix-compilation-warnings.patch
@@ -0,0 +1,70 @@
+From 088954dd3b295ef6401f58e694456c782e57ef39 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 10 Feb 2020 21:10:06 +0300
+Subject: [PATCH] media: i2c: soc_camera: fix compilation warnings
+
+Fix compilation warnings
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0143.c | 2 +-
+ drivers/media/i2c/soc_camera/ar0147.c | 2 +-
+ drivers/media/i2c/soc_camera/ov106xx.c | 3 +++
+ drivers/media/i2c/soc_camera/ox01d10.c | 1 -
+ 4 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c
+index de4ca3c..7d55afb 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.c
++++ b/drivers/media/i2c/soc_camera/ar0143.c
+@@ -349,7 +349,7 @@ static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+ priv->fps_denominator = cp->timeperframe.numerator;
+ priv->fps_denominator = cp->timeperframe.denominator;
+ }
+-out:
++
+ return ret;
+ }
+
+diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c
+index e3ecec2..a444700 100644
+--- a/drivers/media/i2c/soc_camera/ar0147.c
++++ b/drivers/media/i2c/soc_camera/ar0147.c
+@@ -366,7 +366,7 @@ static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+ priv->fps_numerator = cp->timeperframe.numerator;
+ priv->fps_denominator = cp->timeperframe.denominator;
+ }
+-out:
++
+ return ret;
+ }
+
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index 841861c..cf97f28 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -243,6 +243,9 @@ static int ov106xx_remove(struct i2c_client *client)
+ case ID_IMX390:
+ imx390_remove(client);
+ break;
++ case ID_OX01D10:
++ ox01d10_remove(client);
++ break;
+ case ID_OX03A:
+ ox03a_remove(client);
+ break;
+diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c
+index 3ea3fef..082e88c 100644
+--- a/drivers/media/i2c/soc_camera/ox01d10.c
++++ b/drivers/media/i2c/soc_camera/ox01d10.c
+@@ -388,7 +388,6 @@ static DEVICE_ATTR(otp_id_ox01d10, S_IRUGO, ox01d10_otp_id_show, NULL);
+ static int ox01d10_initialize(struct i2c_client *client)
+ {
+ struct ox01d10_priv *priv = to_ox01d10(client);
+- char chip_name[10] = "unknown";
+ u8 val = 0;
+ u16 pid;
+ int ret = 0;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch
new file mode 100644
index 00000000..c00fef19
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0473-media-i2c-ov10640-add-different-imager-addresses.patch
@@ -0,0 +1,96 @@
+From 304be73e907a8c63d774f32358a7087a8b76657a Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 10 Feb 2020 23:41:22 +0300
+Subject: [PATCH] media: i2c: ov10640: add different imager addresses
+
+This adds different i2c imager addresses
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 39 ++++++++++++++++++++++++----------
+ 1 file changed, 28 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index 0af091e..f5f0fdd 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -23,7 +23,7 @@
+ #include "max9286.h"
+ #include "ov10640.h"
+
+-#define OV10640_I2C_ADDR 0x30
++static const int ov10640_i2c_addr[] = {0x30, 0x34, 0x36};
+
+ #define OV10640_PIDA_REG 0x300a
+ #define OV10640_PIDB_REG 0x300b
+@@ -566,16 +566,33 @@ static int ov10640_initialize(struct i2c_client *client)
+ u16 pid;
+ u8 val = 0, rev;
+ int ret = 0;
++ int tmp_addr, i;
+
+ ov10640_s_port(client, 1);
+
+- /* check and show product ID and manufacturer ID */
+- reg16_read(client, OV10640_PIDA_REG, &val);
+- pid = val;
+- reg16_read(client, OV10640_PIDB_REG, &val);
+- pid = (pid << 8) | val;
+- reg16_read(client, OV10640_REV_REG, &val);
+- rev = 0x10 | ((val & 0xf) + 0xa);
++ for (i = 0; i < ARRAY_SIZE(ov10640_i2c_addr); i++) {
++ tmp_addr = client->addr;
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x4_addr;
++ reg8_write(client, 0x5d, ov10640_i2c_addr[i] << 1); /* Sensor native I2C address */
++ usleep_range(2000, 2500);
++ }
++ if (priv->max9286_addr) {
++ client->addr = priv->max9271_addr;
++ reg8_write(client, 0x0a, ov10640_i2c_addr[i] << 1); /* Sensor native I2C address */
++ usleep_range(2000, 2500);
++ };
++ client->addr = tmp_addr;
++
++ /* check product ID */
++ reg16_read(client, OV10640_PIDA_REG, &val);
++ pid = val;
++ reg16_read(client, OV10640_PIDB_REG, &val);
++ pid = (pid << 8) | val;
++
++ if (pid == OV10640_PID)
++ break;
++ }
+
+ if (pid != OV10640_PID) {
+ dev_dbg(&client->dev, "Product ID error %x\n", pid);
+@@ -583,6 +600,9 @@ static int ov10640_initialize(struct i2c_client *client)
+ goto out;
+ }
+
++ /* check revision */
++ reg16_read(client, OV10640_REV_REG, &val);
++ rev = 0x10 | ((val & 0xf) + 0xa);
+ /* Read OTP IDs */
+ ov10640_otp_id_read(client);
+ /* Program wizard registers */
+@@ -655,16 +675,13 @@ static int ov10640_parse_dt(struct device_node *np, struct ov10640_priv *priv)
+ if (priv->max9286_addr) {
+ client->addr = priv->max9271_addr; /* Serializer I2C address */
+ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */
+- reg8_write(client, 0x0A, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */
+ usleep_range(2000, 2500); /* wait 2ms */
+ };
+-
+ if (priv->ti9x4_addr) {
+ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */
+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
+ usleep_range(2000, 2500); /* wait 2ms */
+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
+- reg8_write(client, 0x5d, OV10640_I2C_ADDR << 1); /* Sensor native I2C address */
+ }
+ client->addr = tmp_addr;
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch
new file mode 100644
index 00000000..c15a1f8a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch
@@ -0,0 +1,82 @@
+From 6c0c041b3bbfec436e96fe09fdbf5072688b7ad2 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 12 Feb 2020 01:24:14 +0300
+Subject: [PATCH] media: i2c: soc_camera: add V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+
+Add V4L2_CID_MIN_BUFFERS_FOR_CAPTURE for isx016 and ap0101
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ap0101_ar014x.c | 8 ++++++++
+ drivers/media/i2c/soc_camera/isx016.c | 8 ++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+index 4df5793..c458044 100644
+--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+@@ -347,6 +347,9 @@ static int ap0101_s_ctrl(struct v4l2_ctrl *ctrl)
+ reg16_write16(client, 0xfc00, 0x2800);
+ ret = reg16_write16(client, 0x0040, 0x8100);
+ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
+ }
+
+ return ret;
+@@ -552,6 +555,7 @@ static int ap0101_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+ {
+ struct ap0101_priv *priv;
++ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+@@ -587,6 +591,10 @@ static int ap0101_probe(struct i2c_client *client,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 1);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+ priv->sd.ctrl_handler = &priv->hdl;
+
+ ret = priv->hdl.error;
+diff --git a/drivers/media/i2c/soc_camera/isx016.c b/drivers/media/i2c/soc_camera/isx016.c
+index a9f137c..3001df9 100644
+--- a/drivers/media/i2c/soc_camera/isx016.c
++++ b/drivers/media/i2c/soc_camera/isx016.c
+@@ -319,6 +319,9 @@ static int isx016_s_ctrl(struct v4l2_ctrl *ctrl)
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
+ }
+
+ return ret;
+@@ -519,6 +522,7 @@ static int isx016_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+ {
+ struct isx016_priv *priv;
++ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+@@ -554,6 +558,10 @@ static int isx016_probe(struct i2c_client *client,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&priv->hdl, &isx016_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+ priv->sd.ctrl_handler = &priv->hdl;
+
+ ret = priv->hdl.error;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch
new file mode 100644
index 00000000..de7ca72a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0475-media-i2c-ar0233-add-fps-setup.patch
@@ -0,0 +1,127 @@
+From ec6c2c03f8c59cada4f8b0409b51534c54da282a Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 13 Feb 2020 10:02:20 +0300
+Subject: [PATCH] media: i2c: ar0233: add fps setup
+
+This add FPS setup for AR0233/AR0220
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0233.c | 59 +++++++++++++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index cdd2d8a..fbff49b 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -55,6 +55,8 @@ struct ar0233_priv {
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct v4l2_rect rect;
++ int fps_denominator;
++ int fps_numerator;
+ int init_complete;
+ u8 id[6];
+ bool emb_enable;
+@@ -63,6 +65,7 @@ struct ar0233_priv {
+ int ti9x3_addr;
+ int port;
+ int trigger;
++ int vts;
+ };
+
+ static int extclk = 23;
+@@ -271,6 +274,53 @@ static int ar0233_g_mbus_config(struct v4l2_subdev *sd,
+ return 0;
+ }
+
++static int ar0233_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0233_priv *priv = to_ar0233(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int ar0233_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0233_priv *priv = to_ar0233(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ switch (chipid) {
++ case AR0220_PID:
++ priv->vts = (AR0233_SENSOR_HEIGHT + 794) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; break;
++ case AR0233_PID:
++ priv->vts = (AR0233_SENSOR_HEIGHT + 100) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator; break;
++ };
++
++ ret = reg16_write16(client, 0x300A, priv->vts); /* FRAME_LENGTH_LINES_ */
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return ret;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0233_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -335,7 +385,8 @@ static int ar0233_s_ctrl(struct v4l2_ctrl *ctrl)
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* T1 exposure */
+- ret = reg16_write16(client, 0x3012, ctrl->val);
++ if (ctrl->val < 0x600 * 30 * priv->fps_numerator / priv->fps_denominator)
++ ret = reg16_write16(client, 0x3012, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = reg16_read16(client, 0x3040, &val);
+@@ -374,6 +425,8 @@ static const struct v4l2_ctrl_ops ar0233_ctrl_ops = {
+ static struct v4l2_subdev_video_ops ar0233_video_ops = {
+ .s_stream = ar0233_s_stream,
+ .g_mbus_config = ar0233_g_mbus_config,
++ .g_parm = ar0233_g_parm,
++ .s_parm = ar0233_s_parm,
+ };
+
+ static const struct v4l2_subdev_pad_ops ar0233_subdev_pad_ops = {
+@@ -654,6 +707,8 @@ static int ar0233_probe(struct i2c_client *client,
+
+ v4l2_i2c_subdev_init(&priv->sd, client, &ar0233_subdev_ops);
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops,
+@@ -675,7 +730,7 @@ static int ar0233_probe(struct i2c_client *client,
+ v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops,
+- V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144);
++ V4L2_CID_EXPOSURE, 1, 0x600 * 30, 1, 0x144);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&priv->hdl, &ar0233_ctrl_ops,
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch
new file mode 100644
index 00000000..792ddbdc
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0476-media-i2c-imx390-add-fps-setup.patch
@@ -0,0 +1,158 @@
+From a58b6fe91b46f2e06ad59e80768d5bf548d0b539 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 13 Feb 2020 16:47:36 +0300
+Subject: [PATCH] media: i2c: imx390: add fps setup
+
+This adds FPS setup support on IMX390 imager
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imx390.c | 69 +++++++++++++++++++++++++++++++++--
+ drivers/media/i2c/soc_camera/imx390.h | 9 +++--
+ 2 files changed, 72 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imx390.c b/drivers/media/i2c/soc_camera/imx390.c
+index 9d970b1..4f3d730 100644
+--- a/drivers/media/i2c/soc_camera/imx390.c
++++ b/drivers/media/i2c/soc_camera/imx390.c
+@@ -35,6 +35,8 @@ struct imx390_priv {
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct v4l2_rect rect;
++ int fps_denominator;
++ int fps_numerator;
+ int init_complete;
+ u8 id[6];
+ int exposure;
+@@ -46,6 +48,7 @@ struct imx390_priv {
+ int port;
+ int gpio_resetb;
+ int gpio_fsin;
++ int vts;
+ };
+
+ static inline struct imx390_priv *to_imx390(const struct i2c_client *client)
+@@ -208,6 +211,62 @@ static int imx390_g_mbus_config(struct v4l2_subdev *sd,
+ return 0;
+ }
+
++static int imx390_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int imx390_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0, timeout;
++ u8 val;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ priv->vts = (IMX390_SENSOR_HEIGHT + 29) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++
++ reg16_write(client, 0x0, 1);
++ for (timeout = 100; timeout > 0; timeout--) {
++ reg16_read(client, 0x5001, &val);
++ if (val == 1)
++ break;
++ mdelay(1);
++ }
++ if (!timeout)
++ dev_err(&client->dev, "timeout enter standby\n");
++
++ reg16_write(client, 0x2008, priv->vts & 0xff);
++ reg16_write(client, 0x2009, (priv->vts >> 8) & 0xff);
++ reg16_write(client, 0x200A, priv->vts >> 16);
++ ret = reg16_write(client, 0x0, 0);
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return ret;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int imx390_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -299,9 +358,9 @@ static int imx390_s_ctrl(struct v4l2_ctrl *ctrl)
+ break;
+ case V4L2_CID_EXPOSURE:
+ val = 0xfff - ctrl->val;
+- ret = reg16_write(client, 0x0c, val); /* LSB */
+- ret |= reg16_write(client, 0x0d, val >> 8);
+-// ret |= reg16_write(client, 0x0e, ctrl->val >> 16); /* MSB */
++ reg16_write(client, 0x0c, val); /* LSB */
++ reg16_write(client, 0x0d, val >> 8);
++ ret = reg16_write(client, 0x0e, val >> 16); /* MSB */
+ break;
+ case V4L2_CID_HFLIP:
+ /* hflip */
+@@ -349,6 +408,8 @@ static const struct v4l2_ctrl_ops imx390_ctrl_ops = {
+ static struct v4l2_subdev_video_ops imx390_video_ops = {
+ .s_stream = imx390_s_stream,
+ .g_mbus_config = imx390_g_mbus_config,
++ .g_parm = imx390_g_parm,
++ .s_parm = imx390_s_parm,
+ };
+
+ static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = {
+@@ -509,6 +570,8 @@ static int imx390_probe(struct i2c_client *client,
+
+ v4l2_i2c_subdev_init(&priv->sd, client, &imx390_subdev_ops);
+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
+
+ priv->exposure = 0x100;
+ priv->gain = 0;
+diff --git a/drivers/media/i2c/soc_camera/imx390.h b/drivers/media/i2c/soc_camera/imx390.h
+index efd75a7..e9d9808 100644
+--- a/drivers/media/i2c/soc_camera/imx390.h
++++ b/drivers/media/i2c/soc_camera/imx390.h
+@@ -14,6 +14,9 @@
+ #define IMX390_MAX_WIDTH 1920
+ #define IMX390_MAX_HEIGHT 1080
+
++#define IMX390_SENSOR_WIDTH 1936
++#define IMX390_SENSOR_HEIGHT 1096
++
+ #define IMX390_DELAY 0xffff
+ #define IMX390_DT 0x2c /* MIPI Data Type RAW12 */
+
+@@ -244,9 +247,9 @@ static const struct imx390_reg imx390_regs_wizard[] = {
+ {0x2002, 0x55},
+ {0x2003, 0x05},
+ {0x2004, 0x02},
+-{0x2008, 0x65},
+-{0x2009, 0x04},
+-{0x200A, 0x00},
++{0x2008, (IMX390_SENSOR_HEIGHT + 29) & 0xff},
++{0x2009, ((IMX390_SENSOR_HEIGHT + 29) >> 8) & 0xff},
++{0x200A, (IMX390_SENSOR_HEIGHT + 29) >> 16},
+ {0x200C, 0x30},
+ {0x200D, 0x11},
+ {0x2010, 0x04},
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch
new file mode 100644
index 00000000..c6096a94
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0477-media-i2c-ar0231-fix-FSIN-pin-input.patch
@@ -0,0 +1,54 @@
+From 466e494ad2496bc1ec16a56425efef8023d5520d Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 14 Feb 2020 18:28:21 +0300
+Subject: [PATCH] media: i2c: ar0231: fix FSIN pin input
+
+This fixes lost FSIN gpio pin enablement on AR0231.
+Also explicitly enable gpi pins on ar0143/140
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ar0140.c | 1 +
+ drivers/media/i2c/soc_camera/ar0143.c | 1 +
+ drivers/media/i2c/soc_camera/ar0231.c | 1 +
+ 3 files changed, 3 insertions(+)
+
+diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c
+index ceb2c31..bb7a3ce 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.c
++++ b/drivers/media/i2c/soc_camera/ar0140.c
+@@ -495,6 +495,7 @@ static int ar0140_initialize(struct i2c_client *client)
+ ar0140_set_regs(client, ar0140_regs_wizard, ARRAY_SIZE(ar0140_regs_wizard));
+ /* Enable stream */
+ reg16_read16(client, 0x301a, &val); // read inital reset_register value
++ val |= (1 << 8); /* GPI pins enable */
+ val |= (1 << 2); // Set streamOn bit
+ reg16_write16(client, 0x301a, val); // Start Streaming
+
+diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c
+index 7d55afb..07cc445 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.c
++++ b/drivers/media/i2c/soc_camera/ar0143.c
+@@ -584,6 +584,7 @@ static int ar0143_initialize(struct i2c_client *client)
+
+ /* Enable stream */
+ reg16_read16(client, 0x301a, &val);
++ val |= (1 << 8); /* GPI pins enable */
+ val |= (1 << 2);
+ reg16_write16(client, 0x301a, val);
+
+diff --git a/drivers/media/i2c/soc_camera/ar0231.c b/drivers/media/i2c/soc_camera/ar0231.c
+index c51ae9ad..6c450f7 100644
+--- a/drivers/media/i2c/soc_camera/ar0231.c
++++ b/drivers/media/i2c/soc_camera/ar0231.c
+@@ -455,6 +455,7 @@ static int ar0231_initialize(struct i2c_client *client)
+
+ /* Enable stream */
+ reg16_read16(client, 0x301a, &val);
++ val |= (1 << 8); /* GPI pins enable */
+ val |= (1 << 2);
+ reg16_write16(client, 0x301a, val);
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch
new file mode 100644
index 00000000..3e7b9dd4
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0478-media-i2c-ti9x4-fix-framesync.patch
@@ -0,0 +1,40 @@
+From 08a1910dd33fa0b5628d641854db8fb3200272f6 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 19 Feb 2020 01:49:42 +0300
+Subject: [PATCH] media: i2c: ti9x4: fix framesync
+
+This fixes frames syncronization.
+Cameras must start (fsinc start) simultaneously, hence enable
+framesync when all cameras are set up
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ti9x4.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+index b671736..9004bb1 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -218,8 +218,7 @@ static void ti9x4_initial_setup(struct i2c_client *client)
+ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */
+ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
+ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */
+- reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
+-// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
++ reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */
+ #endif
+ }
+
+@@ -415,6 +414,8 @@ static int ti9x4_registered_async(struct v4l2_subdev *sd)
+ struct i2c_client *client = priv->client;
+
+ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */
++ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
++// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */
+
+ return 0;
+ }
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch
new file mode 100644
index 00000000..960da094
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0479-media-soc_camera-rcar_csi2-add-interrupts.patch
@@ -0,0 +1,150 @@
+From 0812102bc301699c607229cb86b2bc8d385aef2f Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 19 Feb 2020 02:26:11 +0300
+Subject: [PATCH] media: soc_camera: rcar_csi2: add interrupts
+
+This enables interrupts from RCAR CSI2 and grab timestamp
+of received frames (EOF)
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/platform/soc_camera/rcar_csi2.c | 58 ++++++++++++++++++++++++++-
+ 1 file changed, 57 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
+index ffb28c7..ca47ba3 100644
+--- a/drivers/media/platform/soc_camera/rcar_csi2.c
++++ b/drivers/media/platform/soc_camera/rcar_csi2.c
+@@ -200,6 +200,7 @@ struct rcar_csi2_link_config {
+ unsigned long vcdt;
+ unsigned long vcdt2;
+ unsigned int csi_rate;
++ unsigned int use_interrupts;
+ };
+
+ #define INIT_RCAR_CSI2_LINK_CONFIG(m) \
+@@ -228,6 +229,8 @@ struct rcar_csi2 {
+ unsigned int csi_rate;
+ spinlock_t lock;
+ atomic_t use_count;
++ unsigned int use_interrupts;
++ u64 timestamp[4];
+ };
+
+ static int dump = 0;
+@@ -434,6 +437,7 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data)
+ struct rcar_csi2 *priv = data;
+ u32 int_status;
+ unsigned int handled = 0;
++ u64 ts;
+
+ spin_lock(&priv->lock);
+
+@@ -441,6 +445,26 @@ static irqreturn_t rcar_csi2_irq(int irq, void *data)
+ if (!int_status)
+ goto done;
+
++ /* update timestamp on EOF for remote */
++ ts = ktime_get_ns();
++
++ if (int_status & RCAR_CSI2_INTSTATE_VD4_END) {
++ priv->timestamp[3] = ts;
++ //printk("eof vc3\n");
++ }
++ if (int_status & RCAR_CSI2_INTSTATE_VD3_END) {
++ priv->timestamp[2] = ts;
++ //printk("eof vc2\n");
++ }
++ if (int_status & RCAR_CSI2_INTSTATE_VD2_END) {
++ priv->timestamp[1] = ts;
++ //printk("eof vc1\n");
++ }
++ if (int_status & RCAR_CSI2_INTSTATE_VD1_END) {
++ priv->timestamp[0] = ts;
++ //printk("eof vc0\n");
++ }
++
+ /* ack interrupts */
+ iowrite32(int_status, priv->base + RCAR_CSI2_INTSTATE);
+ handled = 1;
+@@ -456,6 +480,10 @@ static void rcar_csi2_hwdeinit(struct rcar_csi2 *priv)
+ {
+ iowrite32(0, priv->base + RCAR_CSI2_PHYCNT);
+
++ /* mask interrupts */
++ iowrite32(~0U, priv->base + RCAR_CSI2_INTCLOSE);
++ /* ack interrupts */
++ iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE);
+ /* reset CSI2 hardware */
+ iowrite32(0x00000001, priv->base + RCAR_CSI2_SRST);
+ udelay(5);
+@@ -550,6 +578,18 @@ static int rcar_csi2_hwinit(struct rcar_csi2 *priv)
+ dev_dbg(&priv->pdev->dev, "CSI2 VCDT2: 0x%x\n",
+ ioread32(priv->base + RCAR_CSI2_VCDT2));
+
++ if (priv->use_interrupts) {
++ /* EOF only interrupts */
++ tmp = RCAR_CSI2_INTSTATE_VD1_END | RCAR_CSI2_INTSTATE_VD2_END |
++ RCAR_CSI2_INTSTATE_VD3_END | RCAR_CSI2_INTSTATE_VD4_END;
++ /* unmask interrupts */
++ iowrite32(~tmp, priv->base + RCAR_CSI2_INTCLOSE);
++ /* ack all interrupts */
++ iowrite32(~0U, priv->base + RCAR_CSI2_INTSTATE);
++ /* enable interrupts */
++ iowrite32(tmp, priv->base + RCAR_CSI2_INTEN);
++ }
++
+ /* wait until video decoder power off */
+ msleep(10);
+ {
+@@ -608,8 +648,21 @@ static int rcar_csi2_s_power(struct v4l2_subdev *sd, int on)
+ return ret;
+ }
+
++static long rcar_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct rcar_csi2 *priv = v4l2_get_subdevdata(sd);
++
++ if (cmd > 4 || !priv->use_interrupts)
++ return -EINVAL;
++
++ *(u64 *)arg = priv->timestamp[cmd];
++
++ return 0;
++}
++
+ static struct v4l2_subdev_core_ops rcar_csi2_subdev_core_ops = {
+ .s_power = rcar_csi2_s_power,
++ .ioctl = rcar_csi2_ioctl,
+ };
+
+ static struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
+@@ -660,6 +713,9 @@ static int rcar_csi2_parse_dt(struct device_node *np,
+ printk(KERN_ERR "csi-rate not set\n");
+ return ret;
+ }
++ config->use_interrupts = 0;
++ if (of_property_read_bool(endpoint, "use-interrupts"))
++ config->use_interrupts = 1;
+ of_node_put(endpoint);
+
+ config->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+@@ -730,7 +786,6 @@ static int rcar_csi2_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- /* Interrupt unused so far */
+ irq = platform_get_irq(pdev, 0);
+
+ if (!res || (int)irq <= 0) {
+@@ -754,6 +809,7 @@ static int rcar_csi2_probe(struct platform_device *pdev)
+ priv->vcdt = link_config.vcdt;
+ priv->vcdt2 = link_config.vcdt2;
+ priv->csi_rate = link_config.csi_rate;
++ priv->use_interrupts = link_config.use_interrupts;
+ atomic_set(&priv->use_count, 0);
+
+ platform_set_drvdata(pdev, priv);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch
new file mode 100644
index 00000000..121bab5a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch
@@ -0,0 +1,29 @@
+From b000da3023f944bb078c7bc284279b91854b0882 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Fri, 28 Feb 2020 11:51:12 +0300
+Subject: [PATCH] media: i2c: soc_camera: ov10640: fix emb lines number
+
+The number of emb lines are documnted as 2+2, but really
+we see 4+4
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.h b/drivers/media/i2c/soc_camera/ov10640.h
+index 04ff326..de89b19 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.h
++++ b/drivers/media/i2c/soc_camera/ov10640.h
+@@ -15,7 +15,7 @@
+ #define OV10640_DEFAULT_WIDTH 1280
+ #define OV10640_DEFAULT_HEIGHT 1080
+
+-#define OV10640_EMB_LINES 4 /* 2 emb lines at top and 2 stat lines at bottom */
++#define OV10640_EMB_LINES 8 /* 2+2 emb lines at top and 2+2 stat lines at bottom */
+ #define OV10640_EMB_PADDED (priv->emb_enable ? OV10640_EMB_LINES : 0) /* embedded data (SOF) and stats (EOF) */
+
+ #define OV10640_DELAY 0xffff
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch
new file mode 100644
index 00000000..d681e07a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch
@@ -0,0 +1,42 @@
+From 7ffd543f70c5455bc0a801036658c03a41cd3589 Mon Sep 17 00:00:00 2001
+From: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Date: Mon, 4 Jun 2018 11:12:25 +0300
+Subject: [PATCH] r8a779[78]-sysc: don't poweroff Cortex R7 core
+
+In V3M/V3H systems, Cortex R7 code normally executes code not anyhow
+related to Linux. Linux should not touch R7's power domain.
+
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+---
+ drivers/soc/renesas/r8a77970-sysc.c | 2 +-
+ drivers/soc/renesas/r8a77980-sysc.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c
+index 5725ad09e4da..6d08a3c81262 100644
+--- a/drivers/soc/renesas/r8a77970-sysc.c
++++ b/drivers/soc/renesas/r8a77970-sysc.c
+@@ -23,6 +23,7 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
+ PD_CPU_NOCR },
+ { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU,
+ PD_CPU_NOCR },
++// { "cr7", 0x240, 0, R8A77970_PD_CR7, R8A77970_PD_ALWAYS_ON, PD_CPU },
+ { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON },
+ { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR },
+ { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR },
+diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c
+index 2affaa27a6f8..ba73ce20d6ba 100644
+--- a/drivers/soc/renesas/r8a77980-sysc.c
++++ b/drivers/soc/renesas/r8a77980-sysc.c
+@@ -28,7 +28,7 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
+ PD_CPU_NOCR },
+ { "ca53-cpu3", 0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU,
+ PD_CPU_NOCR },
+- { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON },
++ { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON, PD_CPU },
+ { "a3ir", 0x180, 0, R8A77980_PD_A3IR, R8A77980_PD_ALWAYS_ON },
+ { "a2ir0", 0x400, 0, R8A77980_PD_A2IR0, R8A77980_PD_A3IR },
+ { "a2ir1", 0x400, 1, R8A77980_PD_A2IR1, R8A77980_PD_A3IR },
+--
+2.11.0
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch
new file mode 100644
index 00000000..ab493586
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch
@@ -0,0 +1,139 @@
+From cc34c21f572727e49f69e10b761bc44d3addf520 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 4 Mar 2020 17:32:44 +0300
+Subject: [PATCH] media: i2c: max9286,ti9x4: power down POCs on reboot
+
+Power down all POCs on reboot/shutdown/halt
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9286.c | 23 +++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ti9x4.c | 22 ++++++++++++++++++++++
+ 2 files changed, 45 insertions(+)
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index 343b8ab..05247ff 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -15,6 +15,7 @@
+ #include <linux/notifier.h>
+ #include <linux/of_gpio.h>
+ #include <linux/of_graph.h>
++#include <linux/reboot.h>
+ #include <linux/videodev2.h>
+
+ #include <media/v4l2-common.h>
+@@ -71,6 +72,7 @@ struct max9286_priv {
+ int max9271_addr_map[4];
+ int ser_id;
+ struct gpio_desc *poc_gpio[4]; /* PoC power supply */
++ struct notifier_block reboot_notifier;
+
+ /* link statistic */
+ int prbserr[4];
+@@ -643,6 +645,19 @@ static int max9286_registered_async(struct v4l2_subdev *sd)
+ return 0;
+ }
+
++static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
++{
++ struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier);
++ int idx;
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx]))
++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
++ }
++
++ return NOTIFY_OK;
++}
++
+ static struct v4l2_subdev_core_ops max9286_subdev_core_ops = {
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = max9286_g_register,
+@@ -996,6 +1011,13 @@ static int max9286_probe(struct i2c_client *client,
+ goto out;
+ }
+
++ priv->reboot_notifier.notifier_call = max9286_reboot_notifier;
++ err = register_reboot_notifier(&priv->reboot_notifier);
++ if (err) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
+ err = sysfs_create_group(&client->dev.kobj,
+ &max9286_group);
+ if (err < 0)
+@@ -1010,6 +1032,7 @@ static int max9286_remove(struct i2c_client *client)
+ int i;
+
+ sysfs_remove_group(&client->dev.kobj, &max9286_group);
++ unregister_reboot_notifier(&priv->reboot_notifier);
+
+ for (i = 0; i < 4; i++) {
+ v4l2_async_unregister_subdev(&priv->sd[i]);
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+index 9004bb1..627612a 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -15,6 +15,7 @@
+ #include <linux/notifier.h>
+ #include <linux/of_gpio.h>
+ #include <linux/of_graph.h>
++#include <linux/reboot.h>
+ #include <linux/videodev2.h>
+
+ #include <media/v4l2-common.h>
+@@ -52,6 +53,7 @@ struct ti9x4_priv {
+ struct gpio_desc *pwen; /* chip power en */
+ struct gpio_desc *poc_gpio[4]; /* PoC power supply */
+ struct v4l2_clk *ref_clk; /* ref clock */
++ struct notifier_block reboot_notifier;
+ };
+
+ static int ser_id;
+@@ -420,6 +422,19 @@ static int ti9x4_registered_async(struct v4l2_subdev *sd)
+ return 0;
+ }
+
++static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
++{
++ struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier);
++ int idx;
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx]))
++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
++ }
++
++ return NOTIFY_OK;
++}
++
+ static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = {
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ti9x4_g_register,
+@@ -676,6 +691,11 @@ static int ti9x4_probe(struct i2c_client *client,
+ goto out;
+ }
+
++ priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier;
++ err = register_reboot_notifier(&priv->reboot_notifier);
++ if (err)
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++
+ out:
+ return err;
+ }
+@@ -685,6 +705,8 @@ static int ti9x4_remove(struct i2c_client *client)
+ struct ti9x4_priv *priv = i2c_get_clientdata(client);
+ int i;
+
++ unregister_reboot_notifier(&priv->reboot_notifier);
++
+ for (i = 0; i < priv->links; i++) {
+ v4l2_async_unregister_subdev(&priv->sd[i]);
+ v4l2_device_unregister_subdev(&priv->sd[i]);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch
new file mode 100644
index 00000000..f654b012
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0484-media-platform-soc_camera-disable-mutex-locking-for-.patch
@@ -0,0 +1,34 @@
+From fdfb65e3d12080ab862a1847f7d2127a9fd3c6b4 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 9 Mar 2020 23:15:28 +0300
+Subject: [PATCH] media: platform: soc_camera: disable mutex locking for
+ ADV_DEBUG
+
+This disabled v4l2_ioctl locking for G/S_REGISTER.
+Hence the this allows to use G/S_REGISTER and Q/DQBUG under
+stress load.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+---
+ drivers/media/platform/soc_camera/soc_camera.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
+index 8084683..654b0df 100644
+--- a/drivers/media/platform/soc_camera/soc_camera.c
++++ b/drivers/media/platform/soc_camera/soc_camera.c
+@@ -2153,6 +2153,10 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
+ v4l2_disable_ioctl(icd->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(icd->vdev, VIDIOC_ENUMSTD);
+ }
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ v4l2_disable_ioctl_locking(icd->vdev, VIDIOC_DBG_G_REGISTER);
++ v4l2_disable_ioctl_locking(icd->vdev, VIDIOC_DBG_S_REGISTER);
++#endif
+ ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch
new file mode 100644
index 00000000..1ddc7f9e
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0485-media-i2c-ov10640-compensate-disabled-mutex.patch
@@ -0,0 +1,85 @@
+From 955d8c3c39605a389f10c96b2cf43b975476f272 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 10 Mar 2020 11:34:03 +0300
+Subject: [PATCH] media: i2c: ov10640: compensate disabled mutex
+
+Compensate ADV_DEBUG mutex after disabling in v4l2_ioctl
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ov10640.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ov10640.c b/drivers/media/i2c/soc_camera/ov10640.c
+index f5f0fdd..d52a0a2 100644
+--- a/drivers/media/i2c/soc_camera/ov10640.c
++++ b/drivers/media/i2c/soc_camera/ov10640.c
+@@ -37,6 +37,7 @@ struct ov10640_priv {
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct v4l2_rect rect;
++ struct mutex lock;
+ int subsampling;
+ int fps_numerator;
+ int fps_denominator;
+@@ -328,6 +329,7 @@ static int ov10640_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
+ int ret;
+ __be64 be_val;
+
+@@ -336,10 +338,14 @@ static int ov10640_g_register(struct v4l2_subdev *sd,
+ if (reg->size > sizeof(reg->val))
+ reg->size = sizeof(reg->val);
+
++ mutex_lock(&priv->lock);
++
+ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
+ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
+ reg->val = be64_to_cpu(be_val);
+
++ mutex_unlock(&priv->lock);
++
+ return ret;
+ }
+
+@@ -347,7 +353,9 @@ static int ov10640_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10640_priv *priv = to_ov10640(client);
+ u32 size = reg->size;
++ int ret;
+ __be64 be_val;
+
+ if (!size)
+@@ -355,10 +363,15 @@ static int ov10640_s_register(struct v4l2_subdev *sd,
+ if (size > sizeof(reg->val))
+ size = sizeof(reg->val);
+
++ mutex_lock(&priv->lock);
++
+ be_val = cpu_to_be64(reg->val);
+ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
+
+- return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++ mutex_unlock(&priv->lock);
++
++ return ret;
+ }
+ #endif
+
+@@ -711,6 +724,7 @@ static int ov10640_probe(struct i2c_client *client,
+ priv->rect.height = OV10640_DEFAULT_HEIGHT;
+ priv->fps_numerator = 1;
+ priv->fps_denominator = 30;
++ mutex_init(&priv->lock);
+
+ v4l2_ctrl_handler_init(&priv->hdl, 4);
+ v4l2_ctrl_new_std(&priv->hdl, &ov10640_ctrl_ops,
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch
new file mode 100644
index 00000000..24ec8902
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0487-i2c-busses-i2c-rcar-block-pm_runtime.patch
@@ -0,0 +1,80 @@
+From 7fc6b55fbd279e287a350b85f45885d51c4de5c4 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Mar 2020 15:07:48 +0300
+Subject: [PATCH] i2c: busses i2c-rcar: block pm_runtime
+
+This allows blocking of i2c clock runtime control by existing dts
+pataremeter multi-master.
+This speeds up i2c transaction during stress use case.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/i2c/busses/i2c-rcar.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
+index ddd3b39..4a3ea72 100644
+--- a/drivers/i2c/busses/i2c-rcar.c
++++ b/drivers/i2c/busses/i2c-rcar.c
+@@ -786,7 +786,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
+ if (priv->suspended)
+ return -EBUSY;
+
+- pm_runtime_get_sync(dev);
++ if (!(priv->flags & ID_P_PM_BLOCKED))
++ pm_runtime_get_sync(dev);
+
+ /* Check bus state before init otherwise bus busy info will be lost */
+ ret = rcar_i2c_bus_barrier(priv);
+@@ -826,7 +827,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
+ ret = num - priv->msgs_left; /* The number of transfer */
+ }
+ out:
+- pm_runtime_put(dev);
++ if (!(priv->flags & ID_P_PM_BLOCKED))
++ pm_runtime_put(dev);
+
+ if (ret < 0 && ret != -ENXIO)
+ dev_err(dev, "error %d : %x\n", ret, priv->flags);
+@@ -845,7 +847,8 @@ static int rcar_reg_slave(struct i2c_client *slave)
+ return -EAFNOSUPPORT;
+
+ /* Keep device active for slave address detection logic */
+- pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
++ if (!(priv->flags & ID_P_PM_BLOCKED))
++ pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
+
+ priv->slave = slave;
+ rcar_i2c_write(priv, ICSAR, slave->addr);
+@@ -867,7 +870,8 @@ static int rcar_unreg_slave(struct i2c_client *slave)
+
+ priv->slave = NULL;
+
+- pm_runtime_put(rcar_i2c_priv_to_dev(priv));
++ if (!(priv->flags & ID_P_PM_BLOCKED))
++ pm_runtime_put(rcar_i2c_priv_to_dev(priv));
+
+ return 0;
+ }
+@@ -1026,6 +1030,8 @@ static int rcar_i2c_suspend(struct device *dev)
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+
++ if (priv->flags & ID_P_PM_BLOCKED)
++ pm_runtime_put(dev);
+ priv->suspended = 1;
+
+ return 0;
+@@ -1045,7 +1051,8 @@ static int rcar_i2c_resume(struct device *dev)
+ dev_err(dev, "Could not calculate clock\n");
+
+ rcar_i2c_init(priv);
+- pm_runtime_put(dev);
++ if (!(priv->flags & ID_P_PM_BLOCKED))
++ pm_runtime_put(dev);
+
+ priv->suspended = 0;
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch
new file mode 100644
index 00000000..ef606653
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0488-arm64-dts-renesas-block-i2c-pm-runtime.patch
@@ -0,0 +1,68 @@
+From 7d99fda5fcfea599b9611f4af562b5ee327e8745 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Mar 2020 15:12:47 +0300
+Subject: [PATCH] arm64: dts: renesas: block i2c pm runtime
+
+Block i2c pm runtime on video boxes.
+This speed up i2c under stress cases: imagers control over
+FPDLINK or GMSL
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts | 1 +
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts | 2 +-
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts | 1 +
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts | 1 +
+ 4 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts
+index 7ab71c8..4eb160c 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk-vbm.dts
+@@ -75,6 +75,7 @@
+ status = "okay";
+
+ clock-frequency = <400000>;
++ multi-master;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
+index 4ca62c6..7c84657 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-4ch.dts
+@@ -143,6 +143,7 @@
+ status = "okay";
+
+ clock-frequency = <400000>;
++ multi-master;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
+index b635132..47f4408 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-8ch.dts
+@@ -143,6 +143,7 @@
+ status = "okay";
+
+ clock-frequency = <400000>;
++ multi-master;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
+index f90951d..dc7938b 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl-8ch.dts
+@@ -137,6 +137,7 @@
+ status = "okay";
+
+ clock-frequency = <400000>;
++ multi-master;
+
+ i2cswitch1: i2c-switch@74 {
+ compatible = "nxp,pca9548";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch
new file mode 100644
index 00000000..7d10e4ce
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0489-media-i2c-max9286-increase-i2c-freq-inside-GMSL-cahn.patch
@@ -0,0 +1,36 @@
+From 07aec3b12f833316963d45681f2dcbf688973621 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Mar 2020 14:34:14 +0300
+Subject: [PATCH] media: i2c: max9286: increase i2c freq inside GMSL cahnnel
+
+This slightly (10%) increases the i2c transaction speed over GMSL.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/max9286.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+index 05247ff..28bd3c3 100644
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ b/drivers/media/i2c/soc_camera/max9286.c
+@@ -31,7 +31,7 @@
+ #define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
+ #define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
+ #define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
+-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_837KHZ
+
+ struct max9286_priv {
+ struct v4l2_subdev sd[4];
+@@ -270,6 +270,7 @@ static void max9286_postinit(struct i2c_client *client, int addr)
+ reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */
+ reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */
+ reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */
++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */
+
+ if (strcmp(priv->fsync_mode, "manual") == 0) {
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch
new file mode 100644
index 00000000..adf70f4b
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch
@@ -0,0 +1,48 @@
+From 16082df9fc35be0488ddd3b4280187a9a361b511 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Mar 2020 14:29:31 +0300
+Subject: [PATCH] media: i2c: ti9x4: increase i2c freq on master bus
+
+This increase the serializer (remote) i2c frequency on master bus.
+This speed up imager access since deafult timings are 100Khz
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ti9x4.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+index 627612a..ca86f1fc 100644
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -147,9 +147,6 @@ static void ti9x4_initial_setup(struct i2c_client *client)
+
+ /* Initial setup */
+ client->addr = priv->des_addr; /* TI9x4 I2C */
+- reg8_write(client, 0x08, 0x1c); /* I2C glitch filter depth */
+- reg8_write(client, 0x0a, 0x79); /* I2C high pulse width */
+- reg8_write(client, 0x0b, 0x79); /* I2C low pulse width */
+ reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */
+ switch (priv->csi_rate) {
+ case 1600: /* REFCLK = 25MHZ */
+@@ -340,6 +337,8 @@ static int ti9x4_initialize(struct i2c_client *client)
+ switch (priv->ser_id) {
+ case TI913_ID:
+ reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */
++ reg8_write(client, 0x11, 0x10); /* I2C high pulse width */
++ reg8_write(client, 0x12, 0x10); /* I2C low pulse width */
+ break;
+ case TI953_ID:
+ reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 |
+@@ -354,6 +353,8 @@ static int ti9x4_initialize(struct i2c_client *client)
+ (!!priv->gpio[1] << 5) |
+ (!!priv->gpio[2] << 6) |
+ (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */
++ reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */
++ reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */
+ break;
+ }
+ client->addr = priv->des_addr;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch
new file mode 100644
index 00000000..05274af5
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch
@@ -0,0 +1,690 @@
+From 479f56c0ec0ce981e9333e7c1628c4850f3c8043 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 25 Mar 2020 17:27:04 +0300
+Subject: [PATCH] media: i2c: soc_camera: switch to u64 adv_debug access
+
+This allows up to 8 bytes block writes/reads using ADV_DEBUG
+interface.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ap0101_ar014x.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0132.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0140.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0143.c | 35 +++++++++++++++++++---------
+ drivers/media/i2c/soc_camera/ar0147.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0231.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0233.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ar0323.c | 34 +++++++++++++++++++--------
+ drivers/media/i2c/soc_camera/ov10635.c | 30 +++++++++++++++++-------
+ drivers/media/i2c/soc_camera/ov2311.c | 30 +++++++++++++++++-------
+ drivers/media/i2c/soc_camera/ox01d10.c | 30 +++++++++++++++++-------
+ drivers/media/i2c/soc_camera/ox03a.c | 30 +++++++++++++++++-------
+ 12 files changed, 280 insertions(+), 113 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+index c458044..8a2d2a6 100644
+--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+@@ -273,28 +273,42 @@ static int ap0101_g_mbus_config(struct v4l2_subdev *sd,
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ap0101_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ap0101_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0132.c b/drivers/media/i2c/soc_camera/ar0132.c
+index 30e9517..9f55364 100644
+--- a/drivers/media/i2c/soc_camera/ar0132.c
++++ b/drivers/media/i2c/soc_camera/ar0132.c
+@@ -232,28 +232,42 @@ static int ar0132_g_mbus_config(struct v4l2_subdev *sd,
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0132_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0132_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0140.c b/drivers/media/i2c/soc_camera/ar0140.c
+index bb7a3ce..4d3893bf 100644
+--- a/drivers/media/i2c/soc_camera/ar0140.c
++++ b/drivers/media/i2c/soc_camera/ar0140.c
+@@ -265,28 +265,42 @@ static int ar0140_g_mbus_config(struct v4l2_subdev *sd,
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0140_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0140_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0143.c b/drivers/media/i2c/soc_camera/ar0143.c
+index 083b7ec..e60e2ec 100644
+--- a/drivers/media/i2c/soc_camera/ar0143.c
++++ b/drivers/media/i2c/soc_camera/ar0143.c
+@@ -356,31 +356,44 @@ static int ar0143_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+ return ret;
+ }
+
+-
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0143_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0143_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0147.c b/drivers/media/i2c/soc_camera/ar0147.c
+index a444700..d7e3f83 100644
+--- a/drivers/media/i2c/soc_camera/ar0147.c
++++ b/drivers/media/i2c/soc_camera/ar0147.c
+@@ -372,28 +372,42 @@ static int ar0147_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0147_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0147_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0231.c b/drivers/media/i2c/soc_camera/ar0231.c
+index 6c450f7..922c078 100644
+--- a/drivers/media/i2c/soc_camera/ar0231.c
++++ b/drivers/media/i2c/soc_camera/ar0231.c
+@@ -253,28 +253,42 @@ static int ar0231_g_mbus_config(struct v4l2_subdev *sd,
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0231_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0231_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
+index fbff49b..2bf260b 100644
+--- a/drivers/media/i2c/soc_camera/ar0233.c
++++ b/drivers/media/i2c/soc_camera/ar0233.c
+@@ -323,28 +323,42 @@ static int ar0233_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0233_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0233_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ar0323.c b/drivers/media/i2c/soc_camera/ar0323.c
+index 2104d6a..1f20fef 100644
+--- a/drivers/media/i2c/soc_camera/ar0323.c
++++ b/drivers/media/i2c/soc_camera/ar0323.c
+@@ -207,28 +207,42 @@ static int ar0323_g_mbus_config(struct v4l2_subdev *sd,
+
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int ar0323_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
++ struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u16 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read16(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ar0323_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
++ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ov10635.c b/drivers/media/i2c/soc_camera/ov10635.c
+index 14bb339..e9e0cdf 100644
+--- a/drivers/media/i2c/soc_camera/ov10635.c
++++ b/drivers/media/i2c/soc_camera/ov10635.c
+@@ -357,24 +357,38 @@ static int ov10635_g_register(struct v4l2_subdev *sd,
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u8 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ov10635_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ov2311.c b/drivers/media/i2c/soc_camera/ov2311.c
+index c61059d..f8099c7 100644
+--- a/drivers/media/i2c/soc_camera/ov2311.c
++++ b/drivers/media/i2c/soc_camera/ov2311.c
+@@ -268,24 +268,38 @@ static int ov2311_g_register(struct v4l2_subdev *sd,
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u8 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u16);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ov2311_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ox01d10.c b/drivers/media/i2c/soc_camera/ox01d10.c
+index 082e88c..cac267a 100644
+--- a/drivers/media/i2c/soc_camera/ox01d10.c
++++ b/drivers/media/i2c/soc_camera/ox01d10.c
+@@ -215,24 +215,38 @@ static int ox01d10_g_register(struct v4l2_subdev *sd,
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u8 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u8);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ox01d10_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+diff --git a/drivers/media/i2c/soc_camera/ox03a.c b/drivers/media/i2c/soc_camera/ox03a.c
+index 162c75b..3b4ae27 100644
+--- a/drivers/media/i2c/soc_camera/ox03a.c
++++ b/drivers/media/i2c/soc_camera/ox03a.c
+@@ -214,24 +214,38 @@ static int ox03a_g_register(struct v4l2_subdev *sd,
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+- u8 val = 0;
++ __be64 be_val;
+
+- ret = reg16_read(client, (u16)reg->reg, &val);
+- if (ret < 0)
+- return ret;
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
+
+- reg->val = val;
+- reg->size = sizeof(u8);
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
+
+- return 0;
++ return ret;
+ }
+
+ static int ox03a_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+ {
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
+
+- return reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
+ }
+ #endif
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch
new file mode 100644
index 00000000..a4851c0d
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch
@@ -0,0 +1,6794 @@
+From 40f71bc01fcacef975e9fd507ec212a08aeeade9 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 10:47:53 +0300
+Subject: [PATCH] media: i2c: move gmsl/fpdlink drivers to separate
+ folder
+
+Move GMSL/FPDLINK driver to separate folder
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/Kconfig | 28 +-
+ drivers/media/i2c/soc_camera/Makefile | 7 +-
+ drivers/media/i2c/soc_camera/dummy.c | 491 -----------
+ drivers/media/i2c/soc_camera/fpdlink/Kconfig | 5 +
+ drivers/media/i2c/soc_camera/fpdlink/Makefile | 2 +
+ drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 745 +++++++++++++++++
+ drivers/media/i2c/soc_camera/fpdlink/ti9x4.h | 204 +++++
+ drivers/media/i2c/soc_camera/gmsl/Kconfig | 11 +
+ drivers/media/i2c/soc_camera/gmsl/Makefile | 3 +
+ drivers/media/i2c/soc_camera/gmsl/max9286.c | 1072 +++++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/gmsl/max9288.c | 768 ++++++++++++++++++
+ drivers/media/i2c/soc_camera/imagers/Kconfig | 5 +
+ drivers/media/i2c/soc_camera/imagers/Makefile | 2 +
+ drivers/media/i2c/soc_camera/imagers/dummy.c | 491 +++++++++++
+ drivers/media/i2c/soc_camera/max9286.c | 1072 -------------------------
+ drivers/media/i2c/soc_camera/max9288.c | 768 ------------------
+ drivers/media/i2c/soc_camera/ti9x4.c | 745 -----------------
+ drivers/media/i2c/soc_camera/ti9x4.h | 204 -----
+ 18 files changed, 3315 insertions(+), 3308 deletions(-)
+ delete mode 100644 drivers/media/i2c/soc_camera/dummy.c
+ create mode 100644 drivers/media/i2c/soc_camera/fpdlink/Kconfig
+ create mode 100644 drivers/media/i2c/soc_camera/fpdlink/Makefile
+ create mode 100644 drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+ create mode 100644 drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/Kconfig
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/Makefile
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9286.c
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9288.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/Kconfig
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/Makefile
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/dummy.c
+ delete mode 100644 drivers/media/i2c/soc_camera/max9286.c
+ delete mode 100644 drivers/media/i2c/soc_camera/max9288.c
+ delete mode 100644 drivers/media/i2c/soc_camera/ti9x4.c
+ delete mode 100644 drivers/media/i2c/soc_camera/ti9x4.h
+
+diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
+index 729b5af..6792522 100644
+--- a/drivers/media/i2c/soc_camera/Kconfig
++++ b/drivers/media/i2c/soc_camera/Kconfig
+@@ -83,30 +83,6 @@ config SOC_CAMERA_TW9910
+ help
+ This is a tw9910 video driver
+
+-config SOC_CAMERA_MAX9286
+- tristate "max9286 GMSL support"
+- depends on SOC_CAMERA && I2C
+- help
+- This is a MAXIM max9286 GMSL driver
+-
+-config SOC_CAMERA_MAX9288
+- tristate "max9288 GMSL support"
+- depends on SOC_CAMERA && I2C
+- help
+- This is a MAXIM max9288 GMSL driver
+-
+-config SOC_CAMERA_TI9X4
+- tristate "ti9x4 FPDLink3 support"
+- depends on SOC_CAMERA && I2C
+- help
+- This is an Texas Instruments ti9X4 FPDLink3 driver
+-
+-config SOC_CAMERA_OV106XX
+- tristate "ov106xx camera support"
+- depends on SOC_CAMERA && I2C
+- help
+- This is a runtime detected GMSL/FPDLink3 sensors driver
+-
+ config SOC_CAMERA_IMX219
+ tristate "imx219 camera support"
+ depends on SOC_CAMERA && I2C
+@@ -118,3 +94,7 @@ config SOC_CAMERA_AR0147
+ depends on SOC_CAMERA && I2C
+ help
+ This is an AR0147 imager glue
++
++source "drivers/media/i2c/soc_camera/gmsl/Kconfig"
++source "drivers/media/i2c/soc_camera/fpdlink/Kconfig"
++source "drivers/media/i2c/soc_camera/imagers/Kconfig"
+diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
+index d916bba..5e08254 100644
+--- a/drivers/media/i2c/soc_camera/Makefile
++++ b/drivers/media/i2c/soc_camera/Makefile
+@@ -11,11 +11,10 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
+ obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
+ obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
+ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+-obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o
+-obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o
+-obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o
+ obj-$(CONFIG_SOC_CAMERA_IMX219) += imx219.o
+-obj-y += dummy.o
+
+ obj-$(CONFIG_SOC_CAMERA_AR0147) += ar0147.o
++obj-y += imagers/
++obj-y += gmsl/
++obj-y += fpdlink/
+diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c
+deleted file mode 100644
+index d213fff..0000000
+--- a/drivers/media/i2c/soc_camera/dummy.c
++++ /dev/null
+@@ -1,491 +0,0 @@
+-/*
+- * Dummy sensor camera driver
+- *
+- * Copyright (C) 2019 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/i2c.h>
+-#include <linux/module.h>
+-#include <linux/of_graph.h>
+-#include <linux/videodev2.h>
+-
+-#include <media/soc_camera.h>
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-ctrls.h>
+-
+-struct dummy_priv {
+- struct v4l2_subdev sd;
+- struct v4l2_ctrl_handler hdl;
+- struct media_pad pad;
+- struct v4l2_rect rect;
+- u8 id[6];
+- int max_width;
+- int max_height;
+- const char * media_bus_format;
+- int mbus_format;
+-};
+-
+-static int width = 1920;
+-module_param(width, int, 0644);
+-MODULE_PARM_DESC(width, " width (default: 1920)");
+-
+-static int height = 1080;
+-module_param(height, int, 0644);
+-MODULE_PARM_DESC(height, " height (default: 1080)");
+-
+-static char *mbus = "yuyv";
+-module_param(mbus, charp, 0644);
+-MODULE_PARM_DESC(mbus, " MEDIA_BUS_FORMAT (default: YUYV)");
+-
+-static inline struct dummy_priv *to_dummy(const struct i2c_client *client)
+-{
+- return container_of(i2c_get_clientdata(client), struct dummy_priv, sd);
+-}
+-
+-static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+-{
+- return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd;
+-}
+-
+-static int dummy_s_stream(struct v4l2_subdev *sd, int enable)
+-{
+- return 0;
+-}
+-
+-static int dummy_get_fmt(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_format *format)
+-{
+- struct v4l2_mbus_framefmt *mf = &format->format;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- if (format->pad)
+- return -EINVAL;
+-
+- mf->width = priv->rect.width;
+- mf->height = priv->rect.height;
+- mf->code = priv->mbus_format;
+- mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+- mf->field = V4L2_FIELD_NONE;
+-
+- return 0;
+-}
+-
+-static int dummy_set_fmt(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_format *format)
+-{
+- struct v4l2_mbus_framefmt *mf = &format->format;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- mf->code = priv->mbus_format;
+- mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+- mf->field = V4L2_FIELD_NONE;
+-
+- if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+- cfg->try_fmt = *mf;
+-
+- return 0;
+-}
+-
+-static int dummy_enum_mbus_code(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_mbus_code_enum *code)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- if (code->pad || code->index > 0)
+- return -EINVAL;
+-
+- code->code = priv->mbus_format;
+-
+- return 0;
+-}
+-
+-static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- memcpy(edid->edid, priv->id, 6);
+-
+- edid->edid[6] = 0xff;
+- edid->edid[7] = client->addr;
+- edid->edid[8] = 'D' >> 8;
+- edid->edid[9] = 'Y' & 0xff;
+-
+- return 0;
+-}
+-
+-static int dummy_set_selection(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_selection *sel)
+-{
+- struct v4l2_rect *rect = &sel->r;
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+- sel->target != V4L2_SEL_TGT_CROP)
+- return -EINVAL;
+-
+- rect->left = ALIGN(rect->left, 2);
+- rect->top = ALIGN(rect->top, 2);
+- rect->width = ALIGN(rect->width, 2);
+- rect->height = ALIGN(rect->height, 2);
+-
+- if ((rect->left + rect->width > priv->max_width) ||
+- (rect->top + rect->height > priv->max_height))
+- *rect = priv->rect;
+-
+- priv->rect.left = rect->left;
+- priv->rect.top = rect->top;
+- priv->rect.width = rect->width;
+- priv->rect.height = rect->height;
+-
+- return 0;
+-}
+-
+-static int dummy_get_selection(struct v4l2_subdev *sd,
+- struct v4l2_subdev_pad_config *cfg,
+- struct v4l2_subdev_selection *sel)
+-{
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+- return -EINVAL;
+-
+- switch (sel->target) {
+- case V4L2_SEL_TGT_CROP_BOUNDS:
+- sel->r.left = 0;
+- sel->r.top = 0;
+- sel->r.width = priv->max_width;
+- sel->r.height = priv->max_height;
+- return 0;
+- case V4L2_SEL_TGT_CROP_DEFAULT:
+- sel->r.left = 0;
+- sel->r.top = 0;
+- sel->r.width = priv->max_width;
+- sel->r.height = priv->max_height;
+- return 0;
+- case V4L2_SEL_TGT_CROP:
+- sel->r = priv->rect;
+- return 0;
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static int dummy_g_mbus_config(struct v4l2_subdev *sd,
+- struct v4l2_mbus_config *cfg)
+-{
+- cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+- cfg->type = V4L2_MBUS_CSI2;
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-static int dummy_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
+-{
+- reg->val = 0;
+- reg->size = sizeof(u16);
+-
+- return 0;
+-}
+-
+-static int dummy_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
+-{
+- return 0;
+-}
+-#endif
+-
+-static struct v4l2_subdev_core_ops dummy_core_ops = {
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- .g_register = dummy_g_register,
+- .s_register = dummy_s_register,
+-#endif
+-};
+-
+-static int dummy_s_ctrl(struct v4l2_ctrl *ctrl)
+-{
+- switch (ctrl->id) {
+- case V4L2_CID_BRIGHTNESS:
+- case V4L2_CID_CONTRAST:
+- case V4L2_CID_SATURATION:
+- case V4L2_CID_HUE:
+- case V4L2_CID_GAMMA:
+- case V4L2_CID_SHARPNESS:
+- case V4L2_CID_AUTOGAIN:
+- case V4L2_CID_GAIN:
+- case V4L2_CID_ANALOGUE_GAIN:
+- case V4L2_CID_EXPOSURE:
+- case V4L2_CID_HFLIP:
+- case V4L2_CID_VFLIP:
+- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+- break;
+- }
+-
+- return 0;
+-}
+-
+-static const struct v4l2_ctrl_ops dummy_ctrl_ops = {
+- .s_ctrl = dummy_s_ctrl,
+-};
+-
+-static struct v4l2_subdev_video_ops dummy_video_ops = {
+- .s_stream = dummy_s_stream,
+- .g_mbus_config = dummy_g_mbus_config,
+-};
+-
+-static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = {
+- .get_edid = dummy_get_edid,
+- .enum_mbus_code = dummy_enum_mbus_code,
+- .get_selection = dummy_get_selection,
+- .set_selection = dummy_set_selection,
+- .get_fmt = dummy_get_fmt,
+- .set_fmt = dummy_set_fmt,
+-};
+-
+-static struct v4l2_subdev_ops dummy_subdev_ops = {
+- .core = &dummy_core_ops,
+- .video = &dummy_video_ops,
+- .pad = &dummy_subdev_pad_ops,
+-};
+-
+-static void dummy_otp_id_read(struct i2c_client *client)
+-{
+- struct dummy_priv *priv = to_dummy(client);
+-
+- /* dummy camera id */
+- priv->id[0] = 'd';
+- priv->id[1] = 'u';
+- priv->id[2] = 'm';
+- priv->id[3] = 'm';
+- priv->id[4] = 'y';
+- priv->id[5] = '.';
+-}
+-
+-static ssize_t dummy_otp_id_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
+- struct i2c_client *client = v4l2_get_subdevdata(sd);
+- struct dummy_priv *priv = to_dummy(client);
+-
+- dummy_otp_id_read(client);
+-
+- return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+- priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+-}
+-
+-static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL);
+-
+-static int dummy_initialize(struct i2c_client *client)
+-{
+- struct dummy_priv *priv = to_dummy(client);
+-
+- if (strcmp(priv->media_bus_format, "yuyv") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8;
+- else if (strcmp(priv->media_bus_format, "uyvy") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8;
+- else if (strcmp(priv->media_bus_format, "grey") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8;
+- else if (strcmp(priv->media_bus_format, "rggb8") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8;
+- else if (strcmp(priv->media_bus_format, "bggr8") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8;
+- else if (strcmp(priv->media_bus_format, "grbg8") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8;
+- else if (strcmp(priv->media_bus_format, "rggb12") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12;
+- else if (strcmp(priv->media_bus_format, "bggr12") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12;
+- else if (strcmp(priv->media_bus_format, "grbg12") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12;
+- else if (strcmp(priv->media_bus_format, "rggb14") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14;
+- else if (strcmp(priv->media_bus_format, "bggr14") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14;
+- else if (strcmp(priv->media_bus_format, "grbg14") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14;
+- else if (strcmp(priv->media_bus_format, "rggb16") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16;
+- else if (strcmp(priv->media_bus_format, "bggr16") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16;
+- else if (strcmp(priv->media_bus_format, "grbg16") == 0)
+- priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16;
+- else {
+- v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format);
+- return -EINVAL;
+- }
+-
+- /* Read OTP IDs */
+- dummy_otp_id_read(client);
+-
+- dev_info(&client->dev, "Dummy camera sensor, res %dx%d, mbus %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+- priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+-
+- return 0;
+-}
+-
+-static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv)
+-{
+- if (of_property_read_u32(np, "dummy,width", &priv->max_width))
+- priv->max_width = width;
+-
+- if (of_property_read_u32(np, "dummy,height", &priv->max_height))
+- priv->max_height = height;
+-
+- if (of_property_read_string(np, "dummy,mbus", &priv->media_bus_format))
+- priv->media_bus_format = mbus;
+-
+- /* module params override dts */
+- if (strcmp(mbus, "yuyv"))
+- priv->media_bus_format = mbus;
+- if (width != 1920)
+- priv->max_width = width;
+- if (height != 1080)
+- priv->max_height = height;
+-
+- return 0;
+-}
+-
+-static int dummy_probe(struct i2c_client *client,
+- const struct i2c_device_id *did)
+-{
+- struct dummy_priv *priv;
+- int ret;
+-
+- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops);
+- priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+-
+- v4l2_ctrl_handler_init(&priv->hdl, 4);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_CONTRAST, 0, 16, 1, 7);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_SATURATION, 0, 7, 1, 2);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_HUE, 0, 23, 1, 12);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_GAMMA, -128, 128, 1, 0);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_SHARPNESS, 0, 10, 1, 3);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_HFLIP, 0, 1, 1, 0);
+- v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
+- V4L2_CID_VFLIP, 0, 1, 1, 0);
+- priv->sd.ctrl_handler = &priv->hdl;
+-
+- ret = priv->hdl.error;
+- if (ret)
+- goto cleanup;
+-
+- v4l2_ctrl_handler_setup(&priv->hdl);
+-
+- priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+- priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
+- ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
+- if (ret < 0)
+- goto cleanup;
+-
+- ret = dummy_parse_dt(client->dev.of_node, priv);
+- if (ret)
+- goto cleanup;
+-
+- ret = dummy_initialize(client);
+- if (ret < 0)
+- goto cleanup;
+-
+- priv->rect.left = 0;
+- priv->rect.top = 0;
+- priv->rect.width = priv->max_width;
+- priv->rect.height = priv->max_height;
+-
+- ret = v4l2_async_register_subdev(&priv->sd);
+- if (ret)
+- goto cleanup;
+-
+- if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) {
+- dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
+- goto cleanup;
+- }
+-
+- return 0;
+-
+-cleanup:
+- media_entity_cleanup(&priv->sd.entity);
+- v4l2_ctrl_handler_free(&priv->hdl);
+- v4l2_device_unregister_subdev(&priv->sd);
+- v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
+- client->addr, client->adapter->name);
+- return ret;
+-}
+-
+-static int dummy_remove(struct i2c_client *client)
+-{
+- struct dummy_priv *priv = i2c_get_clientdata(client);
+-
+- device_remove_file(&client->dev, &dev_attr_otp_id_dummy);
+- v4l2_async_unregister_subdev(&priv->sd);
+- media_entity_cleanup(&priv->sd.entity);
+- v4l2_ctrl_handler_free(&priv->hdl);
+- v4l2_device_unregister_subdev(&priv->sd);
+-
+- return 0;
+-}
+-
+-static const struct i2c_device_id dummy_id[] = {
+- { "dummy-camera", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, dummy_id);
+-
+-static const struct of_device_id dummy_of_ids[] = {
+- { .compatible = "dummy-camera", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, dummy_of_ids);
+-
+-static struct i2c_driver dummy_i2c_driver = {
+- .driver = {
+- .name = "dummy-camera",
+- .of_match_table = dummy_of_ids,
+- },
+- .probe = dummy_probe,
+- .remove = dummy_remove,
+- .id_table = dummy_id,
+-};
+-module_i2c_driver(dummy_i2c_driver);
+-
+-MODULE_DESCRIPTION("Dummy SoC camera driver");
+-MODULE_AUTHOR("Vladimir Barinov");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/Kconfig b/drivers/media/i2c/soc_camera/fpdlink/Kconfig
+new file mode 100644
+index 0000000..9550563
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/fpdlink/Kconfig
+@@ -0,0 +1,5 @@
++config SOC_CAMERA_TI9X4
++ tristate "ti9x4 FPDLink3 support"
++ depends on I2C
++ help
++ This is an Texas Instruments ti9X4 FPDLink3 driver
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/Makefile b/drivers/media/i2c/soc_camera/fpdlink/Makefile
+new file mode 100644
+index 0000000..29f4a59
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/fpdlink/Makefile
+@@ -0,0 +1,2 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+new file mode 100644
+index 0000000..340e61e
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+@@ -0,0 +1,745 @@
++ /*
++ * TI DS90UB954/960/964 FPDLinkIII driver
++ *
++ * Copyright (C) 2017-2018 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-clk.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "ti9x4.h"
++
++struct ti9x4_priv {
++ struct v4l2_subdev sd[4];
++ struct fwnode_handle *sd_fwnode[4];
++ int des_addr;
++ int links;
++ int lanes;
++ int csi_rate;
++ const char *forwarding_mode;
++ int fs_time;
++ int fps_numerator;
++ int fps_denominator;
++ int is_coax;
++ int dvp_bus;
++ int dvp_lsb;
++ int hsync;
++ int vsync;
++ int poc_delay;
++ atomic_t use_count;
++ struct i2c_client *client;
++ int ti9x3_addr_map[4];
++ char chip_id[6];
++ int ser_id;
++ int vc_map;
++ int csi_map;
++ int gpio[4];
++ struct gpio_desc *pwen; /* chip power en */
++ struct gpio_desc *poc_gpio[4]; /* PoC power supply */
++ struct v4l2_clk *ref_clk; /* ref clock */
++ struct notifier_block reboot_notifier;
++};
++
++static int ser_id;
++module_param(ser_id, int, 0644);
++MODULE_PARM_DESC(ser_id, " Serializer ID (default: TI913)");
++
++static int is_stp;
++module_param(is_stp, int, 0644);
++MODULE_PARM_DESC(is_stp, " STP cable (default: Coax cable)");
++
++static int dvp_bus = 8;
++module_param(dvp_bus, int, 0644);
++MODULE_PARM_DESC(dvp_bus, " DVP/CSI over FPDLink (default: DVP 8-bit)");
++
++static int dvp_lsb = 0;
++module_param(dvp_lsb, int, 0644);
++MODULE_PARM_DESC(dvp_lsb, " DVP 8-bit LSB/MSB selection (default: DVP 8-bit MSB)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int poc_delay;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)");
++
++static int vc_map = 0x3210;
++module_param(vc_map, int, 0644);
++MODULE_PARM_DESC(vc_map, " CSI VC MAP (default: 0xe4 - linear map VCx=LINKx)");
++
++static int csi_map = 0;
++module_param(csi_map, int, 0644);
++MODULE_PARM_DESC(csi_map, " CSI TX MAP (default: 0 - forwarding of all links to CSI0)");
++
++static int gpio0 = 0, gpio1 = 0, gpio2 = 0, gpio3 = 0;
++module_param(gpio0, int, 0644);
++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 low level)");
++module_param(gpio1, int, 0644);
++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 low level)");
++module_param(gpio2, int, 0644);
++MODULE_PARM_DESC(gpio2, " GPIO2 function select (default: GPIO2 low level)");
++module_param(gpio3, int, 0644);
++MODULE_PARM_DESC(gpio3, " GPIO3 function select (default: GPIO3 low level)");
++
++#ifdef TI954_SILICON_ERRATA
++static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val)
++{
++ if (page > 7)
++ return -EINVAL;
++
++ reg8_write(client, 0xb0, page << 2);
++ reg8_write(client, 0xb1, reg);
++ reg8_write(client, 0xb2, val);
++
++ return 0;
++}
++
++static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val)
++{
++ if (page > 7)
++ return -EINVAL;
++
++ reg8_write(client, 0xb0, page << 2);
++ reg8_write(client, 0xb1, reg);
++ reg8_read(client, 0xb2, val);
++
++ return 0;
++}
++#endif
++
++static void ti9x4_read_chipid(struct i2c_client *client)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++
++ /* Chip ID */
++ reg8_read(client, 0xf1, &priv->chip_id[0]);
++ reg8_read(client, 0xf2, &priv->chip_id[1]);
++ reg8_read(client, 0xf3, &priv->chip_id[2]);
++ reg8_read(client, 0xf4, &priv->chip_id[3]);
++ reg8_read(client, 0xf5, &priv->chip_id[4]);
++ priv->chip_id[5] = '\0';
++}
++
++static void ti9x4_initial_setup(struct i2c_client *client)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++
++ /* Initial setup */
++ client->addr = priv->des_addr; /* TI9x4 I2C */
++ reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */
++ switch (priv->csi_rate) {
++ case 1600: /* REFCLK = 25MHZ */
++ case 1500: /* REFCLK = 23MHZ */
++ case 1450: /* REFCLK = 22.5MHZ */
++ reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */
++ break;
++ case 1200: /* REFCLK = 25MHZ */
++ case 1100: /* REFCLK = 22.5MHZ */
++ reg8_write(client, 0x1f, 0x01); /* CSI rate 1.1/1.2Gbps */
++ break;
++ case 800: /* REFCLK = 25MHZ */
++ case 700: /* REFCLK = 22.5MHZ */
++ reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */
++ break;
++ case 400: /* REFCLK = 25MHZ */
++ case 350: /* REFCLK = 22.5MHZ */
++ reg8_write(client, 0x1f, 0x03); /* CSI rate 350/400Mbps */
++ break;
++ default:
++ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
++ }
++
++ switch (priv->csi_rate) {
++ case 1600:
++ case 1200:
++ case 800:
++ case 400:
++ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */
++ priv->fs_time = 2790;
++ break;
++ case 1500:
++ /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */
++ priv->fs_time = 2570;
++ break;
++ case 1450:
++ case 1100:
++ case 700:
++ case 350:
++ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */
++ priv->fs_time = 2513;
++ break;
++ default:
++ priv->fs_time = 0;
++ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
++ }
++
++ if (strcmp(priv->forwarding_mode, "round-robin") == 0) {
++ reg8_write(client, 0x21, 0x03); /* Round Robin forwarding enable for CSI0/CSI1 */
++ } else if (strcmp(priv->forwarding_mode, "synchronized") == 0) {
++ reg8_write(client, 0x21, 0x54); /* Basic Syncronized forwarding enable (FrameSync must be enabled!!) for CSI0/CSI1 */
++ }
++
++ reg8_write(client, 0x32, 0x03); /* Select TX for CSI0/CSI1, RX for CSI0 */
++ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4); /* disable CSI output, set CSI lane count, non-continuous CSI mode */
++ reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding */
++#if 0
++ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/2/FPS*25MHz =1/2/30*25Mhz =416666 -> FS_TIME=416666 */
++ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/2/FPS*22.5Mhz=1/2/30*22.5Mhz=375000 -> FS_TIME=375000 */
++// #define FS_TIME (priv->csi_rate == 1450 ? 376000 : 417666)
++ #define FS_TIME (priv->csi_rate == 1450 ? 385000 : 428000) // FPS=29.2 (new vendor's firmware AWB restriction?)
++ reg8_write(client, 0x1a, FS_TIME >> 16); /* FrameSync time 24bit */
++ reg8_write(client, 0x1b, (FS_TIME >> 8) & 0xff);
++ reg8_write(client, 0x1c, FS_TIME & 0xff);
++ reg8_write(client, 0x18, 0x43); /* Enable FrameSync, 50/50 mode, Frame clock from 25MHz */
++#else
++ reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */
++ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */
++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
++ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */
++ reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */
++#endif
++}
++
++static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++ u8 port_config = 0x78;
++ u8 port_config2 = 0;
++
++ /* FPDLinkIII setup */
++ client->addr = priv->des_addr; /* TI9x4 I2C */
++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
++ usleep_range(2000, 2500); /* wait 2ms */
++
++ switch (priv->ser_id) {
++ case TI913_ID:
++ reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */
++ break;
++ case TI953_ID:
++ reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */
++ break;
++ default:
++ break;
++ }
++
++ reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */
++// reg8_write(client, 0x5d, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
++// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */
++
++ if (priv->is_coax)
++ port_config |= 0x04; /* Coax */
++ else
++ port_config |= 0x00; /* STP */
++
++ switch (priv->dvp_bus) {
++ case 8:
++ port_config2 |= (priv->dvp_lsb ? 0xC0 : 0x80); /* RAW10 as 8-bit prosessing using LSB/MSB bits */
++ /* fall through */
++ case 10:
++ port_config |= 0x03; /* DVP over FPDLink (TI913 compatible) RAW10/RAW8 */
++ break;
++ case 12:
++ port_config |= 0x02; /* DVP over FPDLink (TI913 compatible) RAW12 */
++ break;
++ default:
++ port_config |= 0x00; /* CSI over FPDLink (TI953 compatible) */
++ }
++
++ if (priv->vsync)
++ port_config2 |= 0x01; /* VSYNC acive low */
++ if (priv->hsync)
++ port_config2 |= 0x02; /* HSYNC acive low */
++
++ reg8_write(client, 0x6d, port_config);
++ reg8_write(client, 0x7c, port_config2);
++ reg8_write(client, 0x70, ((priv->vc_map >> (idx * 4)) << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */
++ reg8_write(client, 0x71, ((priv->vc_map >> (idx * 4)) << 6) | 0x2c); /* CSI data type: RAW12, assign VC */
++ reg8_write(client, 0xbc, 0x00); /* Setup minimal time between FV and LV to 3 PCLKs */
++ reg8_write(client, 0x72, priv->vc_map >> (idx * 4)); /* CSI VC MAP */
++}
++
++static int ti9x4_initialize(struct i2c_client *client)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++ int idx, timeout;
++ u8 port_sts1[4] = {0, 0, 0, 0}, port_sts2[4] = {0, 0, 0, 0};
++
++ dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n",
++ priv->links, priv->lanes, priv->forwarding_mode, priv->is_coax ? "coax" : "stp", priv->chip_id);
++
++ ti9x4_initial_setup(client);
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx])) {
++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
++ mdelay(priv->poc_delay);
++ }
++
++ ti9x4_fpdlink3_setup(client, idx);
++ }
++
++ client->addr = priv->des_addr;
++
++ /* check lock status */
++ for (timeout = 500 / priv->links; timeout > 0; timeout--) {
++ for (idx = 0; idx < priv->links; idx++) {
++ if ((port_sts1[idx] & 0x1) && (port_sts2[idx] & 0x4))
++ continue;
++
++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
++ usleep_range(1000, 1500); /* wait 1ms */
++ reg8_read(client, 0x4d, &port_sts1[idx]); /* Lock status */
++ reg8_read(client, 0x4e, &port_sts2[idx]); /* Freq stable */
++ }
++ }
++
++ if (!timeout)
++ dev_info(&client->dev, "Receiver lock status [%d,%d,%d,%d]\n",
++ (port_sts1[0] & 0x1) && (port_sts2[0] & 0x4),
++ (port_sts1[1] & 0x1) && (port_sts2[1] & 0x4),
++ (port_sts1[2] & 0x1) && (port_sts2[2] & 0x4),
++ (port_sts1[3] & 0x1) && (port_sts2[3] & 0x4));
++
++ if (priv->poc_delay)
++ mdelay(100);
++
++ for (idx = 0; idx < priv->links; idx++) {
++ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
++ usleep_range(1000, 1500); /* wait 1ms */
++
++ /*
++ * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side:
++ * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by
++ * unstable/bad link, hence unstable backchannel
++ */
++ client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */
++ switch (priv->ser_id) {
++ case TI913_ID:
++ reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */
++ reg8_write(client, 0x11, 0x10); /* I2C high pulse width */
++ reg8_write(client, 0x12, 0x10); /* I2C low pulse width */
++ break;
++ case TI953_ID:
++ reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 |
++ (priv->gpio[1] & 0x1) << 1 |
++ (priv->gpio[2] & 0x1) << 2 |
++ (priv->gpio[3] & 0x1) << 3 |
++ (priv->gpio[0] & 0x2) << 3 |
++ (priv->gpio[1] & 0x2) << 4 |
++ (priv->gpio[2] & 0x2) << 5 |
++ (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */
++ reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) |
++ (!!priv->gpio[1] << 5) |
++ (!!priv->gpio[2] << 6) |
++ (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */
++ reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */
++ reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */
++ break;
++ }
++ client->addr = priv->des_addr;
++
++ reg8_write(client, 0x6e, 0x88 | (priv->gpio[1] << 4) | priv->gpio[0]); /* Remote GPIO1/GPIO0 setup */
++ reg8_write(client, 0x6f, 0x88 | (priv->gpio[3] << 4) | priv->gpio[2]); /* Remote GPIO3/GPIO2 setup */
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ti9x4_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ int ret;
++ u8 val = 0;
++
++ ret = reg8_read(client, (u8)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u8);
++
++ return 0;
++}
++
++static int ti9x4_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ return reg8_write(client, (u8)reg->reg, (u8)reg->val);
++}
++#endif
++
++static int ti9x4_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ if (on) {
++ if (atomic_inc_return(&priv->use_count) == 1)
++ reg8_write(client, 0x20, 0x00 | priv->csi_map); /* enable port forwarding to CSI */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding to CSI */
++ }
++
++ return 0;
++}
++
++static int ti9x4_registered_async(struct v4l2_subdev *sd)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */
++ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
++// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */
++
++ return 0;
++}
++
++static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
++{
++ struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier);
++ int idx;
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx]))
++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
++ }
++
++ return NOTIFY_OK;
++}
++
++static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ti9x4_g_register,
++ .s_register = ti9x4_s_register,
++#endif
++ .s_power = ti9x4_s_power,
++ .registered_async = ti9x4_registered_async,
++};
++
++static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ return 0;
++}
++
++static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ int f_time;
++
++ f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++ reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */
++ reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */
++
++ priv->fps_denominator = cp->timeperframe.denominator;
++ priv->fps_numerator = cp->timeperframe.numerator;
++ }
++
++ return 0;
++}
++
++static struct v4l2_subdev_video_ops ti9x4_video_ops = {
++ .g_parm = ti9x4_g_parm,
++ .s_parm = ti9x4_s_parm,
++};
++
++static struct v4l2_subdev_ops ti9x4_subdev_ops = {
++ .core = &ti9x4_subdev_core_ops,
++ .video = &ti9x4_video_ops,
++};
++
++static int ti9x4_parse_dt(struct i2c_client *client)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ struct property *prop;
++ int i;
++ int sensor_delay;
++ char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */
++ struct property *csi_rate_prop, *dvp_order_prop;
++ u8 val = 0;
++ char name[10];
++
++ if (of_property_read_u32(np, "ti,links", &priv->links))
++ priv->links = 4;
++
++ if (of_property_read_u32(np, "ti,lanes", &priv->lanes))
++ priv->lanes = 4;
++
++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
++ if (!IS_ERR(priv->ref_clk)) {
++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
++ v4l2_clk_enable(priv->ref_clk);
++ }
++
++ priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH);
++ if (!IS_ERR(priv->pwen)) {
++ mdelay(5);
++ gpiod_direction_output(priv->pwen, 0);
++ mdelay(5);
++ }
++
++ for (i = 0; i < 4; i++) {
++ sprintf(name, "POC%d", i);
++ priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(name, GFP_KERNEL), 0);
++ }
++
++ reg8_read(client, 0x00, &val); /* read TI9x4 I2C address */
++ if (val != (priv->des_addr << 1)) {
++ prop = of_find_property(np, "reg", NULL);
++ if (prop)
++ of_remove_property(np, prop);
++ return -ENODEV;
++ }
++
++ ti9x4_read_chipid(client);
++
++#ifdef TI954_SILICON_ERRATA
++ indirect_write(client, 7, 0x15, 0x30);
++ if (pwen > 0)
++ gpio_set_value(pwen, 1);
++ usleep_range(5000, 5500); /* wait 5ms */
++ indirect_write(client, 7, 0x15, 0);
++#endif
++ if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay))
++ mdelay(sensor_delay);
++ if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode))
++ priv->forwarding_mode = forwarding_mode_default;
++ if (of_property_read_bool(np, "ti,stp"))
++ priv->is_coax = 0;
++ else
++ priv->is_coax = 1;
++ if (of_property_read_u32(np, "ti,dvp_bus", &priv->dvp_bus))
++ priv->dvp_bus = 8;
++ if (of_property_read_bool(np, "ti,dvp_lsb"))
++ priv->dvp_lsb = 1;
++ else
++ priv->dvp_lsb = 0;
++ if (of_property_read_u32(np, "ti,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "ti,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "ti,ser_id", &priv->ser_id))
++ priv->ser_id = TI913_ID;
++ if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 10;
++ if (of_property_read_u32(np, "ti,vc-map", &priv->vc_map))
++ priv->vc_map = 0x3210;
++ for (i = 0; i < 4; i++) {
++ sprintf(name, "ti,gpio%d", i);
++ if (of_property_read_u32(np, name, &priv->gpio[i]))
++ priv->gpio[i] = 0;
++ }
++
++ /*
++ * CSI forwarding of all links is to CSI0 by default.
++ * Decide if any link will be forwarded to CSI1 instead CSI0
++ */
++ prop = of_find_property(np, "ti,csi1-links", NULL);
++ if (prop) {
++ const __be32 *link = NULL;
++ u32 v;
++
++ for (i = 0; i < 4; i++) {
++ link = of_prop_next_u32(prop, link, &v);
++ if (!link)
++ break;
++ priv->csi_map |= BIT(v);
++ }
++ } else {
++ priv->csi_map = 0;
++ }
++
++ /* module params override dts */
++ if (is_stp)
++ priv->is_coax = 0;
++ if (dvp_bus != 8)
++ priv->dvp_bus = dvp_bus;
++ if (dvp_lsb)
++ priv->dvp_lsb = dvp_lsb;
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (ser_id)
++ priv->ser_id = ser_id;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (vc_map != 0x3210)
++ priv->vc_map = vc_map;
++ if (csi_map)
++ priv->csi_map = csi_map;
++ if (gpio0)
++ priv->gpio[0] = gpio0;
++ if (gpio1)
++ priv->gpio[1] = gpio1;
++ if (gpio2)
++ priv->gpio[2] = gpio2;
++ if (gpio3)
++ priv->gpio[3] = gpio3;
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (i < priv->links) {
++ if (of_property_read_u32(endpoint, "ti9x3-addr", &priv->ti9x3_addr_map[i])) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "ti9x3-addr not set\n");
++ return -EINVAL;
++ }
++ priv->sd_fwnode[i] = of_fwnode_handle(endpoint);
++ }
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (csi_rate_prop) {
++ of_property_read_u32(endpoint, "csi-rate", &priv->csi_rate);
++ of_update_property(rendpoint, csi_rate_prop);
++ }
++
++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (dvp_order_prop)
++ of_update_property(rendpoint, dvp_order_prop);
++ }
++
++ of_node_put(endpoint);
++ return 0;
++}
++
++static int ti9x4_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ti9x4_priv *priv;
++ int err, i;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ i2c_set_clientdata(client, priv);
++ priv->des_addr = client->addr;
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
++
++ err = ti9x4_parse_dt(client);
++ if (err)
++ goto out;
++
++ err = ti9x4_initialize(client);
++ if (err < 0)
++ goto out;
++
++ for (i = 0; i < priv->links; i++) {
++ v4l2_subdev_init(&priv->sd[i], &ti9x4_subdev_ops);
++ priv->sd[i].owner = client->dev.driver->owner;
++ priv->sd[i].dev = &client->dev;
++ priv->sd[i].grp_id = i;
++ v4l2_set_subdevdata(&priv->sd[i], priv);
++ priv->sd[i].fwnode = priv->sd_fwnode[i];
++
++ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x",
++ client->dev.driver->name, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ err = v4l2_async_register_subdev(&priv->sd[i]);
++ if (err < 0)
++ goto out;
++ }
++
++ priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier;
++ err = register_reboot_notifier(&priv->reboot_notifier);
++ if (err)
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++
++out:
++ return err;
++}
++
++static int ti9x4_remove(struct i2c_client *client)
++{
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ unregister_reboot_notifier(&priv->reboot_notifier);
++
++ for (i = 0; i < priv->links; i++) {
++ v4l2_async_unregister_subdev(&priv->sd[i]);
++ v4l2_device_unregister_subdev(&priv->sd[i]);
++ }
++
++ return 0;
++}
++
++static const struct of_device_id ti9x4_dt_ids[] = {
++ { .compatible = "ti,ti9x4" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, ti9x4_dt_ids);
++
++static const struct i2c_device_id ti9x4_id[] = {
++ { "ti9x4", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ti9x4_id);
++
++static struct i2c_driver ti9x4_i2c_driver = {
++ .driver = {
++ .name = "ti9x4",
++ .of_match_table = of_match_ptr(ti9x4_dt_ids),
++ },
++ .probe = ti9x4_probe,
++ .remove = ti9x4_remove,
++ .id_table = ti9x4_id,
++};
++
++module_i2c_driver(ti9x4_i2c_driver);
++
++MODULE_DESCRIPTION("FPDLinkIII driver for DS90UB9x4");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
+new file mode 100644
+index 0000000..6825f8a
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
+@@ -0,0 +1,204 @@
++/*
++ * TI FPDLinkIII driver include file
++ *
++ * Copyright (C) 2017 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#ifndef _TI9X4_H
++#define _TI9X4_H
++
++//#define DEBUG
++#ifdef DEBUG
++#undef dev_dbg
++#define dev_dbg dev_info
++#endif
++
++#define MAXIM_NUM_RETRIES 1 /* number of read/write retries */
++#define TI913_ID 0x58
++#define TI953_ID 0x30 /* or starapped to 0x32 */
++#define TI9X4_ID 0x00 /* strapped */
++#define BROADCAST 0x6f
++
++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val)
++{
++ int ret, retries;
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_read_byte_data(client, reg);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ret;
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val)
++{
++ int ret, retries;
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_write_byte_data(client, reg, val);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 1);
++ if (ret == 1)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = buf[0];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
++{
++ int ret, retries;
++ u8 buf[3] = {reg >> 8, reg & 0xff, val};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 3);
++ if (ret == 3)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, val, n);
++ if (ret == n)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
++{
++ int ret, retries;
++ u8 buf[2 + n];
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ memcpy(&buf[2], val, n);
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2 + n);
++ if (ret == 2 + n)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 2);
++ if (ret == 2)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ((u16)buf[0] << 8) | buf[1];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
++{
++ int ret, retries;
++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++
++ for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 4);
++ if (ret == 4)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++#endif /* _TI9X4_H */
++
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Kconfig b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+new file mode 100644
+index 0000000..c7a33bf
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+@@ -0,0 +1,11 @@
++config SOC_CAMERA_MAX9286
++ tristate "max9286 GMSL support"
++ depends on I2C
++ help
++ This is a MAXIM max9286 GMSL driver
++
++config SOC_CAMERA_MAX9288
++ tristate "max9288 GMSL support"
++ depends on I2C
++ help
++ This is a MAXIM max9288 GMSL driver
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Makefile b/drivers/media/i2c/soc_camera/gmsl/Makefile
+new file mode 100644
+index 0000000..9925314
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o
++obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9286.c b/drivers/media/i2c/soc_camera/gmsl/max9286.c
+new file mode 100644
+index 0000000..2d56b41
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9286.c
+@@ -0,0 +1,1072 @@
++/*
++ * MAXIM max9286 GMSL driver
++ *
++ * Copyright (C) 2015-2018 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "../max9286.h"
++
++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++
++struct max9286_priv {
++ struct v4l2_subdev sd[4];
++ struct fwnode_handle *sd_fwnode[4];
++ int des_addr;
++ int des_quirk_addr; /* second MAX9286 on the same I2C bus */
++ int links;
++ int links_mask;
++ int lanes;
++ int csi_rate;
++ const char *fsync_mode;
++ int fsync_period;
++ int fps_numerator;
++ int fps_denominator;
++ int pclk;
++ char pclk_rising_edge;
++ int gpio_resetb;
++ int active_low_resetb;
++ int him;
++ int hsync;
++ int vsync;
++ int timeout;
++ int poc_delay;
++ int bws;
++ int dbl;
++ int dt;
++ int hsgen;
++ u64 crossbar;
++ char cb[16];
++ int hts;
++ int vts;
++ int hts_delay;
++ int imager_width;
++ atomic_t use_count;
++ u32 csi2_outord;
++ u32 switchin;
++ struct i2c_client *client;
++ int max9271_addr_map[4];
++ int ser_id;
++ struct gpio_desc *poc_gpio[4]; /* PoC power supply */
++ struct notifier_block reboot_notifier;
++
++ /* link statistic */
++ int prbserr[4];
++ int deterr[4];
++ int correrr[4];
++};
++
++static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int fsync_period;
++module_param(fsync_period, int, 0644);
++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = 3;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14");
++
++static int hsgen;
++module_param(hsgen, int, 0644);
++MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)");
++
++static int pclk = 100;
++module_param(pclk, int, 0644);
++MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)");
++
++static int switchin = 0;
++module_param(switchin, int, 0644);
++MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)");
++
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
++MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)");
++
++enum {
++ RGB888_DT = 0,
++ RGB565_DT,
++ RGB666_DT,
++ YUV8_DT, /* default */
++ YUV10_DT,
++ RAW8_DT,
++ RAW10_DT,
++ RAW12_DT,
++ RAW14_DT,
++};
++
++static int dt2bpp [9] = {
++ 24, /* RGB888 */
++ 16, /* RGB565 */
++ 18, /* RGB666 */
++ 8, /* YUV8 - default */
++ 10, /* YUV10 */
++ 8, /* RAW8/RAW16 */
++ 10, /* RAW10 */
++ 12, /* RAW12 */
++ 14, /* RAW14 */
++};
++
++static char* ser_name(int id)
++{
++ switch (id) {
++ case MAX9271_ID:
++ return "MAX9271";
++ case MAX96705_ID:
++ return "MAX96705";
++ case MAX96707_ID:
++ return "MAX96707";
++ default:
++ return "unknown";
++ }
++}
++
++static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ int tmp_addr;
++ u8 sts = 0;
++ u8 val2 = 0;
++
++ reg8_write(client, reg, val);
++
++ tmp_addr = client->addr;
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_read(client, 0x70, &sts);
++ client->addr = tmp_addr;
++ if (sts & BIT(idx)) /* if ACKed */ {
++ reg8_read(client, reg, &val2);
++ if (val2 == val)
++ break;
++ }
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&client->dev, "timeout remote write acked\n");
++}
++
++static void max9286_preinit(struct i2c_client *client, int addr)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++
++ client->addr = addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */
++ reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */
++// usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x1b, priv->switchin); /* coax polarity (default - normal) */
++ reg8_write(client, 0x1c, (priv->him ? 0xf0 : 0x00) |
++ (priv->bws ? 0x05 : 0x04)); /* high-immunity/legacy mode, BWS 24bit */
++}
++
++static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return;
++
++ if (priv->active_low_resetb)
++ reset_on = !reset_on;
++
++ /* sensor reset/unreset using serializer gpio */
++ client->addr = addr;
++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */
++ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++}
++
++static void max9286_postinit(struct i2c_client *client, int addr)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ int idx;
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID)
++ continue;
++
++ client->addr = priv->des_addr; /* MAX9286 I2C */
++ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */
++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */
++ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */
++
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */
++ max9286_sensor_reset(client, client->addr, 0); /* sensor unreset using gpios. TODO: should be in imager driver */
++ }
++
++ client->addr = addr; /* MAX9286 I2C */
++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */
++ reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */
++ reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */
++ reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */
++ reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */
++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */
++
++ if (strcmp(priv->fsync_mode, "manual") == 0) {
++ reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */
++ } else if (strcmp(priv->fsync_mode, "automatic") == 0) {
++ reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */
++ } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) {
++ reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */
++ } else if (strcmp(priv->fsync_mode, "external") == 0) {
++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */
++ }
++}
++
++static int max9286_reverse_channel_setup(struct i2c_client *client, int idx)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ u8 val = 0, lock_sts = 0, link_sts = 0;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ int ret = 0;
++
++ /* Reverse channel enable */
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */
++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++
++ for (;;) {
++ if (priv->him) {
++ /* HIM mode setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x4d, 0xc0);
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ if (priv->bws) {
++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++ } else {
++ /* Legacy mode setup */
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */
++ reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */
++ reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ if (priv->bws) {
++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_read(client, 0x1e, &val); /* read max9271 ID */
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) {
++ priv->ser_id = val;
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */
++ reg8_read(client, 0x1e, &val); /* read max9271 ID */
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ priv->ser_id = val;
++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(priv->poc_gpio[idx]) && (timeout % poc_trig == 0)) {
++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
++ mdelay(200);
++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max9286_sensor_reset(client, client->addr, 1); /* sensor reset */
++
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_read(client, 0x27, &lock_sts); /* LOCK status */
++ reg8_read(client, 0x49, &link_sts); /* LINK status */
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ priv->links_mask |= BIT(idx);
++ priv->csi2_outord &= ~(0x3 << (idx * 2));
++ priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2));
++
++out:
++ sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx));
++ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id),
++ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx],
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++
++ return ret;
++}
++
++static void max9286_initial_setup(struct i2c_client *client)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++
++ /* Initial setup */
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */
++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
++ reg8_write(client, 0x12, ((priv->lanes - 1) << 6) |
++ (priv->dbl ? 0x30 : 0) |
++ (priv->dt & 0xf)); /* setup lanes, DBL mode, DataType */
++
++ /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */
++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */
++ reg8_write(client, 0x06, priv->fsync_period & 0xff);
++ reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff);
++ reg8_write(client, 0x08, priv->fsync_period >> 16);
++
++ reg8_write(client, 0x63, 0); /* disable overlap window */
++ reg8_write(client, 0x64, 0);
++ reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */
++ reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */
++}
++
++static void max9286_gmsl_link_setup(struct i2c_client *client, int idx)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++
++ /* GMSL setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms */
++ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500); /* wait 2ms */
++
++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) {
++ switch (priv->dt) {
++ case YUV8_DT:
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ reg8_write(client, 0x20, priv->cb[7]);
++ reg8_write(client, 0x21, priv->cb[6]);
++ reg8_write(client, 0x22, priv->cb[5]);
++ reg8_write(client, 0x23, priv->cb[4]);
++ reg8_write(client, 0x24, priv->cb[3]);
++ reg8_write(client, 0x25, priv->cb[2]);
++ reg8_write(client, 0x26, priv->cb[1]);
++ reg8_write(client, 0x27, priv->cb[0]);
++
++ /* this is second byte if DBL=1 */
++ reg8_write(client, 0x30, priv->cb[7] + 16);
++ reg8_write(client, 0x31, priv->cb[6] + 16);
++ reg8_write(client, 0x32, priv->cb[5] + 16);
++ reg8_write(client, 0x33, priv->cb[4] + 16);
++ reg8_write(client, 0x34, priv->cb[3] + 16);
++ reg8_write(client, 0x35, priv->cb[2] + 16);
++ reg8_write(client, 0x36, priv->cb[1] + 16);
++ reg8_write(client, 0x37, priv->cb[0] + 16);
++ break;
++ case RAW12_DT:
++ /* setup crossbar for RAW12: reverse DVP bus */
++ reg8_write(client, 0x20, priv->cb[11]);
++ reg8_write(client, 0x21, priv->cb[10]);
++ reg8_write(client, 0x22, priv->cb[9]);
++ reg8_write(client, 0x23, priv->cb[8]);
++ reg8_write(client, 0x24, priv->cb[7]);
++ reg8_write(client, 0x25, priv->cb[6]);
++ reg8_write(client, 0x26, priv->cb[5]);
++ reg8_write(client, 0x27, priv->cb[4]);
++ reg8_write(client, 0x28, priv->cb[3]);
++ reg8_write(client, 0x29, priv->cb[2]);
++ reg8_write(client, 0x2a, priv->cb[1]);
++ reg8_write(client, 0x2b, priv->cb[0]);
++
++ /* this is second byte if DBL=1 */
++ reg8_write(client, 0x30, priv->cb[11] + 16);
++ reg8_write(client, 0x31, priv->cb[10] + 16);
++ reg8_write(client, 0x32, priv->cb[9] + 16);
++ reg8_write(client, 0x33, priv->cb[8] + 16);
++ reg8_write(client, 0x34, priv->cb[7] + 16);
++ reg8_write(client, 0x35, priv->cb[6] + 16);
++ reg8_write(client, 0x36, priv->cb[5] + 16);
++ reg8_write(client, 0x37, priv->cb[4] + 16);
++ reg8_write(client, 0x38, priv->cb[3] + 16);
++ reg8_write(client, 0x39, priv->cb[2] + 16);
++ reg8_write(client, 0x3a, priv->cb[1] + 16);
++ reg8_write(client, 0x3b, priv->cb[0] + 16);
++
++ if (!priv->bws && priv->dbl)
++ dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++
++ break;
++ }
++
++ if (priv->hsgen) {
++ /* HS/VS pins map */
++ reg8_write(client, 0x3f, 0x10); /* HS (NC) */
++ reg8_write(client, 0x41, 0x10); /* DE (NC) */
++ if (priv->ser_id == MAX96705_ID)
++ reg8_write(client, 0x40, 15); /* VS (DIN13) */
++ if (priv->ser_id == MAX96707_ID)
++ reg8_write(client, 0x40, 13); /* VS (DIN13) */
++#if 0
++ /* following must come from imager */
++#define SENSOR_WIDTH (1280*2)
++#define HTS (1288*2)
++#define VTS 960
++#define HTS_DELAY 0x9
++ reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */
++ reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff);
++ reg8_write(client, 0x50, HTS_DELAY & 0xff);
++ reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */
++ reg8_write(client, 0x55, SENSOR_WIDTH & 0xff);
++ reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */
++ reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff);
++ reg8_write(client, 0x58, VTS >> 8); /* HS count */
++ reg8_write(client, 0x59, VTS & 0xff );
++#endif
++ reg8_write(client, 0x43, 0x15); /* enable HS generator */
++ }
++ }
++
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ usleep_range(2000, 2500); /* wait 2ms */
++
++ /* I2C translator setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */
++// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
++ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */
++ reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */
++ /* I2C addresse change */
++ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */
++ reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */
++ usleep_range(2000, 2500); /* wait 2ms */
++ /* put MAX9271 in configuration link state */
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */
++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms */
++#ifdef MAXIM_DUMP
++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
++ maxim_max927x_dump_regs(client);
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */
++ maxim_max927x_dump_regs(client);
++#endif
++}
++
++static int max9286_initialize(struct i2c_client *client)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ int idx, ret;
++
++ dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n",
++ priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period,
++ priv->pclk_rising_edge ? "rising" : "falling");
++
++ if (priv->des_quirk_addr)
++ max9286_preinit(client, priv->des_quirk_addr);
++
++ max9286_preinit(client, priv->des_addr);
++ max9286_initial_setup(client);
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx])) {
++ gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
++ mdelay(priv->poc_delay);
++ }
++
++ ret = max9286_reverse_channel_setup(client, idx);
++ if (ret)
++ continue;
++ max9286_gmsl_link_setup(client, idx);
++ }
++
++ max9286_postinit(client, priv->des_addr);
++
++ client->addr = priv->des_addr;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max9286_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ int ret;
++ u8 val = 0;
++
++ ret = reg8_read(client, (u8)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u8);
++
++ return 0;
++}
++
++static int max9286_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ return reg8_write(client, (u8)reg->reg, (u8)reg->val);
++}
++#endif
++
++static int max9286_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ if (on) {
++ if (atomic_inc_return(&priv->use_count) == 1)
++ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
++ }
++
++ return 0;
++}
++
++static int max9286_registered_async(struct v4l2_subdev *sd)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ int idx, tmp_addr;
++
++ /* switch to GMSL serial_link for streaming video */
++ tmp_addr = client->addr;
++ idx = sd->grp_id;
++
++ client->addr = priv->des_addr; /* MAX9286 I2C */
++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */
++
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */
++ max9286_write_remote_verify(client, idx, 0x04, conf_link ? 0x43 : 0x83);
++// usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
++
++ client->addr = priv->des_addr; /* MAX9286 I2C */
++ reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */
++
++ client->addr = tmp_addr;
++
++ return 0;
++}
++
++static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
++{
++ struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier);
++ int idx;
++
++ for (idx = 0; idx < priv->links; idx++) {
++ if (!IS_ERR(priv->poc_gpio[idx]))
++ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
++ }
++
++ return NOTIFY_OK;
++}
++
++static struct v4l2_subdev_core_ops max9286_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max9286_g_register,
++ .s_register = max9286_s_register,
++#endif
++ .s_power = max9286_s_power,
++ .registered_async = max9286_registered_async,
++};
++
++static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ return 0;
++}
++
++static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ int f_period;
++
++ f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++ reg8_write(client, 0x06, f_period & 0xff);
++ reg8_write(client, 0x07, (f_period >> 8) & 0xff);
++ reg8_write(client, 0x08, f_period >> 16);
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return 0;
++}
++
++static struct v4l2_subdev_video_ops max9286_video_ops = {
++ .g_parm = max9286_g_parm,
++ .s_parm = max9286_s_parm,
++};
++
++static struct v4l2_subdev_ops max9286_subdev_ops = {
++ .core = &max9286_subdev_core_ops,
++ .video = &max9286_video_ops,
++};
++
++static int max9286_parse_dt(struct i2c_client *client)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL;
++ struct property *prop;
++ int err, pwen, i;
++ int sensor_delay, gpio0 = 1, gpio1 = 1;
++ u8 val = 0;
++ char poc_name[10];
++
++ if (of_property_read_u32(np, "maxim,links", &priv->links))
++ priv->links = 4;
++
++ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes))
++ priv->lanes = 4;
++
++ pwen = of_get_gpio(np, 0);
++ if (pwen > 0) {
++ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev));
++ if (err)
++ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err);
++ }
++
++ mdelay(250);
++
++ for (i = 0; i < 4; i++) {
++ sprintf(poc_name, "POC%d", i);
++ priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0);
++ }
++
++ reg8_read(client, 0x1e, &val); /* read max9286 ID */
++ if (val != MAX9286_ID) {
++ prop = of_find_property(np, "reg", NULL);
++ if (prop)
++ of_remove_property(np, prop);
++ return -ENODEV;
++ }
++
++ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) ||
++ !of_property_read_u32(np, "maxim,gpio1", &gpio1))
++ reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0);
++
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++
++ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay))
++ mdelay(sensor_delay);
++ if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode))
++ priv->fsync_mode = fsync_mode_default;
++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
++ priv->fsync_period = 3200000; /* 96MHz/30fps */
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr))
++ priv->des_quirk_addr = 0;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = 3;
++ if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen))
++ priv->hsgen = 0;
++ if (of_property_read_u32(np, "maxim,pclk", &priv->pclk))
++ priv->pclk = pclk;
++ if (of_property_read_u32(np, "maxim,switchin", &priv->switchin))
++ priv->switchin = 0;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
++
++ /* module params override dts */
++ if (him)
++ priv->him = him;
++ if (fsync_period) {
++ priv->fsync_period = fsync_period;
++ priv->fsync_mode = fsync_mode_default;
++ }
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != 3)
++ priv->dt = dt;
++ if (hsgen)
++ priv->hsgen = hsgen;
++ if (pclk != 100)
++ priv->pclk = pclk;
++ if (switchin)
++ priv->switchin = switchin;
++
++ /* parse crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
++ }
++
++ for (i = 0; i < priv->links; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "max9271-addr not set\n");
++ return -EINVAL;
++ }
++
++ priv->sd_fwnode[i] = of_fwnode_handle(endpoint);
++ }
++
++ of_node_put(endpoint);
++ return 0;
++}
++
++static void max9286_setup_remote_endpoint(struct i2c_client *client)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ int i;
++ struct property *csi_rate_prop, *dvp_order_prop;
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (csi_rate_prop) {
++ /* CSI2_RATE = PCLK*bpp*links/lanes */
++ priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] * hweight8(priv->links_mask) / priv->lanes);
++ csi_rate_prop->value = &priv->csi_rate;
++ of_update_property(rendpoint, csi_rate_prop);
++ }
++
++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (dvp_order_prop)
++ of_update_property(rendpoint, dvp_order_prop);
++ }
++
++ of_node_put(endpoint);
++}
++
++static const char *line_status[] =
++{
++ "BAT",
++ "GND",
++ "NORMAL",
++ "OPEN"
++};
++
++static ssize_t max9286_link_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i = -1;
++ u8 val = 0;
++ bool lenghterr, linebuffof, hlocked, prbsok, vsyncdet, configdet, videodet;
++ int lf;
++ u8 prbserr = 0, deterr = 0, correrr = 0;
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++
++ if (!sscanf(attr->attr.name, "link_%d", &i))
++ return -EINVAL;
++
++ if ((i < 0) || (i > 3))
++ return -EINVAL;
++
++ reg8_read(client, 0x20, &val);
++ lf = (val >> (2 * i)) & 0x03;
++
++ reg8_read(client, 0x21, &val);
++ hlocked = !!(val & (1 << i));
++ prbsok = !!(val & (1 << (i + 4)));
++
++ reg8_read(client, 0x22, &val);
++ lenghterr = !!(val & (1 << i));
++ linebuffof = !!(val & (1 << (i + 4)));
++
++ reg8_read(client, 0x23 + i, &prbserr);
++ priv->prbserr[i] += prbserr;
++
++ reg8_read(client, 0x27, &val);
++ vsyncdet = !!(val & (1 << i));
++
++ reg8_read(client, 0x28 + i, &deterr);
++ priv->deterr[i] += deterr;
++
++ reg8_read(client, 0x2c + i, &correrr);
++ priv->correrr[i] += correrr;
++
++ reg8_read(client, 0x49, &val);
++ configdet = !!(val & (1 << i));
++ videodet = !!(val & (1 << (i + 4)));
++
++ return sprintf(buf, "LINK:%d LF:%s HLOCKED:%d PRBSOK:%d LINBUFFOF:%d"
++ " LENGHTERR:%d VSYNCDET:%d CONFIGDET:%d VIDEODET:%d"
++ " PRBSERR:%d(%d) DETEERR:%d(%d) CORRERR:%d(%d)\n",
++ i, line_status[lf], hlocked, prbsok, lenghterr,
++ linebuffof, vsyncdet, configdet, videodet,
++ priv->prbserr[i], prbserr,
++ priv->deterr[i], deterr,
++ priv->correrr[i], correrr);
++ return 0;
++}
++
++static DEVICE_ATTR(link_0, S_IRUGO, max9286_link_show, NULL);
++static DEVICE_ATTR(link_1, S_IRUGO, max9286_link_show, NULL);
++static DEVICE_ATTR(link_2, S_IRUGO, max9286_link_show, NULL);
++static DEVICE_ATTR(link_3, S_IRUGO, max9286_link_show, NULL);
++
++static struct attribute *max9286_attributes_links[] = {
++ &dev_attr_link_0.attr,
++ &dev_attr_link_1.attr,
++ &dev_attr_link_2.attr,
++ &dev_attr_link_3.attr,
++ NULL
++};
++
++static const struct attribute_group max9286_group = {
++ .attrs = max9286_attributes_links,
++};
++
++static int max9286_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max9286_priv *priv;
++ int err, i;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ i2c_set_clientdata(client, priv);
++ priv->des_addr = client->addr;
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++ priv->csi2_outord = 0xff;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
++
++ err = max9286_parse_dt(client);
++ if (err)
++ goto out;
++
++ err = max9286_initialize(client);
++ if (err < 0)
++ goto out;
++
++ max9286_setup_remote_endpoint(client);
++
++ for (i = 0; i < 4; i++) {
++ v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops);
++ priv->sd[i].owner = client->dev.driver->owner;
++ priv->sd[i].dev = &client->dev;
++ priv->sd[i].grp_id = i;
++ v4l2_set_subdevdata(&priv->sd[i], priv);
++ priv->sd[i].fwnode = priv->sd_fwnode[i];
++
++ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
++ client->dev.driver->name, i, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ err = v4l2_async_register_subdev(&priv->sd[i]);
++ if (err < 0)
++ goto out;
++ }
++
++ priv->reboot_notifier.notifier_call = max9286_reboot_notifier;
++ err = register_reboot_notifier(&priv->reboot_notifier);
++ if (err) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
++ err = sysfs_create_group(&client->dev.kobj,
++ &max9286_group);
++ if (err < 0)
++ dev_err(&client->dev, "Sysfs registration failed\n");
++out:
++ return err;
++}
++
++static int max9286_remove(struct i2c_client *client)
++{
++ struct max9286_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ sysfs_remove_group(&client->dev.kobj, &max9286_group);
++ unregister_reboot_notifier(&priv->reboot_notifier);
++
++ for (i = 0; i < 4; i++) {
++ v4l2_async_unregister_subdev(&priv->sd[i]);
++ v4l2_device_unregister_subdev(&priv->sd[i]);
++ }
++
++ return 0;
++}
++
++static const struct of_device_id max9286_dt_ids[] = {
++ { .compatible = "maxim,max9286" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max9286_dt_ids);
++
++static const struct i2c_device_id max9286_id[] = {
++ { "max9286", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max9286_id);
++
++static struct i2c_driver max9286_i2c_driver = {
++ .driver = {
++ .name = "max9286",
++ .of_match_table = of_match_ptr(max9286_dt_ids),
++ },
++ .probe = max9286_probe,
++ .remove = max9286_remove,
++ .id_table = max9286_id,
++};
++
++module_i2c_driver(max9286_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL driver for MAX9286");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9288.c b/drivers/media/i2c/soc_camera/gmsl/max9288.c
+new file mode 100644
+index 0000000..7de1f9e
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9288.c
+@@ -0,0 +1,768 @@
++/*
++ * MAXIM max9288 GMSL driver
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "../max9286.h"
++
++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++
++struct max9288_priv {
++ struct v4l2_subdev sd;
++ struct fwnode_handle *sd_fwnode;
++ int des_addr;
++ int lanes;
++ int csi_rate;
++ int pclk;
++ char pclk_rising_edge;
++ int gpio_resetb;
++ int active_low_resetb;
++ int him;
++ int hsync;
++ int vsync;
++ int timeout;
++ int poc_delay;
++ int bws;
++ int dbl;
++ int dt;
++ int hsgen;
++ int hts;
++ int vts;
++ int hts_delay;
++ struct i2c_client *client;
++ int max9271_addr;
++ int ser_id;
++ struct gpio_desc *poc_gpio; /* PoC power supply */
++};
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him = 0;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws = 0;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = 3;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14");
++
++static int hsgen;
++module_param(hsgen, int, 0644);
++MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)");
++
++static int pclk = 100;
++module_param(pclk, int, 0644);
++MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)");
++
++enum {
++ RGB888_DT = 0,
++ RGB565_DT,
++ RGB666_DT,
++ YUV8_DT, /* default */
++ YUV10_DT,
++ RAW8_DT,
++ RAW10_DT,
++ RAW12_DT,
++ RAW14_DT,
++};
++
++static int dt2bpp [9] = {
++ 24, /* RGB888 */
++ 16, /* RGB565 */
++ 18, /* RGB666 */
++ 8, /* YUV8 - default */
++ 10, /* YUV10 */
++ 8, /* RAW8/RAW16 */
++ 10, /* RAW10 */
++ 12, /* RAW12 */
++ 14, /* RAW14 */
++};
++
++static char* ser_name(int id)
++{
++ switch (id) {
++ case MAX9271_ID:
++ return "MAX9271";
++ case MAX96705_ID:
++ return "MAX96705";
++ case MAX96707_ID:
++ return "MAX96707";
++ default:
++ return "unknown";
++ }
++}
++
++static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ u8 val2 = 0;
++
++ reg8_write(client, reg, val);
++ reg8_read(client, reg, &val2);
++ if (val2 == val)
++ break;
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&client->dev, "timeout remote write acked\n");
++}
++
++
++static void max9288_preinit(struct i2c_client *client, int addr)
++{
++
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ client->addr = addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x04, 0x00); /* disable reverse control */
++ reg8_write(client, 0x16, (priv->him ? 0x80 : 0x00) |
++ 0x5a); /* high-immunity/legacy mode */
++}
++
++static void max9288_sensor_reset(struct i2c_client *client, int addr, int reset_on)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return;
++
++ /* sensor reset/unreset */
++ client->addr = addr; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++}
++
++static int max9288_reverse_channel_setup(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++ u8 val = 0, lock_sts = 0;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ int ret = 0;
++
++ /* Reverse channel enable */
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x1c, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x04, 0x03); /* enable reverse control */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++
++ for (;;) {
++ if (priv->him) {
++ /* HIM mode setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x4d, 0xc0);
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ if (priv->bws) {
++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS disabled enabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++ } else {
++ /* Legacy mode setup */
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x13, 0x00);
++ reg8_write(client, 0x11, 0x42); /* enable custom reverse channel & first pulse length */
++ reg8_write(client, 0x0a, 0x0f); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ if (priv->bws) {
++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++ reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x0a, 0x0c); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
++ reg8_write(client, 0x13, 0x20); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ }
++
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_read(client, 0x1e, &val); /* read max9271 ID */
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) {
++ priv->ser_id = val;
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C */
++ reg8_read(client, 0x1e, &val); /* read max9271 ID */
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ priv->ser_id = val;
++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(priv->poc_gpio) && (timeout % poc_trig == 0)) {
++ gpiod_direction_output(priv->poc_gpio, 0); /* POC power off */
++ mdelay(200);
++ gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max9288_sensor_reset(client, client->addr, 1); /* sensor reset */
++
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_read(client, 0x04, &lock_sts); /* LOCK status */
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++out:
++ sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80));
++ dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id),
++ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr,
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++
++ return ret;
++}
++
++static void max9288_initial_setup(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ /* Initial setup */
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x09, 0x40); /* Automatic pixel count enable */
++ reg8_write(client, 0x15, 0x70); /* Enable HV and DE tracking by register 0x69 */
++ reg8_write(client, 0x60, (priv->dbl ? 0x20 : 0) |
++ (priv->dt & 0xf)); /* VC=0, DBL mode, DataType */
++ reg8_write(client, 0x65, 0x47 | ((priv->lanes - 1) << 4)); /* setup CSI lanes, DE input is HS */
++
++ reg8_write(client, 0x08, 0x20); /* use D18/19 for HS/VS */
++ reg8_write(client, 0x14, (priv->vsync ? 0x80 : 0) | (priv->hsync ? 0x40 : 0)); /* setup HS/VS inversion */
++ reg8_write(client, 0x64, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */
++}
++
++static void max9288_gmsl_link_setup(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ /* GMSL setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
++ (priv->dbl ? 0x80 : 0) |
++ (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */
++ usleep_range(2000, 2500); /* wait 2ms */
++ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500); /* wait 2ms */
++
++ if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) {
++ switch (priv->dt) {
++ case YUV8_DT:
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ reg8_write(client, 0x20, 3);
++ reg8_write(client, 0x21, 4);
++ reg8_write(client, 0x22, 5);
++ reg8_write(client, 0x23, 6);
++ reg8_write(client, 0x24, 7);
++ reg8_write(client, 0x25, 0x40);
++ reg8_write(client, 0x26, 0x40);
++ if (priv->ser_id == MAX96705_ID) {
++ reg8_write(client, 0x27, 14); /* HS: D14->D18 */
++ reg8_write(client, 0x28, 15); /* VS: D15->D19 */
++ }
++ if (priv->ser_id == MAX96707_ID) {
++ reg8_write(client, 0x27, 14); /* HS: D14->D18, this is a virtual NC pin, hence it is D14 at HS */
++ reg8_write(client, 0x28, 13); /* VS: D13->D19 */
++ }
++ reg8_write(client, 0x29, 0x40);
++ reg8_write(client, 0x2A, 0x40);
++
++ /* this is second byte if DBL=1 */
++ reg8_write(client, 0x30, 0x10 + 0);
++ reg8_write(client, 0x31, 0x10 + 1);
++ reg8_write(client, 0x32, 0x10 + 2);
++ reg8_write(client, 0x33, 0x10 + 3);
++ reg8_write(client, 0x34, 0x10 + 4);
++ reg8_write(client, 0x35, 0x10 + 5);
++ reg8_write(client, 0x36, 0x10 + 6);
++ reg8_write(client, 0x37, 0x10 + 7);
++ reg8_write(client, 0x38, 0);
++ reg8_write(client, 0x39, 1);
++ reg8_write(client, 0x3A, 2);
++
++ reg8_write(client, 0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
++
++ break;
++ case RAW12_DT:
++#if 0 /* Not supported yet */
++ /* setup crossbar for RAW12: reverse DVP bus */
++ reg8_write(client, 0x20, 11);
++ reg8_write(client, 0x21, 10);
++ reg8_write(client, 0x22, 9);
++ reg8_write(client, 0x23, 8);
++ reg8_write(client, 0x24, 7);
++ reg8_write(client, 0x25, 6);
++ reg8_write(client, 0x26, 5);
++ reg8_write(client, 0x27, 4);
++ reg8_write(client, 0x28, 3);
++ reg8_write(client, 0x29, 2);
++ reg8_write(client, 0x2a, 1);
++ reg8_write(client, 0x2b, 0);
++
++ /* this is second byte if DBL=1 */
++ reg8_write(client, 0x30, 27);
++ reg8_write(client, 0x31, 26);
++ reg8_write(client, 0x32, 25);
++ reg8_write(client, 0x33, 24);
++ reg8_write(client, 0x34, 23);
++ reg8_write(client, 0x35, 22);
++ reg8_write(client, 0x36, 21);
++ reg8_write(client, 0x37, 20);
++ reg8_write(client, 0x38, 19);
++ reg8_write(client, 0x39, 18);
++ reg8_write(client, 0x3a, 17);
++ reg8_write(client, 0x3b, 16);
++
++ if (!priv->bws && priv->dbl)
++ dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++#endif
++ break;
++ }
++
++ if (priv->hsgen) {
++ /* HS/VS pins map */
++ reg8_write(client, 0x3f, 0x10); /* HS (NC) */
++ reg8_write(client, 0x41, 0x10); /* DE (NC) */
++ if (priv->ser_id == MAX96705_ID)
++ reg8_write(client, 0x40, 15); /* VS (DIN13) */
++ if (priv->ser_id == MAX96707_ID)
++ reg8_write(client, 0x40, 13); /* VS (DIN13) */
++#if 0
++ /* following must come from imager */
++#define SENSOR_WIDTH (1280*2)
++#define HTS (1288*2)
++#define VTS 960
++#define HTS_DELAY 0x9
++ reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */
++ reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff);
++ reg8_write(client, 0x50, HTS_DELAY & 0xff);
++ reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */
++ reg8_write(client, 0x55, SENSOR_WIDTH & 0xff);
++ reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */
++ reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff);
++ reg8_write(client, 0x58, VTS >> 8); /* HS count */
++ reg8_write(client, 0x59, VTS & 0xff );
++#endif
++ reg8_write(client, 0x43, 0x15); /* enable HS generator */
++ }
++ }
++
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ reg8_write(client, 0x1c, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ usleep_range(2000, 2500); /* wait 2ms */
++
++ /* I2C translator setup */
++ client->addr = 0x40; /* MAX9271-CAMx I2C */
++// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */
++// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
++ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */
++ reg8_write(client, 0x0C, priv->max9271_addr << 1); /* MAX9271-CAMx I2C new */
++ /* I2C addresse change */
++ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9288 I2C */
++ reg8_write(client, 0x00, priv->max9271_addr << 1); /* MAX9271-CAM0 I2C new */
++ usleep_range(2000, 2500); /* wait 2ms */
++ /* put MAX9271 in configuration link state */
++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
++ usleep_range(2000, 2500); /* wait 2ms */
++#ifdef MAXIM_DUMP
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++ maxim_max927x_dump_regs(client);
++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
++ maxim_max927x_dump_regs(client);
++#endif
++}
++
++static int max9288_initialize(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ dev_info(&client->dev, "LANES=%d, PCLK edge=%s\n",
++ priv->lanes, priv->pclk_rising_edge ? "rising" : "falling");
++
++ max9288_preinit(client, priv->des_addr);
++ max9288_initial_setup(client);
++
++ if (!IS_ERR(priv->poc_gpio)) {
++ gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */
++ mdelay(priv->poc_delay);
++ }
++
++ max9288_reverse_channel_setup(client);
++ max9288_gmsl_link_setup(client);
++
++ client->addr = priv->des_addr;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max9288_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct max9288_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++ int ret;
++ u8 val = 0;
++
++ ret = reg8_read(client, (u8)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u8);
++
++ return 0;
++}
++
++static int max9288_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct max9288_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ return reg8_write(client, (u8)reg->reg, (u8)reg->val);
++}
++#endif
++
++static int max9288_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9288_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
++ max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++
++ return 0;
++}
++
++static struct v4l2_subdev_core_ops max9288_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max9288_g_register,
++ .s_register = max9288_s_register,
++#endif
++ .s_power = max9288_s_power,
++};
++
++static struct v4l2_subdev_ops max9288_subdev_ops = {
++ .core = &max9288_subdev_core_ops,
++};
++
++static int max9288_parse_dt(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL;
++ struct property *prop;
++ int err, pwen;
++ int sensor_delay, gpio0 = 1, gpio1 = 1;
++ u8 val = 0;
++ char poc_name[10];
++
++ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes))
++ priv->lanes = 4;
++
++ pwen = of_get_gpio(np, 0);
++ if (pwen > 0) {
++ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev));
++ if (err)
++ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err);
++ }
++
++ mdelay(250);
++
++ sprintf(poc_name, "POC%d", 0);
++ priv->poc_gpio = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0);
++
++ reg8_read(client, 0x1e, &val); /* read max9288 ID */
++ if (val != MAX9288_ID) {
++ prop = of_find_property(np, "reg", NULL);
++ if (prop)
++ of_remove_property(np, prop);
++ return -ENODEV;
++ }
++
++ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) ||
++ !of_property_read_u32(np, "maxim,gpio1", &gpio1))
++ reg8_write(client, 0x06, (gpio1 << 3) | (gpio0 << 1));
++
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++
++ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay))
++ mdelay(sensor_delay);
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = 3;
++ if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen))
++ priv->hsgen = 0;
++ if (of_property_read_u32(np, "maxim,pclk", &priv->pclk))
++ priv->pclk = pclk;
++
++ /* module params override dts */
++ if (him)
++ priv->him = him;
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != 3)
++ priv->dt = dt;
++ if (hsgen)
++ priv->hsgen = hsgen;
++ if (pclk != 100)
++ priv->pclk = pclk;
++
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (endpoint) {
++ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr)) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "max9271-addr not set\n");
++ return -EINVAL;
++ }
++
++ priv->sd_fwnode = of_fwnode_handle(endpoint);
++ }
++
++ of_node_put(endpoint);
++ return 0;
++}
++
++static void max9288_setup_remote_endpoint(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ int i;
++ struct property *csi_rate_prop, *dvp_order_prop;
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (csi_rate_prop) {
++ /* CSI2_RATE = PCLK*bpp/lanes */
++ priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] / priv->lanes);
++ csi_rate_prop->value = &priv->csi_rate;
++ of_update_property(rendpoint, csi_rate_prop);
++ }
++
++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (dvp_order_prop)
++ of_update_property(rendpoint, dvp_order_prop);
++ }
++
++ of_node_put(endpoint);
++}
++
++static int max9288_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max9288_priv *priv;
++ int err;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ i2c_set_clientdata(client, priv);
++ priv->des_addr = client->addr;
++ priv->client = client;
++
++ err = max9288_parse_dt(client);
++ if (err)
++ goto out;
++
++ err = max9288_initialize(client);
++ if (err < 0)
++ goto out;
++
++ max9288_setup_remote_endpoint(client);
++
++ v4l2_subdev_init(&priv->sd, &max9288_subdev_ops);
++ priv->sd.owner = client->dev.driver->owner;
++ priv->sd.dev = &client->dev;
++ v4l2_set_subdevdata(&priv->sd, priv);
++ priv->sd.fwnode = priv->sd_fwnode;
++
++ snprintf(priv->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x",
++ client->dev.driver->name, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ err = v4l2_async_register_subdev(&priv->sd);
++ if (err < 0)
++ goto out;
++out:
++ return err;
++}
++
++static int max9288_remove(struct i2c_client *client)
++{
++ struct max9288_priv *priv = i2c_get_clientdata(client);
++
++ v4l2_async_unregister_subdev(&priv->sd);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static const struct of_device_id max9288_dt_ids[] = {
++ { .compatible = "maxim,max9288" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max9288_dt_ids);
++
++static const struct i2c_device_id max9288_id[] = {
++ { "max9288", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max9288_id);
++
++static struct i2c_driver max9288_i2c_driver = {
++ .driver = {
++ .name = "max9288",
++ .of_match_table = of_match_ptr(max9288_dt_ids),
++ },
++ .probe = max9288_probe,
++ .remove = max9288_remove,
++ .id_table = max9288_id,
++};
++
++module_i2c_driver(max9288_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL driver for MAX9288");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/Kconfig b/drivers/media/i2c/soc_camera/imagers/Kconfig
+new file mode 100644
+index 0000000..a6ccf62
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/Kconfig
+@@ -0,0 +1,5 @@
++config SOC_CAMERA_OV106XX
++ tristate "ov106xx camera support"
++ depends on I2C
++ help
++ This is a runtime detected GMSL1/GMSL2/FPDLink3 sensors driver
+diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile
+new file mode 100644
+index 0000000..ca10bbc
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/Makefile
+@@ -0,0 +1,2 @@
++# SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o
+diff --git a/drivers/media/i2c/soc_camera/imagers/dummy.c b/drivers/media/i2c/soc_camera/imagers/dummy.c
+new file mode 100644
+index 0000000..d213fff
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/dummy.c
+@@ -0,0 +1,491 @@
++/*
++ * Dummy sensor camera driver
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++struct dummy_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ u8 id[6];
++ int max_width;
++ int max_height;
++ const char * media_bus_format;
++ int mbus_format;
++};
++
++static int width = 1920;
++module_param(width, int, 0644);
++MODULE_PARM_DESC(width, " width (default: 1920)");
++
++static int height = 1080;
++module_param(height, int, 0644);
++MODULE_PARM_DESC(height, " height (default: 1080)");
++
++static char *mbus = "yuyv";
++module_param(mbus, charp, 0644);
++MODULE_PARM_DESC(mbus, " MEDIA_BUS_FORMAT (default: YUYV)");
++
++static inline struct dummy_priv *to_dummy(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct dummy_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd;
++}
++
++static int dummy_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int dummy_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = priv->mbus_format;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int dummy_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ mf->code = priv->mbus_format;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int dummy_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = priv->mbus_format;
++
++ return 0;
++}
++
++static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = 'D' >> 8;
++ edid->edid[9] = 'Y' & 0xff;
++
++ return 0;
++}
++
++static int dummy_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > priv->max_width) ||
++ (rect->top + rect->height > priv->max_height))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int dummy_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int dummy_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int dummy_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ reg->val = 0;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int dummy_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ return 0;
++}
++#endif
++
++static struct v4l2_subdev_core_ops dummy_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = dummy_g_register,
++ .s_register = dummy_s_register,
++#endif
++};
++
++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_GAIN:
++ case V4L2_CID_ANALOGUE_GAIN:
++ case V4L2_CID_EXPOSURE:
++ case V4L2_CID_HFLIP:
++ case V4L2_CID_VFLIP:
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ctrl_ops dummy_ctrl_ops = {
++ .s_ctrl = dummy_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops dummy_video_ops = {
++ .s_stream = dummy_s_stream,
++ .g_mbus_config = dummy_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = {
++ .get_edid = dummy_get_edid,
++ .enum_mbus_code = dummy_enum_mbus_code,
++ .get_selection = dummy_get_selection,
++ .set_selection = dummy_set_selection,
++ .get_fmt = dummy_get_fmt,
++ .set_fmt = dummy_set_fmt,
++};
++
++static struct v4l2_subdev_ops dummy_subdev_ops = {
++ .core = &dummy_core_ops,
++ .video = &dummy_video_ops,
++ .pad = &dummy_subdev_pad_ops,
++};
++
++static void dummy_otp_id_read(struct i2c_client *client)
++{
++ struct dummy_priv *priv = to_dummy(client);
++
++ /* dummy camera id */
++ priv->id[0] = 'd';
++ priv->id[1] = 'u';
++ priv->id[2] = 'm';
++ priv->id[3] = 'm';
++ priv->id[4] = 'y';
++ priv->id[5] = '.';
++}
++
++static ssize_t dummy_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ dummy_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL);
++
++static int dummy_initialize(struct i2c_client *client)
++{
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (strcmp(priv->media_bus_format, "yuyv") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8;
++ else if (strcmp(priv->media_bus_format, "uyvy") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8;
++ else if (strcmp(priv->media_bus_format, "grey") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8;
++ else if (strcmp(priv->media_bus_format, "rggb8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8;
++ else if (strcmp(priv->media_bus_format, "bggr8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8;
++ else if (strcmp(priv->media_bus_format, "grbg8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8;
++ else if (strcmp(priv->media_bus_format, "rggb12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12;
++ else if (strcmp(priv->media_bus_format, "bggr12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12;
++ else if (strcmp(priv->media_bus_format, "grbg12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12;
++ else if (strcmp(priv->media_bus_format, "rggb14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14;
++ else if (strcmp(priv->media_bus_format, "bggr14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14;
++ else if (strcmp(priv->media_bus_format, "grbg14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14;
++ else if (strcmp(priv->media_bus_format, "rggb16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16;
++ else if (strcmp(priv->media_bus_format, "bggr16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16;
++ else if (strcmp(priv->media_bus_format, "grbg16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16;
++ else {
++ v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format);
++ return -EINVAL;
++ }
++
++ /* Read OTP IDs */
++ dummy_otp_id_read(client);
++
++ dev_info(&client->dev, "Dummy camera sensor, res %dx%d, mbus %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++
++ return 0;
++}
++
++static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv)
++{
++ if (of_property_read_u32(np, "dummy,width", &priv->max_width))
++ priv->max_width = width;
++
++ if (of_property_read_u32(np, "dummy,height", &priv->max_height))
++ priv->max_height = height;
++
++ if (of_property_read_string(np, "dummy,mbus", &priv->media_bus_format))
++ priv->media_bus_format = mbus;
++
++ /* module params override dts */
++ if (strcmp(mbus, "yuyv"))
++ priv->media_bus_format = mbus;
++ if (width != 1920)
++ priv->max_width = width;
++ if (height != 1080)
++ priv->max_height = height;
++
++ return 0;
++}
++
++static int dummy_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct dummy_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = dummy_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = dummy_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = priv->max_width;
++ priv->rect.height = priv->max_height;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
++ client->addr, client->adapter->name);
++ return ret;
++}
++
++static int dummy_remove(struct i2c_client *client)
++{
++ struct dummy_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_dummy);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static const struct i2c_device_id dummy_id[] = {
++ { "dummy-camera", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, dummy_id);
++
++static const struct of_device_id dummy_of_ids[] = {
++ { .compatible = "dummy-camera", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, dummy_of_ids);
++
++static struct i2c_driver dummy_i2c_driver = {
++ .driver = {
++ .name = "dummy-camera",
++ .of_match_table = dummy_of_ids,
++ },
++ .probe = dummy_probe,
++ .remove = dummy_remove,
++ .id_table = dummy_id,
++};
++module_i2c_driver(dummy_i2c_driver);
++
++MODULE_DESCRIPTION("Dummy SoC camera driver");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c
+deleted file mode 100644
+index 28bd3c3..0000000
+--- a/drivers/media/i2c/soc_camera/max9286.c
++++ /dev/null
+@@ -1,1071 +0,0 @@
+-/*
+- * MAXIM max9286 GMSL driver
+- *
+- * Copyright (C) 2015-2018 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/i2c.h>
+-#include <linux/module.h>
+-#include <linux/notifier.h>
+-#include <linux/of_gpio.h>
+-#include <linux/of_graph.h>
+-#include <linux/reboot.h>
+-#include <linux/videodev2.h>
+-
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-device.h>
+-#include <media/v4l2-subdev.h>
+-
+-#include "max9286.h"
+-
+-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
+-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
+-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
+-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
+-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
+-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
+-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
+-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
+-
+-struct max9286_priv {
+- struct v4l2_subdev sd[4];
+- struct fwnode_handle *sd_fwnode[4];
+- int des_addr;
+- int des_quirk_addr; /* second MAX9286 on the same I2C bus */
+- int links;
+- int links_mask;
+- int lanes;
+- int csi_rate;
+- const char *fsync_mode;
+- int fsync_period;
+- int fps_numerator;
+- int fps_denominator;
+- int pclk;
+- char pclk_rising_edge;
+- int gpio_resetb;
+- int active_low_resetb;
+- int him;
+- int hsync;
+- int vsync;
+- int timeout;
+- int poc_delay;
+- int bws;
+- int dbl;
+- int dt;
+- int hsgen;
+- u64 crossbar;
+- char cb[16];
+- int hts;
+- int vts;
+- int hts_delay;
+- int imager_width;
+- atomic_t use_count;
+- u32 csi2_outord;
+- u32 switchin;
+- struct i2c_client *client;
+- int max9271_addr_map[4];
+- int ser_id;
+- struct gpio_desc *poc_gpio[4]; /* PoC power supply */
+- struct notifier_block reboot_notifier;
+-
+- /* link statistic */
+- int prbserr[4];
+- int deterr[4];
+- int correrr[4];
+-};
+-
+-static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */
+-
+-static int conf_link;
+-module_param(conf_link, int, 0644);
+-MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
+-
+-static int poc_trig;
+-module_param(poc_trig, int, 0644);
+-MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock");
+-
+-static int him;
+-module_param(him, int, 0644);
+-MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
+-
+-static int fsync_period;
+-module_param(fsync_period, int, 0644);
+-MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
+-
+-static int hsync;
+-module_param(hsync, int, 0644);
+-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
+-
+-static int vsync = 1;
+-module_param(vsync, int, 0644);
+-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
+-
+-static int gpio_resetb;
+-module_param(gpio_resetb, int, 0644);
+-MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
+-
+-static int active_low_resetb;
+-module_param(active_low_resetb, int, 0644);
+-MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
+-
+-static int timeout_n = 100;
+-module_param(timeout_n, int, 0644);
+-MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
+-
+-static int poc_delay = 50;
+-module_param(poc_delay, int, 0644);
+-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
+-
+-static int bws;
+-module_param(bws, int, 0644);
+-MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
+-
+-static int dbl = 1;
+-module_param(dbl, int, 0644);
+-MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
+-
+-static int dt = 3;
+-module_param(dt, int, 0644);
+-MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14");
+-
+-static int hsgen;
+-module_param(hsgen, int, 0644);
+-MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)");
+-
+-static int pclk = 100;
+-module_param(pclk, int, 0644);
+-MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)");
+-
+-static int switchin = 0;
+-module_param(switchin, int, 0644);
+-MODULE_PARM_DESC(switchin, " COAX SWITCH IN+ and IN- (default: 0 - not switched)");
+-
+-static unsigned long crossbar = 0xba9876543210;
+-module_param(crossbar, ulong, 0644);
+-MODULE_PARM_DESC(crossbar, " Crossbar setup (default: ba9876543210 - reversed)");
+-
+-enum {
+- RGB888_DT = 0,
+- RGB565_DT,
+- RGB666_DT,
+- YUV8_DT, /* default */
+- YUV10_DT,
+- RAW8_DT,
+- RAW10_DT,
+- RAW12_DT,
+- RAW14_DT,
+-};
+-
+-static int dt2bpp [9] = {
+- 24, /* RGB888 */
+- 16, /* RGB565 */
+- 18, /* RGB666 */
+- 8, /* YUV8 - default */
+- 10, /* YUV10 */
+- 8, /* RAW8/RAW16 */
+- 10, /* RAW10 */
+- 12, /* RAW12 */
+- 14, /* RAW14 */
+-};
+-
+-static char* ser_name(int id)
+-{
+- switch (id) {
+- case MAX9271_ID:
+- return "MAX9271";
+- case MAX96705_ID:
+- return "MAX96705";
+- case MAX96707_ID:
+- return "MAX96707";
+- default:
+- return "unknown";
+- }
+-}
+-
+-static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- int timeout;
+-
+- for (timeout = 0; timeout < 10; timeout++) {
+- int tmp_addr;
+- u8 sts = 0;
+- u8 val2 = 0;
+-
+- reg8_write(client, reg, val);
+-
+- tmp_addr = client->addr;
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_read(client, 0x70, &sts);
+- client->addr = tmp_addr;
+- if (sts & BIT(idx)) /* if ACKed */ {
+- reg8_read(client, reg, &val2);
+- if (val2 == val)
+- break;
+- }
+-
+- usleep_range(1000, 1500);
+- }
+-
+- if (timeout >= 10)
+- dev_err(&client->dev, "timeout remote write acked\n");
+-}
+-
+-static void max9286_preinit(struct i2c_client *client, int addr)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+-
+- client->addr = addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */
+- reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */
+-// usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x1b, priv->switchin); /* coax polarity (default - normal) */
+- reg8_write(client, 0x1c, (priv->him ? 0xf0 : 0x00) |
+- (priv->bws ? 0x05 : 0x04)); /* high-immunity/legacy mode, BWS 24bit */
+-}
+-
+-static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+-
+- if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
+- return;
+-
+- if (priv->active_low_resetb)
+- reset_on = !reset_on;
+-
+- /* sensor reset/unreset using serializer gpio */
+- client->addr = addr;
+- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | (reset_on ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value */
+- reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
+-}
+-
+-static void max9286_postinit(struct i2c_client *client, int addr)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- int idx;
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID)
+- continue;
+-
+- client->addr = priv->des_addr; /* MAX9286 I2C */
+- reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */
+- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */
+- usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */
+-
+- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */
+- max9286_sensor_reset(client, client->addr, 0); /* sensor unreset using gpios. TODO: should be in imager driver */
+- }
+-
+- client->addr = addr; /* MAX9286 I2C */
+- reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */
+- reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */
+- reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */
+- reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */
+- reg8_write(client, 0x1b, priv->switchin | priv->links_mask); /* coax polarity, enable equalizer for CAMs */
+- usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */
+-
+- if (strcmp(priv->fsync_mode, "manual") == 0) {
+- reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */
+- } else if (strcmp(priv->fsync_mode, "automatic") == 0) {
+- reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */
+- } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) {
+- reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */
+- } else if (strcmp(priv->fsync_mode, "external") == 0) {
+- reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */
+- }
+-}
+-
+-static int max9286_reverse_channel_setup(struct i2c_client *client, int idx)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- u8 val = 0, lock_sts = 0, link_sts = 0;
+- int timeout = priv->timeout;
+- char timeout_str[40];
+- int ret = 0;
+-
+- /* Reverse channel enable */
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */
+- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+-
+- for (;;) {
+- if (priv->him) {
+- /* HIM mode setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x4d, 0xc0);
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- if (priv->bws) {
+- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+- } else {
+- /* Legacy mode setup */
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */
+- reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+-
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */
+- reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- if (priv->bws) {
+- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+-
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+-
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_read(client, 0x1e, &val); /* read max9271 ID */
+- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) {
+- priv->ser_id = val;
+- break;
+- }
+-
+- /* Check if already initialized (after reboot/reset ?) */
+- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */
+- reg8_read(client, 0x1e, &val); /* read max9271 ID */
+- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
+- priv->ser_id = val;
+- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- ret = -EADDRINUSE;
+- break;
+- }
+-
+- if (poc_trig) {
+- if (!IS_ERR(priv->poc_gpio[idx]) && (timeout % poc_trig == 0)) {
+- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
+- mdelay(200);
+- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
+- mdelay(priv->poc_delay);
+- }
+- }
+- }
+-
+- max9286_sensor_reset(client, client->addr, 1); /* sensor reset */
+-
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_read(client, 0x27, &lock_sts); /* LOCK status */
+- reg8_read(client, 0x49, &link_sts); /* LINK status */
+-
+- if (!timeout) {
+- ret = -ETIMEDOUT;
+- goto out;
+- }
+-
+- priv->links_mask |= BIT(idx);
+- priv->csi2_outord &= ~(0x3 << (idx * 2));
+- priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2));
+-
+-out:
+- sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx));
+- dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id),
+- ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx],
+- ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
+- priv->timeout - timeout ? timeout_str : "");
+-
+- return ret;
+-}
+-
+-static void max9286_initial_setup(struct i2c_client *client)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+-
+- /* Initial setup */
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */
+- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
+- reg8_write(client, 0x12, ((priv->lanes - 1) << 6) |
+- (priv->dbl ? 0x30 : 0) |
+- (priv->dt & 0xf)); /* setup lanes, DBL mode, DataType */
+-
+- /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */
+- reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */
+- reg8_write(client, 0x06, priv->fsync_period & 0xff);
+- reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff);
+- reg8_write(client, 0x08, priv->fsync_period >> 16);
+-
+- reg8_write(client, 0x63, 0); /* disable overlap window */
+- reg8_write(client, 0x64, 0);
+- reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */
+- reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */
+-}
+-
+-static void max9286_gmsl_link_setup(struct i2c_client *client, int idx)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+-
+- /* GMSL setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+- reg8_write(client, 0x07, 0x04 | (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms */
+- reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
+- usleep_range(2000, 2500); /* wait 2ms */
+-
+- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) {
+- switch (priv->dt) {
+- case YUV8_DT:
+- /* setup crossbar for YUV8/RAW8: reverse DVP bus */
+- reg8_write(client, 0x20, priv->cb[7]);
+- reg8_write(client, 0x21, priv->cb[6]);
+- reg8_write(client, 0x22, priv->cb[5]);
+- reg8_write(client, 0x23, priv->cb[4]);
+- reg8_write(client, 0x24, priv->cb[3]);
+- reg8_write(client, 0x25, priv->cb[2]);
+- reg8_write(client, 0x26, priv->cb[1]);
+- reg8_write(client, 0x27, priv->cb[0]);
+-
+- /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, priv->cb[7] + 16);
+- reg8_write(client, 0x31, priv->cb[6] + 16);
+- reg8_write(client, 0x32, priv->cb[5] + 16);
+- reg8_write(client, 0x33, priv->cb[4] + 16);
+- reg8_write(client, 0x34, priv->cb[3] + 16);
+- reg8_write(client, 0x35, priv->cb[2] + 16);
+- reg8_write(client, 0x36, priv->cb[1] + 16);
+- reg8_write(client, 0x37, priv->cb[0] + 16);
+- break;
+- case RAW12_DT:
+- /* setup crossbar for RAW12: reverse DVP bus */
+- reg8_write(client, 0x20, priv->cb[11]);
+- reg8_write(client, 0x21, priv->cb[10]);
+- reg8_write(client, 0x22, priv->cb[9]);
+- reg8_write(client, 0x23, priv->cb[8]);
+- reg8_write(client, 0x24, priv->cb[7]);
+- reg8_write(client, 0x25, priv->cb[6]);
+- reg8_write(client, 0x26, priv->cb[5]);
+- reg8_write(client, 0x27, priv->cb[4]);
+- reg8_write(client, 0x28, priv->cb[3]);
+- reg8_write(client, 0x29, priv->cb[2]);
+- reg8_write(client, 0x2a, priv->cb[1]);
+- reg8_write(client, 0x2b, priv->cb[0]);
+-
+- /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, priv->cb[11] + 16);
+- reg8_write(client, 0x31, priv->cb[10] + 16);
+- reg8_write(client, 0x32, priv->cb[9] + 16);
+- reg8_write(client, 0x33, priv->cb[8] + 16);
+- reg8_write(client, 0x34, priv->cb[7] + 16);
+- reg8_write(client, 0x35, priv->cb[6] + 16);
+- reg8_write(client, 0x36, priv->cb[5] + 16);
+- reg8_write(client, 0x37, priv->cb[4] + 16);
+- reg8_write(client, 0x38, priv->cb[3] + 16);
+- reg8_write(client, 0x39, priv->cb[2] + 16);
+- reg8_write(client, 0x3a, priv->cb[1] + 16);
+- reg8_write(client, 0x3b, priv->cb[0] + 16);
+-
+- if (!priv->bws && priv->dbl)
+- dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
+-
+- break;
+- }
+-
+- if (priv->hsgen) {
+- /* HS/VS pins map */
+- reg8_write(client, 0x3f, 0x10); /* HS (NC) */
+- reg8_write(client, 0x41, 0x10); /* DE (NC) */
+- if (priv->ser_id == MAX96705_ID)
+- reg8_write(client, 0x40, 15); /* VS (DIN13) */
+- if (priv->ser_id == MAX96707_ID)
+- reg8_write(client, 0x40, 13); /* VS (DIN13) */
+-#if 0
+- /* following must come from imager */
+-#define SENSOR_WIDTH (1280*2)
+-#define HTS (1288*2)
+-#define VTS 960
+-#define HTS_DELAY 0x9
+- reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */
+- reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff);
+- reg8_write(client, 0x50, HTS_DELAY & 0xff);
+- reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */
+- reg8_write(client, 0x55, SENSOR_WIDTH & 0xff);
+- reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */
+- reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff);
+- reg8_write(client, 0x58, VTS >> 8); /* HS count */
+- reg8_write(client, 0x59, VTS & 0xff );
+-#endif
+- reg8_write(client, 0x43, 0x15); /* enable HS generator */
+- }
+- }
+-
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+- usleep_range(2000, 2500); /* wait 2ms */
+-
+- /* I2C translator setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+-// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */
+-// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
+- reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */
+- reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */
+- /* I2C addresse change */
+- reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */
+- reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */
+- usleep_range(2000, 2500); /* wait 2ms */
+- /* put MAX9271 in configuration link state */
+- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */
+- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms */
+-#ifdef MAXIM_DUMP
+- client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
+- maxim_max927x_dump_regs(client);
+- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */
+- maxim_max927x_dump_regs(client);
+-#endif
+-}
+-
+-static int max9286_initialize(struct i2c_client *client)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- int idx, ret;
+-
+- dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n",
+- priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period,
+- priv->pclk_rising_edge ? "rising" : "falling");
+-
+- if (priv->des_quirk_addr)
+- max9286_preinit(client, priv->des_quirk_addr);
+-
+- max9286_preinit(client, priv->des_addr);
+- max9286_initial_setup(client);
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- if (!IS_ERR(priv->poc_gpio[idx])) {
+- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
+- mdelay(priv->poc_delay);
+- }
+-
+- ret = max9286_reverse_channel_setup(client, idx);
+- if (ret)
+- continue;
+- max9286_gmsl_link_setup(client, idx);
+- }
+-
+- max9286_postinit(client, priv->des_addr);
+-
+- client->addr = priv->des_addr;
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-static int max9286_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- int ret;
+- u8 val = 0;
+-
+- ret = reg8_read(client, (u8)reg->reg, &val);
+- if (ret < 0)
+- return ret;
+-
+- reg->val = val;
+- reg->size = sizeof(u8);
+-
+- return 0;
+-}
+-
+-static int max9286_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- return reg8_write(client, (u8)reg->reg, (u8)reg->val);
+-}
+-#endif
+-
+-static int max9286_s_power(struct v4l2_subdev *sd, int on)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- if (on) {
+- if (atomic_inc_return(&priv->use_count) == 1)
+- reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */
+- } else {
+- if (atomic_dec_return(&priv->use_count) == 0)
+- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
+- }
+-
+- return 0;
+-}
+-
+-static int max9286_registered_async(struct v4l2_subdev *sd)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- int idx, tmp_addr;
+-
+- /* switch to GMSL serial_link for streaming video */
+- tmp_addr = client->addr;
+- idx = sd->grp_id;
+-
+- client->addr = priv->des_addr; /* MAX9286 I2C */
+- reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */
+-
+- client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */
+- max9286_write_remote_verify(client, idx, 0x04, conf_link ? 0x43 : 0x83);
+-// usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
+-
+- client->addr = priv->des_addr; /* MAX9286 I2C */
+- reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */
+-
+- client->addr = tmp_addr;
+-
+- return 0;
+-}
+-
+-static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+-{
+- struct max9286_priv *priv = container_of(nb, struct max9286_priv, reboot_notifier);
+- int idx;
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- if (!IS_ERR(priv->poc_gpio[idx]))
+- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
+- }
+-
+- return NOTIFY_OK;
+-}
+-
+-static struct v4l2_subdev_core_ops max9286_subdev_core_ops = {
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- .g_register = max9286_g_register,
+- .s_register = max9286_s_register,
+-#endif
+- .s_power = max9286_s_power,
+- .registered_async = max9286_registered_async,
+-};
+-
+-static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+-{
+- return 0;
+-}
+-
+-static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- struct v4l2_captureparm *cp = &parms->parm.capture;
+-
+- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+- if (cp->extendedmode != 0)
+- return -EINVAL;
+-
+- if (priv->fps_denominator != cp->timeperframe.denominator ||
+- priv->fps_numerator != cp->timeperframe.numerator) {
+- int f_period;
+-
+- f_period = priv->fsync_period * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
+- reg8_write(client, 0x06, f_period & 0xff);
+- reg8_write(client, 0x07, (f_period >> 8) & 0xff);
+- reg8_write(client, 0x08, f_period >> 16);
+-
+- priv->fps_numerator = cp->timeperframe.numerator;
+- priv->fps_denominator = cp->timeperframe.denominator;
+- }
+-
+- return 0;
+-}
+-
+-static struct v4l2_subdev_video_ops max9286_video_ops = {
+- .g_parm = max9286_g_parm,
+- .s_parm = max9286_s_parm,
+-};
+-
+-static struct v4l2_subdev_ops max9286_subdev_ops = {
+- .core = &max9286_subdev_core_ops,
+- .video = &max9286_video_ops,
+-};
+-
+-static int max9286_parse_dt(struct i2c_client *client)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- struct device_node *np = client->dev.of_node;
+- struct device_node *endpoint = NULL;
+- struct property *prop;
+- int err, pwen, i;
+- int sensor_delay, gpio0 = 1, gpio1 = 1;
+- u8 val = 0;
+- char poc_name[10];
+-
+- if (of_property_read_u32(np, "maxim,links", &priv->links))
+- priv->links = 4;
+-
+- if (of_property_read_u32(np, "maxim,lanes", &priv->lanes))
+- priv->lanes = 4;
+-
+- pwen = of_get_gpio(np, 0);
+- if (pwen > 0) {
+- err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev));
+- if (err)
+- dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err);
+- }
+-
+- mdelay(250);
+-
+- for (i = 0; i < 4; i++) {
+- sprintf(poc_name, "POC%d", i);
+- priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0);
+- }
+-
+- reg8_read(client, 0x1e, &val); /* read max9286 ID */
+- if (val != MAX9286_ID) {
+- prop = of_find_property(np, "reg", NULL);
+- if (prop)
+- of_remove_property(np, prop);
+- return -ENODEV;
+- }
+-
+- if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) ||
+- !of_property_read_u32(np, "maxim,gpio1", &gpio1))
+- reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0);
+-
+- if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
+- priv->gpio_resetb = -1;
+- } else {
+- if (of_property_read_bool(np, "maxim,resetb-active-high"))
+- priv->active_low_resetb = 0;
+- else
+- priv->active_low_resetb = 1;
+- }
+-
+- if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay))
+- mdelay(sensor_delay);
+- if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode))
+- priv->fsync_mode = fsync_mode_default;
+- if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
+- priv->fsync_period = 3200000; /* 96MHz/30fps */
+- priv->pclk_rising_edge = true;
+- if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
+- priv->pclk_rising_edge = false;
+- if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
+- priv->timeout = 100;
+- if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr))
+- priv->des_quirk_addr = 0;
+- if (of_property_read_u32(np, "maxim,him", &priv->him))
+- priv->him = 0;
+- if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
+- priv->hsync = 0;
+- if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
+- priv->vsync = 1;
+- if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
+- priv->poc_delay = 50;
+- if (of_property_read_u32(np, "maxim,bws", &priv->bws))
+- priv->bws = 0;
+- if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
+- priv->dbl = 1;
+- if (of_property_read_u32(np, "maxim,dt", &priv->dt))
+- priv->dt = 3;
+- if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen))
+- priv->hsgen = 0;
+- if (of_property_read_u32(np, "maxim,pclk", &priv->pclk))
+- priv->pclk = pclk;
+- if (of_property_read_u32(np, "maxim,switchin", &priv->switchin))
+- priv->switchin = 0;
+- if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
+- priv->crossbar = crossbar;
+-
+- /* module params override dts */
+- if (him)
+- priv->him = him;
+- if (fsync_period) {
+- priv->fsync_period = fsync_period;
+- priv->fsync_mode = fsync_mode_default;
+- }
+- if (hsync)
+- priv->hsync = hsync;
+- if (!vsync)
+- priv->vsync = vsync;
+- if (gpio_resetb)
+- priv->gpio_resetb = gpio_resetb;
+- if (active_low_resetb)
+- priv->active_low_resetb = active_low_resetb;
+- if (timeout_n)
+- priv->timeout = timeout_n;
+- if (poc_delay)
+- priv->poc_delay = poc_delay;
+- if (bws)
+- priv->bws = bws;
+- if (!dbl)
+- priv->dbl = dbl;
+- if (dt != 3)
+- priv->dt = dt;
+- if (hsgen)
+- priv->hsgen = hsgen;
+- if (pclk != 100)
+- priv->pclk = pclk;
+- if (switchin)
+- priv->switchin = switchin;
+-
+- /* parse crossbar setup */
+- for (i = 0; i < 16; i++) {
+- priv->cb[i] = priv->crossbar % 16;
+- priv->crossbar /= 16;
+- }
+-
+- for (i = 0; i < priv->links; i++) {
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (!endpoint)
+- break;
+-
+- if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) {
+- of_node_put(endpoint);
+- dev_err(&client->dev, "max9271-addr not set\n");
+- return -EINVAL;
+- }
+-
+- priv->sd_fwnode[i] = of_fwnode_handle(endpoint);
+- }
+-
+- of_node_put(endpoint);
+- return 0;
+-}
+-
+-static void max9286_setup_remote_endpoint(struct i2c_client *client)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- struct device_node *np = client->dev.of_node;
+- struct device_node *endpoint = NULL, *rendpoint = NULL;
+- int i;
+- struct property *csi_rate_prop, *dvp_order_prop;
+-
+- for (i = 0; ; i++) {
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (!endpoint)
+- break;
+-
+- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
+- if (!rendpoint)
+- continue;
+-
+- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
+- if (csi_rate_prop) {
+- /* CSI2_RATE = PCLK*bpp*links/lanes */
+- priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] * hweight8(priv->links_mask) / priv->lanes);
+- csi_rate_prop->value = &priv->csi_rate;
+- of_update_property(rendpoint, csi_rate_prop);
+- }
+-
+- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
+- if (dvp_order_prop)
+- of_update_property(rendpoint, dvp_order_prop);
+- }
+-
+- of_node_put(endpoint);
+-}
+-
+-static const char *line_status[] =
+-{
+- "BAT",
+- "GND",
+- "NORMAL",
+- "OPEN"
+-};
+-
+-static ssize_t max9286_link_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- int i = -1;
+- u8 val = 0;
+- bool lenghterr, linebuffof, hlocked, prbsok, vsyncdet, configdet, videodet;
+- int lf;
+- u8 prbserr = 0, deterr = 0, correrr = 0;
+- struct i2c_client *client = to_i2c_client(dev);
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+-
+- if (!sscanf(attr->attr.name, "link_%d", &i))
+- return -EINVAL;
+-
+- if ((i < 0) || (i > 3))
+- return -EINVAL;
+-
+- reg8_read(client, 0x20, &val);
+- lf = (val >> (2 * i)) & 0x03;
+-
+- reg8_read(client, 0x21, &val);
+- hlocked = !!(val & (1 << i));
+- prbsok = !!(val & (1 << (i + 4)));
+-
+- reg8_read(client, 0x22, &val);
+- lenghterr = !!(val & (1 << i));
+- linebuffof = !!(val & (1 << (i + 4)));
+-
+- reg8_read(client, 0x23 + i, &prbserr);
+- priv->prbserr[i] += prbserr;
+-
+- reg8_read(client, 0x27, &val);
+- vsyncdet = !!(val & (1 << i));
+-
+- reg8_read(client, 0x28 + i, &deterr);
+- priv->deterr[i] += deterr;
+-
+- reg8_read(client, 0x2c + i, &correrr);
+- priv->correrr[i] += correrr;
+-
+- reg8_read(client, 0x49, &val);
+- configdet = !!(val & (1 << i));
+- videodet = !!(val & (1 << (i + 4)));
+-
+- return sprintf(buf, "LINK:%d LF:%s HLOCKED:%d PRBSOK:%d LINBUFFOF:%d"
+- " LENGHTERR:%d VSYNCDET:%d CONFIGDET:%d VIDEODET:%d"
+- " PRBSERR:%d(%d) DETEERR:%d(%d) CORRERR:%d(%d)\n",
+- i, line_status[lf], hlocked, prbsok, lenghterr,
+- linebuffof, vsyncdet, configdet, videodet,
+- priv->prbserr[i], prbserr,
+- priv->deterr[i], deterr,
+- priv->correrr[i], correrr);
+- return 0;
+-}
+-
+-static DEVICE_ATTR(link_0, S_IRUGO, max9286_link_show, NULL);
+-static DEVICE_ATTR(link_1, S_IRUGO, max9286_link_show, NULL);
+-static DEVICE_ATTR(link_2, S_IRUGO, max9286_link_show, NULL);
+-static DEVICE_ATTR(link_3, S_IRUGO, max9286_link_show, NULL);
+-
+-static struct attribute *max9286_attributes_links[] = {
+- &dev_attr_link_0.attr,
+- &dev_attr_link_1.attr,
+- &dev_attr_link_2.attr,
+- &dev_attr_link_3.attr,
+- NULL
+-};
+-
+-static const struct attribute_group max9286_group = {
+- .attrs = max9286_attributes_links,
+-};
+-
+-static int max9286_probe(struct i2c_client *client,
+- const struct i2c_device_id *did)
+-{
+- struct max9286_priv *priv;
+- int err, i;
+-
+- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- i2c_set_clientdata(client, priv);
+- priv->des_addr = client->addr;
+- priv->client = client;
+- atomic_set(&priv->use_count, 0);
+- priv->csi2_outord = 0xff;
+- priv->fps_numerator = 1;
+- priv->fps_denominator = 30;
+-
+- err = max9286_parse_dt(client);
+- if (err)
+- goto out;
+-
+- err = max9286_initialize(client);
+- if (err < 0)
+- goto out;
+-
+- max9286_setup_remote_endpoint(client);
+-
+- for (i = 0; i < 4; i++) {
+- v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops);
+- priv->sd[i].owner = client->dev.driver->owner;
+- priv->sd[i].dev = &client->dev;
+- priv->sd[i].grp_id = i;
+- v4l2_set_subdevdata(&priv->sd[i], priv);
+- priv->sd[i].fwnode = priv->sd_fwnode[i];
+-
+- snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
+- client->dev.driver->name, i, i2c_adapter_id(client->adapter),
+- client->addr);
+-
+- err = v4l2_async_register_subdev(&priv->sd[i]);
+- if (err < 0)
+- goto out;
+- }
+-
+- priv->reboot_notifier.notifier_call = max9286_reboot_notifier;
+- err = register_reboot_notifier(&priv->reboot_notifier);
+- if (err) {
+- dev_err(&client->dev, "failed to register reboot notifier\n");
+- goto out;
+- }
+-
+- err = sysfs_create_group(&client->dev.kobj,
+- &max9286_group);
+- if (err < 0)
+- dev_err(&client->dev, "Sysfs registration failed\n");
+-out:
+- return err;
+-}
+-
+-static int max9286_remove(struct i2c_client *client)
+-{
+- struct max9286_priv *priv = i2c_get_clientdata(client);
+- int i;
+-
+- sysfs_remove_group(&client->dev.kobj, &max9286_group);
+- unregister_reboot_notifier(&priv->reboot_notifier);
+-
+- for (i = 0; i < 4; i++) {
+- v4l2_async_unregister_subdev(&priv->sd[i]);
+- v4l2_device_unregister_subdev(&priv->sd[i]);
+- }
+-
+- return 0;
+-}
+-
+-static const struct of_device_id max9286_dt_ids[] = {
+- { .compatible = "maxim,max9286" },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, max9286_dt_ids);
+-
+-static const struct i2c_device_id max9286_id[] = {
+- { "max9286", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, max9286_id);
+-
+-static struct i2c_driver max9286_i2c_driver = {
+- .driver = {
+- .name = "max9286",
+- .of_match_table = of_match_ptr(max9286_dt_ids),
+- },
+- .probe = max9286_probe,
+- .remove = max9286_remove,
+- .id_table = max9286_id,
+-};
+-
+-module_i2c_driver(max9286_i2c_driver);
+-
+-MODULE_DESCRIPTION("GMSL driver for MAX9286");
+-MODULE_AUTHOR("Vladimir Barinov");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/max9288.c b/drivers/media/i2c/soc_camera/max9288.c
+deleted file mode 100644
+index 4840795..0000000
+--- a/drivers/media/i2c/soc_camera/max9288.c
++++ /dev/null
+@@ -1,768 +0,0 @@
+-/*
+- * MAXIM max9288 GMSL driver
+- *
+- * Copyright (C) 2019 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/i2c.h>
+-#include <linux/module.h>
+-#include <linux/notifier.h>
+-#include <linux/of_gpio.h>
+-#include <linux/of_graph.h>
+-#include <linux/videodev2.h>
+-
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-device.h>
+-#include <media/v4l2-subdev.h>
+-
+-#include "max9286.h"
+-
+-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
+-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
+-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
+-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
+-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
+-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
+-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
+-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
+-
+-struct max9288_priv {
+- struct v4l2_subdev sd;
+- struct fwnode_handle *sd_fwnode;
+- int des_addr;
+- int lanes;
+- int csi_rate;
+- int pclk;
+- char pclk_rising_edge;
+- int gpio_resetb;
+- int active_low_resetb;
+- int him;
+- int hsync;
+- int vsync;
+- int timeout;
+- int poc_delay;
+- int bws;
+- int dbl;
+- int dt;
+- int hsgen;
+- int hts;
+- int vts;
+- int hts_delay;
+- struct i2c_client *client;
+- int max9271_addr;
+- int ser_id;
+- struct gpio_desc *poc_gpio; /* PoC power supply */
+-};
+-
+-static int conf_link;
+-module_param(conf_link, int, 0644);
+-MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
+-
+-static int poc_trig;
+-module_param(poc_trig, int, 0644);
+-MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock");
+-
+-static int him = 0;
+-module_param(him, int, 0644);
+-MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
+-
+-static int hsync;
+-module_param(hsync, int, 0644);
+-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
+-
+-static int vsync = 1;
+-module_param(vsync, int, 0644);
+-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
+-
+-static int gpio_resetb;
+-module_param(gpio_resetb, int, 0644);
+-MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
+-
+-static int active_low_resetb;
+-module_param(active_low_resetb, int, 0644);
+-MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
+-
+-static int timeout_n = 100;
+-module_param(timeout_n, int, 0644);
+-MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
+-
+-static int poc_delay = 50;
+-module_param(poc_delay, int, 0644);
+-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
+-
+-static int bws = 0;
+-module_param(bws, int, 0644);
+-MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
+-
+-static int dbl = 1;
+-module_param(dbl, int, 0644);
+-MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
+-
+-static int dt = 3;
+-module_param(dt, int, 0644);
+-MODULE_PARM_DESC(dt, " DataType (default: 3 - YUV8), 0 - RGB888, 5 - RAW8, 6 - RAW10, 7 - RAW12, 8 - RAW14");
+-
+-static int hsgen;
+-module_param(hsgen, int, 0644);
+-MODULE_PARM_DESC(hsgen, " Enable HS embedded generator (default: 0 - disabled)");
+-
+-static int pclk = 100;
+-module_param(pclk, int, 0644);
+-MODULE_PARM_DESC(pclk, " PCLK rate (default: 100MHz)");
+-
+-enum {
+- RGB888_DT = 0,
+- RGB565_DT,
+- RGB666_DT,
+- YUV8_DT, /* default */
+- YUV10_DT,
+- RAW8_DT,
+- RAW10_DT,
+- RAW12_DT,
+- RAW14_DT,
+-};
+-
+-static int dt2bpp [9] = {
+- 24, /* RGB888 */
+- 16, /* RGB565 */
+- 18, /* RGB666 */
+- 8, /* YUV8 - default */
+- 10, /* YUV10 */
+- 8, /* RAW8/RAW16 */
+- 10, /* RAW10 */
+- 12, /* RAW12 */
+- 14, /* RAW14 */
+-};
+-
+-static char* ser_name(int id)
+-{
+- switch (id) {
+- case MAX9271_ID:
+- return "MAX9271";
+- case MAX96705_ID:
+- return "MAX96705";
+- case MAX96707_ID:
+- return "MAX96707";
+- default:
+- return "unknown";
+- }
+-}
+-
+-static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+- int timeout;
+-
+- for (timeout = 0; timeout < 10; timeout++) {
+- u8 val2 = 0;
+-
+- reg8_write(client, reg, val);
+- reg8_read(client, reg, &val2);
+- if (val2 == val)
+- break;
+-
+- usleep_range(1000, 1500);
+- }
+-
+- if (timeout >= 10)
+- dev_err(&client->dev, "timeout remote write acked\n");
+-}
+-
+-
+-static void max9288_preinit(struct i2c_client *client, int addr)
+-{
+-
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- client->addr = addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x04, 0x00); /* disable reverse control */
+- reg8_write(client, 0x16, (priv->him ? 0x80 : 0x00) |
+- 0x5a); /* high-immunity/legacy mode */
+-}
+-
+-static void max9288_sensor_reset(struct i2c_client *client, int addr, int reset_on)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
+- return;
+-
+- /* sensor reset/unreset */
+- client->addr = addr; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
+- ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
+- reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
+-}
+-
+-static int max9288_reverse_channel_setup(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+- u8 val = 0, lock_sts = 0;
+- int timeout = priv->timeout;
+- char timeout_str[40];
+- int ret = 0;
+-
+- /* Reverse channel enable */
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x1c, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x04, 0x03); /* enable reverse control */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+-
+- for (;;) {
+- if (priv->him) {
+- /* HIM mode setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x4d, 0xc0);
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- if (priv->bws) {
+- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS disabled enabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+- } else {
+- /* Legacy mode setup */
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x13, 0x00);
+- reg8_write(client, 0x11, 0x42); /* enable custom reverse channel & first pulse length */
+- reg8_write(client, 0x0a, 0x0f); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+-
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- if (priv->bws) {
+- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+- reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+-
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x0a, 0x0c); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */
+- reg8_write(client, 0x13, 0x20); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- }
+-
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_read(client, 0x1e, &val); /* read max9271 ID */
+- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID || --timeout == 0) {
+- priv->ser_id = val;
+- break;
+- }
+-
+- /* Check if already initialized (after reboot/reset ?) */
+- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C */
+- reg8_read(client, 0x1e, &val); /* read max9271 ID */
+- if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
+- priv->ser_id = val;
+- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+- ret = -EADDRINUSE;
+- break;
+- }
+-
+- if (poc_trig) {
+- if (!IS_ERR(priv->poc_gpio) && (timeout % poc_trig == 0)) {
+- gpiod_direction_output(priv->poc_gpio, 0); /* POC power off */
+- mdelay(200);
+- gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */
+- mdelay(priv->poc_delay);
+- }
+- }
+- }
+-
+- max9288_sensor_reset(client, client->addr, 1); /* sensor reset */
+-
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_read(client, 0x04, &lock_sts); /* LOCK status */
+-
+- if (!timeout) {
+- ret = -ETIMEDOUT;
+- goto out;
+- }
+-
+-out:
+- sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80));
+- dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id),
+- ret == -EADDRINUSE ? "already " : "", priv->max9271_addr,
+- ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
+- priv->timeout - timeout ? timeout_str : "");
+-
+- return ret;
+-}
+-
+-static void max9288_initial_setup(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- /* Initial setup */
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x09, 0x40); /* Automatic pixel count enable */
+- reg8_write(client, 0x15, 0x70); /* Enable HV and DE tracking by register 0x69 */
+- reg8_write(client, 0x60, (priv->dbl ? 0x20 : 0) |
+- (priv->dt & 0xf)); /* VC=0, DBL mode, DataType */
+- reg8_write(client, 0x65, 0x47 | ((priv->lanes - 1) << 4)); /* setup CSI lanes, DE input is HS */
+-
+- reg8_write(client, 0x08, 0x20); /* use D18/19 for HS/VS */
+- reg8_write(client, 0x14, (priv->vsync ? 0x80 : 0) | (priv->hsync ? 0x40 : 0)); /* setup HS/VS inversion */
+- reg8_write(client, 0x64, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */
+-}
+-
+-static void max9288_gmsl_link_setup(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- /* GMSL setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+- reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+- reg8_write(client, 0x07, (priv->pclk_rising_edge ? 0 : 0x10) |
+- (priv->dbl ? 0x80 : 0) |
+- (priv->bws ? 0x20 : 0)); /* RAW/YUV, PCLK edge, HS/VS encoding disabled, DBL mode, BWS 24/32-bit */
+- usleep_range(2000, 2500); /* wait 2ms */
+- reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
+- usleep_range(2000, 2500); /* wait 2ms */
+-
+- if (priv->ser_id == MAX96705_ID || priv->ser_id == MAX96707_ID) {
+- switch (priv->dt) {
+- case YUV8_DT:
+- /* setup crossbar for YUV8/RAW8: reverse DVP bus */
+- reg8_write(client, 0x20, 3);
+- reg8_write(client, 0x21, 4);
+- reg8_write(client, 0x22, 5);
+- reg8_write(client, 0x23, 6);
+- reg8_write(client, 0x24, 7);
+- reg8_write(client, 0x25, 0x40);
+- reg8_write(client, 0x26, 0x40);
+- if (priv->ser_id == MAX96705_ID) {
+- reg8_write(client, 0x27, 14); /* HS: D14->D18 */
+- reg8_write(client, 0x28, 15); /* VS: D15->D19 */
+- }
+- if (priv->ser_id == MAX96707_ID) {
+- reg8_write(client, 0x27, 14); /* HS: D14->D18, this is a virtual NC pin, hence it is D14 at HS */
+- reg8_write(client, 0x28, 13); /* VS: D13->D19 */
+- }
+- reg8_write(client, 0x29, 0x40);
+- reg8_write(client, 0x2A, 0x40);
+-
+- /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, 0x10 + 0);
+- reg8_write(client, 0x31, 0x10 + 1);
+- reg8_write(client, 0x32, 0x10 + 2);
+- reg8_write(client, 0x33, 0x10 + 3);
+- reg8_write(client, 0x34, 0x10 + 4);
+- reg8_write(client, 0x35, 0x10 + 5);
+- reg8_write(client, 0x36, 0x10 + 6);
+- reg8_write(client, 0x37, 0x10 + 7);
+- reg8_write(client, 0x38, 0);
+- reg8_write(client, 0x39, 1);
+- reg8_write(client, 0x3A, 2);
+-
+- reg8_write(client, 0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
+-
+- break;
+- case RAW12_DT:
+-#if 0 /* Not supported yet */
+- /* setup crossbar for RAW12: reverse DVP bus */
+- reg8_write(client, 0x20, 11);
+- reg8_write(client, 0x21, 10);
+- reg8_write(client, 0x22, 9);
+- reg8_write(client, 0x23, 8);
+- reg8_write(client, 0x24, 7);
+- reg8_write(client, 0x25, 6);
+- reg8_write(client, 0x26, 5);
+- reg8_write(client, 0x27, 4);
+- reg8_write(client, 0x28, 3);
+- reg8_write(client, 0x29, 2);
+- reg8_write(client, 0x2a, 1);
+- reg8_write(client, 0x2b, 0);
+-
+- /* this is second byte if DBL=1 */
+- reg8_write(client, 0x30, 27);
+- reg8_write(client, 0x31, 26);
+- reg8_write(client, 0x32, 25);
+- reg8_write(client, 0x33, 24);
+- reg8_write(client, 0x34, 23);
+- reg8_write(client, 0x35, 22);
+- reg8_write(client, 0x36, 21);
+- reg8_write(client, 0x37, 20);
+- reg8_write(client, 0x38, 19);
+- reg8_write(client, 0x39, 18);
+- reg8_write(client, 0x3a, 17);
+- reg8_write(client, 0x3b, 16);
+-
+- if (!priv->bws && priv->dbl)
+- dev_err(&client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
+-#endif
+- break;
+- }
+-
+- if (priv->hsgen) {
+- /* HS/VS pins map */
+- reg8_write(client, 0x3f, 0x10); /* HS (NC) */
+- reg8_write(client, 0x41, 0x10); /* DE (NC) */
+- if (priv->ser_id == MAX96705_ID)
+- reg8_write(client, 0x40, 15); /* VS (DIN13) */
+- if (priv->ser_id == MAX96707_ID)
+- reg8_write(client, 0x40, 13); /* VS (DIN13) */
+-#if 0
+- /* following must come from imager */
+-#define SENSOR_WIDTH (1280*2)
+-#define HTS (1288*2)
+-#define VTS 960
+-#define HTS_DELAY 0x9
+- reg8_write(client, 0x4e, HTS_DELAY >> 16); /* HS delay */
+- reg8_write(client, 0x4f, (HTS_DELAY >> 8) & 0xff);
+- reg8_write(client, 0x50, HTS_DELAY & 0xff);
+- reg8_write(client, 0x54, SENSOR_WIDTH >> 8); /* HS high period */
+- reg8_write(client, 0x55, SENSOR_WIDTH & 0xff);
+- reg8_write(client, 0x56, (HTS - SENSOR_WIDTH) >> 8); /* HS low period */
+- reg8_write(client, 0x57, (HTS - SENSOR_WIDTH) & 0xff);
+- reg8_write(client, 0x58, VTS >> 8); /* HS count */
+- reg8_write(client, 0x59, VTS & 0xff );
+-#endif
+- reg8_write(client, 0x43, 0x15); /* enable HS generator */
+- }
+- }
+-
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- reg8_write(client, 0x1c, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+- usleep_range(2000, 2500); /* wait 2ms */
+-
+- /* I2C translator setup */
+- client->addr = 0x40; /* MAX9271-CAMx I2C */
+-// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */
+-// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
+- reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */
+- reg8_write(client, 0x0C, priv->max9271_addr << 1); /* MAX9271-CAMx I2C new */
+- /* I2C addresse change */
+- reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9288 I2C */
+- reg8_write(client, 0x00, priv->max9271_addr << 1); /* MAX9271-CAM0 I2C new */
+- usleep_range(2000, 2500); /* wait 2ms */
+- /* put MAX9271 in configuration link state */
+- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
+- reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */
+- usleep_range(2000, 2500); /* wait 2ms */
+-#ifdef MAXIM_DUMP
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+- maxim_max927x_dump_regs(client);
+- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
+- maxim_max927x_dump_regs(client);
+-#endif
+-}
+-
+-static int max9288_initialize(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- dev_info(&client->dev, "LANES=%d, PCLK edge=%s\n",
+- priv->lanes, priv->pclk_rising_edge ? "rising" : "falling");
+-
+- max9288_preinit(client, priv->des_addr);
+- max9288_initial_setup(client);
+-
+- if (!IS_ERR(priv->poc_gpio)) {
+- gpiod_direction_output(priv->poc_gpio, 1); /* POC power on */
+- mdelay(priv->poc_delay);
+- }
+-
+- max9288_reverse_channel_setup(client);
+- max9288_gmsl_link_setup(client);
+-
+- client->addr = priv->des_addr;
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-static int max9288_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
+-{
+- struct max9288_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- int ret;
+- u8 val = 0;
+-
+- ret = reg8_read(client, (u8)reg->reg, &val);
+- if (ret < 0)
+- return ret;
+-
+- reg->val = val;
+- reg->size = sizeof(u8);
+-
+- return 0;
+-}
+-
+-static int max9288_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
+-{
+- struct max9288_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- return reg8_write(client, (u8)reg->reg, (u8)reg->val);
+-}
+-#endif
+-
+-static int max9288_s_power(struct v4l2_subdev *sd, int on)
+-{
+- struct max9288_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
+- max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+-
+- return 0;
+-}
+-
+-static struct v4l2_subdev_core_ops max9288_subdev_core_ops = {
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- .g_register = max9288_g_register,
+- .s_register = max9288_s_register,
+-#endif
+- .s_power = max9288_s_power,
+-};
+-
+-static struct v4l2_subdev_ops max9288_subdev_ops = {
+- .core = &max9288_subdev_core_ops,
+-};
+-
+-static int max9288_parse_dt(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+- struct device_node *np = client->dev.of_node;
+- struct device_node *endpoint = NULL;
+- struct property *prop;
+- int err, pwen;
+- int sensor_delay, gpio0 = 1, gpio1 = 1;
+- u8 val = 0;
+- char poc_name[10];
+-
+- if (of_property_read_u32(np, "maxim,lanes", &priv->lanes))
+- priv->lanes = 4;
+-
+- pwen = of_get_gpio(np, 0);
+- if (pwen > 0) {
+- err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev));
+- if (err)
+- dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err);
+- }
+-
+- mdelay(250);
+-
+- sprintf(poc_name, "POC%d", 0);
+- priv->poc_gpio = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0);
+-
+- reg8_read(client, 0x1e, &val); /* read max9288 ID */
+- if (val != MAX9288_ID) {
+- prop = of_find_property(np, "reg", NULL);
+- if (prop)
+- of_remove_property(np, prop);
+- return -ENODEV;
+- }
+-
+- if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) ||
+- !of_property_read_u32(np, "maxim,gpio1", &gpio1))
+- reg8_write(client, 0x06, (gpio1 << 3) | (gpio0 << 1));
+-
+- if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
+- priv->gpio_resetb = -1;
+- } else {
+- if (of_property_read_bool(np, "maxim,resetb-active-high"))
+- priv->active_low_resetb = 0;
+- else
+- priv->active_low_resetb = 1;
+- }
+-
+- if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay))
+- mdelay(sensor_delay);
+- priv->pclk_rising_edge = true;
+- if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
+- priv->pclk_rising_edge = false;
+- if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
+- priv->timeout = 100;
+- if (of_property_read_u32(np, "maxim,him", &priv->him))
+- priv->him = 0;
+- if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
+- priv->hsync = 0;
+- if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
+- priv->vsync = 1;
+- if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
+- priv->poc_delay = 50;
+- if (of_property_read_u32(np, "maxim,bws", &priv->bws))
+- priv->bws = 0;
+- if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
+- priv->dbl = 1;
+- if (of_property_read_u32(np, "maxim,dt", &priv->dt))
+- priv->dt = 3;
+- if (of_property_read_u32(np, "maxim,hsgen", &priv->hsgen))
+- priv->hsgen = 0;
+- if (of_property_read_u32(np, "maxim,pclk", &priv->pclk))
+- priv->pclk = pclk;
+-
+- /* module params override dts */
+- if (him)
+- priv->him = him;
+- if (hsync)
+- priv->hsync = hsync;
+- if (!vsync)
+- priv->vsync = vsync;
+- if (gpio_resetb)
+- priv->gpio_resetb = gpio_resetb;
+- if (active_low_resetb)
+- priv->active_low_resetb = active_low_resetb;
+- if (timeout_n)
+- priv->timeout = timeout_n;
+- if (poc_delay)
+- priv->poc_delay = poc_delay;
+- if (bws)
+- priv->bws = bws;
+- if (!dbl)
+- priv->dbl = dbl;
+- if (dt != 3)
+- priv->dt = dt;
+- if (hsgen)
+- priv->hsgen = hsgen;
+- if (pclk != 100)
+- priv->pclk = pclk;
+-
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (endpoint) {
+- if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr)) {
+- of_node_put(endpoint);
+- dev_err(&client->dev, "max9271-addr not set\n");
+- return -EINVAL;
+- }
+-
+- priv->sd_fwnode = of_fwnode_handle(endpoint);
+- }
+-
+- of_node_put(endpoint);
+- return 0;
+-}
+-
+-static void max9288_setup_remote_endpoint(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+- struct device_node *np = client->dev.of_node;
+- struct device_node *endpoint = NULL, *rendpoint = NULL;
+- int i;
+- struct property *csi_rate_prop, *dvp_order_prop;
+-
+- for (i = 0; ; i++) {
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (!endpoint)
+- break;
+-
+- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
+- if (!rendpoint)
+- continue;
+-
+- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
+- if (csi_rate_prop) {
+- /* CSI2_RATE = PCLK*bpp/lanes */
+- priv->csi_rate = cpu_to_be32(priv->pclk * dt2bpp[priv->dt] / priv->lanes);
+- csi_rate_prop->value = &priv->csi_rate;
+- of_update_property(rendpoint, csi_rate_prop);
+- }
+-
+- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
+- if (dvp_order_prop)
+- of_update_property(rendpoint, dvp_order_prop);
+- }
+-
+- of_node_put(endpoint);
+-}
+-
+-static int max9288_probe(struct i2c_client *client,
+- const struct i2c_device_id *did)
+-{
+- struct max9288_priv *priv;
+- int err;
+-
+- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- i2c_set_clientdata(client, priv);
+- priv->des_addr = client->addr;
+- priv->client = client;
+-
+- err = max9288_parse_dt(client);
+- if (err)
+- goto out;
+-
+- err = max9288_initialize(client);
+- if (err < 0)
+- goto out;
+-
+- max9288_setup_remote_endpoint(client);
+-
+- v4l2_subdev_init(&priv->sd, &max9288_subdev_ops);
+- priv->sd.owner = client->dev.driver->owner;
+- priv->sd.dev = &client->dev;
+- v4l2_set_subdevdata(&priv->sd, priv);
+- priv->sd.fwnode = priv->sd_fwnode;
+-
+- snprintf(priv->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x",
+- client->dev.driver->name, i2c_adapter_id(client->adapter),
+- client->addr);
+-
+- err = v4l2_async_register_subdev(&priv->sd);
+- if (err < 0)
+- goto out;
+-out:
+- return err;
+-}
+-
+-static int max9288_remove(struct i2c_client *client)
+-{
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+-
+- v4l2_async_unregister_subdev(&priv->sd);
+- v4l2_device_unregister_subdev(&priv->sd);
+-
+- return 0;
+-}
+-
+-static const struct of_device_id max9288_dt_ids[] = {
+- { .compatible = "maxim,max9288" },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, max9288_dt_ids);
+-
+-static const struct i2c_device_id max9288_id[] = {
+- { "max9288", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, max9288_id);
+-
+-static struct i2c_driver max9288_i2c_driver = {
+- .driver = {
+- .name = "max9288",
+- .of_match_table = of_match_ptr(max9288_dt_ids),
+- },
+- .probe = max9288_probe,
+- .remove = max9288_remove,
+- .id_table = max9288_id,
+-};
+-
+-module_i2c_driver(max9288_i2c_driver);
+-
+-MODULE_DESCRIPTION("GMSL driver for MAX9288");
+-MODULE_AUTHOR("Vladimir Barinov");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
+deleted file mode 100644
+index 340e61e..0000000
+--- a/drivers/media/i2c/soc_camera/ti9x4.c
++++ /dev/null
+@@ -1,745 +0,0 @@
+- /*
+- * TI DS90UB954/960/964 FPDLinkIII driver
+- *
+- * Copyright (C) 2017-2018 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#include <linux/delay.h>
+-#include <linux/i2c.h>
+-#include <linux/module.h>
+-#include <linux/notifier.h>
+-#include <linux/of_gpio.h>
+-#include <linux/of_graph.h>
+-#include <linux/reboot.h>
+-#include <linux/videodev2.h>
+-
+-#include <media/v4l2-common.h>
+-#include <media/v4l2-clk.h>
+-#include <media/v4l2-device.h>
+-#include <media/v4l2-subdev.h>
+-
+-#include "ti9x4.h"
+-
+-struct ti9x4_priv {
+- struct v4l2_subdev sd[4];
+- struct fwnode_handle *sd_fwnode[4];
+- int des_addr;
+- int links;
+- int lanes;
+- int csi_rate;
+- const char *forwarding_mode;
+- int fs_time;
+- int fps_numerator;
+- int fps_denominator;
+- int is_coax;
+- int dvp_bus;
+- int dvp_lsb;
+- int hsync;
+- int vsync;
+- int poc_delay;
+- atomic_t use_count;
+- struct i2c_client *client;
+- int ti9x3_addr_map[4];
+- char chip_id[6];
+- int ser_id;
+- int vc_map;
+- int csi_map;
+- int gpio[4];
+- struct gpio_desc *pwen; /* chip power en */
+- struct gpio_desc *poc_gpio[4]; /* PoC power supply */
+- struct v4l2_clk *ref_clk; /* ref clock */
+- struct notifier_block reboot_notifier;
+-};
+-
+-static int ser_id;
+-module_param(ser_id, int, 0644);
+-MODULE_PARM_DESC(ser_id, " Serializer ID (default: TI913)");
+-
+-static int is_stp;
+-module_param(is_stp, int, 0644);
+-MODULE_PARM_DESC(is_stp, " STP cable (default: Coax cable)");
+-
+-static int dvp_bus = 8;
+-module_param(dvp_bus, int, 0644);
+-MODULE_PARM_DESC(dvp_bus, " DVP/CSI over FPDLink (default: DVP 8-bit)");
+-
+-static int dvp_lsb = 0;
+-module_param(dvp_lsb, int, 0644);
+-MODULE_PARM_DESC(dvp_lsb, " DVP 8-bit LSB/MSB selection (default: DVP 8-bit MSB)");
+-
+-static int hsync;
+-module_param(hsync, int, 0644);
+-MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
+-
+-static int vsync = 1;
+-module_param(vsync, int, 0644);
+-MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
+-
+-static int poc_delay;
+-module_param(poc_delay, int, 0644);
+-MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)");
+-
+-static int vc_map = 0x3210;
+-module_param(vc_map, int, 0644);
+-MODULE_PARM_DESC(vc_map, " CSI VC MAP (default: 0xe4 - linear map VCx=LINKx)");
+-
+-static int csi_map = 0;
+-module_param(csi_map, int, 0644);
+-MODULE_PARM_DESC(csi_map, " CSI TX MAP (default: 0 - forwarding of all links to CSI0)");
+-
+-static int gpio0 = 0, gpio1 = 0, gpio2 = 0, gpio3 = 0;
+-module_param(gpio0, int, 0644);
+-MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 low level)");
+-module_param(gpio1, int, 0644);
+-MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 low level)");
+-module_param(gpio2, int, 0644);
+-MODULE_PARM_DESC(gpio2, " GPIO2 function select (default: GPIO2 low level)");
+-module_param(gpio3, int, 0644);
+-MODULE_PARM_DESC(gpio3, " GPIO3 function select (default: GPIO3 low level)");
+-
+-#ifdef TI954_SILICON_ERRATA
+-static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val)
+-{
+- if (page > 7)
+- return -EINVAL;
+-
+- reg8_write(client, 0xb0, page << 2);
+- reg8_write(client, 0xb1, reg);
+- reg8_write(client, 0xb2, val);
+-
+- return 0;
+-}
+-
+-static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val)
+-{
+- if (page > 7)
+- return -EINVAL;
+-
+- reg8_write(client, 0xb0, page << 2);
+- reg8_write(client, 0xb1, reg);
+- reg8_read(client, 0xb2, val);
+-
+- return 0;
+-}
+-#endif
+-
+-static void ti9x4_read_chipid(struct i2c_client *client)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+-
+- /* Chip ID */
+- reg8_read(client, 0xf1, &priv->chip_id[0]);
+- reg8_read(client, 0xf2, &priv->chip_id[1]);
+- reg8_read(client, 0xf3, &priv->chip_id[2]);
+- reg8_read(client, 0xf4, &priv->chip_id[3]);
+- reg8_read(client, 0xf5, &priv->chip_id[4]);
+- priv->chip_id[5] = '\0';
+-}
+-
+-static void ti9x4_initial_setup(struct i2c_client *client)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+-
+- /* Initial setup */
+- client->addr = priv->des_addr; /* TI9x4 I2C */
+- reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */
+- switch (priv->csi_rate) {
+- case 1600: /* REFCLK = 25MHZ */
+- case 1500: /* REFCLK = 23MHZ */
+- case 1450: /* REFCLK = 22.5MHZ */
+- reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */
+- break;
+- case 1200: /* REFCLK = 25MHZ */
+- case 1100: /* REFCLK = 22.5MHZ */
+- reg8_write(client, 0x1f, 0x01); /* CSI rate 1.1/1.2Gbps */
+- break;
+- case 800: /* REFCLK = 25MHZ */
+- case 700: /* REFCLK = 22.5MHZ */
+- reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */
+- break;
+- case 400: /* REFCLK = 25MHZ */
+- case 350: /* REFCLK = 22.5MHZ */
+- reg8_write(client, 0x1f, 0x03); /* CSI rate 350/400Mbps */
+- break;
+- default:
+- dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
+- }
+-
+- switch (priv->csi_rate) {
+- case 1600:
+- case 1200:
+- case 800:
+- case 400:
+- /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */
+- priv->fs_time = 2790;
+- break;
+- case 1500:
+- /* FrameSync setup for REFCLK=23MHz, FPS=30: period_counts=1/FPS/13.043mks=1/30/13.043e-6=2556 -> HI=2, LO=2554 */
+- priv->fs_time = 2570;
+- break;
+- case 1450:
+- case 1100:
+- case 700:
+- case 350:
+- /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */
+- priv->fs_time = 2513;
+- break;
+- default:
+- priv->fs_time = 0;
+- dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
+- }
+-
+- if (strcmp(priv->forwarding_mode, "round-robin") == 0) {
+- reg8_write(client, 0x21, 0x03); /* Round Robin forwarding enable for CSI0/CSI1 */
+- } else if (strcmp(priv->forwarding_mode, "synchronized") == 0) {
+- reg8_write(client, 0x21, 0x54); /* Basic Syncronized forwarding enable (FrameSync must be enabled!!) for CSI0/CSI1 */
+- }
+-
+- reg8_write(client, 0x32, 0x03); /* Select TX for CSI0/CSI1, RX for CSI0 */
+- reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4); /* disable CSI output, set CSI lane count, non-continuous CSI mode */
+- reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding */
+-#if 0
+- /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/2/FPS*25MHz =1/2/30*25Mhz =416666 -> FS_TIME=416666 */
+- /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/2/FPS*22.5Mhz=1/2/30*22.5Mhz=375000 -> FS_TIME=375000 */
+-// #define FS_TIME (priv->csi_rate == 1450 ? 376000 : 417666)
+- #define FS_TIME (priv->csi_rate == 1450 ? 385000 : 428000) // FPS=29.2 (new vendor's firmware AWB restriction?)
+- reg8_write(client, 0x1a, FS_TIME >> 16); /* FrameSync time 24bit */
+- reg8_write(client, 0x1b, (FS_TIME >> 8) & 0xff);
+- reg8_write(client, 0x1c, FS_TIME & 0xff);
+- reg8_write(client, 0x18, 0x43); /* Enable FrameSync, 50/50 mode, Frame clock from 25MHz */
+-#else
+- reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */
+- reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */
+- reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
+- reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */
+- reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */
+-#endif
+-}
+-
+-static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+- u8 port_config = 0x78;
+- u8 port_config2 = 0;
+-
+- /* FPDLinkIII setup */
+- client->addr = priv->des_addr; /* TI9x4 I2C */
+- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
+- usleep_range(2000, 2500); /* wait 2ms */
+-
+- switch (priv->ser_id) {
+- case TI913_ID:
+- reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */
+- break;
+- case TI953_ID:
+- reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */
+- break;
+- default:
+- break;
+- }
+-
+- reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */
+-// reg8_write(client, 0x5d, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */
+-// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */
+-
+- if (priv->is_coax)
+- port_config |= 0x04; /* Coax */
+- else
+- port_config |= 0x00; /* STP */
+-
+- switch (priv->dvp_bus) {
+- case 8:
+- port_config2 |= (priv->dvp_lsb ? 0xC0 : 0x80); /* RAW10 as 8-bit prosessing using LSB/MSB bits */
+- /* fall through */
+- case 10:
+- port_config |= 0x03; /* DVP over FPDLink (TI913 compatible) RAW10/RAW8 */
+- break;
+- case 12:
+- port_config |= 0x02; /* DVP over FPDLink (TI913 compatible) RAW12 */
+- break;
+- default:
+- port_config |= 0x00; /* CSI over FPDLink (TI953 compatible) */
+- }
+-
+- if (priv->vsync)
+- port_config2 |= 0x01; /* VSYNC acive low */
+- if (priv->hsync)
+- port_config2 |= 0x02; /* HSYNC acive low */
+-
+- reg8_write(client, 0x6d, port_config);
+- reg8_write(client, 0x7c, port_config2);
+- reg8_write(client, 0x70, ((priv->vc_map >> (idx * 4)) << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */
+- reg8_write(client, 0x71, ((priv->vc_map >> (idx * 4)) << 6) | 0x2c); /* CSI data type: RAW12, assign VC */
+- reg8_write(client, 0xbc, 0x00); /* Setup minimal time between FV and LV to 3 PCLKs */
+- reg8_write(client, 0x72, priv->vc_map >> (idx * 4)); /* CSI VC MAP */
+-}
+-
+-static int ti9x4_initialize(struct i2c_client *client)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+- int idx, timeout;
+- u8 port_sts1[4] = {0, 0, 0, 0}, port_sts2[4] = {0, 0, 0, 0};
+-
+- dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n",
+- priv->links, priv->lanes, priv->forwarding_mode, priv->is_coax ? "coax" : "stp", priv->chip_id);
+-
+- ti9x4_initial_setup(client);
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- if (!IS_ERR(priv->poc_gpio[idx])) {
+- gpiod_direction_output(priv->poc_gpio[idx], 1); /* POC power on */
+- mdelay(priv->poc_delay);
+- }
+-
+- ti9x4_fpdlink3_setup(client, idx);
+- }
+-
+- client->addr = priv->des_addr;
+-
+- /* check lock status */
+- for (timeout = 500 / priv->links; timeout > 0; timeout--) {
+- for (idx = 0; idx < priv->links; idx++) {
+- if ((port_sts1[idx] & 0x1) && (port_sts2[idx] & 0x4))
+- continue;
+-
+- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
+- usleep_range(1000, 1500); /* wait 1ms */
+- reg8_read(client, 0x4d, &port_sts1[idx]); /* Lock status */
+- reg8_read(client, 0x4e, &port_sts2[idx]); /* Freq stable */
+- }
+- }
+-
+- if (!timeout)
+- dev_info(&client->dev, "Receiver lock status [%d,%d,%d,%d]\n",
+- (port_sts1[0] & 0x1) && (port_sts2[0] & 0x4),
+- (port_sts1[1] & 0x1) && (port_sts2[1] & 0x4),
+- (port_sts1[2] & 0x1) && (port_sts2[2] & 0x4),
+- (port_sts1[3] & 0x1) && (port_sts2[3] & 0x4));
+-
+- if (priv->poc_delay)
+- mdelay(100);
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */
+- usleep_range(1000, 1500); /* wait 1ms */
+-
+- /*
+- * Enable only FSIN for remote gpio, all permanent states (0 or 1) setup on serializer side:
+- * this avoids intermittent remote gpio noise (f.e. reset or spuriouse fsin) caused by
+- * unstable/bad link, hence unstable backchannel
+- */
+- client->addr = priv->ti9x3_addr_map[idx]; /* TI9X3 I2C addr */
+- switch (priv->ser_id) {
+- case TI913_ID:
+- reg8_write(client, 0x0d, 0x55); /* Enable remote GPIO0/1 */
+- reg8_write(client, 0x11, 0x10); /* I2C high pulse width */
+- reg8_write(client, 0x12, 0x10); /* I2C low pulse width */
+- break;
+- case TI953_ID:
+- reg8_write(client, 0x0d, (priv->gpio[0] & 0x1) << 0 |
+- (priv->gpio[1] & 0x1) << 1 |
+- (priv->gpio[2] & 0x1) << 2 |
+- (priv->gpio[3] & 0x1) << 3 |
+- (priv->gpio[0] & 0x2) << 3 |
+- (priv->gpio[1] & 0x2) << 4 |
+- (priv->gpio[2] & 0x2) << 5 |
+- (priv->gpio[3] & 0x2) << 6); /* Enable FSIN remote GPIOs and set local constant gpios */
+- reg8_write(client, 0x0e, (!!priv->gpio[0] << 4) |
+- (!!priv->gpio[1] << 5) |
+- (!!priv->gpio[2] << 6) |
+- (!!priv->gpio[3] << 7)); /* Enable serializer GPIOs only for output */
+- reg8_write(client, 0x0b, 0x10); /* I2C high pulse width */
+- reg8_write(client, 0x0c, 0x10); /* I2C low pulse width */
+- break;
+- }
+- client->addr = priv->des_addr;
+-
+- reg8_write(client, 0x6e, 0x88 | (priv->gpio[1] << 4) | priv->gpio[0]); /* Remote GPIO1/GPIO0 setup */
+- reg8_write(client, 0x6f, 0x88 | (priv->gpio[3] << 4) | priv->gpio[2]); /* Remote GPIO3/GPIO2 setup */
+- }
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+-static int ti9x4_g_register(struct v4l2_subdev *sd,
+- struct v4l2_dbg_register *reg)
+-{
+- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- int ret;
+- u8 val = 0;
+-
+- ret = reg8_read(client, (u8)reg->reg, &val);
+- if (ret < 0)
+- return ret;
+-
+- reg->val = val;
+- reg->size = sizeof(u8);
+-
+- return 0;
+-}
+-
+-static int ti9x4_s_register(struct v4l2_subdev *sd,
+- const struct v4l2_dbg_register *reg)
+-{
+- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- return reg8_write(client, (u8)reg->reg, (u8)reg->val);
+-}
+-#endif
+-
+-static int ti9x4_s_power(struct v4l2_subdev *sd, int on)
+-{
+- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- if (on) {
+- if (atomic_inc_return(&priv->use_count) == 1)
+- reg8_write(client, 0x20, 0x00 | priv->csi_map); /* enable port forwarding to CSI */
+- } else {
+- if (atomic_dec_return(&priv->use_count) == 0)
+- reg8_write(client, 0x20, 0xf0 | priv->csi_map); /* disable port forwarding to CSI */
+- }
+-
+- return 0;
+-}
+-
+-static int ti9x4_registered_async(struct v4l2_subdev *sd)
+-{
+- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */
+- reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */
+-// reg8_write(client, 0x18, 0x80); /* Enable FrameSync, Frame clock is external */
+-
+- return 0;
+-}
+-
+-static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+-{
+- struct ti9x4_priv *priv = container_of(nb, struct ti9x4_priv, reboot_notifier);
+- int idx;
+-
+- for (idx = 0; idx < priv->links; idx++) {
+- if (!IS_ERR(priv->poc_gpio[idx]))
+- gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
+- }
+-
+- return NOTIFY_OK;
+-}
+-
+-static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = {
+-#ifdef CONFIG_VIDEO_ADV_DEBUG
+- .g_register = ti9x4_g_register,
+- .s_register = ti9x4_s_register,
+-#endif
+- .s_power = ti9x4_s_power,
+- .registered_async = ti9x4_registered_async,
+-};
+-
+-static int ti9x4_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+-{
+- return 0;
+-}
+-
+-static int ti9x4_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+-{
+- struct ti9x4_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+- struct v4l2_captureparm *cp = &parms->parm.capture;
+-
+- if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+- if (cp->extendedmode != 0)
+- return -EINVAL;
+-
+- if (priv->fps_denominator != cp->timeperframe.denominator ||
+- priv->fps_numerator != cp->timeperframe.numerator) {
+- int f_time;
+-
+- f_time = priv->fs_time * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
+- reg8_write(client, 0x1b, f_time >> 8); /* FrameSync low time MSB */
+- reg8_write(client, 0x1c, f_time & 0xff); /* FrameSync low time LSB */
+-
+- priv->fps_denominator = cp->timeperframe.denominator;
+- priv->fps_numerator = cp->timeperframe.numerator;
+- }
+-
+- return 0;
+-}
+-
+-static struct v4l2_subdev_video_ops ti9x4_video_ops = {
+- .g_parm = ti9x4_g_parm,
+- .s_parm = ti9x4_s_parm,
+-};
+-
+-static struct v4l2_subdev_ops ti9x4_subdev_ops = {
+- .core = &ti9x4_subdev_core_ops,
+- .video = &ti9x4_video_ops,
+-};
+-
+-static int ti9x4_parse_dt(struct i2c_client *client)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+- struct device_node *np = client->dev.of_node;
+- struct device_node *endpoint = NULL, *rendpoint = NULL;
+- struct property *prop;
+- int i;
+- int sensor_delay;
+- char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */
+- struct property *csi_rate_prop, *dvp_order_prop;
+- u8 val = 0;
+- char name[10];
+-
+- if (of_property_read_u32(np, "ti,links", &priv->links))
+- priv->links = 4;
+-
+- if (of_property_read_u32(np, "ti,lanes", &priv->lanes))
+- priv->lanes = 4;
+-
+- priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
+- if (!IS_ERR(priv->ref_clk)) {
+- dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
+- v4l2_clk_enable(priv->ref_clk);
+- }
+-
+- priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH);
+- if (!IS_ERR(priv->pwen)) {
+- mdelay(5);
+- gpiod_direction_output(priv->pwen, 0);
+- mdelay(5);
+- }
+-
+- for (i = 0; i < 4; i++) {
+- sprintf(name, "POC%d", i);
+- priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(name, GFP_KERNEL), 0);
+- }
+-
+- reg8_read(client, 0x00, &val); /* read TI9x4 I2C address */
+- if (val != (priv->des_addr << 1)) {
+- prop = of_find_property(np, "reg", NULL);
+- if (prop)
+- of_remove_property(np, prop);
+- return -ENODEV;
+- }
+-
+- ti9x4_read_chipid(client);
+-
+-#ifdef TI954_SILICON_ERRATA
+- indirect_write(client, 7, 0x15, 0x30);
+- if (pwen > 0)
+- gpio_set_value(pwen, 1);
+- usleep_range(5000, 5500); /* wait 5ms */
+- indirect_write(client, 7, 0x15, 0);
+-#endif
+- if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay))
+- mdelay(sensor_delay);
+- if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode))
+- priv->forwarding_mode = forwarding_mode_default;
+- if (of_property_read_bool(np, "ti,stp"))
+- priv->is_coax = 0;
+- else
+- priv->is_coax = 1;
+- if (of_property_read_u32(np, "ti,dvp_bus", &priv->dvp_bus))
+- priv->dvp_bus = 8;
+- if (of_property_read_bool(np, "ti,dvp_lsb"))
+- priv->dvp_lsb = 1;
+- else
+- priv->dvp_lsb = 0;
+- if (of_property_read_u32(np, "ti,hsync", &priv->hsync))
+- priv->hsync = 0;
+- if (of_property_read_u32(np, "ti,vsync", &priv->vsync))
+- priv->vsync = 1;
+- if (of_property_read_u32(np, "ti,ser_id", &priv->ser_id))
+- priv->ser_id = TI913_ID;
+- if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay))
+- priv->poc_delay = 10;
+- if (of_property_read_u32(np, "ti,vc-map", &priv->vc_map))
+- priv->vc_map = 0x3210;
+- for (i = 0; i < 4; i++) {
+- sprintf(name, "ti,gpio%d", i);
+- if (of_property_read_u32(np, name, &priv->gpio[i]))
+- priv->gpio[i] = 0;
+- }
+-
+- /*
+- * CSI forwarding of all links is to CSI0 by default.
+- * Decide if any link will be forwarded to CSI1 instead CSI0
+- */
+- prop = of_find_property(np, "ti,csi1-links", NULL);
+- if (prop) {
+- const __be32 *link = NULL;
+- u32 v;
+-
+- for (i = 0; i < 4; i++) {
+- link = of_prop_next_u32(prop, link, &v);
+- if (!link)
+- break;
+- priv->csi_map |= BIT(v);
+- }
+- } else {
+- priv->csi_map = 0;
+- }
+-
+- /* module params override dts */
+- if (is_stp)
+- priv->is_coax = 0;
+- if (dvp_bus != 8)
+- priv->dvp_bus = dvp_bus;
+- if (dvp_lsb)
+- priv->dvp_lsb = dvp_lsb;
+- if (hsync)
+- priv->hsync = hsync;
+- if (!vsync)
+- priv->vsync = vsync;
+- if (ser_id)
+- priv->ser_id = ser_id;
+- if (poc_delay)
+- priv->poc_delay = poc_delay;
+- if (vc_map != 0x3210)
+- priv->vc_map = vc_map;
+- if (csi_map)
+- priv->csi_map = csi_map;
+- if (gpio0)
+- priv->gpio[0] = gpio0;
+- if (gpio1)
+- priv->gpio[1] = gpio1;
+- if (gpio2)
+- priv->gpio[2] = gpio2;
+- if (gpio3)
+- priv->gpio[3] = gpio3;
+-
+- for (i = 0; ; i++) {
+- endpoint = of_graph_get_next_endpoint(np, endpoint);
+- if (!endpoint)
+- break;
+-
+- if (i < priv->links) {
+- if (of_property_read_u32(endpoint, "ti9x3-addr", &priv->ti9x3_addr_map[i])) {
+- of_node_put(endpoint);
+- dev_err(&client->dev, "ti9x3-addr not set\n");
+- return -EINVAL;
+- }
+- priv->sd_fwnode[i] = of_fwnode_handle(endpoint);
+- }
+-
+- rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
+- if (!rendpoint)
+- continue;
+-
+- csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL);
+- if (csi_rate_prop) {
+- of_property_read_u32(endpoint, "csi-rate", &priv->csi_rate);
+- of_update_property(rendpoint, csi_rate_prop);
+- }
+-
+- dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
+- if (dvp_order_prop)
+- of_update_property(rendpoint, dvp_order_prop);
+- }
+-
+- of_node_put(endpoint);
+- return 0;
+-}
+-
+-static int ti9x4_probe(struct i2c_client *client,
+- const struct i2c_device_id *did)
+-{
+- struct ti9x4_priv *priv;
+- int err, i;
+-
+- priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- i2c_set_clientdata(client, priv);
+- priv->des_addr = client->addr;
+- priv->client = client;
+- atomic_set(&priv->use_count, 0);
+- priv->fps_numerator = 1;
+- priv->fps_denominator = 30;
+-
+- err = ti9x4_parse_dt(client);
+- if (err)
+- goto out;
+-
+- err = ti9x4_initialize(client);
+- if (err < 0)
+- goto out;
+-
+- for (i = 0; i < priv->links; i++) {
+- v4l2_subdev_init(&priv->sd[i], &ti9x4_subdev_ops);
+- priv->sd[i].owner = client->dev.driver->owner;
+- priv->sd[i].dev = &client->dev;
+- priv->sd[i].grp_id = i;
+- v4l2_set_subdevdata(&priv->sd[i], priv);
+- priv->sd[i].fwnode = priv->sd_fwnode[i];
+-
+- snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x",
+- client->dev.driver->name, i2c_adapter_id(client->adapter),
+- client->addr);
+-
+- err = v4l2_async_register_subdev(&priv->sd[i]);
+- if (err < 0)
+- goto out;
+- }
+-
+- priv->reboot_notifier.notifier_call = ti9x4_reboot_notifier;
+- err = register_reboot_notifier(&priv->reboot_notifier);
+- if (err)
+- dev_err(&client->dev, "failed to register reboot notifier\n");
+-
+-out:
+- return err;
+-}
+-
+-static int ti9x4_remove(struct i2c_client *client)
+-{
+- struct ti9x4_priv *priv = i2c_get_clientdata(client);
+- int i;
+-
+- unregister_reboot_notifier(&priv->reboot_notifier);
+-
+- for (i = 0; i < priv->links; i++) {
+- v4l2_async_unregister_subdev(&priv->sd[i]);
+- v4l2_device_unregister_subdev(&priv->sd[i]);
+- }
+-
+- return 0;
+-}
+-
+-static const struct of_device_id ti9x4_dt_ids[] = {
+- { .compatible = "ti,ti9x4" },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, ti9x4_dt_ids);
+-
+-static const struct i2c_device_id ti9x4_id[] = {
+- { "ti9x4", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, ti9x4_id);
+-
+-static struct i2c_driver ti9x4_i2c_driver = {
+- .driver = {
+- .name = "ti9x4",
+- .of_match_table = of_match_ptr(ti9x4_dt_ids),
+- },
+- .probe = ti9x4_probe,
+- .remove = ti9x4_remove,
+- .id_table = ti9x4_id,
+-};
+-
+-module_i2c_driver(ti9x4_i2c_driver);
+-
+-MODULE_DESCRIPTION("FPDLinkIII driver for DS90UB9x4");
+-MODULE_AUTHOR("Vladimir Barinov");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/ti9x4.h b/drivers/media/i2c/soc_camera/ti9x4.h
+deleted file mode 100644
+index 6825f8a..0000000
+--- a/drivers/media/i2c/soc_camera/ti9x4.h
++++ /dev/null
+@@ -1,204 +0,0 @@
+-/*
+- * TI FPDLinkIII driver include file
+- *
+- * Copyright (C) 2017 Cogent Embedded, Inc.
+- *
+- * 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 (at your
+- * option) any later version.
+- */
+-
+-#ifndef _TI9X4_H
+-#define _TI9X4_H
+-
+-//#define DEBUG
+-#ifdef DEBUG
+-#undef dev_dbg
+-#define dev_dbg dev_info
+-#endif
+-
+-#define MAXIM_NUM_RETRIES 1 /* number of read/write retries */
+-#define TI913_ID 0x58
+-#define TI953_ID 0x30 /* or starapped to 0x32 */
+-#define TI9X4_ID 0x00 /* strapped */
+-#define BROADCAST 0x6f
+-
+-static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val)
+-{
+- int ret, retries;
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_smbus_read_byte_data(client, reg);
+- if (!(ret < 0))
+- break;
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "read fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- } else {
+- *val = ret;
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val)
+-{
+- int ret, retries;
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_smbus_write_byte_data(client, reg, val);
+- if (!(ret < 0))
+- break;
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "write fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val)
+-{
+- int ret, retries;
+- u8 buf[2] = {reg >> 8, reg & 0xff};
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 2);
+- if (ret == 2) {
+- ret = i2c_master_recv(client, buf, 1);
+- if (ret == 1)
+- break;
+- }
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "read fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- } else {
+- *val = buf[0];
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
+-{
+- int ret, retries;
+- u8 buf[3] = {reg >> 8, reg & 0xff, val};
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 3);
+- if (ret == 3)
+- break;
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "write fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
+-{
+- int ret, retries;
+- u8 buf[2] = {reg >> 8, reg & 0xff};
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 2);
+- if (ret == 2) {
+- ret = i2c_master_recv(client, val, n);
+- if (ret == n)
+- break;
+- }
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
+- client->addr, reg, reg + n, ret);
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
+-{
+- int ret, retries;
+- u8 buf[2 + n];
+-
+- buf[0] = reg >> 8;
+- buf[1] = reg & 0xff;
+- memcpy(&buf[2], val, n);
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 2 + n);
+- if (ret == 2 + n)
+- break;
+- }
+-
+- if (ret < 0) {
+- dev_dbg(&client->dev,
+- "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
+- client->addr, reg, reg + n, ret);
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
+-{
+- int ret, retries;
+- u8 buf[2] = {reg >> 8, reg & 0xff};
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 2);
+- if (ret == 2) {
+- ret = i2c_master_recv(client, buf, 2);
+- if (ret == 2)
+- break;
+- }
+- }
+-
+- if (ret < 0) {
+- dev_err(&client->dev,
+- "read fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- } else {
+- *val = ((u16)buf[0] << 8) | buf[1];
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-
+-static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
+-{
+- int ret, retries;
+- u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
+-
+- for (retries = MAXIM_NUM_RETRIES; retries; retries--) {
+- ret = i2c_master_send(client, buf, 4);
+- if (ret == 4)
+- break;
+- }
+-
+- if (ret < 0) {
+- dev_err(&client->dev,
+- "write fail: chip 0x%x register 0x%x: %d\n",
+- client->addr, reg, ret);
+- }
+-
+- return ret < 0 ? ret : 0;
+-}
+-#endif /* _TI9X4_H */
+-
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch
new file mode 100644
index 00000000..a9535a92
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch
@@ -0,0 +1,4855 @@
+From 845697c2d8a9620131759d72483923ed5612063d Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 10:52:23 +0300
+Subject: [PATCH] media: i2c: add max96712 and max9296
+
+This adds GMSL2 drivers for MAX96712 and MAX9296
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/Kconfig | 14 +
+ drivers/media/i2c/soc_camera/gmsl/Makefile | 2 +
+ drivers/media/i2c/soc_camera/gmsl/common.h | 499 +++++++
+ drivers/media/i2c/soc_camera/gmsl/max9295.h | 29 +
+ drivers/media/i2c/soc_camera/gmsl/max9296.c | 1423 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/gmsl/max9296.h | 281 ++++
+ drivers/media/i2c/soc_camera/gmsl/max9296_debug.h | 462 +++++++
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 1423 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/gmsl/max96712.h | 263 ++++
+ drivers/media/i2c/soc_camera/gmsl/max96712_debug.h | 362 +++++
+ 10 files changed, 4758 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/common.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9295.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.c
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.c
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Kconfig b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+index c7a33bf..4a7dd6c 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/Kconfig
++++ b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+@@ -9,3 +9,17 @@ config SOC_CAMERA_MAX9288
+ depends on I2C
+ help
+ This is a MAXIM max9288 GMSL driver
++
++config SOC_CAMERA_MAX9296
++ tristate "max9296 GMSL2 support"
++ depends on I2C
++ select REGMAP_I2C
++ help
++ This is a MAXIM max9296 GMSL2 driver
++
++config SOC_CAMERA_MAX96712
++ tristate "max96712 GMSL2 support"
++ depends on I2C
++ select REGMAP_I2C
++ help
++ This is a MAXIM max96712 GMSL2 driver
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Makefile b/drivers/media/i2c/soc_camera/gmsl/Makefile
+index 9925314..bda7a58 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/Makefile
++++ b/drivers/media/i2c/soc_camera/gmsl/Makefile
+@@ -1,3 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o
+ obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o
++obj-$(CONFIG_SOC_CAMERA_MAX9296) += max9296.o
++obj-$(CONFIG_SOC_CAMERA_MAX96712) += max96712.o
+diff --git a/drivers/media/i2c/soc_camera/gmsl/common.h b/drivers/media/i2c/soc_camera/gmsl/common.h
+new file mode 100644
+index 0000000..98bb1c0
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/common.h
+@@ -0,0 +1,499 @@
++/*
++ * MAXIM GMSL common header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/i2c-mux.h>
++#include "max9295.h"
++
++#define MAX9271_ID 0x09
++#define MAX9286_ID 0x40
++#define MAX9288_ID 0x2A
++#define MAX9290_ID 0x2C
++#define MAX9295A_ID 0x91
++#define MAX9295B_ID 0x93
++#define MAX9296A_ID 0x94
++#define MAX96705_ID 0x41
++#define MAX96706_ID 0x4A
++#define MAX96707_ID 0x45 /* MAX96715: same but lack of HS pin */
++#define MAX96708_ID 0x4C
++#define MAX96712_ID 0x20
++
++#define UB960_ID 0x00 /* strapped */
++
++#define BROADCAST 0x6f
++
++#define REG8_NUM_RETRIES 1 /* number of read/write retries */
++#define REG16_NUM_RETRIES 10 /* number of read/write retries */
++
++static inline char* chip_name(int id)
++{
++ switch (id) {
++ case MAX9271_ID:
++ return "MAX9271";
++ case MAX9286_ID:
++ return "MAX9286";
++ case MAX9288_ID:
++ return "MAX9288";
++ case MAX9290_ID:
++ return "MAX9290";
++ case MAX9295A_ID:
++ return "MAX9295A";
++ case MAX9295B_ID:
++ return "MAX9295B";
++ case MAX9296A_ID:
++ return "MAX9296A";
++ case MAX96705_ID:
++ return "MAX96705";
++ case MAX96706_ID:
++ return "MAX96706";
++ case MAX96707_ID:
++ return "MAX96707";
++ case MAX96712_ID:
++ return "MAX96712";
++ default:
++ return "serializer";
++ }
++}
++
++enum gmsl_mode {
++ MODE_GMSL1 = 1,
++ MODE_GMSL2,
++};
++
++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++
++#define MIPI_DT_GENERIC 0x10
++#define MIPI_DT_GENERIC_1 0x11
++#define MIPI_DT_EMB 0x12
++#define MIPI_DT_YUV8 0x1e
++#define MIPI_DT_YUV10 0x1f
++#define MIPI_DT_RGB565 0x22
++#define MIPI_DT_RGB666 0x23
++#define MIPI_DT_RGB888 0x24
++#define MIPI_DT_RAW8 0x2a
++#define MIPI_DT_RAW10 0x2b
++#define MIPI_DT_RAW12 0x2c
++#define MIPI_DT_RAW14 0x2d
++#define MIPI_DT_RAW16 0x2e
++#define MIPI_DT_RAW20 0x2f
++#define MIPI_DT_YUV12 0x30
++
++static inline int mipi_dt_to_bpp(unsigned int dt)
++{
++ switch (dt) {
++ case 0x2a:
++ case 0x10 ... 0x12:
++ case 0x31 ... 0x37:
++ return 0x08;
++ case 0x2b:
++ return 0x0a;
++ case 0x2c:
++ return 0x0c;
++ case 0x0d:
++ return 0x0e;
++ case 0x22:
++ case 0x1e:
++ case 0x2e:
++ return 0x10;
++ case 0x23:
++ return 0x12;
++ case 0x1f:
++ case 0x2f:
++ return 0x14;
++ case 0x24:
++ case 0x30:
++ return 0x18;
++ default:
++ return 0x08;
++ }
++}
++
++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val)
++{
++ int ret, retries;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_read_byte_data(client, reg);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ret;
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val)
++{
++ int ret, retries;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_write_byte_data(client, reg, val);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2;
++ reg8_read(client, reg, &val2);
++ if (val != val2)
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x "
++ "0x%x->0x%x\n", client->addr, reg, val, val2);
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 1);
++ if (ret == 1)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = buf[0];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
++{
++ int ret, retries;
++ u8 buf[3] = {reg >> 8, reg & 0xff, val};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 3);
++ if (ret == 3)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2;
++ reg16_read(client, reg, &val2);
++ if (val != val2)
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x "
++ "0x%x->0x%x\n", client->addr, reg, val, val2);
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 2);
++ if (ret == 2)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ((u16)buf[0] << 8) | buf[1];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
++{
++ int ret, retries;
++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 4);
++ if (ret == 4)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, val, n);
++ if (ret == n)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
++{
++ int ret, retries;
++ u8 buf[2 + n];
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ memcpy(&buf[2], val, n);
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2 + n);
++ if (ret == 2 + n)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2[n];
++ ret = reg16_read_n(client, reg, val2, n);
++ if (ret < 0)
++ return ret;
++
++ if (memcmp(val, val2, n)) {
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x-0x%x "
++ "'%*phN'->'%*phN'\n", client->addr, reg, reg + n,
++ n, val, n, val2);
++ ret = -EBADE;
++ }
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_read_addr(struct i2c_client *client, int addr, u8 reg, u8 *val)
++{
++ int ret, retries;
++ union i2c_smbus_data data;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags,
++ I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ addr, reg, ret);
++ } else {
++ *val = data.byte;
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_write_addr(struct i2c_client *client, u8 addr, u8 reg, u8 val)
++{
++ int ret, retries;
++ union i2c_smbus_data data;
++
++ data.byte = val;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags,
++ I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x value 0x%0x: %d\n",
++ addr, reg, val, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++
++static inline int reg16_write_addr(struct i2c_client *client, int chip, u16 reg, u8 val)
++{
++ struct i2c_msg msg[1];
++ u8 wbuf[3];
++ int ret;
++
++ msg->addr = chip;
++ msg->flags = 0;
++ msg->len = 3;
++ msg->buf = wbuf;
++ wbuf[0] = reg >> 8;
++ wbuf[1] = reg & 0xff;
++ wbuf[2] = val;
++
++ ret = i2c_transfer(client->adapter, msg, 1);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x wr 0x%04x (0x%02x): %d\n",
++ chip, reg, val, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static inline int reg16_read_addr(struct i2c_client *client, int chip, u16 reg, int *val)
++{
++ struct i2c_msg msg[2];
++ u8 wbuf[2];
++ u8 rbuf[1];
++ int ret;
++
++ msg[0].addr = chip;
++ msg[0].flags = 0;
++ msg[0].len = 2;
++ msg[0].buf = wbuf;
++ wbuf[0] = reg >> 8;
++ wbuf[1] = reg & 0xff;
++
++ msg[1].addr = chip;
++ msg[1].flags = I2C_M_RD;
++ msg[1].len = 1;
++ msg[1].buf = rbuf;
++
++ ret = i2c_transfer(client->adapter, msg, 2);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x rd 0x%04x: %d\n", chip, reg, ret);
++ return ret;
++ }
++
++ *val = rbuf[0];
++
++ return 0;
++}
++
++#define __reg8_read(addr, reg, val) reg8_read_addr(priv->client, addr, reg, val)
++#define __reg8_write(addr, reg, val) reg8_write_addr(priv->client, addr, reg, val)
++#define __reg16_read(addr, reg, val) reg16_read_addr(priv->client, addr, reg, val)
++#define __reg16_write(addr, reg, val) reg16_write_addr(priv->client, addr, reg, val)
++
++/* copy this struct from drivers/i2c/i2c-mux.c for getting muxc from adapter private data */
++struct i2c_mux_priv {
++ struct i2c_adapter adap;
++ struct i2c_algorithm algo;
++ struct i2c_mux_core *muxc;
++ u32 chan_id;
++};
++
++static inline int get_des_id(struct i2c_client *client)
++{
++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data;
++
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9286"))
++ return MAX9286_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9288"))
++ return MAX9288_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9296"))
++ return MAX9296A_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96706"))
++ return MAX96706_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96712"))
++ return MAX96712_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "ti9x4"))
++ return UB960_ID;
++
++ return -EINVAL;
++}
++
++static inline int get_des_addr(struct i2c_client *client)
++{
++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data;
++
++ return to_i2c_client(mux_priv->muxc->dev)->addr;
++}
++
++static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr, int gmsl_mode)
++{
++ switch (get_des_id(client)) {
++ case MAX9286_ID:
++ case MAX9288_ID:
++ case MAX9296A_ID:
++ case MAX96706_ID:
++ case MAX96712_ID:
++ if (gmsl_mode == MODE_GMSL1) {
++ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */
++ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */
++ }
++ if (gmsl_mode == MODE_GMSL2) {
++ reg16_write_addr(client, ser_addr, MAX9295_I2C2, client->addr << 1); /* Sensor translated I2C address */
++ reg16_write_addr(client, ser_addr, MAX9295_I2C3, sensor_addr << 1); /* Sensor native I2C address */
++ }
++ break;
++ case UB960_ID:
++ reg8_write_addr(client, get_des_addr(client), 0x65, client->addr << 1); /* Sensor translated I2C address */
++ reg8_write_addr(client, get_des_addr(client), 0x5d, sensor_addr << 1); /* Sensor native I2C address */
++ break;
++ }
++ usleep_range(2000, 2500);
++}
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9295.h b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+new file mode 100644
+index 0000000..cf12d3c
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+@@ -0,0 +1,29 @@
++/*
++ * MAXIM max9295 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#define MAX9295_REG2 0x02
++#define MAX9295_REG7 0x07
++#define MAX9295_CTRL0 0x10
++#define MAX9295_I2C2 0x42
++#define MAX9295_I2C3 0x43
++#define MAX9295_I2C4 0x44
++#define MAX9295_I2C5 0x45
++#define MAX9295_I2C6 0x46
++
++#define MAX9295_CROSS(n) (0x1b0 + n)
++
++#define MAX9295_GPIO_A(n) (0x2be + (3 * n))
++#define MAX9295_GPIO_B(n) (0x2bf + (3 * n))
++#define MAX9295_GPIO_C(n) (0x2c0 + (3 * n))
++
++#define MAX9295_VIDEO_TX_BASE(n) (0x100 + (0x8 * n))
++#define MAX9295_VIDEO_TX0(n) (MAX9295_VIDEO_TX_BASE(n) + 0)
++#define MAX9295_VIDEO_TX1(n) (MAX9295_VIDEO_TX_BASE(n) + 1)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+new file mode 100644
+index 0000000..a6d286f
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+@@ -0,0 +1,1423 @@
++/*
++ * MAXIM max9296 GMSL2 driver
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/i2c-mux.h>
++#include <linux/module.h>
++#include <linux/regulator/consumer.h>
++#include <linux/notifier.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/regmap.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-clk.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "common.h"
++#include "max9296.h"
++#include "max9296_debug.h"
++
++static char mbus_default[10] = "dvp"; /* mipi, dvp */
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int fsync_period;
++module_param(fsync_period, int, 0644);
++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = MIPI_DT_YUV8;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)");
++
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)");
++
++static int gmsl = MODE_GMSL2;
++module_param(gmsl, int, 0644);
++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
++
++static char *mbus = "dvp";
++module_param(mbus, charp, 0644);
++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
++
++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1;
++module_param(gpio0, int, 0644);
++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)");
++module_param(gpio1, int, 0644);
++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)");
++module_param(gpio7, int, 0644);
++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)");
++module_param(gpio8, int, 0644);
++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)");
++
++static const struct regmap_config max9296_regmap[] = {
++ {
++ /* max9296 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1f03,
++ }, {
++ /* max9271/max96705 */
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 0xff,
++ }, {
++ /* max9695 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1b03,
++ }
++};
++
++static void max9296_write_remote_verify(struct max9296_priv *priv, int link_n, u8 reg, int val)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ int sts = 0;
++ u8 val2 = 0;
++
++ ser_write(reg, val);
++ des_read(MAX9296_COMMON1, &sts);
++ /* check ACKed */
++ if (sts & BIT(link_n)) {
++ ser_read(reg, &val2);
++ if (val2 == val)
++ break;
++ }
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&priv->client->dev, "timeout remote write acked\n");
++}
++
++static void max9296_reset_oneshot(struct max9296_priv *priv)
++{
++ int timeout;
++ int reg = 0;
++
++ des_update_bits(MAX9296_CTRL0, BIT(5), BIT(5)); /* set reset one-shot */
++
++ /* wait for one-shot bit self-cleared */
++ for (timeout = 0; timeout < 100; timeout++) {
++ des_read(MAX9296_CTRL0, &reg);
++ if (!(reg & BIT(5)))
++ break;
++
++ msleep(1);
++ }
++
++ if (reg & BIT(5))
++ dev_err(&priv->client->dev, "Failed reset oneshot\n");
++}
++
++/* -----------------------------------------------------------------------------
++ * MIPI, mapping, routing
++ */
++
++static void max9296_pipe_override(struct max9296_priv *priv, unsigned int pipe,
++ unsigned int dt, unsigned int vc)
++{
++ int bpp, bank;
++
++ bpp = mipi_dt_to_bpp(dt);
++ bank = pipe / 4;
++ pipe %= 4;
++
++ if (priv->dbl == 1) {
++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */
++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */
++ bpp = bpp / 2; /* divide because of MUX=1 */
++ }
++
++ switch (pipe) {
++ case 0:
++ /* Pipe X: 0 or 4 */
++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */
++ break;
++ case 1:
++ /* Pipe Y: 1 or 5 */
++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f);
++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ case 2:
++ /* Pipe Z: 2 or 6 */
++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03);
++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */
++ break;
++ case 3:
++ /* Pipe U: 3 or 7 */
++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ }
++}
++
++static void max9296_set_pipe_to_mipi_mapping(struct max9296_priv *priv,
++ unsigned int pipe, unsigned int map_n,
++ unsigned int in_dt, unsigned int in_vc,
++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi)
++{
++ int offset = 2 * (map_n % 4);
++
++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt);
++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt);
++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset);
++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */
++}
++
++static void max9296_mipi_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_REG2, 0); /* disable all pipes */
++
++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */
++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */
++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */
++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */
++ //des_write(MAX_MIPI_PHY6, 0x00);
++
++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */
++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */
++
++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */
++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++
++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL1
++ */
++
++static int max9296_gmsl1_sensor_reset(struct max9296_priv *priv, int link_n, int reset_on)
++{
++ struct max9296_link *link = priv->link[link_n];
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return -EINVAL;
++
++ /* sensor reset/unreset */
++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++
++ return 0;
++}
++
++static void max9296_gmsl1_cc_enable(struct max9296_priv *priv, int link, int on)
++{
++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00);
++ usleep_range(2000, 2500);
++}
++
++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX_GMSL1_CB(link_n), &val);
++
++ return !!(val & BIT(0));
++}
++
++static void max9296_gmsl1_link_crossbar_setup(struct max9296_priv *priv, int link, int dt)
++{
++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */
++ switch (dt) {
++ case MIPI_DT_YUV8:
++ des_write(MAX_CROSS(link, 0), 7);
++ des_write(MAX_CROSS(link, 1), 6);
++ des_write(MAX_CROSS(link, 2), 5);
++ des_write(MAX_CROSS(link, 3), 4);
++ des_write(MAX_CROSS(link, 4), 3);
++ des_write(MAX_CROSS(link, 5), 2);
++ des_write(MAX_CROSS(link, 6), 1);
++ des_write(MAX_CROSS(link, 7), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 8), 15);
++ des_write(MAX_CROSS(link, 9), 14);
++ des_write(MAX_CROSS(link, 10), 13);
++ des_write(MAX_CROSS(link, 11), 12);
++ des_write(MAX_CROSS(link, 12), 11);
++ des_write(MAX_CROSS(link, 13), 10);
++ des_write(MAX_CROSS(link, 14), 9);
++ des_write(MAX_CROSS(link, 15), 8);
++ }
++ break;
++ case MIPI_DT_RAW12:
++ des_write(MAX_CROSS(link, 0), 11);
++ des_write(MAX_CROSS(link, 1), 10);
++ des_write(MAX_CROSS(link, 2), 9);
++ des_write(MAX_CROSS(link, 3), 8);
++ des_write(MAX_CROSS(link, 4), 7);
++ des_write(MAX_CROSS(link, 5), 6);
++ des_write(MAX_CROSS(link, 6), 5);
++ des_write(MAX_CROSS(link, 7), 4);
++ des_write(MAX_CROSS(link, 8), 3);
++ des_write(MAX_CROSS(link, 9), 2);
++ des_write(MAX_CROSS(link, 10), 1);
++ des_write(MAX_CROSS(link, 11), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 12), 23);
++ des_write(MAX_CROSS(link, 13), 22);
++ des_write(MAX_CROSS(link, 14), 21);
++ des_write(MAX_CROSS(link, 15), 20);
++ des_write(MAX_CROSS(link, 16), 19);
++ des_write(MAX_CROSS(link, 17), 18);
++ des_write(MAX_CROSS(link, 18), 17);
++ des_write(MAX_CROSS(link, 19), 16);
++ des_write(MAX_CROSS(link, 20), 15);
++ des_write(MAX_CROSS(link, 21), 14);
++ des_write(MAX_CROSS(link, 22), 13);
++ des_write(MAX_CROSS(link, 23), 12);
++ }
++ break;
++ default:
++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt);
++ break;
++ }
++
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max9296_gmsl1_initial_setup(struct max9296_priv *priv)
++{
++ int i;
++
++ des_write(MAX9296_REG6, 0x10); /* set GMSL1 mode */
++ des_write(MAX9296_REG1, 0x01); /* 187.5M/3G */
++
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */
++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */
++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */
++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */
++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */
++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */
++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */
++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */
++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */
++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */
++ }
++}
++
++static int max9296_gmsl1_reverse_channel_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */
++ int lock_sts;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ u8 val = 0;
++ int ret = 0;
++
++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */
++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */
++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */
++ usleep_range(2000, 2500);
++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */
++ des_write(MAX9296_GMSL1_EN, BIT(link_n)); /* enable GMSL link# */
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++ usleep_range(2000, 2500);
++
++ for (; timeout > 0; timeout--) {
++ if (priv->him) {
++ /* HIM mode setup */
++ __reg8_write(ser_addrs[0], 0x4d, 0xc0);
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++ } else {
++ /* Legacy mode setup */
++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */
++ usleep_range(2000, 2500);
++
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */
++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500);
++
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++
++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */
++ usleep_range(2000, 2500);
++ }
++
++ __reg8_read(ser_addrs[0], 0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ ser_read(0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) {
++ regulator_disable(link->poc_reg); /* POC power off */
++ mdelay(200);
++ ret = regulator_enable(link->poc_reg); /* POC power on */
++ if (ret)
++ dev_err(&link->client->dev, "failed to enable poc regulator\n");
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max9296_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */
++
++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */
++ usleep_range(2000, 2500);
++ des_read(MAX_GMSL1_CB(link_n), &lock_sts);
++ lock_sts = !!(lock_sts & 0x01);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts);
++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr,
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++ return ret;
++}
++
++static int max9296_gmsl1_link_serializer_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++
++ /* GMSL setup */
++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500);
++
++ if (link->ser_id != MAX9271_ID) {
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ if (priv->dbl == 1) {
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ ser_write(0x20, priv->cb[7]);
++ ser_write(0x21, priv->cb[6]);
++ ser_write(0x22, priv->cb[5]);
++ ser_write(0x23, priv->cb[4]);
++ ser_write(0x24, priv->cb[3]);
++ ser_write(0x25, priv->cb[2]);
++ ser_write(0x26, priv->cb[1]);
++ ser_write(0x27, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer always) */
++ ser_write(0x30, priv->cb[7] + 16);
++ ser_write(0x31, priv->cb[6] + 16);
++ ser_write(0x32, priv->cb[5] + 16);
++ ser_write(0x33, priv->cb[4] + 16);
++ ser_write(0x34, priv->cb[3] + 16);
++ ser_write(0x35, priv->cb[2] + 16);
++ ser_write(0x36, priv->cb[1] + 16);
++ ser_write(0x37, priv->cb[0] + 16);
++ } else {
++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */
++ ser_write(0x20, priv->cb[4]);
++ ser_write(0x21, priv->cb[3]);
++ ser_write(0x22, priv->cb[2]);
++ ser_write(0x23, priv->cb[1]);
++ ser_write(0x24, priv->cb[0]);
++ ser_write(0x25, 0x40);
++ ser_write(0x26, 0x40);
++ if (link->ser_id == MAX96705_ID) {
++ ser_write(0x27, 14); /* HS: D14->D18 */
++ ser_write(0x28, 15); /* VS: D15->D19 */
++ ser_write(0x29, 14); /* DE: D14->D20 */
++ }
++ if (link->ser_id == MAX96707_ID) {
++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */
++ ser_write(0x28, 13); /* VS: D13->D19 */
++ ser_write(0x29, 12); /* DE: D12->D20 */
++ }
++ ser_write(0x2A, 0x40);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, 0x10 + priv->cb[7]);
++ ser_write(0x31, 0x10 + priv->cb[6]);
++ ser_write(0x32, 0x10 + priv->cb[5]);
++ ser_write(0x33, 0x10 + priv->cb[4]);
++ ser_write(0x34, 0x10 + priv->cb[3]);
++ ser_write(0x35, 0x10 + priv->cb[2]);
++ ser_write(0x36, 0x10 + priv->cb[1]);
++ ser_write(0x37, 0x10 + priv->cb[0]);
++ ser_write(0x38, priv->cb[7]);
++ ser_write(0x39, priv->cb[6]);
++ ser_write(0x3A, priv->cb[5]);
++
++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
++ }
++ break;
++ case MIPI_DT_RAW12:
++ /* setup crossbar for RAW12: reverse DVP bus */
++ ser_write(0x20, priv->cb[11]);
++ ser_write(0x21, priv->cb[10]);
++ ser_write(0x22, priv->cb[9]);
++ ser_write(0x23, priv->cb[8]);
++ ser_write(0x24, priv->cb[7]);
++ ser_write(0x25, priv->cb[6]);
++ ser_write(0x26, priv->cb[5]);
++ ser_write(0x27, priv->cb[4]);
++ ser_write(0x28, priv->cb[3]);
++ ser_write(0x29, priv->cb[2]);
++ ser_write(0x2a, priv->cb[1]);
++ ser_write(0x2b, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, priv->cb[11] + 16);
++ ser_write(0x31, priv->cb[10] + 16);
++ ser_write(0x32, priv->cb[9] + 16);
++ ser_write(0x33, priv->cb[8] + 16);
++ ser_write(0x34, priv->cb[7] + 16);
++ ser_write(0x35, priv->cb[6] + 16);
++ ser_write(0x36, priv->cb[5] + 16);
++ ser_write(0x37, priv->cb[4] + 16);
++ ser_write(0x38, priv->cb[3] + 16);
++ ser_write(0x39, priv->cb[2] + 16);
++ ser_write(0x3a, priv->cb[1] + 16);
++ ser_write(0x3b, priv->cb[0] + 16);
++
++ if (!(priv->bws || priv->hibw) && priv->dbl)
++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++ break;
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */
++ /* put serializer in configuration link state */
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static void max9296_gmsl1_link_pipe_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight map */
++ int dt = priv->dt; /* should come from imager */
++ int in_vc = 0;
++
++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ /* use map #0 for payload data */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */
++ dt, in_vc, /* src DT, VC */
++ dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #1 for FS */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */
++ 0x00, in_vc, /* src DT, VC */
++ 0x00, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #2 for FE */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */
++ 0x01, in_vc, /* src DT, VC */
++ 0x01, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ usleep_range(5000, 5500);
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max9296_gmsl1_postinit(struct max9296_priv *priv)
++{
++ int i;
++ u8 val = 0;
++
++ for (i = 0; i < priv->n_links; i++) {
++ struct max9296_link *link = priv->link[i];
++
++ if (!(priv->links_mask & BIT(i)))
++ continue;
++
++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */
++ des_write(MAX9296_GMSL1_EN, BIT(i)); /* enable GMSL link# */
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(i)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++ usleep_range(2000, 2500);
++
++ ser_read(0x15, &val);
++ if (!(val & BIT(1)))
++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i);
++
++ /* switch to GMSL serial_link for streaming video */
++ max9296_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83);
++ usleep_range(2000, 2500);
++
++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */
++
++ switch (priv->link[i]->ser_id) {
++ case MAX9271_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */
++ break;
++ case MAX96705_ID:
++ case MAX96707_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */
++ break;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */
++
++ des_write(MAX9296_GMSL1_EN, priv->links_mask); /* enable detected links */
++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */
++ max9296_reset_oneshot(priv); /* one-shot reset links */
++}
++
++static void max9296_gmsl1_fsync_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX9296_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX9296_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ //des_write(MAX9296_FSYNC_8, 0x00); /* Disable Err Thresh */
++ //des_write(MAX9296_FSYNC_9, 0x00); /* Disable Err Thresh */
++ des_write(MAX9296_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX9296_FSYNC_11, 0x00);
++
++ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */
++
++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */
++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */
++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */
++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */
++
++ des_write(MAX9296_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL2
++ */
++
++static void max9296_gmsl2_cc_enable(struct max9296_priv *priv, int link, int on)
++{
++ /* nothing */
++}
++
++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX9296_CTRL3, &val);
++
++ return !!(val & BIT(3)) && (val & BIT(link_n + 4));
++}
++
++static void max9296_gmsl2_initial_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_REG6, 0xC0 | 0x10); /* set GMSL2 mode */
++ des_write(MAX9296_REG1, 0x02); /* 187.5M/6G */
++}
++
++static int max9296_gmsl2_reverse_channel_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */
++ int timeout = priv->timeout;
++ int ret = 0;
++ int i = 0;
++
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++
++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
++ while ((!max9296_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
++ msleep(1);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) {
++ int val = 0;
++
++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */
++ if (val == MAX9295A_ID || val == MAX9295B_ID) {
++ link->ser_id = val;
++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++ }
++
++ if (i == ARRAY_SIZE(ser_addrs)) {
++ dev_err(&priv->client->dev, "serializer not found\n");
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i],
++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : "");
++ return ret;
++}
++
++static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int i;
++
++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
++ //msleep(100);
++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
++ }
++
++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
++
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++
++ for (i = 0; i < 11; i++) {
++ if (priv->gpio[i] == 0) {
++ /* GPIO set 0 */
++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */
++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */
++ }
++ if (priv->gpio[i] == 1) {
++ /* GPIO set 1 */
++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */
++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */
++ }
++ if (priv->gpio[i] == 2) {
++ /* GPIO FSIN */
++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ }
++ if (priv->gpio[i] == 3) {
++ /* GPIO Interrupt */
++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */
++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static struct {
++ int in_dt;
++ int out_dt;
++} gmsl2_pipe_maps[] = {
++ {0x00, 0x00}, /* FS */
++ {0x01, 0x01}, /* FE */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++};
++
++static void max9296_gmsl2_pipe_set_source(struct max9296_priv *priv, int pipe, int phy, int in_pipe)
++{
++ // TODO
++}
++
++static void max9296_gmsl2_link_pipe_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight mapping */
++ int dt = priv->dt; /* must come from imager */
++ int in_vc = 0;
++ int i;
++
++ max9296_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ des_write(MAX9296_RX0(pipe), 0); /* stream_id = 0 */
++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */
++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++ }
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) {
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */
++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */
++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ }
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max9296_gmsl2_postinit(struct max9296_priv *priv)
++{
++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */
++ max9296_reset_oneshot(priv); /* one-shot reset links */
++}
++
++static void max9296_gmsl2_link_crossbar_setup(struct max9296_priv *priv, int link, int dt)
++{
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv)
++{
++ /* TODO */
++}
++
++/* -----------------------------------------------------------------------------
++ * I2C Multiplexer
++ */
++
++static int max9296_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
++{
++ /* Do nothing! */
++ return 0;
++}
++
++static int max9296_i2c_mux_init(struct max9296_priv *priv)
++{
++ struct i2c_client *client = priv->client;
++
++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
++ return -ENODEV;
++
++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev,
++ priv->n_links, 0, I2C_MUX_LOCKED,
++ max9296_i2c_mux_select, NULL);
++ if (!priv->mux)
++ return -ENOMEM;
++
++ priv->mux->priv = priv;
++
++ return 0;
++}
++
++#define max9296_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_cc_enable(priv, i, en) : \
++ max9296_gmsl1_cc_enable(priv, i, en))
++#define max9296_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_initial_setup(priv) : \
++ max9296_gmsl1_initial_setup(priv))
++#define max9296_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_reverse_channel_setup(priv, i) : \
++ max9296_gmsl1_reverse_channel_setup(priv, i))
++#define max9296_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_serializer_setup(priv, i) : \
++ max9296_gmsl1_link_serializer_setup(priv, i))
++#define max9296_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_pipe_setup(priv, i) : \
++ max9296_gmsl1_link_pipe_setup(priv, i))
++#define max9296_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_crossbar_setup(priv, i, dt) : \
++ max9296_gmsl1_link_crossbar_setup(priv, i, dt))
++#define max9296_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_postinit(priv) : \
++ max9296_gmsl1_postinit(priv))
++#define max9296_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_fsync_setup(priv) : \
++ max9296_gmsl1_fsync_setup(priv))
++
++static int max9296_preinit(struct max9296_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX9296_CTRL0, BIT(7), BIT(7)); /* reset chip */
++ mdelay(5);
++
++ /* enable internal regulator for 1.2V VDD supply */
++ des_update_bits(MAX9296_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */
++ des_update_bits(MAX9296_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */
++
++ /* this is needed for engineering samples */
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_RLMS4(i), 0x29);
++ des_write(MAX_RLMSA4(i), 0xc8);
++ des_write(MAX_RLMSA(i), 0x00);
++ des_write(MAX_RLMSB(i), 0x00);
++ }
++
++ /* I2C-I2C timings */
++ des_write(MAX9296_I2C_PT_0, 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX9296_I2C_PT_1, 0x51); /* i2c speed: 397Kbps, 32mS timeout */
++ des_write(MAX9296_I2C_0, 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX9296_I2C_1, 0x51); /* i2c speed: 397Kbps, 1mS timeout */
++
++ des_write(MAX9296_CTRL1, priv->is_coax ? 0x5 : 0); /* cable mode */
++ des_write(MAX9296_GMSL1_EN, 0); /* disable all links */
++ des_update_bits(MAX9296_CTRL0, 0x13, 0); /* disable all links */
++
++ return 0;
++}
++
++static int max9296_initialize(struct max9296_priv *priv)
++{
++ int ret, i;
++
++ max9296_preinit(priv);
++ max9296_initial_setup(priv);
++ max9296_mipi_setup(priv);
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg)) {
++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */
++ if (ret) {
++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n");
++ continue;
++ }
++ mdelay(priv->poc_delay);
++ }
++
++ ret = max9296_reverse_channel_setup(priv, i);
++ if (ret == -ETIMEDOUT)
++ continue;
++ if (!ret)
++ max9296_link_serializer_setup(priv, i);
++
++ max9296_link_pipe_setup(priv, i);
++ max9296_link_crossbar_setup(priv, i, priv->dt);
++
++ i2c_mux_add_adapter(priv->mux, 0, i, 0);
++ max9296_cc_enable(priv, i, 0);
++ }
++
++ max9296_postinit(priv);
++ max9296_fsync_setup(priv);
++
++ return 0;
++}
++
++static int max9296_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data)
++{
++ struct max9296_priv *priv = container_of(nb, struct max9296_priv, reboot_nb);
++ int i;
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return NOTIFY_DONE;
++}
++
++static int max9296_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++
++ if (on) {
++ if (atomic_inc_return(&priv->use_count) == 1)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max9296_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++ int ret;
++ int val = 0;
++
++ ret = des_read(reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int max9296_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++
++ return des_write(reg->reg, (u8)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops max9296_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max9296_g_register,
++ .s_register = max9296_s_register,
++#endif
++ .s_power = max9296_s_power,
++};
++
++static struct v4l2_subdev_ops max9296_subdev_ops = {
++ .core = &max9296_subdev_core_ops,
++};
++
++static const struct of_device_id max9296_dt_ids[] = {
++ { .compatible = "maxim,max9296" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max9296_dt_ids);
++
++static int max9296_parse_dt(struct i2c_client *client)
++{
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ struct property *prop;
++ char name[16];
++ int i, csi_rate;
++
++ if (of_property_read_u32(np, "maxim,links", &priv->n_links))
++ priv->n_links = MAX9296_MAX_LINKS;
++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode))
++ priv->gmsl_mode = MODE_GMSL2;
++ if (of_property_read_bool(np, "maxim,stp"))
++ priv->is_coax = 0;
++ else
++ priv->is_coax = 1;
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
++ priv->fsync_period = 3210000;/* 96MHz/30fps */
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,hven", &priv->hven))
++ priv->hven = 1;
++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw))
++ priv->hibw = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = MIPI_DT_YUV8;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus))
++ priv->mbus = mbus_default;
++ for (i = 0; i < 11; i++) {
++ sprintf(name, "maxim,gpio%d", i);
++ if (of_property_read_u32(np, name, &priv->gpio[i]))
++ priv->gpio[i] = -1;
++ }
++
++ /* module params override dts */
++ if (gmsl != MODE_GMSL2)
++ priv->gmsl_mode = gmsl;
++ if (him)
++ priv->him = him;
++ if (fsync_period) {
++ priv->fsync_period = fsync_period;
++// priv->fsync_mode = fsync_mode_default;
++ }
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != MIPI_DT_YUV8)
++ priv->dt = dt;
++// if (hsgen)
++// priv->hsgen = hsgen;
++ if (gpio0 >= 0)
++ priv->gpio[0] = gpio0;
++ if (gpio1 >= 0)
++ priv->gpio[1] = gpio1;
++ if (gpio7 >= 0)
++ priv->gpio[7] = gpio7;
++ if (gpio8 >= 0)
++ priv->gpio[8] = gpio8;
++
++ /* parse serializer crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
++ }
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (i < priv->n_links) {
++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "ser-addr not set\n");
++ return -EINVAL;
++ }
++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint);
++ }
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (prop) {
++ of_property_read_u32(endpoint, "csi-rate", &csi_rate);
++ of_update_property(rendpoint, prop);
++ }
++
++ prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (prop)
++ of_update_property(rendpoint, prop);
++ }
++
++ of_node_put(endpoint);
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */
++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */
++ }
++
++ prop = of_find_property(np, "maxim,links-mipi-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= MAX9296_MAX_MIPI)
++ return -EINVAL;
++ priv->link[i]->out_mipi = val;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate;
++
++ prop = of_find_property(np, "maxim,links-vc-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= 4)
++ return -EINVAL;
++ priv->link[i]->out_vc = val;
++ }
++ }
++
++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n");
++ for (i = 0; i < priv->n_links; i++)
++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc);
++
++ return 0;
++}
++
++static int max9296_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max9296_priv *priv;
++ struct gpio_desc *pwdn_gpio;
++ int ret, i;
++ int val = 0;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->regmap = devm_regmap_init_i2c(client, &max9296_regmap[0]);
++ if (IS_ERR(priv->regmap))
++ return PTR_ERR(priv->regmap);
++
++ i2c_set_clientdata(client, priv);
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++
++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
++ if (!IS_ERR(priv->ref_clk)) {
++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
++ v4l2_clk_enable(priv->ref_clk);
++ }
++
++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH);
++ if (!IS_ERR(pwdn_gpio)) {
++ udelay(5);
++ gpiod_set_value_cansleep(pwdn_gpio, 0);
++ usleep_range(3000, 5000);
++ }
++
++ des_read(MAX9296_REG13, &val);
++ if (val != MAX9296A_ID)
++ return -ENODEV;
++
++ for (i = 0; i < MAX9296_MAX_LINKS; i++) {
++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL);
++ if (!priv->link[i])
++ return -ENOMEM;
++ }
++
++ ret = max9296_parse_dt(client);
++ if (ret)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ char poc_name[10];
++
++ sprintf(poc_name, "poc%d", i);
++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name);
++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ }
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr);
++ if (!priv->link[i]->client)
++ return -ENOMEM;
++
++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max9296_regmap[priv->gmsl_mode]);
++ if (IS_ERR(priv->link[i]->regmap))
++ return PTR_ERR(priv->link[i]->regmap);
++ }
++
++ ret = max9296_i2c_mux_init(priv);
++ if (ret) {
++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
++ goto out;
++ }
++
++ ret = max9296_initialize(priv);
++ if (ret < 0)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_subdev_init(&priv->link[i]->sd, &max9296_subdev_ops);
++ priv->link[i]->sd.owner = client->dev.driver->owner;
++ priv->link[i]->sd.dev = &client->dev;
++ priv->link[i]->sd.grp_id = i;
++ v4l2_set_subdevdata(&priv->link[i]->sd, priv);
++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode;
++
++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
++ client->dev.driver->name, i, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ ret = v4l2_async_register_subdev(&priv->link[i]->sd);
++ if (ret < 0)
++ goto out;
++ }
++
++ priv->reboot_nb.notifier_call = max9296_reboot_notifier;
++ ret = register_reboot_notifier(&priv->reboot_nb);
++ if (ret) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
++ //max9296_debug_add(priv);
++out:
++ return ret;
++}
++
++static int max9296_remove(struct i2c_client *client)
++{
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ //max9296_debug_remove(priv);
++ i2c_mux_del_adapters(priv->mux);
++ unregister_reboot_notifier(&priv->reboot_nb);
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_async_unregister_subdev(&priv->link[i]->sd);
++ v4l2_device_unregister_subdev(&priv->link[i]->sd);
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ 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",
++ .of_match_table = of_match_ptr(max9296_dt_ids),
++ },
++ .probe = max9296_probe,
++ .remove = max9296_remove,
++ .id_table = max9296_id,
++};
++
++module_i2c_driver(max9296_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL2 driver for MAX9296");
++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+new file mode 100644
+index 0000000..800df43
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+@@ -0,0 +1,281 @@
++/*
++ * MAXIM max9296 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#define MAX9296_MAX_LINKS 2
++#define MAX9296_MAX_PIPES 4
++#define MAX9296_MAX_PIPE_MAPS 16
++#define MAX9296_MAX_MIPI 4
++
++struct max9296_link {
++ struct v4l2_subdev sd;
++ struct fwnode_handle *sd_fwnode;
++ struct i2c_client *client;
++ struct regmap *regmap;
++ int ser_id;
++ int ser_addr;
++ int pipes_mask; /* mask of pipes used by this link */
++ int out_mipi; /* MIPI# */
++ int out_vc; /* VC# */
++ struct regulator *poc_reg; /* PoC power supply */
++};
++
++struct max9296_priv {
++ struct i2c_client *client;
++ struct regmap *regmap;
++ struct i2c_mux_core *mux;
++ int n_links;
++ int links_mask;
++ enum gmsl_mode gmsl_mode;
++ struct max9296_link *link[MAX9296_MAX_LINKS];
++ int gpio_resetb;
++ int active_low_resetb;
++ bool pclk_rising_edge;
++ bool is_coax;
++ int him;
++ int bws;
++ int dbl;
++ int hibw;
++ int hven;
++ int hsync;
++ int vsync;
++ int dt;
++ u64 crossbar;
++ char cb[16];
++ const char *mbus;
++ int gpio[11];
++ int timeout;
++ int poc_delay;
++ struct v4l2_clk *ref_clk;
++ int csi_rate[MAX9296_MAX_MIPI];
++ int fsync_period;
++ atomic_t use_count;
++ struct notifier_block reboot_nb;
++};
++
++#define MAX9296_REG1 0x01
++#define MAX9296_REG2 0x02
++#define MAX9296_REG3 0x03
++#define MAX9296_REG4 0x04
++#define MAX9296_REG5 0x05
++#define MAX9296_REG6 0x06
++#define MAX9296_REG13 0x0d
++#define MAX9296_REG14 0x0e
++#define MAX9296_REG26 0x26
++
++#define MAX9296_INTR3 0x1b
++#define MAX9296_INTR5 0x1d
++#define MAX9296_INTR7 0x1f
++#define MAX9296_DEC_ERR_A 0x22
++#define MAX9296_DEC_ERR_B 0x23
++#define MAX9296_IDLE_ERR 0x24
++#define MAX9296_PKT_CNT 0x25
++#define MAX9296_RX_0 0x2c
++#define MAX9296_RX_3 0x2f
++
++#define MAX9296_CTRL0 0x17
++#define MAX9296_CTRL1 0x18
++#define MAX9296_CTRL2 0x19
++#define MAX9296_CTRL3 0x1a
++#define MAX9296_CTRL11 0x22
++#define MAX9296_CTRL12 0x0a
++#define MAX9296_CTRL13 0x0b
++#define MAX9296_CTRL14 0x0c
++
++#define MAX9296_CNT(n) (0x22 + n)
++
++#define MAX9296_I2C_PT_0 0x4c
++#define MAX9296_I2C_PT_1 0x4d
++
++#define MAX9296_CNT4 0x55c
++
++#define MAX9296_GMSL1_EN 0xf00
++#define MAX9296_COMMON1 0xf02
++#define MAX9296_I2C_0 0xf05
++#define MAX9296_I2C_1 0xf06
++#define MAX9296_I2C_2 0xf07
++#define MAX9296_I2C_3 0xf08
++#define MAX9296_I2C_4 0xf09
++#define MAX9296_I2C_5 0xf0a
++
++#define MAX9296_RX0(n) (0x50 + n)
++
++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \
++ (0x160 + (0x12 * (n - 5))))
++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00)
++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03)
++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08)
++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a)
++
++#define MAX_VPRBS(n) (0x1dc + (0x20 * n))
++
++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n))
++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m)
++
++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank))
++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00)
++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a)
++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b)
++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c)
++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d)
++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e)
++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f)
++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10)
++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11)
++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12)
++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13)
++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14)
++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15)
++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16)
++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17)
++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18)
++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19)
++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a)
++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b)
++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c)
++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d)
++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e)
++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f)
++
++#define MAX9296_FSYNC_0 0x3a0
++#define MAX9296_FSYNC_5 0x3a5
++#define MAX9296_FSYNC_6 0x3a6
++#define MAX9296_FSYNC_7 0x3a7
++#define MAX9296_FSYNC_8 0x3a8
++#define MAX9296_FSYNC_9 0x3a9
++#define MAX9296_FSYNC_10 0x3aa
++#define MAX9296_FSYNC_11 0x3ab
++#define MAX9296_FSYNC_15 0x3af
++
++#define MAX_MIPI_PHY_BASE 0x8a0
++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02)
++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03)
++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04)
++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05)
++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06)
++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08)
++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09)
++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a)
++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b)
++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d)
++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e)
++
++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n)
++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02)
++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a)
++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b)
++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c)
++
++/* 16 pairs of source-dest registers */
++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n))
++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n))
++/* Phy dst. Each reg contains 4 dest */
++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n)
++
++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch))
++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch))
++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch))
++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch))
++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch))
++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch))
++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch))
++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch))
++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch))
++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch))
++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch))
++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch))
++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch))
++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch))
++
++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch))
++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch))
++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch))
++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch))
++
++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch))
++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch))
++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch))
++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch))
++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch))
++
++static inline int max9296_write(struct max9296_priv *priv, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_read(struct max9296_priv *priv, int reg, int *val)
++{
++ int ret;
++
++ ret = regmap_read(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_update_bits(struct max9296_priv *priv, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(priv->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define des_read(reg, val) max9296_read(priv, reg, val)
++#define des_write(reg, val) max9296_write(priv, reg, val)
++#define des_update_bits(reg, mask, bits) max9296_update_bits(priv, reg, mask, bits)
++
++static inline int max9296_ser_write(struct max9296_link *link, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(link->regmap, reg, val);
++ if (ret < 0)
++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_ser_read(struct max9296_link *link, int reg, u8 *val)
++{
++ int ret;
++
++ ret = regmap_read(link->regmap, reg, (int *)val);
++ if (ret)
++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_ser_update_bits(struct max9296_link *link, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(link->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define ser_read(reg, val) max9296_ser_read(link, reg, val)
++#define ser_write(reg, val) max9296_ser_write(link, reg, val)
++#define ser_update_bits(reg, mask, bits) max9296_ser_update_bits(link, reg, mask, bits)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+new file mode 100644
+index 0000000..6bf03a2
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+@@ -0,0 +1,462 @@
++/*
++ * MAXIM max9296 GMSL2 driver debug stuff
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static char *max9296_link_mode[4] = {
++ "Splitter mode",
++ "Link A",
++ "Link B",
++ "Dual link",
++};
++
++static char *line_status[8] = {
++ "Short to battery",
++ "Short to GND",
++ "Normal operation",
++ "Line open",
++ "Line-to-line short",
++ "Line-to-line short",
++ "Line-to-line short",
++ "Line-to-line short"
++};
++
++static char *paxket_cnt_types[] = {
++ "None",
++ "VIDEO",
++ "AUDIO",
++ "INFO Frame",
++ "SPI",
++ "I2C",
++ "UART",
++ "GPIO",
++ "AHDCP",
++ "RGMII",
++ "Reserved",
++ "Reserved",
++ "Reserved",
++ "Reserved",
++ "All",
++ "Unknown and packets with error",
++};
++
++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n);
++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n);
++
++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1))
++
++static ssize_t max_link_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i = -1;
++ int j;
++ int gmsl2;
++ u32 crc = 0 ;
++ char *_buf = buf;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "link_%d", &i))
++ return -EINVAL;
++
++ if (i < 0)
++ return -EINVAL;
++
++ if (i >= priv->n_links) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ buf += sprintf(buf, "Link %c status\n", 'A' + i);
++
++ des_read(MAX9296_REG6, &reg);
++ gmsl2 = !!(reg & BIT(6 + i));
++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1");
++
++ if (gmsl2) {
++ buf += sprintf(buf, "GMSL2 Link lock: %d\n",
++ max9296_gmsl2_get_link_lock(priv, i));
++ } else {
++ reg = max9296_gmsl1_get_link_lock(priv, i);
++ buf += sprintf(buf,
++ "GMSL1_CB: 0x%02x:\t"
++ "LOCKED_G1: %d\n",
++ reg, reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_CA(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_CA: 0x%02x:\t"
++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n",
++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_1B(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1B: 0x%02x:\t"
++ "LINE_CRC_ERR: %d ",
++ reg, reg_bits(2, 1));
++ for (j = 0; j < 4; j++) {
++ des_read(MAX_GMSL1_20(i) + j, &reg);
++ crc = crc | ((reg & 0xff) << (j * 8));
++ }
++ buf += sprintf(buf, "last crc 0x%08x\n", crc);
++
++ des_read(MAX_GMSL1_19(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_19: CC_CRC_ERRCNT %d\n",
++ reg);
++
++ des_read(MAX_GMSL1_1D(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1D: 0x%02x:\t"
++ "UNDERBOOST: %d, AEQ-BST: %d\n",
++ reg, reg_bits(4, 1), reg_bits(0, 4));
++
++ {
++ des_read(MAX9296_CTRL1, &reg);
++ buf += sprintf(buf,
++ "CTRL1: 0x%02x:\t"
++ "Cable: %s\n",
++ reg,
++ reg_bits(i * 2, 1) ? "coax" : "stp");
++
++ des_read(MAX9296_REG26, &reg);
++ buf += sprintf(buf,
++ "REG26: 0x%02x:\t"
++ "Line status: %s\n",
++ reg,
++ line_status[reg_bits(i * 4, 3)]);
++
++ des_read(MAX9296_CNT(i), &reg);
++ buf += sprintf(buf,
++ "CNT%d: DEC_ERR_x: %d\n",
++ i, reg);
++ }
++ /* TODO: add same for 96712 */
++ }
++
++ return (buf - _buf);
++}
++
++static ssize_t max_pipe_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ char *_buf = buf;
++ int pipe = 0;
++ int map;
++ int maps_en = 0;
++ int pipes_en;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe))
++ return -EINVAL;
++
++ if (pipe < 0)
++ return -EINVAL;
++
++ if (pipe >= MAX9296_MAX_PIPES) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ des_read(MAX9296_REG2, &pipes_en);
++ pipes_en = pipes_en >> 4;
++
++ buf += sprintf(buf, "Video Pipe %d %s\n",
++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled");
++ if (!(pipes_en & BIT(pipe)))
++ goto out;
++
++ des_read(MAX_VPRBS(pipe), &reg);
++ /* bit 5 is not valid for MAX96712 */
++ buf += sprintf(buf,
++ "\tVPRBS: 0x%02x\t"
++ "VPRBS_FAIL: %d,"
++ "VIDEO_LOCK: %d\n",
++ reg,
++ reg_bits(5, 1), reg_bits(0, 1));
++
++ /* show source */
++ /* TODO */
++
++ /* show maps */
++ des_read(MAX_MIPI_TX11(pipe), &maps_en);
++ des_read(MAX_MIPI_TX12(pipe), &reg);
++ maps_en |= reg << 8;
++
++ for (map = 0; map < MAX9296_MAX_PIPE_MAPS; map++) {
++ int src, dst, mipi;
++ if (!(maps_en & BIT(map)))
++ continue;
++
++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src);
++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst);
++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi);
++
++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n",
++ map,
++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03,
++ (mipi >> ((map % 4) * 2)) & 0x03);
++ }
++
++ des_read(MAX9296_CNT4 + pipe, &reg);
++ buf += sprintf(buf, "VID_PXL_CRC_ERR: 0x%02x\n", reg);
++
++ des_read(MAX_VIDEO_RX0(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX0: 0x%02x\t"
++ "LCRC_ERR: %d, "
++ "LINE_CRC_SEL: %d, "
++ "LINE_CRC_EN: %d, "
++ "DIS_PKT_DET: %d\n",
++ reg,
++ reg_bits(7, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX3(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX3: 0x%02x\t"
++ "HD_TR_MODE: %d, "
++ "DLOCKED: %d, "
++ "VLOCKED: %d, "
++ "HLOCKED: %d, "
++ "DTRACKEN: %d, "
++ "VTRACKEN: %d, "
++ "HTRACKEN: %d\n",
++ reg,
++ reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX8(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX8: 0x%02x\t"
++ "VID_BLK_LEN_ERR: %d, "
++ "VID_LOCK: %d, "
++ "VID_PKT_DET: %d, "
++ "VID_SEQ_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1));
++ des_read(MAX_VIDEO_RX10(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX10: 0x%02x\t"
++ "MASK_VIDEO_DE: %d\n",
++ reg,
++ reg_bits(6, 1));
++
++out:
++ return (buf - _buf);
++}
++
++static ssize_t max_stat_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i;
++ char *_buf = buf;
++ int reg = 0, reg2 = 0;
++
++ des_read(MAX9296_REG3, &reg);
++ buf += sprintf(buf,
++ "REG_REG3: 0x%02x\t"
++ "LOCK_CFG: %d\n",
++ reg, reg_bits(7, 1));
++
++ des_read(MAX9296_CTRL0, &reg);
++ buf += sprintf(buf,
++ "CTRL0: 0x%02x\n",
++ reg);
++
++ des_read(MAX9296_CTRL3, &reg);
++ buf += sprintf(buf,
++ "CTRL3: 0x%02x:\t"
++ "LINK_MODE: %s, "
++ "GMSL2 LOCKED: %d, ERROR: %d, "
++ "CMU_LOCKED: %d\n",
++ reg,
++ max9296_link_mode[reg_bits(4, 2)],
++ reg_bits(3, 1), reg_bits(2 ,1),
++ reg_bits(1, 1));
++ /* get errors */
++ if (reg_bits(2, 1)) {
++ des_read(MAX9296_INTR3, &reg);
++ buf += sprintf(buf,
++ "INTR3: 0x%02x:\t"
++ "PHY_INT_OEN_B: %d "
++ "PHY_INT_OEN_A: %d "
++ "REM_ERR_FLAG: %d "
++ "MEM_INT_ERR_FLAG: %d "
++ "LFLT_INT: %d "
++ "IDLE_ERR_FLAG: %d "
++ "DEC_ERR_FLAG_B: %d "
++ "DEC_ERR_FLAG_A: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX9296_INTR5, &reg);
++ buf += sprintf(buf,
++ "INTR5: 0x%02x:\t"
++ "EOM_ERR_FLAG_B: %d "
++ "EOM_ERR_FLAG_A: %d "
++ "MAX_RT_FLAG: %d "
++ "RT_CNT_FLAG: %d "
++ "PKT_CNT_FLAG: %d "
++ "WM_ERR_FLAG: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX9296_INTR7, &reg);
++ buf += sprintf(buf,
++ "INTR7: 0x%02x:\t"
++ "VDDCMP_INT_FLAG: %d "
++ "PORZ_INT_FLAG: %d "
++ "VDDBAD_INT_FLAG: %d "
++ "LCRC_ERR_FLAG: %d "
++ "VPRBS_ERR_FLAG: %d "
++ "VID_PXL_CRC_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(0, 1));
++
++ des_read(MAX9296_DEC_ERR_A, &reg);
++ buf += sprintf(buf,
++ "ERR_A: 0x%02x\n", reg);
++ des_read(MAX9296_DEC_ERR_B, &reg);
++ buf += sprintf(buf,
++ "ERR_B: 0x%02x\n", reg);
++ des_read(MAX9296_IDLE_ERR, &reg);
++ buf += sprintf(buf,
++ "IDLE_ERR: 0x%02x\n", reg);
++ des_read(MAX9296_PKT_CNT, &reg);
++ buf += sprintf(buf,
++ "PKT_CNT: 0x%02x\n", reg);
++
++ }
++
++ des_read(MAX9296_CNT(2), &reg);
++ buf += sprintf(buf,
++ "CNT2: IDLE_ERR: %d\n",
++ reg);
++
++ des_read(MAX9296_CNT(3), &reg);
++ des_read(MAX9296_RX_0, &reg2);
++ buf += sprintf(buf,
++ "CNT3: PKT_CNT: 0x%02x (type %x: %s)\n",
++ reg, reg2 & 0x0f,
++ paxket_cnt_types[reg2 & 0x0f]);
++
++ des_read(MAX9296_RX_3, &reg);
++ buf += sprintf(buf,
++ "RX3: 0x%02x:\t"
++ "PRBS_SYNCED_B: %d, "
++ "SYNC_LOCKED_B: %d, "
++ "WBLOCK_B: %d, "
++ "FAILLOCK_B: %d, "
++ "PRBS_SYNCED_A: %d, "
++ "SYNC_LOCKED_A: %d, "
++ "WBLOCK_A: %d, "
++ "FAILLOCK_A: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_BACKTOP1(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP1: 0x%02x:\t"
++ "CSIPLLU_LOCK: %d, "
++ "CSIPLLZ_LOCK: %d, "
++ "CSIPLLY_LOCK: %d, "
++ "CSIPLLX_LOCK: %d, "
++ "LINE_SPL2: %d, "
++ "LINE_SPL1: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1));
++
++ des_read(MAX_BACKTOP11(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP11: 0x%02x:\t"
++ "CMD_OWERFLOW4: %d, "
++ "CMD_OWERFLOW3: %d, "
++ "CMD_OWERFLOW2: %d, "
++ "CMD_OWERFLOW1: %d, "
++ "LMO_Z: %d, "
++ "LMO_Y: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(2, 1), reg_bits(1, 1));
++
++ for (i = 0; i < MAX9296_MAX_MIPI; i++) {
++ buf += sprintf(buf, "MIPI %d\n", i);
++ des_read(MAX_MIPI_TX2(i), &reg);
++ buf += sprintf(buf,
++ "\tMIPI_TX2: 0x%02x\n",
++ reg);
++ }
++
++ return (buf - _buf);
++}
++
++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL);
++
++static struct attribute *max9296_attributes[] = {
++ &dev_attr_link_0.attr,
++ &dev_attr_link_1.attr,
++ &dev_attr_link_2.attr,
++ &dev_attr_link_3.attr,
++ &dev_attr_pipe_0.attr,
++ &dev_attr_pipe_1.attr,
++ &dev_attr_pipe_2.attr,
++ &dev_attr_pipe_3.attr,
++ &dev_attr_pipe_4.attr,
++ &dev_attr_pipe_5.attr,
++ &dev_attr_pipe_6.attr,
++ &dev_attr_pipe_7.attr,
++ &dev_attr_stat.attr,
++ NULL
++};
++
++static const struct attribute_group max9296_group = {
++ .attrs = max9296_attributes,
++};
++
++int max9296_debug_add(struct max9296_priv *priv)
++{
++ int ret;
++
++ ret = sysfs_create_group(&priv->client->dev.kobj, &max9296_group);
++ if (ret < 0) {
++ dev_err(&priv->client->dev, "Sysfs registration failed\n");
++ return ret;
++ }
++
++ /* count video packets */
++ des_update_bits(MAX9296_RX_0, 0x0f, 0x01);
++
++ return ret;
++}
++
++void max9296_debug_remove(struct max9296_priv *priv)
++{
++ sysfs_remove_group(&priv->client->dev.kobj, &max9296_group);
++}
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+new file mode 100644
+index 0000000..af5e1d7
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -0,0 +1,1423 @@
++/*
++ * MAXIM max96712 GMSL2 driver
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/i2c-mux.h>
++#include <linux/module.h>
++#include <linux/regulator/consumer.h>
++#include <linux/notifier.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/regmap.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-clk.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "common.h"
++#include "max96712.h"
++#include "max96712_debug.h"
++
++static char mbus_default[10] = "dvp"; /* mipi, dvp */
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int fsync_period;
++module_param(fsync_period, int, 0644);
++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = MIPI_DT_YUV8;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)");
++
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)");
++
++static int gmsl = MODE_GMSL2;
++module_param(gmsl, int, 0644);
++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
++
++static char *mbus = "dvp";
++module_param(mbus, charp, 0644);
++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
++
++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1;
++module_param(gpio0, int, 0644);
++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)");
++module_param(gpio1, int, 0644);
++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)");
++module_param(gpio7, int, 0644);
++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)");
++module_param(gpio8, int, 0644);
++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)");
++
++static const struct regmap_config max96712_regmap[] = {
++ {
++ /* max96712 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1f03,
++ }, {
++ /* max9271/max96705 */
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 0xff,
++ }, {
++ /* max9695 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1b03,
++ }
++};
++
++static void max96712_write_remote_verify(struct max96712_priv *priv, int link_n, u8 reg, int val)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ u8 val2 = 0;
++
++ ser_write(reg, val);
++ ser_read(reg, &val2);
++ if (val2 == val)
++ break;
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&priv->client->dev, "timeout remote write acked\n");
++}
++
++static void max96712_reset_oneshot(struct max96712_priv *priv, int mask)
++{
++ int timeout;
++ int reg = 0;
++
++ mask &= 0x0f;
++ des_update_bits(MAX96712_CTRL1, mask, mask); /* set reset one-shot */
++
++ /* wait for one-shot bit self-cleared */
++ for (timeout = 0; timeout < 100; timeout++) {
++ des_read(MAX96712_CTRL1, &reg);
++ if (!(reg & mask))
++ break;
++
++ msleep(1);
++ }
++
++ if (reg & mask)
++ dev_err(&priv->client->dev, "Failed reset oneshot 0x%x\n", mask);
++}
++
++/* -----------------------------------------------------------------------------
++ * MIPI, mapping, routing
++ */
++
++static void max96712_pipe_override(struct max96712_priv *priv, unsigned int pipe,
++ unsigned int dt, unsigned int vc)
++{
++ int bpp, bank;
++
++ bpp = mipi_dt_to_bpp(dt);
++ bank = pipe / 4;
++ pipe %= 4;
++
++ if (priv->dbl == 1) {
++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */
++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */
++ bpp = bpp / 2; /* divide because of MUX=1 */
++ }
++
++ switch (pipe) {
++ case 0:
++ /* Pipe X: 0 or 4 */
++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */
++ break;
++ case 1:
++ /* Pipe Y: 1 or 5 */
++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f);
++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ case 2:
++ /* Pipe Z: 2 or 6 */
++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03);
++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */
++ break;
++ case 3:
++ /* Pipe U: 3 or 7 */
++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ }
++}
++
++static void max96712_set_pipe_to_mipi_mapping(struct max96712_priv *priv,
++ unsigned int pipe, unsigned int map_n,
++ unsigned int in_dt, unsigned int in_vc,
++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi)
++{
++ int offset = 2 * (map_n % 4);
++
++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt);
++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt);
++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset);
++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */
++}
++
++static void max96712_mipi_setup(struct max96712_priv *priv)
++{
++ des_write(MAX96712_VIDEO_PIPE_EN, 0); /* disable all pipes */
++
++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */
++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */
++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */
++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */
++ //des_write(MAX_MIPI_PHY6, 0x00);
++
++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */
++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */
++
++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */
++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++
++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL1
++ */
++
++static int max96712_gmsl1_sensor_reset(struct max96712_priv *priv, int link_n, int reset_on)
++{
++ struct max96712_link *link = priv->link[link_n];
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return -EINVAL;
++
++ /* sensor reset/unreset */
++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++
++ return 0;
++}
++
++static void max96712_gmsl1_cc_enable(struct max96712_priv *priv, int link, int on)
++{
++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00);
++ usleep_range(2000, 2500);
++}
++
++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX_GMSL1_CB(link_n), &val);
++
++ return !!(val & BIT(0));
++}
++
++static void max96712_gmsl1_link_crossbar_setup(struct max96712_priv *priv, int link, int dt)
++{
++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */
++ switch (dt) {
++ case MIPI_DT_YUV8:
++ des_write(MAX_CROSS(link, 0), 7);
++ des_write(MAX_CROSS(link, 1), 6);
++ des_write(MAX_CROSS(link, 2), 5);
++ des_write(MAX_CROSS(link, 3), 4);
++ des_write(MAX_CROSS(link, 4), 3);
++ des_write(MAX_CROSS(link, 5), 2);
++ des_write(MAX_CROSS(link, 6), 1);
++ des_write(MAX_CROSS(link, 7), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 8), 15);
++ des_write(MAX_CROSS(link, 9), 14);
++ des_write(MAX_CROSS(link, 10), 13);
++ des_write(MAX_CROSS(link, 11), 12);
++ des_write(MAX_CROSS(link, 12), 11);
++ des_write(MAX_CROSS(link, 13), 10);
++ des_write(MAX_CROSS(link, 14), 9);
++ des_write(MAX_CROSS(link, 15), 8);
++ }
++ break;
++ case MIPI_DT_RAW12:
++ des_write(MAX_CROSS(link, 0), 11);
++ des_write(MAX_CROSS(link, 1), 10);
++ des_write(MAX_CROSS(link, 2), 9);
++ des_write(MAX_CROSS(link, 3), 8);
++ des_write(MAX_CROSS(link, 4), 7);
++ des_write(MAX_CROSS(link, 5), 6);
++ des_write(MAX_CROSS(link, 6), 5);
++ des_write(MAX_CROSS(link, 7), 4);
++ des_write(MAX_CROSS(link, 8), 3);
++ des_write(MAX_CROSS(link, 9), 2);
++ des_write(MAX_CROSS(link, 10), 1);
++ des_write(MAX_CROSS(link, 11), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 12), 23);
++ des_write(MAX_CROSS(link, 13), 22);
++ des_write(MAX_CROSS(link, 14), 21);
++ des_write(MAX_CROSS(link, 15), 20);
++ des_write(MAX_CROSS(link, 16), 19);
++ des_write(MAX_CROSS(link, 17), 18);
++ des_write(MAX_CROSS(link, 18), 17);
++ des_write(MAX_CROSS(link, 19), 16);
++ des_write(MAX_CROSS(link, 20), 15);
++ des_write(MAX_CROSS(link, 21), 14);
++ des_write(MAX_CROSS(link, 22), 13);
++ des_write(MAX_CROSS(link, 23), 12);
++ }
++ break;
++ default:
++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt);
++ break;
++ }
++
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max96712_gmsl1_initial_setup(struct max96712_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX96712_REG6, 0xf0, 0); /* set GMSL1 mode */
++ des_write(MAX96712_REG26, 0x11); /* 187.5M/3G */
++ des_write(MAX96712_REG27, 0x11); /* 187.5M/3G */
++
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */
++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */
++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */
++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */
++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */
++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */
++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */
++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */
++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */
++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */
++ }
++}
++
++static int max96712_gmsl1_reverse_channel_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */
++ int lock_sts;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ u8 val = 0;
++ int ret = 0;
++
++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */
++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */
++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */
++ usleep_range(2000, 2500);
++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */
++ des_write(MAX96712_REG6, BIT(link_n)); /* GMSL1 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(link_n));
++ usleep_range(2000, 2500);
++
++ for (; timeout > 0; timeout--) {
++ if (priv->him) {
++ /* HIM mode setup */
++ __reg8_write(ser_addrs[0], 0x4d, 0xc0);
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++ } else {
++ /* Legacy mode setup */
++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */
++ usleep_range(2000, 2500);
++
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */
++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500);
++
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++
++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */
++ usleep_range(2000, 2500);
++ }
++
++ __reg8_read(ser_addrs[0], 0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ ser_read(0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) {
++ regulator_disable(link->poc_reg); /* POC power off */
++ mdelay(200);
++ ret = regulator_enable(link->poc_reg); /* POC power on */
++ if (ret)
++ dev_err(&link->client->dev, "failed to enable poc regulator\n");
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max96712_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */
++
++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */
++ usleep_range(2000, 2500);
++ des_read(MAX_GMSL1_CB(link_n), &lock_sts);
++ lock_sts = !!(lock_sts & 0x01);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts);
++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr,
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++ return ret;
++}
++
++static int max96712_gmsl1_link_serializer_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++
++ /* GMSL setup */
++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500);
++
++ if (link->ser_id != MAX9271_ID) {
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ if (priv->dbl == 1) {
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ ser_write(0x20, priv->cb[7]);
++ ser_write(0x21, priv->cb[6]);
++ ser_write(0x22, priv->cb[5]);
++ ser_write(0x23, priv->cb[4]);
++ ser_write(0x24, priv->cb[3]);
++ ser_write(0x25, priv->cb[2]);
++ ser_write(0x26, priv->cb[1]);
++ ser_write(0x27, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer always) */
++ ser_write(0x30, priv->cb[7] + 16);
++ ser_write(0x31, priv->cb[6] + 16);
++ ser_write(0x32, priv->cb[5] + 16);
++ ser_write(0x33, priv->cb[4] + 16);
++ ser_write(0x34, priv->cb[3] + 16);
++ ser_write(0x35, priv->cb[2] + 16);
++ ser_write(0x36, priv->cb[1] + 16);
++ ser_write(0x37, priv->cb[0] + 16);
++ } else {
++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */
++ ser_write(0x20, priv->cb[4]);
++ ser_write(0x21, priv->cb[3]);
++ ser_write(0x22, priv->cb[2]);
++ ser_write(0x23, priv->cb[1]);
++ ser_write(0x24, priv->cb[0]);
++ ser_write(0x25, 0x40);
++ ser_write(0x26, 0x40);
++ if (link->ser_id == MAX96705_ID) {
++ ser_write(0x27, 14); /* HS: D14->D18 */
++ ser_write(0x28, 15); /* VS: D15->D19 */
++ ser_write(0x29, 14); /* DE: D14->D20 */
++ }
++ if (link->ser_id == MAX96707_ID) {
++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */
++ ser_write(0x28, 13); /* VS: D13->D19 */
++ ser_write(0x29, 12); /* DE: D12->D20 */
++ }
++ ser_write(0x2A, 0x40);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, 0x10 + priv->cb[7]);
++ ser_write(0x31, 0x10 + priv->cb[6]);
++ ser_write(0x32, 0x10 + priv->cb[5]);
++ ser_write(0x33, 0x10 + priv->cb[4]);
++ ser_write(0x34, 0x10 + priv->cb[3]);
++ ser_write(0x35, 0x10 + priv->cb[2]);
++ ser_write(0x36, 0x10 + priv->cb[1]);
++ ser_write(0x37, 0x10 + priv->cb[0]);
++ ser_write(0x38, priv->cb[7]);
++ ser_write(0x39, priv->cb[6]);
++ ser_write(0x3A, priv->cb[5]);
++
++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
++ }
++ break;
++ case MIPI_DT_RAW12:
++ /* setup crossbar for RAW12: reverse DVP bus */
++ ser_write(0x20, priv->cb[11]);
++ ser_write(0x21, priv->cb[10]);
++ ser_write(0x22, priv->cb[9]);
++ ser_write(0x23, priv->cb[8]);
++ ser_write(0x24, priv->cb[7]);
++ ser_write(0x25, priv->cb[6]);
++ ser_write(0x26, priv->cb[5]);
++ ser_write(0x27, priv->cb[4]);
++ ser_write(0x28, priv->cb[3]);
++ ser_write(0x29, priv->cb[2]);
++ ser_write(0x2a, priv->cb[1]);
++ ser_write(0x2b, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, priv->cb[11] + 16);
++ ser_write(0x31, priv->cb[10] + 16);
++ ser_write(0x32, priv->cb[9] + 16);
++ ser_write(0x33, priv->cb[8] + 16);
++ ser_write(0x34, priv->cb[7] + 16);
++ ser_write(0x35, priv->cb[6] + 16);
++ ser_write(0x36, priv->cb[5] + 16);
++ ser_write(0x37, priv->cb[4] + 16);
++ ser_write(0x38, priv->cb[3] + 16);
++ ser_write(0x39, priv->cb[2] + 16);
++ ser_write(0x3a, priv->cb[1] + 16);
++ ser_write(0x3b, priv->cb[0] + 16);
++
++ if (!(priv->bws || priv->hibw) && priv->dbl)
++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++ break;
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */
++ /* put serializer in configuration link state */
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static void max96712_gmsl1_link_pipe_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight map */
++ int dt = priv->dt; /* should come from imager */
++ int in_vc = 0;
++
++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ /* use map #0 for payload data */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */
++ dt, in_vc, /* src DT, VC */
++ dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #1 for FS */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */
++ 0x00, in_vc, /* src DT, VC */
++ 0x00, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #2 for FE */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */
++ 0x01, in_vc, /* src DT, VC */
++ 0x01, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ usleep_range(5000, 5500);
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max96712_gmsl1_postinit(struct max96712_priv *priv)
++{
++ int i;
++ u8 val = 0;
++
++ for (i = 0; i < priv->n_links; i++) {
++ struct max96712_link *link = priv->link[i];
++
++ if (!(priv->links_mask & BIT(i)))
++ continue;
++
++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */
++ des_write(MAX96712_REG6, BIT(i)); /* GMSL1 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(i));
++ usleep_range(2000, 2500);
++
++ ser_read(0x15, &val);
++ if (!(val & BIT(1)))
++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i);
++
++ /* switch to GMSL serial_link for streaming video */
++ max96712_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83);
++ usleep_range(2000, 2500);
++
++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */
++
++ switch (priv->link[i]->ser_id) {
++ case MAX9271_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */
++ break;
++ case MAX96705_ID:
++ case MAX96707_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */
++ break;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */
++
++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */
++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */
++}
++
++static void max96712_gmsl1_fsync_setup(struct max96712_priv *priv)
++{
++ des_write(MAX96712_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX96712_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX96712_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ //des_write(MAX96712_FSYNC_8, 0x00); /* Disable Err Thresh */
++ //des_write(MAX96712_FSYNC_9, 0x00); /* Disable Err Thresh */
++ des_write(MAX96712_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX96712_FSYNC_11, 0x00);
++
++ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */
++
++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */
++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */
++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */
++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */
++
++ des_write(MAX96712_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL2
++ */
++
++static void max96712_gmsl2_cc_enable(struct max96712_priv *priv, int link, int on)
++{
++ /* nothing */
++}
++
++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n)
++{
++ int lock_reg[] = {MAX96712_CTRL3, MAX96712_CTRL12, MAX96712_CTRL13, MAX96712_CTRL14};
++ int val = 0;
++
++ des_read(lock_reg[link_n], &val);
++
++ return !!(val & BIT(3));
++}
++
++static void max96712_gmsl2_initial_setup(struct max96712_priv *priv)
++{
++ des_update_bits(MAX96712_REG6, 0xf0, 0xf0); /* set GMSL2 mode */
++ des_write(MAX96712_REG26, 0x22); /* 187.5M/6G */
++ des_write(MAX96712_REG27, 0x22); /* 187.5M/6G */
++}
++
++static int max96712_gmsl2_reverse_channel_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */
++ int timeout = priv->timeout;
++ int ret = 0;
++ int i = 0;
++
++ des_write(MAX96712_REG6, 0xf0 | BIT(link_n)); /* GMSL2 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(link_n));
++
++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
++ while ((!max96712_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
++ msleep(1);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) {
++ int val = 0;
++
++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */
++ if (val == MAX9295A_ID || val == MAX9295B_ID) {
++ link->ser_id = val;
++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++ }
++
++ if (i == ARRAY_SIZE(ser_addrs)) {
++ dev_err(&priv->client->dev, "serializer not found\n");
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i],
++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : "");
++ return ret;
++}
++
++static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int i;
++
++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
++ //msleep(100);
++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
++ }
++
++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
++
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++
++ for (i = 0; i < 11; i++) {
++ if (priv->gpio[i] == 0) {
++ /* GPIO set 0 */
++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */
++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */
++ }
++ if (priv->gpio[i] == 1) {
++ /* GPIO set 1 */
++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */
++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */
++ }
++ if (priv->gpio[i] == 2) {
++ /* GPIO FSIN */
++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ }
++ if (priv->gpio[i] == 3) {
++ /* GPIO Interrupt */
++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */
++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static struct {
++ int in_dt;
++ int out_dt;
++} gmsl2_pipe_maps[] = {
++ {0x00, 0x00}, /* FS */
++ {0x01, 0x01}, /* FE */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++};
++
++static void max96712_gmsl2_pipe_set_source(struct max96712_priv *priv, int pipe, int phy, int in_pipe)
++{
++ int offset = (pipe % 2) * 4;
++
++ des_update_bits(MAX96712_VIDEO_PIPE_SEL(pipe / 2), 0x0f << offset, (phy << (offset + 2)) |
++ (in_pipe << offset));
++}
++
++static void max96712_gmsl2_link_pipe_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight mapping */
++ int dt = priv->dt; /* must come from imager */
++ int in_vc = 0;
++ int i;
++
++ max96712_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ des_write(MAX96712_RX0(pipe), 0); /* stream_id = 0 */
++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */
++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++ }
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) {
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */
++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */
++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ }
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max96712_gmsl2_postinit(struct max96712_priv *priv)
++{
++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */
++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */
++}
++
++static void max96712_gmsl2_link_crossbar_setup(struct max96712_priv *priv, int link, int dt)
++{
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv)
++{
++ /* TODO */
++}
++
++/* -----------------------------------------------------------------------------
++ * I2C Multiplexer
++ */
++
++static int max96712_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
++{
++ /* Do nothing! */
++ return 0;
++}
++
++static int max96712_i2c_mux_init(struct max96712_priv *priv)
++{
++ struct i2c_client *client = priv->client;
++
++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
++ return -ENODEV;
++
++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev,
++ priv->n_links, 0, I2C_MUX_LOCKED,
++ max96712_i2c_mux_select, NULL);
++ if (!priv->mux)
++ return -ENOMEM;
++
++ priv->mux->priv = priv;
++
++ return 0;
++}
++
++#define max96712_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_cc_enable(priv, i, en) : \
++ max96712_gmsl1_cc_enable(priv, i, en))
++#define max96712_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_initial_setup(priv) : \
++ max96712_gmsl1_initial_setup(priv))
++#define max96712_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_reverse_channel_setup(priv, i) : \
++ max96712_gmsl1_reverse_channel_setup(priv, i))
++#define max96712_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_serializer_setup(priv, i) : \
++ max96712_gmsl1_link_serializer_setup(priv, i))
++#define max96712_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_pipe_setup(priv, i) : \
++ max96712_gmsl1_link_pipe_setup(priv, i))
++#define max96712_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_crossbar_setup(priv, i, dt) : \
++ max96712_gmsl1_link_crossbar_setup(priv, i, dt))
++#define max96712_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_postinit(priv) : \
++ max96712_gmsl1_postinit(priv))
++#define max96712_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_fsync_setup(priv) : \
++ max96712_gmsl1_fsync_setup(priv))
++
++static int max96712_preinit(struct max96712_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX96712_PWR1, BIT(6), BIT(6)); /* reset chip */
++ mdelay(5);
++
++ /* enable internal regulator for 1.2V VDD supply */
++ des_update_bits(MAX96712_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */
++ des_update_bits(MAX96712_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */
++
++ //for (i = 0; i < priv->n_links; i++) {
++ // des_write(MAX_RLMS58(i), 0x28);
++ // des_write(MAX_RLMS59(i), 0x68);
++ // max96712_reset_oneshot(priv, BIT(i));
++ //}
++
++ /* I2C-I2C timings */
++ for (i = 0; i < 8; i++) {
++ des_write(MAX96712_I2C_0(i), 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX96712_I2C_1(i), 0x51); /* i2c speed: 397Kbps, 1mS timeout */
++ }
++
++ des_update_bits(MAX96712_CTRL11, 0x55, priv->is_coax ? 0x55 : 0); /* cable mode */
++ des_update_bits(MAX96712_REG6, 0x0f, 0); /* disable all links */
++
++ return 0;
++}
++
++static int max96712_initialize(struct max96712_priv *priv)
++{
++ int ret, i;
++
++ max96712_preinit(priv);
++ max96712_initial_setup(priv);
++ max96712_mipi_setup(priv);
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg)) {
++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */
++ if (ret) {
++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n");
++ continue;
++ }
++ mdelay(priv->poc_delay);
++ }
++
++ ret = max96712_reverse_channel_setup(priv, i);
++ if (ret == -ETIMEDOUT)
++ continue;
++ if (!ret)
++ max96712_link_serializer_setup(priv, i);
++
++ max96712_link_pipe_setup(priv, i);
++ max96712_link_crossbar_setup(priv, i, priv->dt);
++
++ i2c_mux_add_adapter(priv->mux, 0, i, 0);
++ max96712_cc_enable(priv, i, 0);
++ }
++
++ max96712_postinit(priv);
++ max96712_fsync_setup(priv);
++
++ return 0;
++}
++
++static int max96712_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data)
++{
++ struct max96712_priv *priv = container_of(nb, struct max96712_priv, reboot_nb);
++ int i;
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return NOTIFY_DONE;
++}
++
++static int max96712_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++ int i = sd->grp_id;
++ int pipes_mask = priv->link[i]->pipes_mask;
++
++ if (on) {
++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, pipes_mask); /* enable link pipes */
++ if (atomic_inc_return(&priv->use_count) == 1)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */
++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, 0); /* disable link pipes */
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max96712_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++ int ret;
++ int val = 0;
++
++ ret = des_read(reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int max96712_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++
++ return des_write(reg->reg, (u8)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops max96712_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max96712_g_register,
++ .s_register = max96712_s_register,
++#endif
++ .s_power = max96712_s_power,
++};
++
++static struct v4l2_subdev_ops max96712_subdev_ops = {
++ .core = &max96712_subdev_core_ops,
++};
++
++static const struct of_device_id max96712_dt_ids[] = {
++ { .compatible = "maxim,max96712" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max96712_dt_ids);
++
++static int max96712_parse_dt(struct i2c_client *client)
++{
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ struct property *prop;
++ char name[16];
++ int i, csi_rate;
++
++ if (of_property_read_u32(np, "maxim,links", &priv->n_links))
++ priv->n_links = MAX96712_MAX_LINKS;
++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode))
++ priv->gmsl_mode = MODE_GMSL2;
++ if (of_property_read_bool(np, "maxim,stp"))
++ priv->is_coax = 0;
++ else
++ priv->is_coax = 1;
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
++ priv->fsync_period = 3210000;/* 96MHz/30fps */
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,hven", &priv->hven))
++ priv->hven = 1;
++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw))
++ priv->hibw = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = MIPI_DT_YUV8;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus))
++ priv->mbus = mbus_default;
++ for (i = 0; i < 11; i++) {
++ sprintf(name, "maxim,gpio%d", i);
++ if (of_property_read_u32(np, name, &priv->gpio[i]))
++ priv->gpio[i] = -1;
++ }
++
++ /* module params override dts */
++ if (gmsl != MODE_GMSL2)
++ priv->gmsl_mode = gmsl;
++ if (him)
++ priv->him = him;
++ if (fsync_period) {
++ priv->fsync_period = fsync_period;
++// priv->fsync_mode = fsync_mode_default;
++ }
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != MIPI_DT_YUV8)
++ priv->dt = dt;
++// if (hsgen)
++// priv->hsgen = hsgen;
++ if (gpio0 >= 0)
++ priv->gpio[0] = gpio0;
++ if (gpio1 >= 0)
++ priv->gpio[1] = gpio1;
++ if (gpio7 >= 0)
++ priv->gpio[7] = gpio7;
++ if (gpio8 >= 0)
++ priv->gpio[8] = gpio8;
++
++ /* parse serializer crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
++ }
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (i < priv->n_links) {
++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "ser-addr not set\n");
++ return -EINVAL;
++ }
++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint);
++ }
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (prop) {
++ of_property_read_u32(endpoint, "csi-rate", &csi_rate);
++ of_update_property(rendpoint, prop);
++ }
++
++ prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (prop)
++ of_update_property(rendpoint, prop);
++ }
++
++ of_node_put(endpoint);
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */
++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */
++ }
++
++ prop = of_find_property(np, "maxim,links-mipi-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= MAX96712_MAX_MIPI)
++ return -EINVAL;
++ priv->link[i]->out_mipi = val;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate;
++
++ prop = of_find_property(np, "maxim,links-vc-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= 4)
++ return -EINVAL;
++ priv->link[i]->out_vc = val;
++ }
++ }
++
++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n");
++ for (i = 0; i < priv->n_links; i++)
++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc);
++
++ return 0;
++}
++
++static int max96712_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max96712_priv *priv;
++ struct gpio_desc *pwdn_gpio;
++ int ret, i;
++ int val = 0;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->regmap = devm_regmap_init_i2c(client, &max96712_regmap[0]);
++ if (IS_ERR(priv->regmap))
++ return PTR_ERR(priv->regmap);
++
++ i2c_set_clientdata(client, priv);
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++
++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
++ if (!IS_ERR(priv->ref_clk)) {
++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
++ v4l2_clk_enable(priv->ref_clk);
++ }
++
++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH);
++ if (!IS_ERR(pwdn_gpio)) {
++ udelay(5);
++ gpiod_set_value_cansleep(pwdn_gpio, 0);
++ usleep_range(3000, 5000);
++ }
++
++ des_read(MAX96712_DEV_ID, &val);
++ if (val != MAX96712_ID)
++ return -ENODEV;
++
++ for (i = 0; i < MAX96712_MAX_LINKS; i++) {
++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL);
++ if (!priv->link[i])
++ return -ENOMEM;
++ }
++
++ ret = max96712_parse_dt(client);
++ if (ret)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ char poc_name[10];
++
++ sprintf(poc_name, "poc%d", i);
++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name);
++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ }
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr);
++ if (!priv->link[i]->client)
++ return -ENOMEM;
++
++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max96712_regmap[priv->gmsl_mode]);
++ if (IS_ERR(priv->link[i]->regmap))
++ return PTR_ERR(priv->link[i]->regmap);
++ }
++
++ ret = max96712_i2c_mux_init(priv);
++ if (ret) {
++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
++ goto out;
++ }
++
++ ret = max96712_initialize(priv);
++ if (ret < 0)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_subdev_init(&priv->link[i]->sd, &max96712_subdev_ops);
++ priv->link[i]->sd.owner = client->dev.driver->owner;
++ priv->link[i]->sd.dev = &client->dev;
++ priv->link[i]->sd.grp_id = i;
++ v4l2_set_subdevdata(&priv->link[i]->sd, priv);
++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode;
++
++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
++ client->dev.driver->name, i, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ ret = v4l2_async_register_subdev(&priv->link[i]->sd);
++ if (ret < 0)
++ goto out;
++ }
++
++ priv->reboot_nb.notifier_call = max96712_reboot_notifier;
++ ret = register_reboot_notifier(&priv->reboot_nb);
++ if (ret) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
++ //max96712_debug_add(priv);
++out:
++ return ret;
++}
++
++static int max96712_remove(struct i2c_client *client)
++{
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ //max96712_debug_remove(priv);
++ i2c_mux_del_adapters(priv->mux);
++ unregister_reboot_notifier(&priv->reboot_nb);
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_async_unregister_subdev(&priv->link[i]->sd);
++ v4l2_device_unregister_subdev(&priv->link[i]->sd);
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return 0;
++}
++
++static const struct i2c_device_id max96712_id[] = {
++ { "max96712", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max96712_id);
++
++static struct i2c_driver max96712_i2c_driver = {
++ .driver = {
++ .name = "max96712",
++ .of_match_table = of_match_ptr(max96712_dt_ids),
++ },
++ .probe = max96712_probe,
++ .remove = max96712_remove,
++ .id_table = max96712_id,
++};
++
++module_i2c_driver(max96712_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL2 driver for MAX96712");
++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+new file mode 100644
+index 0000000..2976027
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+@@ -0,0 +1,263 @@
++/*
++ * MAXIM max96712 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#define MAX96712_MAX_LINKS 4
++#define MAX96712_MAX_PIPES 8
++#define MAX96712_MAX_PIPE_MAPS 16
++#define MAX96712_MAX_MIPI 4
++
++struct max96712_link {
++ struct v4l2_subdev sd;
++ struct fwnode_handle *sd_fwnode;
++ struct i2c_client *client;
++ struct regmap *regmap;
++ int ser_id;
++ int ser_addr;
++ int pipes_mask; /* mask of pipes used by this link */
++ int out_mipi; /* MIPI# */
++ int out_vc; /* VC# */
++ struct regulator *poc_reg; /* PoC power supply */
++};
++
++struct max96712_priv {
++ struct i2c_client *client;
++ struct regmap *regmap;
++ struct i2c_mux_core *mux;
++ int n_links;
++ int links_mask;
++ enum gmsl_mode gmsl_mode;
++ struct max96712_link *link[MAX96712_MAX_LINKS];
++ int gpio_resetb;
++ int active_low_resetb;
++ bool pclk_rising_edge;
++ bool is_coax;
++ int him;
++ int bws;
++ int dbl;
++ int hibw;
++ int hven;
++ int hsync;
++ int vsync;
++ int dt;
++ u64 crossbar;
++ char cb[16];
++ const char *mbus;
++ int gpio[11];
++ int timeout;
++ int poc_delay;
++ struct v4l2_clk *ref_clk;
++ int csi_rate[MAX96712_MAX_MIPI];
++ int fsync_period;
++ atomic_t use_count;
++ struct notifier_block reboot_nb;
++};
++
++#define MAX96712_REG4 0x04
++#define MAX96712_REG5 0x05
++#define MAX96712_REG6 0x06
++#define MAX96712_REG14 0x0e
++#define MAX96712_REG26 0x10
++#define MAX96712_REG27 0x11
++
++#define MAX96712_CTRL0 0x17
++#define MAX96712_CTRL1 0x18
++#define MAX96712_CTRL2 0x19
++#define MAX96712_CTRL3 0x1a
++#define MAX96712_CTRL11 0x22
++#define MAX96712_CTRL12 0x0a
++#define MAX96712_CTRL13 0x0b
++#define MAX96712_CTRL14 0x0c
++
++#define MAX96712_PWR1 0x13
++
++#define MAX96712_DEV_ID 0x4a
++#define MAX96712_REV 0x4c
++
++#define MAX96712_VIDEO_PIPE_SEL(n) (0xf0 + n)
++#define MAX96712_VIDEO_PIPE_EN 0xf4
++
++#define MAX96712_I2C_0(n) (0x640 + (0x10 * n))
++#define MAX96712_I2C_1(n) (0x641 + (0x10 * n))
++
++#define MAX96712_RX0(n) (0x50 + n)
++
++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \
++ (0x160 + (0x12 * (n - 5))))
++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00)
++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03)
++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08)
++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a)
++
++#define MAX_VPRBS(n) (0x1dc + (0x20 * n))
++
++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n))
++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m)
++
++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank))
++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00)
++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a)
++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b)
++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c)
++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d)
++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e)
++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f)
++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10)
++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11)
++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12)
++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13)
++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14)
++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15)
++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16)
++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17)
++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18)
++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19)
++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a)
++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b)
++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c)
++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d)
++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e)
++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f)
++
++#define MAX96712_FSYNC_0 0x4a0
++#define MAX96712_FSYNC_5 0x4a5
++#define MAX96712_FSYNC_6 0x4a6
++#define MAX96712_FSYNC_7 0x4a7
++#define MAX96712_FSYNC_8 0x4a8
++#define MAX96712_FSYNC_9 0x4a9
++#define MAX96712_FSYNC_10 0x4aa
++#define MAX96712_FSYNC_11 0x4ab
++#define MAX96712_FSYNC_15 0x4af
++
++#define MAX_MIPI_PHY_BASE 0x8a0
++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02)
++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03)
++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04)
++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05)
++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06)
++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08)
++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09)
++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a)
++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b)
++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d)
++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e)
++
++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n)
++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02)
++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a)
++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b)
++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c)
++
++/* 16 pairs of source-dest registers */
++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n))
++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n))
++/* Phy dst. Each reg contains 4 dest */
++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n)
++
++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch))
++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch))
++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch))
++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch))
++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch))
++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch))
++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch))
++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch))
++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch))
++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch))
++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch))
++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch))
++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch))
++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch))
++
++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch))
++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch))
++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch))
++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch))
++
++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch))
++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch))
++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch))
++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch))
++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch))
++
++static inline int max96712_write(struct max96712_priv *priv, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_read(struct max96712_priv *priv, int reg, int *val)
++{
++ int ret;
++
++ ret = regmap_read(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_update_bits(struct max96712_priv *priv, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(priv->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define des_read(reg, val) max96712_read(priv, reg, val)
++#define des_write(reg, val) max96712_write(priv, reg, val)
++#define des_update_bits(reg, mask, bits) max96712_update_bits(priv, reg, mask, bits)
++
++static inline int max96712_ser_write(struct max96712_link *link, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(link->regmap, reg, val);
++ if (ret < 0)
++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_ser_read(struct max96712_link *link, int reg, u8 *val)
++{
++ int ret;
++
++ ret = regmap_read(link->regmap, reg, (int *)val);
++ if (ret)
++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_ser_update_bits(struct max96712_link *link, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(link->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define ser_read(reg, val) max96712_ser_read(link, reg, val)
++#define ser_write(reg, val) max96712_ser_write(link, reg, val)
++#define ser_update_bits(reg, mask, bits) max96712_ser_update_bits(link, reg, mask, bits)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+new file mode 100644
+index 0000000..ee47c04
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+@@ -0,0 +1,362 @@
++/*
++ * MAXIM max96712 GMSL2 driver debug stuff
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static char *pipe_names[4] = {
++ "X", "Y", "Z", "U"
++};
++
++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n);
++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n);
++
++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1))
++
++static ssize_t max_link_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i = -1;
++ int j;
++ int gmsl2;
++ u32 crc = 0 ;
++ char *_buf = buf;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "link_%d", &i))
++ return -EINVAL;
++
++ if (i < 0)
++ return -EINVAL;
++
++ if (i >= priv->n_links) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ buf += sprintf(buf, "Link %c status\n", 'A' + i);
++
++ des_read(MAX96712_REG6, &reg);
++ gmsl2 = !!(reg & BIT(4 + i));
++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1");
++
++ if (gmsl2) {
++ buf += sprintf(buf, "GMSL2 Link lock: %d\n", max96712_gmsl2_get_link_lock(priv, i));
++ } else {
++ reg = max96712_gmsl1_get_link_lock(priv, i);
++ buf += sprintf(buf,
++ "GMSL1_CB: 0x%02x:\t"
++ "LOCKED_G1: %d\n",
++ reg, reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_CA(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_CA: 0x%02x:\t"
++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n",
++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_1B(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1B: 0x%02x:\t"
++ "LINE_CRC_ERR: %d ",
++ reg, reg_bits(2, 1));
++ for (j = 0; j < 4; j++) {
++ des_read(MAX_GMSL1_20(i) + j, &reg);
++ crc = crc | ((reg & 0xff) << (j * 8));
++ }
++ buf += sprintf(buf, "last crc 0x%08x\n", crc);
++
++ des_read(MAX_GMSL1_19(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_19: CC_CRC_ERRCNT %d\n",
++ reg);
++
++ des_read(MAX_GMSL1_1D(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1D: 0x%02x:\t"
++ "UNDERBOOST: %d, AEQ-BST: %d\n",
++ reg, reg_bits(4, 1), reg_bits(0, 4));
++ }
++
++ return (buf - _buf);
++}
++
++static ssize_t max_pipe_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ char *_buf = buf;
++ int pipe = 0;
++ int map;
++ int maps_en = 0;
++ int pipes_en;
++ int reg = 0;
++ int shift;
++
++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe))
++ return -EINVAL;
++
++ if (pipe < 0)
++ return -EINVAL;
++
++ if (pipe >= MAX96712_MAX_PIPES) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ des_read(MAX96712_VIDEO_PIPE_EN, &pipes_en);
++
++ buf += sprintf(buf, "Video Pipe %d %s\n",
++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled");
++ if (!(pipes_en & BIT(pipe)))
++ goto out;
++
++ des_read(MAX_VPRBS(pipe), &reg);
++ /* bit 5 is not valid for MAX96712 */
++ buf += sprintf(buf,
++ "\tVPRBS: 0x%02x\t"
++ "VPRBS_FAIL: %d,"
++ "VIDEO_LOCK: %d\n",
++ reg,
++ reg_bits(5, 1), reg_bits(0, 1));
++
++ /* show source */
++ shift = (pipe % 2) * 4;
++ des_read(MAX96712_VIDEO_PIPE_SEL(pipe / 2), &reg);
++ buf += sprintf(buf, "SRC: PHY %c, PIPE %s\n",
++ 'A' + (char)((reg >> (shift + 2)) & 0x03),
++ pipe_names[(reg >> shift) & 0x03]);
++
++ /* show maps */
++ des_read(MAX_MIPI_TX11(pipe), &maps_en);
++ des_read(MAX_MIPI_TX12(pipe), &reg);
++ maps_en |= reg << 8;
++
++ for (map = 0; map < MAX96712_MAX_PIPE_MAPS; map++) {
++ int src, dst, mipi;
++ if (!(maps_en & BIT(map)))
++ continue;
++
++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src);
++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst);
++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi);
++
++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n",
++ map,
++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03,
++ (mipi >> ((map % 4) * 2)) & 0x03);
++ }
++
++ des_read(MAX_VIDEO_RX0(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX0: 0x%02x\t"
++ "LCRC_ERR: %d, "
++ "LINE_CRC_SEL: %d, "
++ "LINE_CRC_EN: %d, "
++ "DIS_PKT_DET: %d\n",
++ reg,
++ reg_bits(7, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX3(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX3: 0x%02x\t"
++ "HD_TR_MODE: %d, "
++ "DLOCKED: %d, "
++ "VLOCKED: %d, "
++ "HLOCKED: %d, "
++ "DTRACKEN: %d, "
++ "VTRACKEN: %d, "
++ "HTRACKEN: %d\n",
++ reg,
++ reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX8(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX8: 0x%02x\t"
++ "VID_BLK_LEN_ERR: %d, "
++ "VID_LOCK: %d, "
++ "VID_PKT_DET: %d, "
++ "VID_SEQ_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1));
++ des_read(MAX_VIDEO_RX10(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX10: 0x%02x\t"
++ "MASK_VIDEO_DE: %d\n",
++ reg,
++ reg_bits(6, 1));
++
++out:
++ return (buf - _buf);
++}
++
++static ssize_t max_stat_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i;
++ char *_buf = buf;
++ int reg = 0;
++
++ /* TODO: add same for 96712 */
++ des_read(MAX96712_REG4, &reg);
++ buf += sprintf(buf,
++ "REG_REG4: 0x%02x\t"
++ "LOCK_CFG: %d\n",
++ reg, reg_bits(5, 1));
++
++ des_read(MAX_BACKTOP1(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP1: 0x%02x:\t"
++ "CSIPLL3_LOCK: %d, "
++ "CSIPLL2_LOCK: %d, "
++ "CSIPLL1_LOCK: %d, "
++ "CSIPLL0_LOCK: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1));
++
++ des_read(MAX_BACKTOP11(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP11: 0x%02x:\t"
++ "CMD_OWERFLOW4: %d, "
++ "CMD_OWERFLOW3: %d, "
++ "CMD_OWERFLOW2: %d, "
++ "CMD_OWERFLOW1: %d, "
++ "LMO_3: %d, "
++ "LMO_2: %d, "
++ "LMO_1: %d, "
++ "LMO_0: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ for (i = 0; i < MAX96712_MAX_MIPI; i++) {
++ buf += sprintf(buf, "MIPI %d\n", i);
++ des_read(MAX_MIPI_TX2(i), &reg);
++ buf += sprintf(buf,
++ "\tMIPI_TX2: 0x%02x\n",
++ reg);
++ }
++
++ return (buf - _buf);
++}
++
++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL);
++
++static struct attribute *max96712_attributes[] = {
++ &dev_attr_link_0.attr,
++ &dev_attr_link_1.attr,
++ &dev_attr_link_2.attr,
++ &dev_attr_link_3.attr,
++ &dev_attr_pipe_0.attr,
++ &dev_attr_pipe_1.attr,
++ &dev_attr_pipe_2.attr,
++ &dev_attr_pipe_3.attr,
++ &dev_attr_pipe_4.attr,
++ &dev_attr_pipe_5.attr,
++ &dev_attr_pipe_6.attr,
++ &dev_attr_pipe_7.attr,
++ &dev_attr_stat.attr,
++ NULL
++};
++
++static const struct attribute_group max96712_group = {
++ .attrs = max96712_attributes,
++};
++
++int max96712_debug_add(struct max96712_priv *priv)
++{
++ int ret;
++
++ ret = sysfs_create_group(&priv->client->dev.kobj, &max96712_group);
++ if (ret < 0) {
++ dev_err(&priv->client->dev, "Sysfs registration failed\n");
++ return ret;
++ }
++
++ return ret;
++}
++
++void max96712_debug_remove(struct max96712_priv *priv)
++{
++ sysfs_remove_group(&priv->client->dev.kobj, &max96712_group);
++}
++
++#if 0
++int max96712_patgen(struct max96712_priv *priv)
++{
++ int ret = 0;
++
++ const u32 xres = 1280;
++ const u32 yres = 800;
++ const u32 hbp = 128;
++ const u32 hfp = 80;
++ const u32 hsa = 32;
++ const u32 vbp = 17;
++ const u32 vfp = 4;
++ const u32 vsa = 3;
++
++ u32 vtotal = vfp + vsa + vbp + yres;
++ u32 htotal = xres + hfp + hbp + hsa;
++ u32 vs_high = vsa * htotal;
++ u32 vs_low = (vfp + yres + vbp) * htotal;
++ u32 v2h = (vsa + vbp) * htotal + hfp;
++ u32 hs_high = hsa;
++ u32 hs_low = xres + hfp + hbp;
++ u32 v2d = v2h + hsa + hbp;
++ u32 de_high = xres;
++ u32 de_low = hfp + hsa + hbp;
++ u32 de_cnt = yres;
++
++ /* DEBUG_EXTRA & PATGEN_CLK_SRC = 75Mhz pclk */
++ des_write(0x0009, 0x01); /* if DEBUG_EXTRA[1:0] = 2b01, PCLK Frequency is 75MHz (don't care PATGEN_CLK_SRC) */
++ des_write(0x01dc, 0x00);
++
++ des_write_n(0x1052, 3, 0); /* vs delay */
++ des_write_n(0x1055, 3, vs_high);
++ des_write_n(0x1058, 3, vs_low);
++ des_write_n(0x105B, 3, v2h);
++ des_write_n(0x105E, 2, hs_high);
++ des_write_n(0x1060, 2, hs_low);
++ des_write_n(0x1062, 2, vtotal); /* hs cnt */
++ des_write_n(0x1064, 3, v2d);
++ des_write_n(0x1067, 2, de_high);
++ des_write_n(0x1069, 2, de_low);
++ des_write_n(0x106B, 2, de_cnt);
++
++ des_write_n(0x106E, 3, 0xff0000); /* color A */
++ des_write_n(0x1071, 3, 0x0000ff); /* color B */
++
++ des_write(0x1074, 0x50); /* chkr_rpt_a = 80 */
++ des_write(0x1075, 0x50); /* chkr_rpt_b = 80 */
++ des_write(0x1076, 0x50); /* chkr_alt = 80 */
++
++ des_write(0x1050, 0xfb); /* gen_vs,gen_hs,gen_de, vtg[0:1] */
++ des_write(0x1051, 0x10); /* patgen_mode[5:4] = 0b1,checkerboard */
++
++out:
++ return ret;
++}
++#endif
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch
new file mode 100644
index 00000000..ea20fd1d
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0494-media-i2c-max9286-max9288-use-common.h-file.patch
@@ -0,0 +1,218 @@
+From 083a58c074efe94a68fbb2deac66d404f7644e32 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 10:56:45 +0300
+Subject: [PATCH] media: i2c: max9286,max9288: use common.h file
+
+Use common.h file for all gmsl drivers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/max9286.c | 61 +++++++++--------------------
+ drivers/media/i2c/soc_camera/gmsl/max9288.c | 54 +++++++------------------
+ 2 files changed, 34 insertions(+), 81 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9286.c b/drivers/media/i2c/soc_camera/gmsl/max9286.c
+index 2d56b41..c37e972 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9286.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max9286.c
+@@ -22,16 +22,7 @@
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-subdev.h>
+
+-#include "../max9286.h"
+-
+-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
+-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
+-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
+-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
+-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
+-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
+-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
+-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++#include "common.h"
+
+ struct max9286_priv {
+ struct v4l2_subdev sd[4];
+@@ -174,20 +165,6 @@ static int dt2bpp [9] = {
+ 14, /* RAW14 */
+ };
+
+-static char* ser_name(int id)
+-{
+- switch (id) {
+- case MAX9271_ID:
+- return "MAX9271";
+- case MAX96705_ID:
+- return "MAX96705";
+- case MAX96707_ID:
+- return "MAX96707";
+- default:
+- return "unknown";
+- }
+-}
+-
+ static void max9286_write_remote_verify(struct i2c_client *client, int idx, u8 reg, u8 val)
+ {
+ struct max9286_priv *priv = i2c_get_clientdata(client);
+@@ -384,7 +361,7 @@ static int max9286_reverse_channel_setup(struct i2c_client *client, int idx)
+
+ out:
+ sprintf(timeout_str, "retries=%d lock_sts=%d link_sts=0x%x", priv->timeout - timeout, !!(lock_sts & 0x80), link_sts & (0x11 << idx));
+- dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id),
++ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, chip_name(priv->ser_id),
+ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx],
+ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
+ priv->timeout - timeout ? timeout_str : "");
+@@ -576,6 +553,22 @@ static int max9286_initialize(struct i2c_client *client)
+ return 0;
+ }
+
++static int max9286_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ if (on) {
++ if (atomic_inc_return(&priv->use_count) == 1)
++ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
++ }
++
++ return 0;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int max9286_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -605,22 +598,6 @@ static int max9286_s_register(struct v4l2_subdev *sd,
+ }
+ #endif
+
+-static int max9286_s_power(struct v4l2_subdev *sd, int on)
+-{
+- struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- if (on) {
+- if (atomic_inc_return(&priv->use_count) == 1)
+- reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */
+- } else {
+- if (atomic_dec_return(&priv->use_count) == 0)
+- reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */
+- }
+-
+- return 0;
+-}
+-
+ static int max9286_registered_async(struct v4l2_subdev *sd)
+ {
+ struct max9286_priv *priv = v4l2_get_subdevdata(sd);
+@@ -656,7 +633,7 @@ static int max9286_reboot_notifier(struct notifier_block *nb, unsigned long even
+ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
+ }
+
+- return NOTIFY_OK;
++ return NOTIFY_DONE;
+ }
+
+ static struct v4l2_subdev_core_ops max9286_subdev_core_ops = {
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9288.c b/drivers/media/i2c/soc_camera/gmsl/max9288.c
+index 7de1f9e..ce44e2b 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9288.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max9288.c
+@@ -21,16 +21,7 @@
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-subdev.h>
+
+-#include "../max9286.h"
+-
+-#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
+-#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
+-#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
+-#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
+-#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
+-#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
+-#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
+-#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++#include "common.h"
+
+ struct max9288_priv {
+ struct v4l2_subdev sd;
+@@ -140,23 +131,8 @@ static int dt2bpp [9] = {
+ 14, /* RAW14 */
+ };
+
+-static char* ser_name(int id)
+-{
+- switch (id) {
+- case MAX9271_ID:
+- return "MAX9271";
+- case MAX96705_ID:
+- return "MAX96705";
+- case MAX96707_ID:
+- return "MAX96707";
+- default:
+- return "unknown";
+- }
+-}
+-
+ static void max9288_write_remote_verify(struct i2c_client *client, u8 reg, u8 val)
+ {
+- struct max9288_priv *priv = i2c_get_clientdata(client);
+ int timeout;
+
+ for (timeout = 0; timeout < 10; timeout++) {
+@@ -297,7 +273,7 @@ static int max9288_reverse_channel_setup(struct i2c_client *client)
+
+ out:
+ sprintf(timeout_str, "retries=%d lock_sts=%d", priv->timeout - timeout, !!(lock_sts & 0x80));
+- dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", ser_name(priv->ser_id),
++ dev_info(&client->dev, "link %s %sat 0x%x %s %s\n", chip_name(priv->ser_id),
+ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr,
+ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
+ priv->timeout - timeout ? timeout_str : "");
+@@ -487,6 +463,19 @@ static int max9288_initialize(struct i2c_client *client)
+ return 0;
+ }
+
++static int max9288_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9288_priv *priv = v4l2_get_subdevdata(sd);
++ struct i2c_client *client = priv->client;
++
++ client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
++ max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */
++ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
++ client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
++
++ return 0;
++}
++
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ static int max9288_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+@@ -516,19 +505,6 @@ static int max9288_s_register(struct v4l2_subdev *sd,
+ }
+ #endif
+
+-static int max9288_s_power(struct v4l2_subdev *sd, int on)
+-{
+- struct max9288_priv *priv = v4l2_get_subdevdata(sd);
+- struct i2c_client *client = priv->client;
+-
+- client->addr = priv->max9271_addr; /* MAX9271-CAMx I2C new */
+- max9288_write_remote_verify(client, 0x04, on ? (conf_link ? 0x43 : 0x83) : 0x43); /* enable serial_link or conf_link */
+- usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */
+- client->addr = priv->des_addr; /* MAX9288-CAMx I2C */
+-
+- return 0;
+-}
+-
+ static struct v4l2_subdev_core_ops max9288_subdev_core_ops = {
+ #ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = max9288_g_register,
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch
new file mode 100644
index 00000000..9069ad63
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch
@@ -0,0 +1,62 @@
+From 6ecc8987af944ca48a3565111bd1af7293d5a3ac Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 10:59:10 +0300
+Subject: [PATCH] media: i2c: ti9x4: fix rebot_notify and gpiod_request
+
+This fixed reboot return value and initialize power gpiod
+during request
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 8 ++++----
+ drivers/media/i2c/soc_camera/fpdlink/ti9x4.h | 2 +-
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+index 340e61e..24ac2e5 100644
+--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+@@ -1,7 +1,7 @@
+- /*
++/*
+ * TI DS90UB954/960/964 FPDLinkIII driver
+ *
+- * Copyright (C) 2017-2018 Cogent Embedded, Inc.
++ * Copyright (C) 2017-2020 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -433,7 +433,7 @@ static int ti9x4_reboot_notifier(struct notifier_block *nb, unsigned long event,
+ gpiod_direction_output(priv->poc_gpio[idx], 0); /* POC power off */
+ }
+
+- return NOTIFY_OK;
++ return NOTIFY_DONE;
+ }
+
+ static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = {
+@@ -511,7 +511,7 @@ static int ti9x4_parse_dt(struct i2c_client *client)
+ v4l2_clk_enable(priv->ref_clk);
+ }
+
+- priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOF_OUT_INIT_HIGH);
++ priv->pwen = devm_gpiod_get(&client->dev, NULL, GPIOD_OUT_HIGH);
+ if (!IS_ERR(priv->pwen)) {
+ mdelay(5);
+ gpiod_direction_output(priv->pwen, 0);
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
+index 6825f8a..964ab78 100644
+--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.h
+@@ -1,7 +1,7 @@
+ /*
+ * TI FPDLinkIII driver include file
+ *
+- * Copyright (C) 2017 Cogent Embedded, Inc.
++ * Copyright (C) 2017-2020 Cogent Embedded, Inc.
+ *
+ * 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
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch
new file mode 100644
index 00000000..267cff29
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0496-media-i2c-add-interim-LVDS-imager-drivers.patch
@@ -0,0 +1,5202 @@
+From b60ec01692d2a2e8ee28e6aae58fe78fd806d733 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 11:02:31 +0300
+Subject: [PATCH] media: i2c: add interim LVDS imager drivers
+
+This adds new LVDS imager drivers that support all enabled
+serializers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/Makefile | 5 +
+ .../media/i2c/soc_camera/imagers/ap0101_ar014x.c | 618 +++++++++++
+ .../media/i2c/soc_camera/imagers/ap0101_ar014x.h | 28 +
+ .../media/i2c/soc_camera/imagers/ap0201_ar023x.c | 588 ++++++++++
+ .../media/i2c/soc_camera/imagers/ap0201_ar023x.h | 24 +
+ drivers/media/i2c/soc_camera/imagers/ov10635.c | 690 ++++++++++++
+ drivers/media/i2c/soc_camera/imagers/ov10635.h | 1143 ++++++++++++++++++++
+ .../media/i2c/soc_camera/imagers/ov10635_debug.h | 54 +
+ drivers/media/i2c/soc_camera/imagers/ov2311.c | 571 ++++++++++
+ drivers/media/i2c/soc_camera/imagers/ov2311.h | 217 ++++
+ drivers/media/i2c/soc_camera/imagers/ov490.c | 1051 ++++++++++++++++++
+ drivers/media/i2c/soc_camera/imagers/ov490.h | 102 ++
+ 12 files changed, 5091 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov10635_debug.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov2311.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov2311.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov490.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ov490.h
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile
+index ca10bbc..0d0ff32 100644
+--- a/drivers/media/i2c/soc_camera/imagers/Makefile
++++ b/drivers/media/i2c/soc_camera/imagers/Makefile
+@@ -1,2 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+new file mode 100644
+index 0000000..1df3f3b
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+@@ -0,0 +1,618 @@
++/*
++ * ON Semiconductor AP0101-AR014X sensor camera driver
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "ap0101_ar014x.h"
++
++static const int ap0101_i2c_addr[] = {0x5d, 0x48};
++
++#define AP0101_PID_REG 0x0000
++#define AP0101_REV_REG 0x0058
++#define AP0101_PID 0x0160
++
++#define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8
++
++struct ap0101_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int max_width;
++ int max_height;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int autogain;
++ /* serializers */
++ int ser_addr;
++ int hts;
++ int vts;
++ int frame_preamble;
++};
++
++static inline struct ap0101_priv *to_ap0101(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ap0101_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ap0101_priv, hdl)->sd;
++}
++
++static int ap0101_set_regs(struct i2c_client *client,
++ const struct ap0101_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == AP0101_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write16(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static u16 ap0101_ar014x_read(struct i2c_client *client, u16 addr)
++{
++ u16 reg_val = 0;
++
++ reg16_write16(client, 0x0040, 0x8d00);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0xfc00, addr);
++ reg16_write16(client, 0xfc02, 0x0200); /* 2 bytes */
++ reg16_write16(client, 0x0040, 0x8d05);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d08);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_read16(client, 0xfc00, &reg_val);
++ reg16_write16(client, 0x0040, 0x8d02);
++ usleep_range(1000, 1500); /* wait 1000 us */
++
++ return reg_val;
++}
++
++static void ap0101_ar014x_write(struct i2c_client *client, u16 addr, u16 val)
++{
++ reg16_write16(client, 0x0040, 0x8d00);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0xfc00, addr);
++ reg16_write16(client, 0xfc02, 0x0200 | (val >> 8)); /* 2 bytes */
++ reg16_write16(client, 0xfc04, (val & 0xff) << 8);
++ reg16_write16(client, 0x0040, 0x8d06);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d08);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d02);
++ usleep_range(1000, 1500); /* wait 1000 us */
++}
++
++static void ap0101_otp_id_read(struct i2c_client *client)
++{
++ struct ap0101_priv *priv = to_ap0101(client);
++ int i;
++
++ /* read camera id from ar014x OTP memory */
++ ap0101_ar014x_write(client, 0x3054, 0x400);
++ ap0101_ar014x_write(client, 0x304a, 0x110);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i += 2) {
++ /* first 4 bytes are equal on all ar014x */
++ priv->id[i] = (ap0101_ar014x_read(client, 0x3800 + i + 4) >> 8) ^ (ap0101_ar014x_read(client, 0x3800 + i + 16) >> 8);
++ priv->id[i + 1] = (ap0101_ar014x_read(client, 0x3800 + i + 4) & 0xff) ^ (ap0101_ar014x_read(client, 0x3800 + i + 16) & 0xff);
++ }
++}
++
++static int ap0101_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ap0101_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = AP0101_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ap0101_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = AP0101_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ap0101_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = AP0101_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ap0101_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++
++ ap0101_otp_id_read(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = AP0101_PID >> 8;
++ edid->edid[9] = AP0101_PID & 0xff;
++
++ return 0;
++}
++
++static int ap0101_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > priv->max_width) ||
++ (rect->top + rect->height > priv->max_height))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int ap0101_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ap0101_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ap0101_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ __be64 be_val;
++
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
++
++ return ret;
++}
++
++static int ap0101_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
++
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ return reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++}
++#endif
++
++static struct v4l2_subdev_core_ops ap0101_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ap0101_g_register,
++ .s_register = ap0101_s_register,
++#endif
++};
++
++static int ap0101_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++ int ret = -EINVAL;
++ u16 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_GAIN:
++ case V4L2_CID_EXPOSURE:
++ break;
++ case V4L2_CID_HFLIP:
++ reg16_read16(client, 0xc846, &val);
++ if (ctrl->val)
++ val |= 0x01;
++ else
++ val &= ~0x01;
++ reg16_write16(client, 0xc846, val);
++ reg16_write16(client, 0xfc00, 0x2800);
++ ret = reg16_write16(client, 0x0040, 0x8100);
++ break;
++ case V4L2_CID_VFLIP:
++ reg16_read16(client, 0xc846, &val);
++ if (ctrl->val)
++ val |= 0x02;
++ else
++ val &= ~0x02;
++ reg16_write16(client, 0xc846, val);
++ reg16_write16(client, 0xfc00, 0x2800);
++ ret = reg16_write16(client, 0x0040, 0x8100);
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ap0101_ctrl_ops = {
++ .s_ctrl = ap0101_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ap0101_video_ops = {
++ .s_stream = ap0101_s_stream,
++ .g_mbus_config = ap0101_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ap0101_subdev_pad_ops = {
++ .get_edid = ap0101_get_edid,
++ .enum_mbus_code = ap0101_enum_mbus_code,
++ .get_selection = ap0101_get_selection,
++ .set_selection = ap0101_set_selection,
++ .get_fmt = ap0101_get_fmt,
++ .set_fmt = ap0101_set_fmt,
++};
++
++static struct v4l2_subdev_ops ap0101_subdev_ops = {
++ .core = &ap0101_core_ops,
++ .video = &ap0101_video_ops,
++ .pad = &ap0101_subdev_pad_ops,
++};
++
++static ssize_t ap0101_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0101_priv *priv = to_ap0101(client);
++
++ ap0101_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ap0101, S_IRUGO, ap0101_otp_id_show, NULL);
++
++static int ap0101_initialize(struct i2c_client *client)
++{
++ struct ap0101_priv *priv = to_ap0101(client);
++ u16 pid = 0, rev = 0, val = 0;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ap0101_i2c_addr); i++) {
++ setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i], MODE_GMSL1);
++
++ /* check model ID */
++ reg16_read16(client, AP0101_PID_REG, &pid);
++ if (pid == AP0101_PID)
++ break;
++ }
++
++ if (pid != AP0101_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ reg16_read16(client, AP0101_REV_REG, &rev);
++#if 1
++ /* read resolution used by current firmware */
++ reg16_read16(client, 0xca90, &val);
++ priv->max_width = val;
++ reg16_read16(client, 0xca92, &val);
++ priv->max_height = val;
++#else
++ priv->max_width = AP0101_MAX_WIDTH;
++ priv->max_height = AP0101_MAX_HEIGHT;
++#endif
++ /* Program wizard registers */
++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard));
++ /* Read OTP IDs */
++ ap0101_otp_id_read(client);
++
++ switch (get_des_id(client)) {
++ case MAX9286_ID:
++ case MAX9288_ID:
++ case MAX9296A_ID:
++ case MAX96712_ID:
++ /* setup serializer HS generator */
++ priv->frame_preamble = 5;
++ priv->hts = 1280 * 2 + 548;
++ priv->vts = 960;
++ reg8_write_addr(client, priv->ser_addr, 0x4e, priv->frame_preamble >> 16); /* HS delay */
++ reg8_write_addr(client, priv->ser_addr, 0x4f, (priv->frame_preamble >> 8) & 0xff);
++ reg8_write_addr(client, priv->ser_addr, 0x50, priv->frame_preamble & 0xff);
++ reg8_write_addr(client, priv->ser_addr, 0x54, (priv->max_width * 2) >> 8); /* HS high period */
++ reg8_write_addr(client, priv->ser_addr, 0x55, (priv->max_width * 2) & 0xff);
++ reg8_write_addr(client, priv->ser_addr, 0x56, (priv->hts - priv->max_width * 2) >> 8); /* HS low period */
++ reg8_write_addr(client, priv->ser_addr, 0x57, (priv->hts - priv->max_width * 2) & 0xff);
++ reg8_write_addr(client, priv->ser_addr, 0x58, priv->vts >> 8); /* HS count */
++ reg8_write_addr(client, priv->ser_addr, 0x59, priv->vts & 0xff);
++ break;
++ }
++
++ dev_info(&client->dev, "ap0101 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id ap0101_id[] = {
++ { "ap0101", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ap0101_id);
++
++static const struct of_device_id ap0101_of_ids[] = {
++ { .compatible = "onsemi,ap0101", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ap0101_of_ids);
++
++static int ap0101_parse_dt(struct device_node *np, struct ap0101_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ return 0;
++}
++
++static int ap0101_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ap0101_priv *priv;
++ struct v4l2_ctrl *ctrl;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ap0101_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ priv->exposure = 0x100;
++ priv->gain = 0x100;
++ priv->autogain = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 1);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 1);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ap0101_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ap0101_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ap0101_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = priv->max_width;
++ priv->rect.height = priv->max_height;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ap0101) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ap0101_remove(struct i2c_client *client)
++{
++ struct ap0101_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ap0101);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ap0101_i2c_driver = {
++ .driver = {
++ .name = "ap0101",
++ .of_match_table = ap0101_of_ids,
++ },
++ .probe = ap0101_probe,
++ .remove = ap0101_remove,
++ .id_table = ap0101_id,
++};
++
++module_i2c_driver(ap0101_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for AP0101");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
+new file mode 100644
+index 0000000..d0d6205
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
+@@ -0,0 +1,28 @@
++/*
++ * ON Semiconductor ap0101-ar014x sensor camera wizard 1280x720@30/UYVY/BT601/8bit
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#define AP0101_MAX_WIDTH 1280
++#define AP0101_MAX_HEIGHT 720
++
++#define AP0101_DELAY 0xffff
++
++struct ap0101_reg {
++ u16 reg;
++ u16 val;
++};
++
++static const struct ap0101_reg ap0101_regs_wizard[] = {
++/* enable FSIN */
++{0xc88c, 0x0303},
++{0xfc00, 0x2800},
++{0x0040, 0x8100},
++{AP0101_DELAY, 100},
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+new file mode 100644
+index 0000000..35169b8
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+@@ -0,0 +1,588 @@
++/*
++ * ON Semiconductor AP0201-AR023X sensor camera driver
++ *
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "ap0201_ar023x.h"
++#include "../gmsl/common.h"
++
++static const int ap0201_i2c_addr[] = {0x5d, 0x48};
++
++#define AP0201_PID_REG 0x0000
++#define AP0201_REV_REG 0x0058
++#define AP0201_PID 0x0064
++
++#define AP0201_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8
++
++struct ap0201_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int max_width;
++ int max_height;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int autogain;
++ /* serializer */
++ int ser_addr;
++};
++
++static inline struct ap0201_priv *to_ap0201(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ap0201_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ap0201_priv, hdl)->sd;
++}
++
++static int ap0201_set_regs(struct i2c_client *client,
++ const struct ap0201_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == AP0201_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write16(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static u16 ap0201_ar023x_read(struct i2c_client *client, u16 addr)
++{
++ u16 reg_val = 0;
++
++ reg16_write16(client, 0x0040, 0x8d00);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0xfc00, addr);
++ reg16_write16(client, 0xfc02, 0x0200); /* 2 bytes */
++ reg16_write16(client, 0x0040, 0x8d05);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d08);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_read16(client, 0xfc00, &reg_val);
++ reg16_write16(client, 0x0040, 0x8d02);
++ usleep_range(1000, 1500); /* wait 1000 us */
++
++ return reg_val;
++}
++
++static void ap0201_ar023x_write(struct i2c_client *client, u16 addr, u16 val)
++{
++ reg16_write16(client, 0x0040, 0x8d00);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0xfc00, addr);
++ reg16_write16(client, 0xfc02, 0x0200 | (val >> 8)); /* 2 bytes */
++ reg16_write16(client, 0xfc04, (val & 0xff) << 8);
++ reg16_write16(client, 0x0040, 0x8d06);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d08);
++ usleep_range(1000, 1500); /* wait 1000 us */
++ reg16_write16(client, 0x0040, 0x8d02);
++ usleep_range(1000, 1500); /* wait 1000 us */
++}
++
++static void ap0201_otp_id_read(struct i2c_client *client)
++{
++ struct ap0201_priv *priv = to_ap0201(client);
++ int i;
++
++ /* read camera id from ar023x OTP memory */
++ ap0201_ar023x_write(client, 0x3054, 0x400);
++ ap0201_ar023x_write(client, 0x304a, 0x110);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i += 2) {
++ u16 val = 0;
++ /* first 4 bytes are equal on all ar023x */
++ val = ap0201_ar023x_read(client, 0x3800 + i + 4);
++ priv->id[i] = val >> 8;
++ priv->id[i + 1] = val & 0xff;
++ }
++}
++
++static int ap0201_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ap0201_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = AP0201_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ap0201_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = AP0201_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ap0201_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = AP0201_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ap0201_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++
++ ap0201_otp_id_read(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = AP0201_PID >> 8;
++ edid->edid[9] = AP0201_PID & 0xff;
++
++ return 0;
++}
++
++static int ap0201_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > priv->max_width) ||
++ (rect->top + rect->height > priv->max_height))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int ap0201_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ap0201_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ap0201_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ u16 val = 0;
++
++ ret = reg16_read16(client, (u16)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int ap0201_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops ap0201_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ap0201_g_register,
++ .s_register = ap0201_s_register,
++#endif
++};
++
++static int ap0201_change_config(struct i2c_client *client)
++{
++ reg16_write16(client, 0x098e, 0x7c00);
++ usleep_range(1000, 1500); /* wait 1 ms */
++ reg16_write16(client, 0xfc00, 0x2800);
++ reg16_write16(client, 0x0040, 0x8100);
++
++ return 0;
++}
++
++static int ap0201_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++ int ret = -EINVAL;
++ u16 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_GAIN:
++ case V4L2_CID_EXPOSURE:
++ break;
++ case V4L2_CID_HFLIP:
++ reg16_read16(client, 0xc846, &val);
++ if (ctrl->val)
++ val |= 0x01;
++ else
++ val &= ~0x01;
++ reg16_write16(client, 0xc846, val);
++ ret = ap0201_change_config(client);
++ break;
++ case V4L2_CID_VFLIP:
++ reg16_read16(client, 0xc846, &val);
++ if (ctrl->val)
++ val |= 0x02;
++ else
++ val &= ~0x02;
++ reg16_write16(client, 0xc846, val);
++ ret = ap0201_change_config(client);
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ap0201_ctrl_ops = {
++ .s_ctrl = ap0201_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ap0201_video_ops = {
++ .s_stream = ap0201_s_stream,
++ .g_mbus_config = ap0201_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ap0201_subdev_pad_ops = {
++ .get_edid = ap0201_get_edid,
++ .enum_mbus_code = ap0201_enum_mbus_code,
++ .get_selection = ap0201_get_selection,
++ .set_selection = ap0201_set_selection,
++ .get_fmt = ap0201_get_fmt,
++ .set_fmt = ap0201_set_fmt,
++};
++
++static struct v4l2_subdev_ops ap0201_subdev_ops = {
++ .core = &ap0201_core_ops,
++ .video = &ap0201_video_ops,
++ .pad = &ap0201_subdev_pad_ops,
++};
++
++static ssize_t ap0201_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ap0201_priv *priv = to_ap0201(client);
++
++ ap0201_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ap0201, S_IRUGO, ap0201_otp_id_show, NULL);
++
++static int ap0201_initialize(struct i2c_client *client)
++{
++ struct ap0201_priv *priv = to_ap0201(client);
++ u16 pid = 0, rev = 0, val = 0;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ap0201_i2c_addr); i++) {
++ setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i], MODE_GMSL2);
++
++ /* check product ID */
++ reg16_read16(client, AP0201_PID_REG, &pid);
++ if (pid == AP0201_PID)
++ break;
++ }
++
++ if (pid != AP0201_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ reg16_read16(client, AP0201_REV_REG, &rev);
++#if 1
++ /* read resolution used by current firmware */
++ reg16_read16(client, 0xcae4, &val);
++ priv->max_width = val;
++ reg16_read16(client, 0xcae6, &val);
++ priv->max_height = val;
++#else
++ priv->max_width = AP0201_MAX_WIDTH;
++ priv->max_height = AP0201_MAX_HEIGHT;
++#endif
++ /* Program wizard registers */
++ ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard));
++ /* Read OTP IDs */
++ ap0201_otp_id_read(client);
++
++ dev_info(&client->dev, "ap0201 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id ap0201_id[] = {
++ { "ap0201", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ap0201_id);
++
++static const struct of_device_id ap0201_of_ids[] = {
++ { .compatible = "onsemi,ap0201", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ap0201_of_ids);
++
++static int ap0201_parse_dt(struct device_node *np, struct ap0201_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ return 0;
++}
++
++static int ap0201_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ap0201_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ap0201_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ priv->exposure = 0x100;
++ priv->gain = 0x100;
++ priv->autogain = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ap0201_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ap0201_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ap0201_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = priv->max_width;
++ priv->rect.height = priv->max_height;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ap0201) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ap0201_remove(struct i2c_client *client)
++{
++ struct ap0201_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ap0201);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ap0201_i2c_driver = {
++ .driver = {
++ .name = "ap0201",
++ .of_match_table = ap0201_of_ids,
++ },
++ .probe = ap0201_probe,
++ .remove = ap0201_remove,
++ .id_table = ap0201_id,
++};
++
++module_i2c_driver(ap0201_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for AP0201");
++MODULE_AUTHOR("Andrey Gusakov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
+new file mode 100644
+index 0000000..c857edc
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
+@@ -0,0 +1,24 @@
++/*
++ * ON Semiconductor AP0201-AR023X sensor camera
++ *
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#define AP0201_MAX_WIDTH 1920
++#define AP0201_MAX_HEIGHT 1200
++
++#define AP0201_DELAY 0xffff
++
++struct ap0201_reg {
++ u16 reg;
++ u16 val;
++};
++
++static const struct ap0201_reg ap0201_regs_wizard[] = {
++/* enable FSIN */
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.c b/drivers/media/i2c/soc_camera/imagers/ov10635.c
+new file mode 100644
+index 0000000..b9813f7
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.c
+@@ -0,0 +1,690 @@
++/*
++ * OmniVision ov10635 sensor camera driver
++ *
++ * Copyright (C) 2015-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "ov10635.h"
++
++#define OV10635_I2C_ADDR 0x30
++
++#define OV10635_PID_REGA 0x300a
++#define OV10635_PID_REGB 0x300b
++#define OV10635_PID 0xa635
++
++struct ov10635_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int subsampling;
++ int fps_denominator;
++ int init_complete;
++ u8 id[6];
++ int dvp_order;
++ /* serializers */
++ int ser_addr;
++};
++
++static int dvp_order = 0;
++module_param(dvp_order, int, 0644);
++MODULE_PARM_DESC(dvp_order, " DVP bus bits order");
++
++static inline struct ov10635_priv *to_ov10635(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ov10635_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ov10635_priv, hdl)->sd;
++}
++
++static int ov10635_set_regs(struct i2c_client *client,
++ const struct ov10635_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (reg16_write(client, regs[i].reg, regs[i].val)) {
++ usleep_range(100, 150); /* wait 100ns */
++ if (reg16_write(client, regs[i].reg, regs[i].val))
++ printk("ov10635 reg 0x%04x write failed\n", regs[i].reg);
++ }
++ }
++
++ return 0;
++}
++
++static void ov10635_otp_id_read(struct i2c_client *client)
++{
++ struct ov10635_priv *priv = to_ov10635(client);
++ int i;
++
++ /* read camera id from OTP memory */
++ reg16_write(client, 0x3d10, 1);
++
++ usleep_range(15000, 16000); /* wait 15ms */
++
++ for (i = 0; i < 6; i++)
++ reg16_read(client, 0x3d00 + i, &priv->id[i]);
++}
++
++static int ov10635_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ov10635_set_window(struct v4l2_subdev *sd, int subsampling)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++
++ /* disable clocks */
++ reg16_write(client, 0x302e, 0x00);
++ reg16_write(client, 0x301b, 0xff);
++ reg16_write(client, 0x301c, 0xff);
++ reg16_write(client, 0x301a, 0xff);
++
++ /* setup resolution */
++ reg16_write(client, 0x3808, priv->rect.width >> 8);
++ reg16_write(client, 0x3809, priv->rect.width & 0xff);
++ reg16_write(client, 0x380a, priv->rect.height >> 8);
++ reg16_write(client, 0x380b, priv->rect.height & 0xff);
++
++ /* enable/disable subsampling */
++ reg16_write(client, 0x5005, subsampling ? 0x89 : 0x08);
++ reg16_write(client, 0x3007, subsampling ? 0x02 : 0x01);
++ reg16_write(client, 0x4004, subsampling ? 0x02 : 0x04);
++
++#if 0 /* This is implemented in VIN via SOC_CAMERA layer, hence skip */
++ /* horiz crop start */
++ reg16_write(client, 0x3800, priv->rect.left >> 8);
++ reg16_write(client, 0x3801, priv->rect.left & 0xff);
++ /* horiz crop end */
++ reg16_write(client, 0x3804, (priv->rect.left + priv->rect.width + 1) >> 8);
++ reg16_write(client, 0x3805, (priv->rect.left + priv->rect.width + 1) & 0xff);
++ /* vert crop start */
++ reg16_write(client, 0x3802, priv->rect.top >> 8);
++ reg16_write(client, 0x3803, priv->rect.top & 0xff);
++ /* vert crop end */
++ reg16_write(client, 0x3806, (priv->rect.top + priv->rect.height + 1) >> 8);
++ reg16_write(client, 0x3807, (priv->rect.top + priv->rect.height + 1) & 0xff);
++#endif
++ /* enable clocks */
++ reg16_write(client, 0x301b, 0xf0);
++ reg16_write(client, 0x301c, 0xf0);
++ reg16_write(client, 0x301a, 0xf0);
++ reg16_write(client, 0x302e, 0x01);
++
++ return 0;
++};
++
++static int ov10635_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ov10635_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ov10635_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = MEDIA_BUS_FMT_YUYV8_2X8;
++
++ return 0;
++}
++
++static int ov10635_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = OV10635_PID >> 8;
++ edid->edid[9] = OV10635_PID & 0xff;
++
++ return 0;
++}
++
++static int ov10635_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++ int subsampling = 0;
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > OV10635_MAX_WIDTH) ||
++ (rect->top + rect->height > OV10635_MAX_HEIGHT))
++ *rect = priv->rect;
++
++ if (rect->width == OV10635_MAX_WIDTH / 2 &&
++ rect->height == OV10635_MAX_HEIGHT / 2)
++ subsampling = 1;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ /* change window only for subsampling, crop is done by VIN */
++ if (subsampling != priv->subsampling) {
++ ov10635_set_window(sd, subsampling);
++ priv->subsampling = subsampling;
++ }
++
++ return 0;
++}
++
++static int ov10635_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OV10635_MAX_WIDTH;
++ sel->r.height = OV10635_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OV10635_MAX_WIDTH;
++ sel->r.height = OV10635_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ov10635_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++static int ov10635_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = 1;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int ov10635_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator) {
++ switch (cp->timeperframe.denominator) {
++ case 5:
++ ret = ov10635_set_regs(client, ov10635_regs_5fps,
++ ARRAY_SIZE(ov10635_regs_5fps));
++ break;
++ case 10:
++ ret = ov10635_set_regs(client, ov10635_regs_10fps,
++ ARRAY_SIZE(ov10635_regs_10fps));
++ break;
++ case 15:
++ ret = ov10635_set_regs(client, ov10635_regs_15fps,
++ ARRAY_SIZE(ov10635_regs_15fps));
++ break;
++ case 30:
++ ret = ov10635_set_regs(client, ov10635_regs_30fps,
++ ARRAY_SIZE(ov10635_regs_30fps));
++ break;
++ default:
++ ret = -EINVAL;
++ goto out;
++ }
++
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++out:
++ return ret;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ov10635_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ __be64 be_val;
++
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
++
++ return ret;
++}
++
++static int ov10635_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
++
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
++}
++#endif
++
++static struct v4l2_subdev_core_ops ov10635_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ov10635_g_register,
++ .s_register = ov10635_s_register,
++#endif
++};
++
++static int ov10635_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++ int ret = -EINVAL;
++ u8 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ /* AEC/AGC target */
++ ret = reg16_write(client, 0xc46a, ctrl->val);
++ break;
++ case V4L2_CID_CONTRAST:
++ udelay(100);
++ ret = ov10635_set_regs(client, &ov10635_regs_contrast[ctrl->val][0], 18);
++ break;
++ case V4L2_CID_SATURATION:
++ ret = reg16_write(client, 0xc316, ctrl->val);
++ break;
++ case V4L2_CID_HUE:
++ /* CMX ? */
++ ret = 0;
++ break;
++ case V4L2_CID_GAMMA:
++ ret = reg16_write(client, 0xc4be, ctrl->val >> 8);
++ ret |= reg16_write(client, 0xc4bf, ctrl->val & 0xff);
++ break;
++ case V4L2_CID_AUTOGAIN:
++ /* automatic gain/exposure */
++ ret = reg16_write(client, 0x56d0, !ctrl->val);
++ break;
++ case V4L2_CID_GAIN:
++ /* manual gain */
++ ret = reg16_write(client, 0x3504, 0);
++ ret |= reg16_write(client, 0x56d1, ctrl->val >> 8);
++ ret |= reg16_write(client, 0x56d2, ctrl->val & 0xff);
++ ret |= reg16_write(client, 0x3504, 1); /* validate gain */
++ break;
++ case V4L2_CID_EXPOSURE:
++ /* manual exposure */
++ ret = reg16_write(client, 0x3504, 0);
++ ret |= reg16_write(client, 0x56d5, ctrl->val >> 8);
++ ret |= reg16_write(client, 0x56d6, ctrl->val & 0xff);
++ ret |= reg16_write(client, 0x3504, 1); /* validate exposure */
++ break;
++ case V4L2_CID_HFLIP:
++ ret = reg16_read(client, 0x381d, &val);
++ if (ctrl->val)
++ val |= 0x3;
++ else
++ val &= ~0x3;
++ ret |= reg16_write(client, 0x381d, val);
++ break;
++ case V4L2_CID_VFLIP:
++ ret = reg16_read(client, 0x381c, &val);
++ if (ctrl->val)
++ val |= 0xc0;
++ else
++ val &= ~0xc0;
++ ret |= reg16_write(client, 0x381c, val);
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ov10635_ctrl_ops = {
++ .s_ctrl = ov10635_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ov10635_video_ops = {
++ .s_stream = ov10635_s_stream,
++ .g_mbus_config = ov10635_g_mbus_config,
++ .g_parm = ov10635_g_parm,
++ .s_parm = ov10635_s_parm,
++};
++
++static const struct v4l2_subdev_pad_ops ov10635_subdev_pad_ops = {
++ .get_edid = ov10635_get_edid,
++ .enum_mbus_code = ov10635_enum_mbus_code,
++ .get_selection = ov10635_get_selection,
++ .set_selection = ov10635_set_selection,
++ .get_fmt = ov10635_get_fmt,
++ .set_fmt = ov10635_set_fmt,
++};
++
++static struct v4l2_subdev_ops ov10635_subdev_ops = {
++ .core = &ov10635_core_ops,
++ .video = &ov10635_video_ops,
++ .pad = &ov10635_subdev_pad_ops,
++};
++
++static ssize_t ov10635_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov10635_priv *priv = to_ov10635(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ov10635, S_IRUGO, ov10635_otp_id_show, NULL);
++
++static int ov10635_initialize(struct i2c_client *client)
++{
++ struct ov10635_priv *priv = to_ov10635(client);
++ u8 val = 0;
++ u16 pid = 0;
++
++ setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR, MODE_GMSL1);
++ udelay(100);
++
++ reg16_read(client, OV10635_PID_REGA, &val);
++ pid = val;
++ reg16_read(client, OV10635_PID_REGB, &val);
++ pid = (pid << 8) | val;
++
++ if (pid != OV10635_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ /* s/w reset sensor */
++ reg16_write(client, 0x103, 0x1);
++ udelay(100);
++ /* Program wizard registers */
++ ov10635_set_regs(client, ov10635_regs_wizard, ARRAY_SIZE(ov10635_regs_wizard));
++ /* Set DVP bit swap */
++ reg16_write(client, 0x4709, priv->dvp_order << 4);
++ /* Read OTP IDs */
++ ov10635_otp_id_read(client);
++
++ dev_info(&client->dev, "ov10635 PID %x, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id ov10635_id[] = {
++ { "ov10635", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ov10635_id);
++
++static const struct of_device_id ov10635_of_ids[] = {
++ { .compatible = "ovti,ov10635", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ov10635_of_ids);
++
++static int ov10635_parse_dt(struct device_node *np, struct ov10635_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ if (of_property_read_u32(np, "dvp-order", &priv->dvp_order))
++ priv->dvp_order = 0;
++
++ /* module params override dts */
++ if (dvp_order)
++ priv->dvp_order = dvp_order;
++
++ return 0;
++}
++
++static int ov10635_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ov10635_priv *priv;
++ struct v4l2_ctrl *ctrl;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ov10635_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = OV10635_MAX_WIDTH;
++ priv->rect.height = OV10635_MAX_HEIGHT;
++ priv->fps_denominator = 30;
++
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 4, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_HUE, 0, 255, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0x3ff, 1, 0x10);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x80);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ov10635_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ov10635_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10635) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ov10635_remove(struct i2c_client *client)
++{
++ struct ov10635_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ov10635);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ov10635_i2c_driver = {
++ .driver = {
++ .name = "ov10635",
++ .of_match_table = ov10635_of_ids,
++ },
++ .probe = ov10635_probe,
++ .remove = ov10635_remove,
++ .id_table = ov10635_id,
++};
++
++module_i2c_driver(ov10635_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for OV10635");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.h b/drivers/media/i2c/soc_camera/imagers/ov10635.h
+new file mode 100644
+index 0000000..38b4256
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.h
+@@ -0,0 +1,1143 @@
++/*
++ * OmniVision ov10635 sensor camera wizard 1280x800@30/UYVY/BT601/8bit
++ *
++ * Copyright (C) 2015-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define OV10635_DISPLAY_PATTERN
++
++#define OV10635_SENSOR_WIDTH 1312
++#define OV10635_SENSOR_HEIGHT 814
++
++#define OV10635_MAX_WIDTH 1280
++#define OV10635_MAX_HEIGHT 800
++
++#define OV10635_PCLK_96MHZ
++//#define OV10635_PCLK_88MHZ
++
++#if defined(OV10635_PCLK_96MHZ)
++/* VTS=PCLK/FPS/HTS/2 (=96MHz/30/1750/2) */
++ #define OV10635_HTS 1750
++ #define OV10635_VTS 914 /* fps=30 */
++#elif defined(OV10635_PCLK_88MHZ)
++/* VTS=PCLK/FPS/HTS/2 (=88MHz/1572/30/2) */
++ #define OV10635_HTS 1572
++ #define OV10635_VTS 933 /* fps=29.9998 */
++#else
++ #error PCLK not defined
++#endif
++
++struct ov10635_reg {
++ u16 reg;
++ u8 val;
++};
++
++static const struct ov10635_reg ov10635_regs_wizard[] = {
++//{0x0103, 0x01},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x300C, 0x61},
++{0x301B, 0xFF},
++{0x301C, 0xFF},
++{0x301A, 0xFF},
++{0x3011, 0x42},
++{0x6900, 0x0C},
++{0x6901, 0x19},
++{0x3503, 0x10},
++{0x3025, 0x03},
++#if defined(OV10635_PCLK_96MHZ)
++{0x3003, 0x20},
++{0x3004, 0x21},
++#elif defined(OV10635_PCLK_88MHZ)
++{0x3003, 0x16},
++{0x3004, 0x30},
++#endif
++{0x3005, 0x40},
++{0x3006, 0x91},
++{0x3600, 0x74},
++{0x3601, 0x2B},
++{0x3612, 0x00},
++{0x3611, 0x67},
++{0x3633, 0xCA},
++{0x3602, 0xAF},
++{0x3603, 0x04},
++{0x3630, 0x28},
++{0x3631, 0x16},
++{0x3714, 0x10},
++{0x371D, 0x01},
++{0x4300, 0x3A},
++{0x3007, 0x01},
++{0x3024, 0x03},
++{0x3020, 0x0A},
++{0x3702, 0x0D},
++{0x3703, 0x20},
++{0x3704, 0x15},
++{0x3709, 0xA8},
++{0x370C, 0xC7},
++{0x370D, 0x80},
++{0x3712, 0x00},
++{0x3713, 0x20},
++{0x3715, 0x04},
++{0x381D, 0x40},
++{0x381C, 0x00},
++{0x3822, 0x50},
++{0x3824, 0x10},
++{0x3815, 0x8C},
++{0x3804, 0x05},
++{0x3805, 0x1F},
++{0x3800, 0x00},
++{0x3801, 0x00},
++{0x3806, 0x03},
++{0x3807, 0x28},
++{0x3802, 0x00},
++{0x3803, 0x07},
++{0x3808, 0x05},
++{0x3809, 0x00},
++{0x380A, 0x03},
++{0x380B, 0x20},
++{0x380C, OV10635_HTS >> 8},
++{0x380D, OV10635_HTS & 0xff},
++{0x380E, OV10635_VTS >> 8},
++{0x380F, OV10635_VTS & 0xff},
++{0x3813, 0x02},
++{0x3811, 0x08},
++{0x381F, 0x0C},
++{0x3819, 0x04},
++{0x3804, 0x01},
++{0x3805, 0x00},
++{0x3828, 0x03},
++{0x3829, 0x10},
++{0x382A, 0x10},
++{0x3621, 0x63},
++{0x5005, 0x08},
++{0x56D5, 0x00},
++{0x56D6, 0x80},
++{0x56D7, 0x00},
++{0x56D8, 0x00},
++{0x56D9, 0x00},
++{0x56DA, 0x80},
++{0x56DB, 0x00},
++{0x56DC, 0x00},
++{0x56E8, 0x00},
++{0x56E9, 0x7F},
++{0x56EA, 0x00},
++{0x56EB, 0x7F},
++{0x5100, 0x00},
++{0x5101, 0x80},
++{0x5102, 0x00},
++{0x5103, 0x80},
++{0x5104, 0x00},
++{0x5105, 0x80},
++{0x5106, 0x00},
++{0x5107, 0x80},
++{0x5108, 0x00},
++{0x5109, 0x00},
++{0x510A, 0x00},
++{0x510B, 0x00},
++{0x510C, 0x00},
++{0x510D, 0x00},
++{0x510E, 0x00},
++{0x510F, 0x00},
++{0x5110, 0x00},
++{0x5111, 0x80},
++{0x5112, 0x00},
++{0x5113, 0x80},
++{0x5114, 0x00},
++{0x5115, 0x80},
++{0x5116, 0x00},
++{0x5117, 0x80},
++{0x5118, 0x00},
++{0x5119, 0x00},
++{0x511A, 0x00},
++{0x511B, 0x00},
++{0x511C, 0x00},
++{0x511D, 0x00},
++{0x511E, 0x00},
++{0x511F, 0x00},
++{0x56D0, 0x00},
++{0x5006, 0x04},
++{0x5608, 0x05},
++{0x52D7, 0x06},
++{0x528D, 0x08},
++{0x5293, 0x12},
++{0x52D3, 0x12},
++{0x5288, 0x06},
++{0x5289, 0x20},
++{0x52C8, 0x06},
++{0x52C9, 0x20},
++{0x52CD, 0x04},
++{0x5381, 0x00},
++{0x5382, 0xFF},
++{0x5589, 0x76},
++{0x558A, 0x47},
++{0x558B, 0xEF},
++{0x558C, 0xC9},
++{0x558D, 0x49},
++{0x558E, 0x30},
++{0x558F, 0x67},
++{0x5590, 0x3F},
++{0x5591, 0xF0},
++{0x5592, 0x10},
++{0x55A2, 0x6D},
++{0x55A3, 0x55},
++{0x55A4, 0xC3},
++{0x55A5, 0xB5},
++{0x55A6, 0x43},
++{0x55A7, 0x38},
++{0x55A8, 0x5F},
++{0x55A9, 0x4B},
++{0x55AA, 0xF0},
++{0x55AB, 0x10},
++{0x5581, 0x52},
++{0x5300, 0x01},
++{0x5301, 0x00},
++{0x5302, 0x00},
++{0x5303, 0x0E},
++{0x5304, 0x00},
++{0x5305, 0x0E},
++{0x5306, 0x00},
++{0x5307, 0x36},
++{0x5308, 0x00},
++{0x5309, 0xD9},
++{0x530A, 0x00},
++{0x530B, 0x0F},
++{0x530C, 0x00},
++{0x530D, 0x2C},
++{0x530E, 0x00},
++{0x530F, 0x59},
++{0x5310, 0x00},
++{0x5311, 0x7B},
++{0x5312, 0x00},
++{0x5313, 0x22},
++{0x5314, 0x00},
++{0x5315, 0xD5},
++{0x5316, 0x00},
++{0x5317, 0x13},
++{0x5318, 0x00},
++{0x5319, 0x18},
++{0x531A, 0x00},
++{0x531B, 0x26},
++{0x531C, 0x00},
++{0x531D, 0xDC},
++{0x531E, 0x00},
++{0x531F, 0x02},
++{0x5320, 0x00},
++{0x5321, 0x24},
++{0x5322, 0x00},
++{0x5323, 0x56},
++{0x5324, 0x00},
++{0x5325, 0x85},
++{0x5326, 0x00},
++{0x5327, 0x20},
++{0x5609, 0x01},
++{0x560A, 0x40},
++{0x560B, 0x01},
++{0x560C, 0x40},
++{0x560D, 0x00},
++{0x560E, 0xFA},
++{0x560F, 0x00},
++{0x5610, 0xFA},
++{0x5611, 0x02},
++{0x5612, 0x80},
++{0x5613, 0x02},
++{0x5614, 0x80},
++{0x5615, 0x01},
++{0x5616, 0x2C},
++{0x5617, 0x01},
++{0x5618, 0x2C},
++{0x563B, 0x01},
++{0x563C, 0x01},
++{0x563D, 0x01},
++{0x563E, 0x01},
++{0x563F, 0x03},
++{0x5640, 0x03},
++{0x5641, 0x03},
++{0x5642, 0x05},
++{0x5643, 0x09},
++{0x5644, 0x05},
++{0x5645, 0x05},
++{0x5646, 0x05},
++{0x5647, 0x05},
++{0x5651, 0x00},
++{0x5652, 0x80},
++{0x521A, 0x01},
++{0x521B, 0x03},
++{0x521C, 0x06},
++{0x521D, 0x0A},
++{0x521E, 0x0E},
++{0x521F, 0x12},
++{0x5220, 0x16},
++{0x5223, 0x02},
++{0x5225, 0x04},
++{0x5227, 0x08},
++{0x5229, 0x0C},
++{0x522B, 0x12},
++{0x522D, 0x18},
++{0x522F, 0x1E},
++{0x5241, 0x04},
++{0x5242, 0x01},
++{0x5243, 0x03},
++{0x5244, 0x06},
++{0x5245, 0x0A},
++{0x5246, 0x0E},
++{0x5247, 0x12},
++{0x5248, 0x16},
++{0x524A, 0x03},
++{0x524C, 0x04},
++{0x524E, 0x08},
++{0x5250, 0x0C},
++{0x5252, 0x12},
++{0x5254, 0x18},
++{0x5256, 0x1E},
++{0x4606, (2*OV10635_HTS) >> 8}, /* fifo_line_length = 2*hts */
++{0x4607, (2*OV10635_HTS) & 0xff},
++{0x460a, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) >> 8}, /* fifo_hsync_start = 2*(hts - xres) */
++{0x460b, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) & 0xff },
++{0x460C, 0x00},
++{0x4620, 0x0E},
++#if 0
++{0x4700, 0x02}, // BT656: mode is acceptable but artefact lines on left/bottom due to BT656 SAV/EAV are parsed as image data
++#else
++{0x4700, 0x04}, // BT601: 0x08 is also accaptable as HS/VS mode
++#endif
++{0x4701, 0x00},
++{0x4702, 0x01},
++{0x4004, 0x04},
++{0x4005, 0x18},
++{0x4001, 0x06},
++{0x4050, 0x22},
++{0x4051, 0x24},
++{0x4052, 0x02},
++{0x4057, 0x9C},
++{0x405A, 0x00},
++{0x4202, 0x02},
++{0x3023, 0x10},
++{0x0100, 0x01},
++{0x0100, 0x01},
++{0x0100, 0x01},
++{0x0100, 0x01},
++{0x0100, 0x01},
++{0x0100, 0x01},
++{0x6F10, 0x07},
++{0x6F11, 0x82},
++{0x6F12, 0x04},
++{0x6F13, 0x00},
++{0xD000, 0x19},
++{0xD001, 0xA0},
++{0xD002, 0x00},
++{0xD003, 0x01},
++{0xD004, 0xA9},
++{0xD005, 0xAD},
++{0xD006, 0x10},
++{0xD007, 0x40},
++{0xD008, 0x44},
++{0xD009, 0x00},
++{0xD00A, 0x68},
++{0xD00B, 0x00},
++{0xD00C, 0x15},
++{0xD00D, 0x00},
++{0xD00E, 0x00},
++{0xD00F, 0x00},
++{0xD040, 0x9C},
++{0xD041, 0x21},
++{0xD042, 0xFF},
++{0xD043, 0xF8},
++{0xD044, 0xD4},
++{0xD045, 0x01},
++{0xD046, 0x48},
++{0xD047, 0x00},
++{0xD048, 0xD4},
++{0xD049, 0x01},
++{0xD04A, 0x50},
++{0xD04B, 0x04},
++{0xD04C, 0x18},
++{0xD04D, 0x60},
++{0xD04E, 0x00},
++{0xD04F, 0x01},
++{0xD050, 0xA8},
++{0xD051, 0x63},
++{0xD052, 0x02},
++{0xD053, 0xA4},
++{0xD054, 0x85},
++{0xD055, 0x43},
++{0xD056, 0x00},
++{0xD057, 0x00},
++{0xD058, 0x18},
++{0xD059, 0x60},
++{0xD05A, 0x00},
++{0xD05B, 0x01},
++{0xD05C, 0xA8},
++{0xD05D, 0x63},
++{0xD05E, 0x03},
++{0xD05F, 0xF0},
++{0xD060, 0x98},
++{0xD061, 0xA3},
++{0xD062, 0x00},
++{0xD063, 0x00},
++{0xD064, 0x8C},
++{0xD065, 0x6A},
++{0xD066, 0x00},
++{0xD067, 0x6E},
++{0xD068, 0xE5},
++{0xD069, 0x85},
++{0xD06A, 0x18},
++{0xD06B, 0x00},
++{0xD06C, 0x10},
++{0xD06D, 0x00},
++{0xD06E, 0x00},
++{0xD06F, 0x10},
++{0xD070, 0x9C},
++{0xD071, 0x80},
++{0xD072, 0x00},
++{0xD073, 0x03},
++{0xD074, 0x18},
++{0xD075, 0x60},
++{0xD076, 0x00},
++{0xD077, 0x01},
++{0xD078, 0xA8},
++{0xD079, 0x63},
++{0xD07A, 0x07},
++{0xD07B, 0x80},
++{0xD07C, 0x07},
++{0xD07D, 0xFF},
++{0xD07E, 0xF9},
++{0xD07F, 0x03},
++{0xD080, 0x8C},
++{0xD081, 0x63},
++{0xD082, 0x00},
++{0xD083, 0x00},
++{0xD084, 0xA5},
++{0xD085, 0x6B},
++{0xD086, 0x00},
++{0xD087, 0xFF},
++{0xD088, 0x18},
++{0xD089, 0x80},
++{0xD08A, 0x00},
++{0xD08B, 0x01},
++{0xD08C, 0xA8},
++{0xD08D, 0x84},
++{0xD08E, 0x01},
++{0xD08F, 0x04},
++{0xD090, 0xE1},
++{0xD091, 0x6B},
++{0xD092, 0x58},
++{0xD093, 0x00},
++{0xD094, 0x94},
++{0xD095, 0x6A},
++{0xD096, 0x00},
++{0xD097, 0x70},
++{0xD098, 0xE1},
++{0xD099, 0x6B},
++{0xD09A, 0x20},
++{0xD09B, 0x00},
++{0xD09C, 0x95},
++{0xD09D, 0x6B},
++{0xD09E, 0x00},
++{0xD09F, 0x00},
++{0xD0A0, 0xE4},
++{0xD0A1, 0x8B},
++{0xD0A2, 0x18},
++{0xD0A3, 0x00},
++{0xD0A4, 0x0C},
++{0xD0A5, 0x00},
++{0xD0A6, 0x00},
++{0xD0A7, 0x23},
++{0xD0A8, 0x15},
++{0xD0A9, 0x00},
++{0xD0AA, 0x00},
++{0xD0AB, 0x00},
++{0xD0AC, 0x18},
++{0xD0AD, 0x60},
++{0xD0AE, 0x80},
++{0xD0AF, 0x06},
++{0xD0B0, 0xA8},
++{0xD0B1, 0x83},
++{0xD0B2, 0x40},
++{0xD0B3, 0x08},
++{0xD0B4, 0xA8},
++{0xD0B5, 0xE3},
++{0xD0B6, 0x38},
++{0xD0B7, 0x2A},
++{0xD0B8, 0xA8},
++{0xD0B9, 0xC3},
++{0xD0BA, 0x40},
++{0xD0BB, 0x09},
++{0xD0BC, 0xA8},
++{0xD0BD, 0xA3},
++{0xD0BE, 0x38},
++{0xD0BF, 0x29},
++{0xD0C0, 0x8C},
++{0xD0C1, 0x65},
++{0xD0C2, 0x00},
++{0xD0C3, 0x00},
++{0xD0C4, 0xD8},
++{0xD0C5, 0x04},
++{0xD0C6, 0x18},
++{0xD0C7, 0x00},
++{0xD0C8, 0x8C},
++{0xD0C9, 0x67},
++{0xD0CA, 0x00},
++{0xD0CB, 0x00},
++{0xD0CC, 0xD8},
++{0xD0CD, 0x06},
++{0xD0CE, 0x18},
++{0xD0CF, 0x00},
++{0xD0D0, 0x18},
++{0xD0D1, 0x60},
++{0xD0D2, 0x80},
++{0xD0D3, 0x06},
++{0xD0D4, 0xA8},
++{0xD0D5, 0xE3},
++{0xD0D6, 0x67},
++{0xD0D7, 0x02},
++{0xD0D8, 0xA9},
++{0xD0D9, 0x03},
++{0xD0DA, 0x67},
++{0xD0DB, 0x03},
++{0xD0DC, 0xA8},
++{0xD0DD, 0xC3},
++{0xD0DE, 0x3D},
++{0xD0DF, 0x05},
++{0xD0E0, 0x8C},
++{0xD0E1, 0x66},
++{0xD0E2, 0x00},
++{0xD0E3, 0x00},
++{0xD0E4, 0xB8},
++{0xD0E5, 0x63},
++{0xD0E6, 0x00},
++{0xD0E7, 0x18},
++{0xD0E8, 0xB8},
++{0xD0E9, 0x63},
++{0xD0EA, 0x00},
++{0xD0EB, 0x98},
++{0xD0EC, 0xBC},
++{0xD0ED, 0x03},
++{0xD0EE, 0x00},
++{0xD0EF, 0x00},
++{0xD0F0, 0x10},
++{0xD0F1, 0x00},
++{0xD0F2, 0x00},
++{0xD0F3, 0x16},
++{0xD0F4, 0xB8},
++{0xD0F5, 0x83},
++{0xD0F6, 0x00},
++{0xD0F7, 0x19},
++{0xD0F8, 0x8C},
++{0xD0F9, 0x67},
++{0xD0FA, 0x00},
++{0xD0FB, 0x00},
++{0xD0FC, 0xB8},
++{0xD0FD, 0xA4},
++{0xD0FE, 0x00},
++{0xD0FF, 0x98},
++{0xD100, 0xB8},
++{0xD101, 0x83},
++{0xD102, 0x00},
++{0xD103, 0x08},
++{0xD104, 0x8C},
++{0xD105, 0x68},
++{0xD106, 0x00},
++{0xD107, 0x00},
++{0xD108, 0xE0},
++{0xD109, 0x63},
++{0xD10A, 0x20},
++{0xD10B, 0x04},
++{0xD10C, 0xE0},
++{0xD10D, 0x65},
++{0xD10E, 0x18},
++{0xD10F, 0x00},
++{0xD110, 0xA4},
++{0xD111, 0x83},
++{0xD112, 0xFF},
++{0xD113, 0xFF},
++{0xD114, 0xB8},
++{0xD115, 0x64},
++{0xD116, 0x00},
++{0xD117, 0x48},
++{0xD118, 0xD8},
++{0xD119, 0x07},
++{0xD11A, 0x18},
++{0xD11B, 0x00},
++{0xD11C, 0xD8},
++{0xD11D, 0x08},
++{0xD11E, 0x20},
++{0xD11F, 0x00},
++{0xD120, 0x9C},
++{0xD121, 0x60},
++{0xD122, 0x00},
++{0xD123, 0x00},
++{0xD124, 0xD8},
++{0xD125, 0x06},
++{0xD126, 0x18},
++{0xD127, 0x00},
++{0xD128, 0x00},
++{0xD129, 0x00},
++{0xD12A, 0x00},
++{0xD12B, 0x08},
++{0xD12C, 0x15},
++{0xD12D, 0x00},
++{0xD12E, 0x00},
++{0xD12F, 0x00},
++{0xD130, 0x8C},
++{0xD131, 0x6A},
++{0xD132, 0x00},
++{0xD133, 0x76},
++{0xD134, 0xBC},
++{0xD135, 0x23},
++{0xD136, 0x00},
++{0xD137, 0x00},
++{0xD138, 0x13},
++{0xD139, 0xFF},
++{0xD13A, 0xFF},
++{0xD13B, 0xE6},
++{0xD13C, 0x18},
++{0xD13D, 0x60},
++{0xD13E, 0x80},
++{0xD13F, 0x06},
++{0xD140, 0x03},
++{0xD141, 0xFF},
++{0xD142, 0xFF},
++{0xD143, 0xDD},
++{0xD144, 0xA8},
++{0xD145, 0x83},
++{0xD146, 0x40},
++{0xD147, 0x08},
++{0xD148, 0x85},
++{0xD149, 0x21},
++{0xD14A, 0x00},
++{0xD14B, 0x00},
++{0xD14C, 0x85},
++{0xD14D, 0x41},
++{0xD14E, 0x00},
++{0xD14F, 0x04},
++{0xD150, 0x44},
++{0xD151, 0x00},
++{0xD152, 0x48},
++{0xD153, 0x00},
++{0xD154, 0x9C},
++{0xD155, 0x21},
++{0xD156, 0x00},
++{0xD157, 0x08},
++{0x6F0E, 0x03},
++{0x6F0F, 0x00},
++{0x460E, 0x08},
++{0x460F, 0x01},
++{0x4610, 0x00},
++{0x4611, 0x01},
++{0x4612, 0x00},
++{0x4613, 0x01},
++{0x4605, 0x08}, // 8bit
++//{0x4709, 0x10}, // swap data bits order [9:0] -> [0:9]
++{0x4608, 0x00},
++{0x4609, 0x08},
++{0x6804, 0x00},
++{0x6805, 0x06},
++{0x6806, 0x00},
++{0x5120, 0x00},
++{0x3510, 0x00},
++{0x3504, 0x00},
++{0x6800, 0x00},
++{0x6F0D, 0x01},
++{0x4708, 0x03}, // PCLK rising edge
++{0x5000, 0xFF},
++{0x5001, 0xBF},
++{0x5002, 0x7E},
++#ifdef OV10635_DISPLAY_PATTERN
++{0x503d, 0x80},
++#else
++{0x503D, 0x00},
++#endif
++{0xC450, 0x01}, /* AA mode */
++{0xC452, 0x04},
++{0xC453, 0x00},
++{0xC454, 0x00},
++{0xC455, 0x01},
++{0xC456, 0x01},
++{0xC457, 0x00},
++{0xC458, 0x00},
++{0xC459, 0x00},
++{0xC45B, 0x00},
++{0xC45C, 0x01},
++{0xC45D, 0x00},
++{0xC45E, 0x00},
++{0xC45F, 0x00},
++{0xC460, 0x00},
++{0xC461, 0x01},
++{0xC462, 0x01},
++{0xC464, 0x03},
++{0xC465, 0x00},
++{0xC466, 0x8A},
++{0xC467, 0x00},
++{0xC468, 0x86},
++{0xC469, 0x00},
++{0xC46A, 0x30},
++{0xC46B, 0x50},
++{0xC46C, 0x30},
++{0xC46D, 0x28},
++{0xC46E, 0x60},
++{0xC46F, 0x40},
++{0xC47C, 0x01},
++{0xC47D, 0x38},
++{0xC47E, 0x00},
++{0xC47F, 0x00},
++{0xC480, 0x00},
++{0xC481, 0xFF},
++{0xC482, 0x00},
++{0xC483, 0x40},
++{0xC484, 0x00},
++{0xC485, 0x18},
++{0xC486, 0x00},
++{0xC487, 0x18},
++{0xC488, (OV10635_VTS-8)*16 >> 8},
++{0xC489, (OV10635_VTS-8)*16 & 0xff},
++{0xC48A, (OV10635_VTS-8)*16 >> 8},
++{0xC48B, (OV10635_VTS-8)*16 & 0xff},
++{0xC48C, 0x00},
++{0xC48D, 0x04},
++{0xC48E, 0x00},
++{0xC48F, 0x04},
++{0xC490, 0x03},
++{0xC492, 0x20},
++{0xC493, 0x08},
++{0xC498, 0x02},
++{0xC499, 0x00},
++{0xC49A, 0x02},
++{0xC49B, 0x00},
++{0xC49C, 0x02},
++{0xC49D, 0x00},
++{0xC49E, 0x02},
++{0xC49F, 0x60},
++{0xC4A0, 0x03},
++{0xC4A1, 0x00},
++{0xC4A2, 0x04},
++{0xC4A3, 0x00},
++{0xC4A4, 0x00},
++{0xC4A5, 0x10},
++{0xC4A6, 0x00},
++{0xC4A7, 0x40},
++{0xC4A8, 0x00},
++{0xC4A9, 0x80},
++{0xC4AA, 0x0D},
++{0xC4AB, 0x00},
++{0xC4AC, 0x0F},
++{0xC4AD, 0xC0},
++{0xC4B4, 0x01},
++{0xC4B5, 0x01},
++{0xC4B6, 0x00},
++{0xC4B7, 0x01},
++{0xC4B8, 0x00},
++{0xC4B9, 0x01},
++{0xC4BA, 0x01},
++{0xC4BB, 0x00},
++{0xC4BC, 0x01},
++{0xC4BD, 0x60},
++{0xC4BE, 0x02},
++{0xC4BF, 0x33},
++{0xC4C8, 0x03},
++{0xC4C9, 0xD0},
++{0xC4CA, 0x0E},
++{0xC4CB, 0x00},
++{0xC4CC, 0x0E},
++{0xC4CD, 0x51},
++{0xC4CE, 0x0E},
++{0xC4CF, 0x51},
++{0xC4D0, 0x04},
++{0xC4D1, 0x80},
++{0xC4E0, 0x04},
++{0xC4E1, 0x02},
++{0xC4E2, 0x01},
++{0xC4E4, 0x10},
++{0xC4E5, 0x20},
++{0xC4E6, 0x30},
++{0xC4E7, 0x40},
++{0xC4E8, 0x50},
++{0xC4E9, 0x60},
++{0xC4EA, 0x70},
++{0xC4EB, 0x80},
++{0xC4EC, 0x90},
++{0xC4ED, 0xA0},
++{0xC4EE, 0xB0},
++{0xC4EF, 0xC0},
++{0xC4F0, 0xD0},
++{0xC4F1, 0xE0},
++{0xC4F2, 0xF0},
++{0xC4F3, 0x80},
++{0xC4F4, 0x00},
++{0xC4F5, 0x20},
++{0xC4F6, 0x02},
++{0xC4F7, 0x00},
++{0xC4F8, 0x00},
++{0xC4F9, 0x00},
++{0xC4FA, 0x00},
++{0xC4FB, 0x01},
++{0xC4FC, 0x01},
++{0xC4FD, 0x00},
++{0xC4FE, 0x04},
++{0xC4FF, 0x02},
++{0xC500, 0x48},
++{0xC501, 0x74},
++{0xC502, 0x58},
++{0xC503, 0x80},
++{0xC504, 0x05},
++{0xC505, 0x80},
++{0xC506, 0x03},
++{0xC507, 0x80},
++{0xC508, 0x01},
++{0xC509, 0xC0},
++{0xC50A, 0x01},
++{0xC50B, 0xA0},
++{0xC50C, 0x01},
++{0xC50D, 0x2C},
++{0xC50E, 0x01},
++{0xC50F, 0x0A},
++{0xC510, 0x00},
++{0xC511, 0x00},
++{0xC512, 0xE5},
++{0xC513, 0x14},
++{0xC514, 0x04},
++{0xC515, 0x00},
++{0xC518, OV10635_VTS >> 8},
++{0xC519, OV10635_VTS & 0xff},
++{0xC51A, OV10635_HTS >> 8},
++{0xC51B, OV10635_HTS & 0xff},
++{0xC2E0, 0x00},
++{0xC2E1, 0x51},
++{0xC2E2, 0x00},
++{0xC2E3, 0xD6},
++{0xC2E4, 0x01},
++{0xC2E5, 0x5E},
++{0xC2E9, 0x01},
++{0xC2EA, 0x7A},
++{0xC2EB, 0x90},
++{0xC2ED, 0x00},
++{0xC2EE, 0x7A},
++{0xC2EF, 0x64},
++{0xC308, 0x00},
++{0xC309, 0x00},
++{0xC30A, 0x00},
++{0xC30C, 0x00},
++{0xC30D, 0x01},
++{0xC30E, 0x00},
++{0xC30F, 0x00},
++{0xC310, 0x01},
++{0xC311, 0x60},
++{0xC312, 0xFF},
++{0xC313, 0x08},
++{0xC314, 0x01},
++{0xC315, 0x00}, /* min saturation gain */
++{0xC316, 0xFF}, /* max saturation gain */
++{0xC317, 0x0B},
++{0xC318, 0x00},
++{0xC319, 0x0C},
++{0xC31A, 0x00},
++{0xC31B, 0xE0},
++{0xC31C, 0x00},
++{0xC31D, 0x14},
++{0xC31E, 0x00},
++{0xC31F, 0xC5},
++{0xC320, 0xFF},
++{0xC321, 0x4B},
++{0xC322, 0xFF},
++{0xC323, 0xF0},
++{0xC324, 0xFF},
++{0xC325, 0xE8},
++{0xC326, 0x00},
++{0xC327, 0x46},
++{0xC328, 0xFF},
++{0xC329, 0xD2},
++{0xC32A, 0xFF},
++{0xC32B, 0xE4},
++{0xC32C, 0xFF},
++{0xC32D, 0xBB},
++{0xC32E, 0x00},
++{0xC32F, 0x61},
++{0xC330, 0xFF},
++{0xC331, 0xF9},
++{0xC332, 0x00},
++{0xC333, 0xD9},
++{0xC334, 0x00},
++{0xC335, 0x2E},
++{0xC336, 0x00},
++{0xC337, 0xB1},
++{0xC338, 0xFF},
++{0xC339, 0x64},
++{0xC33A, 0xFF},
++{0xC33B, 0xEB},
++{0xC33C, 0xFF},
++{0xC33D, 0xE8},
++{0xC33E, 0x00},
++{0xC33F, 0x48},
++{0xC340, 0xFF},
++{0xC341, 0xD0},
++{0xC342, 0xFF},
++{0xC343, 0xED},
++{0xC344, 0xFF},
++{0xC345, 0xAD},
++{0xC346, 0x00},
++{0xC347, 0x66},
++{0xC348, 0x01},
++{0xC349, 0x00},
++{0x6700, 0x04},
++{0x6701, 0x7B},
++{0x6702, 0xFD},
++{0x6703, 0xF9},
++{0x6704, 0x3D},
++{0x6705, 0x71},
++{0x6706, 0x78},
++{0x6708, 0x05},
++{0x6F06, 0x6F},
++{0x6F07, 0x00},
++{0x6F0A, 0x6F},
++{0x6F0B, 0x00},
++{0x6F00, 0x03},
++{0xC34C, 0x01},
++{0xC34D, 0x00},
++{0xC34E, 0x46},
++{0xC34F, 0x55},
++{0xC350, 0x00},
++{0xC351, 0x40},
++{0xC352, 0x00},
++{0xC353, 0xFF},
++{0xC354, 0x04},
++{0xC355, 0x08},
++{0xC356, 0x01},
++{0xC357, 0xEF},
++{0xC358, 0x30},
++{0xC359, 0x01},
++{0xC35A, 0x64},
++{0xC35B, 0x46},
++{0xC35C, 0x00},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0x3042, 0xF0},
++{0xC261, 0x01},
++{0x301B, 0xF0},
++{0x301C, 0xF0},
++{0x301A, 0xF0},
++{0x6F00, 0xC3},
++{0xC46A, 0x30},
++{0xC46D, 0x20},
++{0xC464, 0x84},
++{0xC465, 0x00},
++{0x6F00, 0x03},
++{0x6F00, 0x43},
++{0x381C, 0x00},
++{0x381D, 0x40},
++{0xC454, 0x01},
++{0x6F00, 0xC3},
++{0xC454, 0x00},
++{0xC4B1, 0x02},
++{0xC4B2, 0x01},
++{0xC4B3, 0x03},
++{0x6F00, 0x03},
++{0x6F00, 0x43},
++/* enable FSIN (FRAMESYNC input) functionality */
++{0x3832, (0x0d+2*0x20+0x15+38) >> 8},
++{0x3833, (0x0d+2*0x20+0x15+38) & 0xff},
++{0x3834, OV10635_VTS >> 8},
++{0x3835, OV10635_VTS & 0xff},
++{0x302E, 0x01},
++};
++
++static const struct ov10635_reg ov10635_regs_30fps[] = {
++/* disable clocks */
++{0x301b, 0xff},
++{0x301c, 0xff},
++{0x301a, 0xff},
++/* clk = 24Mhz/2*32/2(1+1)=96Mhz, 30fps */
++{0x3003, 0x20},
++{0x3004, 0x21},
++/* enable clocks */
++{0x301b, 0xf0},
++{0x301c, 0xf0},
++{0x301a, 0xf0},
++};
++
++static const struct ov10635_reg ov10635_regs_15fps[] = {
++/* disable clocks */
++{0x301b, 0xff},
++{0x301c, 0xff},
++{0x301a, 0xff},
++/* clk = 24Mhz/2*32/2(1+3)=48Mhz, 15fps */
++{0x3003, 0x20},
++{0x3004, 0x23},
++/* enable clocks */
++{0x301b, 0xf0},
++{0x301c, 0xf0},
++{0x301a, 0xf0},
++};
++
++static const struct ov10635_reg ov10635_regs_10fps[] = {
++/* disable clocks */
++{0x301b, 0xff},
++{0x301c, 0xff},
++{0x301a, 0xff},
++/* clk = 24Mhz/2*32/2(1+5)=32Mhz, 10fps */
++{0x3003, 0x20},
++{0x3004, 0x25},
++/* enable clocks */
++{0x301b, 0xf0},
++{0x301c, 0xf0},
++{0x301a, 0xf0},
++};
++
++static const struct ov10635_reg ov10635_regs_5fps[] = {
++/* disable clocks */
++{0x301b, 0xff},
++{0x301c, 0xff},
++{0x301a, 0xff},
++/* clk = 24Mhz/4*32/2(1+5)=96Mhz, 5fps */
++{0x3003, 0x20},
++{0x3004, 0x45},
++/* enable clocks */
++{0x301b, 0xf0},
++{0x301c, 0xf0},
++{0x301a, 0xf0},
++};
++
++static const struct ov10635_reg ov10635_regs_contrast[5][18] = {
++{
++ {0x6f00, 0xc3},
++ {0xc4e4, 0x20},
++ {0xc4e5, 0x40},
++ {0xc4e6, 0x60},
++ {0xc4e7, 0x80},
++ {0xc4e8, 0xa0},
++ {0xc4e9, 0xb4},
++ {0xc4ea, 0xc0},
++ {0xc4eb, 0xcb},
++ {0xc4ec, 0xd5},
++ {0xc4ed, 0xde},
++ {0xc4ee, 0xe6},
++ {0xc4ef, 0xed},
++ {0xc4f0, 0xf3},
++ {0xc4f1, 0xf8},
++ {0xc4f2, 0xfc},
++ {0x6f00, 0x03},
++ {0x6f00, 0x43},
++}, {
++ {0x6f00, 0xc3},
++ {0xc4e4, 0x18},
++ {0xc4e5, 0x30},
++ {0xc4e6, 0x48},
++ {0xc4e7, 0x60},
++ {0xc4e8, 0x78},
++ {0xc4e9, 0x90},
++ {0xc4ea, 0xa4},
++ {0xc4eb, 0xb4},
++ {0xc4ec, 0xc2},
++ {0xc4ed, 0xcf},
++ {0xc4ee, 0xdb},
++ {0xc4ef, 0xe5},
++ {0xc4f0, 0xee},
++ {0xc4f1, 0xf6},
++ {0xc4f2, 0xfc},
++ {0x6f00, 0x03},
++ {0x6f00, 0x43},
++}, {
++ {0x6f00, 0xc3},
++ {0xc4e4, 0x10},
++ {0xc4e5, 0x20},
++ {0xc4e6, 0x30},
++ {0xc4e7, 0x40},
++ {0xc4e8, 0x50},
++ {0xc4e9, 0x60},
++ {0xc4ea, 0x70},
++ {0xc4eb, 0x80},
++ {0xc4ec, 0x90},
++ {0xc4ed, 0xa0},
++ {0xc4ee, 0xb0},
++ {0xc4ef, 0xc0},
++ {0xc4f0, 0xd0},
++ {0xc4f1, 0xe0},
++ {0xc4f2, 0xf0},
++ {0x6f00, 0x03},
++ {0x6f00, 0x43},
++}, {
++ {0x6f00, 0xc3},
++ {0xc4e4, 0x0c},
++ {0xc4e5, 0x18},
++ {0xc4e6, 0x24},
++ {0xc4e7, 0x30},
++ {0xc4e8, 0x3c},
++ {0xc4e9, 0x48},
++ {0xc4ea, 0x54},
++ {0xc4eb, 0x62},
++ {0xc4ec, 0x72},
++ {0xc4ed, 0x84},
++ {0xc4ee, 0x94},
++ {0xc4ef, 0xa6},
++ {0xc4f0, 0xb9},
++ {0xc4f1, 0xcd},
++ {0xc4f2, 0xe2},
++ {0x6f00, 0x03},
++ {0x6f00, 0x43},
++}, {
++ {0x6f00, 0xc3},
++ {0xc4e4, 0x06},
++ {0xc4e5, 0x0d},
++ {0xc4e6, 0x15},
++ {0xc4e7, 0x1e},
++ {0xc4e8, 0x28},
++ {0xc4e9, 0x32},
++ {0xc4ea, 0x3c},
++ {0xc4eb, 0x48},
++ {0xc4ec, 0x56},
++ {0xc4ed, 0x66},
++ {0xc4ee, 0x78},
++ {0xc4ef, 0x8c},
++ {0xc4f0, 0xa2},
++ {0xc4f1, 0xba},
++ {0xc4f2, 0xd4},
++ {0x6f00, 0x03},
++ {0x6f00, 0x43},
++}
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h b/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h
+new file mode 100644
+index 0000000..4c3515a
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov10635_debug.h
+@@ -0,0 +1,54 @@
++
++#if 0
++{0x4700, 0x02}, // BT656
++{0x381d, 0x40}, // mirror off
++{0x381c, 0x00}, // flip off
++{0x4300, 0x3a}, // YUV: UYVY
++{0x4708, 0x00}, // PCLK rising edge
++
++// clk = 24Mhz/3*22/2= 88Mhz
++{0x3003, 0x16},
++{0x3004, 0x30},
++#endif
++
++#define WIDTH 1280
++#define HEIGHT 720
++
++// DVP frame size
++{0x3808, WIDTH >> 8},
++{0x3809, WIDTH & 0xff},
++{0x380a, HEIGHT >> 8},
++{0x380b, HEIGHT & 0xff},
++
++{0x3802, ((814 - HEIGHT)/2) >> 8}, // vert crop start
++{0x3803, ((814 - HEIGHT)/2) & 0xff},
++{0x3806, ((814 - HEIGHT)/2 + HEIGHT + 1) >> 8}, // vert crop end
++{0x3807, ((814 - HEIGHT)/2 + HEIGHT + 1) & 0xff},
++
++#if 0
++#define HTS 0x6f6 // got from above table 1782
++#define VTS (0x2ec+80) // got from above table 748 + 80
++
++{0x380c, HTS >> 8}, // hts
++{0x380d, HTS & 0xff},
++{0x380e, VTS >> 8}, // vts
++{0x380f, VTS & 0xff},
++
++// fifo
++{0x4606, (2*HTS) >> 8}, // fifo_line_length = 2*hts
++{0x4607, (2*HTS) & 0xff},
++{0x460a, (2*(HTS-1280)) >> 8}, // fifo_hsync_start = 2*(hts - xres)
++{0x460b, (2*(HTS-1280)) & 0xff },
++
++// exposure
++{0xC488, (VTS-8)*16 >> 8},
++{0xC489, (VTS-8)*16 & 0xff},
++{0xC48A, (VTS-8)*16 >> 8},
++{0xC48B, (VTS-8)*16 & 0xff},
++
++// vts/hts
++{0xC518, VTS >> 8},
++{0xC519, VTS & 0xff},
++{0xC51A, HTS >> 8},
++{0xC51B, HTS & 0xff},
++#endif
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+new file mode 100644
+index 0000000..ce4999b
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+@@ -0,0 +1,571 @@
++/*
++ * OmniVision ov2311 sensor camera driver
++ *
++ * Copyright (C) 2015-2019 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "ov2311.h"
++
++#define OV2311_I2C_ADDR 0x60
++
++#define OV2311_PID_REGA 0x300a
++#define OV2311_PID_REGB 0x300b
++#define OV2311_REV_REG 0x300c
++#define OV2311_PID 0x2311
++
++#define OV2311_MEDIA_BUS_FMT MEDIA_BUS_FMT_Y8_1X8
++
++struct ov2311_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int subsampling;
++ int fps_denominator;
++ int init_complete;
++ u8 id[6];
++ int dvp_order;
++ /* serializers */
++ int ser_addr;
++};
++
++static inline struct ov2311_priv *to_ov2311(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ov2311_priv, sd);
++}
++
++static inline struct v4l2_subdev *ov2311_to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ov2311_priv, hdl)->sd;
++}
++
++static int ov2311_set_regs(struct i2c_client *client,
++ const struct ov2311_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == OV2311_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ if (reg16_write(client, regs[i].reg, regs[i].val)) {
++ usleep_range(100, 150); /* wait 100ns */
++ reg16_write(client, regs[i].reg, regs[i].val);
++ }
++ }
++
++ return 0;
++}
++
++static void ov2311_otp_id_read(struct i2c_client *client)
++{
++ struct ov2311_priv *priv = to_ov2311(client);
++ int i;
++
++ reg16_write(client, 0x3d81, 1);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i++) {
++ /* first 6 bytes are equal on all ov2311 */
++ reg16_read(client, 0x7000 + i + 6, &priv->id[i]);
++ }
++}
++
++static int ov2311_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ov2311_set_window(struct v4l2_subdev *sd)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height);
++#if 0
++ /* setup resolution */
++ reg16_write(client, 0x3808, priv->rect.width >> 8);
++ reg16_write(client, 0x3809, priv->rect.width & 0xff);
++ reg16_write(client, 0x380a, priv->rect.height >> 8);
++ reg16_write(client, 0x380b, priv->rect.height & 0xff);
++
++ /* horiz isp windowstart */
++ reg16_write(client, 0x3810, priv->rect.left >> 8);
++ reg16_write(client, 0x3811, priv->rect.left & 0xff);
++ reg16_write(client, 0x3812, priv->rect.top >> 8);
++ reg16_write(client, 0x3813, priv->rect.top & 0xff);
++#endif
++ return 0;
++};
++
++static int ov2311_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = OV2311_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ov2311_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = OV2311_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ov2311_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = OV2311_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ov2311_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = OV2311_PID >> 8;
++ edid->edid[9] = OV2311_PID & 0xff;
++
++ return 0;
++}
++
++static int ov2311_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > OV2311_MAX_WIDTH) ||
++ (rect->top + rect->height > OV2311_MAX_HEIGHT))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ ov2311_set_window(sd);
++
++ return 0;
++}
++
++static int ov2311_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OV2311_MAX_WIDTH;
++ sel->r.height = OV2311_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = OV2311_MAX_WIDTH;
++ sel->r.height = OV2311_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ov2311_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ov2311_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ __be64 be_val;
++
++ if (!reg->size)
++ reg->size = sizeof(u8);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
++
++ return ret;
++}
++
++static int ov2311_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u8);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
++
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
++}
++#endif
++
++static struct v4l2_subdev_core_ops ov2311_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ov2311_g_register,
++ .s_register = ov2311_s_register,
++#endif
++};
++
++static int ov2311_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = ov2311_to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++ int ret = 0;
++ u8 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ break;
++ case V4L2_CID_GAIN:
++ reg16_write(client, 0x350A, ctrl->val / 0x3ff); // COARSE: 4.10 format
++ reg16_write(client, 0x350B, (ctrl->val % 0x3ff) >> 2); // FINE: 4.10 format
++ reg16_write(client, 0x350C, (ctrl->val % 0x3ff) << 6); // FINE: 4.10 format
++ break;
++ case V4L2_CID_ANALOGUE_GAIN:
++ reg16_write(client, 0x3508, ctrl->val / 0xf); // COARSE: 5.4 format
++ reg16_write(client, 0x3509, (ctrl->val % 0xf) << 4); // FINE: 5.4 format
++ break;
++ case V4L2_CID_EXPOSURE:
++ reg16_write(client, 0x3501, ctrl->val >> 8);
++ reg16_write(client, 0x3502, ctrl->val & 0xff);
++ break;
++ case V4L2_CID_HFLIP:
++ reg16_read(client, 0x3821, &val);
++ val &= ~0x04;
++ val |= (ctrl->val ? 0x04 : 0);
++ reg16_write(client, 0x3821, val);
++ break;
++ case V4L2_CID_VFLIP:
++ reg16_read(client, 0x3820, &val);
++ val &= ~0x44;
++ val |= (ctrl->val ? 0x44 : 0);
++ reg16_write(client, 0x3820, val);
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ov2311_ctrl_ops = {
++ .s_ctrl = ov2311_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ov2311_video_ops = {
++ .s_stream = ov2311_s_stream,
++ .g_mbus_config = ov2311_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ov2311_subdev_pad_ops = {
++ .get_edid = ov2311_get_edid,
++ .enum_mbus_code = ov2311_enum_mbus_code,
++ .get_selection = ov2311_get_selection,
++ .set_selection = ov2311_set_selection,
++ .get_fmt = ov2311_get_fmt,
++ .set_fmt = ov2311_set_fmt,
++};
++
++static struct v4l2_subdev_ops ov2311_subdev_ops = {
++ .core = &ov2311_core_ops,
++ .video = &ov2311_video_ops,
++ .pad = &ov2311_subdev_pad_ops,
++};
++
++static ssize_t ov2311_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov2311_priv *priv = to_ov2311(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ov2311, S_IRUGO, ov2311_otp_id_show, NULL);
++
++static int ov2311_initialize(struct i2c_client *client)
++{
++ struct ov2311_priv *priv = to_ov2311(client);
++ u16 pid;
++ u8 val = 0, rev = 0;
++ int ret = 0;
++
++ setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2);
++
++ reg16_read(client, OV2311_PID_REGA, &val);
++ pid = val;
++ reg16_read(client, OV2311_PID_REGB, &val);
++ pid = (pid << 8) | val;
++
++ if (pid != OV2311_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ if (get_des_id(client) == UB960_ID)
++ reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */
++
++ /* check revision */
++ reg16_read(client, OV2311_REV_REG, &rev);
++ /* Program wizard registers */
++ ov2311_set_regs(client, ov2311_regs_wizard_r1c, ARRAY_SIZE(ov2311_regs_wizard_r1c));
++ /* Read OTP IDs */
++ ov2311_otp_id_read(client);
++
++ dev_info(&client->dev, "ov2311 PID %x (rev %x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, rev, OV2311_MAX_WIDTH, OV2311_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return ret;
++}
++
++static const struct i2c_device_id ov2311_id[] = {
++ { "ov2311", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ov2311_id);
++
++static const struct of_device_id ov2311_of_ids[] = {
++ { .compatible = "ovti,ov2311", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ov2311_of_ids);
++
++static int ov2311_parse_dt(struct device_node *np, struct ov2311_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ return 0;
++}
++
++static int ov2311_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ov2311_priv *priv;
++ struct v4l2_ctrl *ctrl;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ov2311_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = OV2311_MAX_WIDTH;
++ priv->rect.height = OV2311_MAX_HEIGHT;
++ priv->fps_denominator = 30;
++
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 4, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_HUE, 0, 255, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0x3ff*4, 1, 0x3ff);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 0, 0xf*5, 1, 0xf);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0x580, 1, 0x57c);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov2311_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ov2311_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ov2311_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov2311) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ov2311_remove(struct i2c_client *client)
++{
++ struct ov2311_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ov2311);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ov2311_i2c_driver = {
++ .driver = {
++ .name = "ov2311",
++ .of_match_table = ov2311_of_ids,
++ },
++ .probe = ov2311_probe,
++ .remove = ov2311_remove,
++ .id_table = ov2311_id,
++};
++
++module_i2c_driver(ov2311_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for OV2311");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.h b/drivers/media/i2c/soc_camera/imagers/ov2311.h
+new file mode 100644
+index 0000000..3a56b0b
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.h
+@@ -0,0 +1,217 @@
++/*
++ * OmniVision ov2311 sensor camera wizard 1600x130@30/GREY8/MIPI
++ *
++ * Copyright (C) 2015-2017 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define OV2311_DISPLAY_PATTERN
++//#define OV2311_FSIN_ENABLE
++
++#define OV2311_MAX_WIDTH 1600
++#define OV2311_MAX_HEIGHT 1300
++
++#define OV2311_DELAY 0xffff
++
++#define OV2311_SENSOR_WIDTH 1616
++#define OV2311_SENSOR_HEIGHT 1316
++
++#define OV2311_X_START ((OV2311_SENSOR_WIDTH - OV2311_MAX_WIDTH) / 2)
++#define OV2311_Y_START ((OV2311_SENSOR_HEIGHT - OV2311_MAX_HEIGHT) / 2)
++#define OV2311_X_END (OV2311_X_START + OV2311_MAX_WIDTH - 1)
++#define OV2311_Y_END (OV2311_Y_START + OV2311_MAX_HEIGHT - 1)
++
++struct ov2311_reg {
++ u16 reg;
++ u8 val;
++};
++
++/* R1600x1300 RAW10 MIPI 60fps */
++static const struct ov2311_reg ov2311_regs_wizard_r1c[] = {
++{0x0103, 0x01},
++{0x0100, 0x00},
++{0x010c, 0x02},
++{0x010b, 0x01},
++{0x0300, 0x01},
++{0x0302, 0x32},
++{0x0303, 0x00},
++{0x0304, 0x03},
++{0x0305, 0x02},
++{0x0306, 0x01},
++{0x030d, 0x5a},
++{0x030e, 0x04},
++{0x3001, 0x02},
++{0x3004, 0x00},
++{0x3005, 0x00},
++{0x3006, 0x0a},
++{0x3011, 0x0d},
++{0x3014, 0x04},
++{0x301c, 0xf0},
++{0x3020, 0x20},
++{0x302c, 0x00},
++{0x302d, 0x00},
++{0x302e, 0x00},
++{0x302f, 0x03},
++{0x3030, 0x10},
++{0x303f, 0x03},
++{0x3103, 0x00},
++{0x3106, 0x08},
++{0x31ff, 0x01},
++{0x3501, 0x05},
++{0x3502, 0x7c},
++{0x3506, 0x00},
++{0x3507, 0x00},
++{0x3620, 0x67},
++{0x3633, 0x78},
++{0x3662, 0x65},
++{0x3664, 0xb0},
++{0x3666, 0x70},
++{0x3670, 0x68},
++{0x3674, 0x10},
++{0x3675, 0x00},
++{0x367e, 0x90},
++{0x3680, 0x84},
++{0x36a2, 0x04},
++{0x36a3, 0x80},
++{0x36b0, 0x00},
++{0x3700, 0x35},
++{0x3704, 0x39},
++{0x370a, 0x50},
++{0x3712, 0x00},
++{0x3713, 0x02},
++{0x3778, 0x00},
++{0x379b, 0x01},
++{0x379c, 0x10},
++{0x3800, 0x00},
++{0x3801, 0x00},
++{0x3802, 0x00},
++{0x3803, 0x00},
++{0x3804, 0x06},
++{0x3805, 0x4f},
++{0x3806, 0x05},
++{0x3807, 0x23},
++{0x3808, OV2311_MAX_WIDTH >> 8},
++{0x3809, OV2311_MAX_WIDTH & 0xff},
++{0x380a, OV2311_MAX_HEIGHT >> 8},
++{0x380b, OV2311_MAX_HEIGHT & 0xff},
++{0x380c, 0x03},
++{0x380d, 0xa8},
++{0x380e, 0x05},
++{0x380f, 0x88},
++{0x3810, OV2311_X_START >> 8},
++{0x3811, OV2311_X_START & 0xff},
++{0x3812, OV2311_Y_START >> 8},
++{0x3813, OV2311_X_START & 0xff},
++{0x3814, 0x11},
++{0x3815, 0x11},
++{0x3816, 0x00},
++{0x3817, 0x01},
++{0x3818, 0x00},
++{0x3819, 0x05},
++{0x3820, 0x00},
++{0x3821, 0x00},
++{0x382b, 0x5a},
++{0x382c, 0x0a},
++{0x382d, 0xf8},
++{0x3881, 0x44},
++{0x3882, 0x02},
++{0x3883, 0x8c},
++{0x3885, 0x07},
++{0x389d, 0x03},
++{0x38a6, 0x00},
++{0x38a7, 0x01},
++{0x38b3, 0x07},
++{0x38b1, 0x00},
++{0x38e5, 0x02},
++{0x38e7, 0x00},
++{0x38e8, 0x00},
++{0x3910, 0xff},
++{0x3911, 0xff},
++{0x3912, 0x08},
++{0x3913, 0x00},
++{0x3914, 0x00},
++{0x3915, 0x00},
++{0x391c, 0x00},
++{0x3920, 0xff},
++{0x3921, 0x80},
++{0x3922, 0x00},
++{0x3923, 0x00},
++{0x3924, 0x05},
++{0x3925, 0x00},
++{0x3926, 0x00},
++{0x3927, 0x00},
++{0x3928, 0x1a},
++{0x392d, 0x03},
++{0x392e, 0xa8},
++{0x392f, 0x08},
++{0x4001, 0x00},
++{0x4003, 0x40},
++{0x4008, 0x04},
++{0x4009, 0x1b},
++{0x400c, 0x04},
++{0x400d, 0x1b},
++{0x4010, 0xf4},
++{0x4011, 0x00},
++{0x4016, 0x00},
++{0x4017, 0x04},
++{0x4042, 0x11},
++{0x4043, 0x70},
++{0x4045, 0x00},
++{0x4409, 0x5f},
++{0x4509, 0x00},
++{0x450b, 0x00},
++{0x4600, 0x00},
++{0x4601, 0xa0},
++{0x4708, 0x09},
++{0x470c, 0x81},
++{0x4710, 0x06},
++{0x4711, 0x00},
++{0x4800, 0x00},
++{0x481f, 0x30},
++{0x4837, 0x14},
++{0x4f00, 0x00},
++{0x4f07, 0x00},
++{0x4f08, 0x03},
++{0x4f09, 0x08},
++{0x4f0c, 0x05},
++{0x4f0d, 0xb4},
++{0x4f10, 0x00},
++{0x4f11, 0x00},
++{0x4f12, 0x07},
++{0x4f13, 0xe2},
++{0x5000, 0x9f},
++{0x5001, 0x20},
++{0x5026, 0x00},
++{0x5c00, 0x00},
++{0x5c01, 0x2c},
++{0x5c02, 0x00},
++{0x5c03, 0x7f},
++{0x5e00, 0x00},
++{0x5e01, 0x41},
++{0x38b1, 0x02},
++{0x3880, 0x00},
++
++#if 1 /* Y8 mode */
++{0x3016, 0xF1},
++{0x0100, 0x01},
++{0x4814, 0x6A}, //; dt_man en, both embed/image data type are 0x2A
++{0x3218, 0x32},
++{0x3216, 0x01},
++{0x3208, 0x04},
++{0x3D81, 0x01},
++{0x4605, 0x02},
++{0x4816, 0x0A},
++{0x3208, 0x14},
++{0x3662, 0x67}, //; [1] raw8
++{0x366F, 0x1A}, //; [6] MSB
++//{0x3674, 0x11}, //; [0] embed_en, add embed data before normal image
++{0x3674, 0x10}, //; [0] embed_dis, add embed data before normal image
++{0x3016, 0xF0},
++#endif
++
++{0x0100, 0x01},
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.c b/drivers/media/i2c/soc_camera/imagers/ov490.c
+new file mode 100644
+index 0000000..3c47398
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov490.c
+@@ -0,0 +1,1051 @@
++/*
++ * OmniVision ov490-10640 sensor camera driver
++ *
++ * Copyright (C) 2016-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "ov490.h"
++
++#define OV490_I2C_ADDR 0x24
++
++#define OV490_PID_REGA 0x300a
++#define OV490_PID_REGB 0x300b
++#define OV490_PID 0x0490
++
++#define OV490_ISP_HSIZE_LOW 0x60
++#define OV490_ISP_HSIZE_HIGH 0x61
++#define OV490_ISP_VSIZE_LOW 0x62
++#define OV490_ISP_VSIZE_HIGH 0x63
++
++struct ov490_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int max_width;
++ int max_height;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int autogain;
++ int red;
++ int green_r;
++ int green_b;
++ int blue;
++ int awb;
++ int dvp_order;
++ int group;
++ /* serializers */
++ int ser_addr;
++ int des_addr;
++ int reset_gpio;
++ int active_low_resetb;
++};
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int group = 0;
++module_param(group, int, 0644);
++MODULE_PARM_DESC(group, " group number (0 - does not apply)");
++
++static int dvp_order = 0;
++module_param(dvp_order, int, 0644);
++MODULE_PARM_DESC(dvp_order, " DVP bus bits order");
++
++static int reset_gpio = 0;
++module_param(reset_gpio, int, 0644);
++MODULE_PARM_DESC(reset_gpio, " serializer gpio number on imager RESETB");
++
++static inline struct ov490_priv *to_ov490(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ov490_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ov490_priv, hdl)->sd;
++}
++
++static void ov490_reset(struct i2c_client *client)
++{
++ struct ov490_priv *priv = to_ov490(client);
++
++ switch (get_des_id(client)) {
++ case MAX9286_ID:
++ case MAX9288_ID:
++ case MAX9296A_ID:
++ case MAX96712_ID:
++ reg8_write_addr(client, priv->ser_addr, 0x0f, (0xfe & ~BIT(priv->reset_gpio))); /* set GPIOn value to reset */
++ usleep_range(2000, 2500);
++ reg8_write_addr(client, priv->ser_addr, 0x0f, 0xfe | BIT(priv->reset_gpio)); /* set GPIOn value to un-reset */
++ usleep_range(2000, 2500);
++ break;
++ case UB960_ID:
++ reg8_write_addr(client, get_des_addr(client), 0x6e, 0x8a); /* set GPIO1 value to reset */
++ usleep_range(2000, 2500);
++ reg8_write_addr(client, get_des_addr(client), 0x6e, 0x9a); /* set GPIO1 value to un-reset */
++ usleep_range(2000, 2500);
++ break;
++ }
++}
++
++static int ov490_set_regs(struct i2c_client *client,
++ const struct ov490_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (reg16_write(client, regs[i].reg, regs[i].val)) {
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, regs[i].reg, regs[i].val);
++ }
++
++ if (regs[i].reg == 0xFFFE)
++ usleep_range(100, 150); /* wait 100 us */
++ }
++
++ return 0;
++}
++
++static u8 ov490_ov10640_read(struct i2c_client *client, u16 addr)
++{
++ u8 reg_val = 0;
++
++ reg16_write(client, 0xFFFD, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x5000, 0x01); /* read operation */
++ reg16_write(client, 0x5001, addr >> 8);
++ reg16_write(client, 0x5002, addr & 0xff);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x00C0, 0xc1);
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(1000, 1500); /* wait 1 ms */
++ reg16_read(client, 0x5000, &reg_val);
++
++ return reg_val;
++}
++
++static void ov490_ov10640_write(struct i2c_client *client, u16 addr, u8 val)
++{
++ reg16_write(client, 0xFFFD, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x5000, 0x00); /* write operation */
++ reg16_write(client, 0x5001, addr >> 8);
++ reg16_write(client, 0x5002, addr & 0xff);
++ reg16_write(client, 0x5003, val);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x00C0, 0xc1);
++}
++
++static void ov490_otp_id_read(struct i2c_client *client)
++{
++ struct ov490_priv *priv = to_ov490(client);
++ int i;
++ int otp_bank0_allzero = 1;
++#if 0
++ /* read camera id from ov490 OTP memory */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x28);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0xE084, 0x40); /* manual mode, bank#0 */
++ reg16_write(client, 0xE081, 1); /* start OTP read */
++
++ usleep_range(25000, 26000); /* wait 25 ms */
++
++ for (i = 0; i < 6; i++)
++ reg16_read(client, 0xe000 + i + 4, &priv->id[i]);
++#else
++ /* read camera id from ov10640 OTP memory */
++ ov490_ov10640_write(client, 0x349C, 1);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i++) {
++ /* first 6 bytes are equal on all ov10640 */
++ priv->id[i] = ov490_ov10640_read(client, 0x349e + i + 6);
++ if (priv->id[i])
++ otp_bank0_allzero = 0;
++ }
++
++ if (otp_bank0_allzero) {
++ ov490_ov10640_write(client, 0x3495, 0x41); /* bank#1 */
++ ov490_ov10640_write(client, 0x349C, 1);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i++)
++ priv->id[i] = ov490_ov10640_read(client, 0x34ae + i);
++ }
++#endif
++}
++
++static int ov490_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ov490_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ov490_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ov490_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = MEDIA_BUS_FMT_YUYV8_2X8;
++
++ return 0;
++}
++
++static int ov490_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = OV490_PID >> 8;
++ edid->edid[9] = OV490_PID & 0xff;
++
++ return 0;
++}
++
++static int ov490_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > priv->max_width) ||
++ (rect->top + rect->height > priv->max_height))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int ov490_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ov490_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ov490_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ u8 val = 0;
++
++ ret = reg16_read(client, (u16)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int ov490_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++
++ ret = reg16_write(client, (u16)reg->reg, (u8)reg->val);
++ if ((u8)reg->reg == 0xFFFD)
++ usleep_range(100, 150); /* wait 100 us */
++ if ((u8)reg->reg == 0xFFFE)
++ usleep_range(100, 150); /* wait 100 us */
++ return ret;
++}
++#endif
++
++static struct v4l2_subdev_core_ops ov490_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ov490_g_register,
++ .s_register = ov490_s_register,
++#endif
++};
++
++static int ov490_s_gamma(int a, int ref)
++{
++ if ((a + ref) > 0xff)
++ return 0xff;
++
++ if ((a + ref) < 0)
++ return 0;
++
++ return a + ref;
++}
++
++static int ov490_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++ int ret = -EINVAL;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ /* SDE (rough) brightness */
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00);
++ ret |= reg16_write(client, 0x5001, ctrl->val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xf1);
++ break;
++ case V4L2_CID_CONTRAST:
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xfd);
++ break;
++ case V4L2_CID_SATURATION:
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xf3);
++ break;
++ case V4L2_CID_HUE:
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xf5);
++ break;
++ case V4L2_CID_GAMMA:
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ov490_s_gamma(ctrl->val, 0x12));
++ ret |= reg16_write(client, 0x5001, ov490_s_gamma(ctrl->val, 0x20));
++ ret |= reg16_write(client, 0x5002, ov490_s_gamma(ctrl->val, 0x3b));
++ ret |= reg16_write(client, 0x5003, ov490_s_gamma(ctrl->val, 0x5d));
++ ret |= reg16_write(client, 0x5004, ov490_s_gamma(ctrl->val, 0x6a));
++ ret |= reg16_write(client, 0x5005, ov490_s_gamma(ctrl->val, 0x76));
++ ret |= reg16_write(client, 0x5006, ov490_s_gamma(ctrl->val, 0x81));
++ ret |= reg16_write(client, 0x5007, ov490_s_gamma(ctrl->val, 0x8b));
++ ret |= reg16_write(client, 0x5008, ov490_s_gamma(ctrl->val, 0x96));
++ ret |= reg16_write(client, 0x5009, ov490_s_gamma(ctrl->val, 0x9e));
++ ret |= reg16_write(client, 0x500a, ov490_s_gamma(ctrl->val, 0xae));
++ ret |= reg16_write(client, 0x500b, ov490_s_gamma(ctrl->val, 0xbc));
++ ret |= reg16_write(client, 0x500c, ov490_s_gamma(ctrl->val, 0xcf));
++ ret |= reg16_write(client, 0x500d, ov490_s_gamma(ctrl->val, 0xde));
++ ret |= reg16_write(client, 0x500e, ov490_s_gamma(ctrl->val, 0xec));
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xf9);
++ break;
++ case V4L2_CID_SHARPNESS:
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xfb);
++ break;
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_GAIN:
++ case V4L2_CID_EXPOSURE:
++ if (ctrl->id == V4L2_CID_AUTOGAIN)
++ priv->autogain = ctrl->val;
++ if (ctrl->id == V4L2_CID_GAIN)
++ priv->gain = ctrl->val;
++ if (ctrl->id == V4L2_CID_EXPOSURE)
++ priv->exposure = ctrl->val;
++
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, !priv->autogain);
++ ret |= reg16_write(client, 0x5001, priv->exposure >> 8);
++ ret |= reg16_write(client, 0x5002, priv->exposure & 0xff);
++ ret |= reg16_write(client, 0x5003, priv->exposure >> 8);
++ ret |= reg16_write(client, 0x5004, priv->exposure & 0xff);
++ ret |= reg16_write(client, 0x5005, priv->exposure >> 8);
++ ret |= reg16_write(client, 0x5006, priv->exposure & 0xff);
++ ret |= reg16_write(client, 0x5007, priv->gain >> 8);
++ ret |= reg16_write(client, 0x5008, priv->gain & 0xff);
++ ret |= reg16_write(client, 0x5009, priv->gain >> 8);
++ ret |= reg16_write(client, 0x500a, priv->gain & 0xff);
++ ret |= reg16_write(client, 0x500b, priv->gain >> 8);
++ ret |= reg16_write(client, 0x500c, priv->gain & 0xff);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xea);
++ break;
++ case V4L2_CID_AUTO_WHITE_BALANCE:
++ case V4L2_CID_RED_BALANCE:
++ case V4L2_CID_BLUE_BALANCE:
++ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE)
++ priv->awb = ctrl->val;
++ if (ctrl->id == V4L2_CID_RED_BALANCE) {
++ priv->red = ctrl->val;
++ priv->red <<= 8;
++ priv->green_r = priv->red / 2;
++ }
++ if (ctrl->id == V4L2_CID_BLUE_BALANCE) {
++ priv->blue = ctrl->val;
++ priv->blue <<= 8;
++ priv->green_b = priv->blue / 2;
++ }
++
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, !priv->awb);
++ ret |= reg16_write(client, 0x5001, priv->red >> 8);
++ ret |= reg16_write(client, 0x5002, priv->red & 0xff);
++ ret |= reg16_write(client, 0x5003, priv->green_r >> 8);
++ ret |= reg16_write(client, 0x5004, priv->green_r & 0xff);
++ ret |= reg16_write(client, 0x5005, priv->green_b >> 8);
++ ret |= reg16_write(client, 0x5006, priv->green_b & 0xff);
++ ret |= reg16_write(client, 0x5007, priv->blue >> 8);
++ ret |= reg16_write(client, 0x5008, priv->blue & 0xff);
++ ret |= reg16_write(client, 0x5009, priv->red >> 8);
++ ret |= reg16_write(client, 0x500a, priv->red & 0xff);
++ ret |= reg16_write(client, 0x500b, priv->green_r >> 8);
++ ret |= reg16_write(client, 0x500c, priv->green_r & 0xff);
++ ret |= reg16_write(client, 0x500d, priv->green_b >> 8);
++ ret |= reg16_write(client, 0x500e, priv->green_b & 0xff);
++ ret |= reg16_write(client, 0x500f, priv->blue >> 8);
++ ret |= reg16_write(client, 0x5010, priv->blue & 0xff);
++ ret |= reg16_write(client, 0x5011, priv->red >> 8);
++ ret |= reg16_write(client, 0x5012, priv->red & 0xff);
++ ret |= reg16_write(client, 0x5013, priv->green_r >> 8);
++ ret |= reg16_write(client, 0x5014, priv->green_r & 0xff);
++ ret |= reg16_write(client, 0x5015, priv->green_b >> 8);
++ ret |= reg16_write(client, 0x5016, priv->green_b & 0xff);
++ ret |= reg16_write(client, 0x5017, priv->blue >> 8);
++ ret |= reg16_write(client, 0x5018, priv->blue & 0xff);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xeb);
++ break;
++ case V4L2_CID_HFLIP:
++#if 1
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0x5001, 0x00);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xdc);
++#else
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128
++ ret |= reg16_write(client, 0x5001, 0x31);
++ ret |= reg16_write(client, 0x5002, 0x28);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 0);
++ val |= (ctrl->val << 0);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128
++ ret |= reg16_write(client, 0x5001, 0x31);
++ ret |= reg16_write(client, 0x5002, 0x28);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291
++ ret |= reg16_write(client, 0x5001, 0x32);
++ ret |= reg16_write(client, 0x5002, 0x91);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 1);
++ val |= (ctrl->val << 1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291
++ ret |= reg16_write(client, 0x5001, 0x32);
++ ret |= reg16_write(client, 0x5002, 0x91);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090
++ ret |= reg16_write(client, 0x5001, 0x30);
++ ret |= reg16_write(client, 0x5002, 0x90);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 2);
++ val |= (ctrl->val << 2);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090
++ ret |= reg16_write(client, 0x5001, 0x30);
++ ret |= reg16_write(client, 0x5002, 0x90);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++#endif
++ break;
++ case V4L2_CID_VFLIP:
++#if 1
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, ctrl->val);
++ ret |= reg16_write(client, 0x5001, 0x01);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xdc);
++#else
++ ret = reg16_write(client, 0xFFFD, 0x80);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128
++ ret |= reg16_write(client, 0x5001, 0x31);
++ ret |= reg16_write(client, 0x5002, 0x28);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 1);
++ val |= (ctrl->val << 1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128
++ ret |= reg16_write(client, 0x5001, 0x31);
++ ret |= reg16_write(client, 0x5002, 0x28);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291
++ ret |= reg16_write(client, 0x5001, 0x32);
++ ret |= reg16_write(client, 0x5002, 0x91);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 2);
++ val |= (ctrl->val << 2);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291
++ ret |= reg16_write(client, 0x5001, 0x32);
++ ret |= reg16_write(client, 0x5002, 0x91);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090
++ ret |= reg16_write(client, 0x5001, 0x30);
++ ret |= reg16_write(client, 0x5002, 0x90);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_read(client, 0x5000, &val);
++ val &= ~(0x1 << 3);
++ val |= (ctrl->val << 3);
++ ret |= reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090
++ ret |= reg16_write(client, 0x5001, 0x30);
++ ret |= reg16_write(client, 0x5002, 0x90);
++ ret |= reg16_write(client, 0x5003, val);
++ ret |= reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ ret |= reg16_write(client, 0x00C0, 0xc1);
++#endif
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ov490_ctrl_ops = {
++ .s_ctrl = ov490_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ov490_video_ops = {
++ .s_stream = ov490_s_stream,
++ .g_mbus_config = ov490_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ov490_subdev_pad_ops = {
++ .get_edid = ov490_get_edid,
++ .enum_mbus_code = ov490_enum_mbus_code,
++ .get_selection = ov490_get_selection,
++ .set_selection = ov490_set_selection,
++ .get_fmt = ov490_get_fmt,
++ .set_fmt = ov490_set_fmt,
++};
++
++static struct v4l2_subdev_ops ov490_subdev_ops = {
++ .core = &ov490_core_ops,
++ .video = &ov490_video_ops,
++ .pad = &ov490_subdev_pad_ops,
++};
++
++static ssize_t ov490_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ov490_priv *priv = to_ov490(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ov490, S_IRUGO, ov490_otp_id_show, NULL);
++
++static int ov490_initialize(struct i2c_client *client)
++{
++ struct ov490_priv *priv = to_ov490(client);
++ u8 val = 0;
++ u16 pid = 0;
++ int timeout, retry_timeout = 3;
++
++ setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR, MODE_GMSL1);
++
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_read(client, OV490_PID_REGA, &val);
++ pid = val;
++ reg16_read(client, OV490_PID_REGB, &val);
++ pid = (pid << 8) | val;
++
++ if (pid != OV490_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ if (unlikely(conf_link))
++ goto out;
++again:
++ /* Check if firmware booted by reading stream-on status */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x29);
++ usleep_range(100, 150); /* wait 100 us */
++ for (timeout = 300; timeout > 0; timeout--) {
++ reg16_read(client, 0xd000, &val);
++ if (val == 0x0c)
++ break;
++ mdelay(1);
++ }
++
++ /* wait firmware apps started by reading OV10640 ID */
++ for (;timeout > 0; timeout--) {
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x5000, 0x01);
++ reg16_write(client, 0x5001, 0x30);
++ reg16_write(client, 0x5002, 0x0a);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0xC0, 0xc1);
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(1000, 1500); /* wait 1 ms */
++ reg16_read(client, 0x5000, &val);
++ if (val == 0xa6)
++ break;
++ mdelay(1);
++ }
++
++ if (!timeout) {
++ dev_err(&client->dev, "Timeout firmware boot wait, retrying\n");
++ /* reset OV10640 using RESETB pin controlled by OV490 GPIO0 */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x0050, 0x01);
++ reg16_write(client, 0x0054, 0x01);
++ reg16_write(client, 0x0058, 0x00);
++ mdelay(10);
++ reg16_write(client, 0x0058, 0x01);
++ /* reset OV490 using RESETB pin controlled by serializer */
++ ov490_reset(client);
++ if (retry_timeout--)
++ goto again;
++ }
++
++ if (priv->group) {
++ /* switch to group# */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x19);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x5000, priv->group);
++ reg16_write(client, 0xFFFE, 0x80);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0xc0, 0x3f);
++
++ mdelay(30);
++ }
++
++ /* read resolution used by current firmware */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x82);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_read(client, OV490_ISP_HSIZE_HIGH, &val);
++ priv->max_width = val;
++ reg16_read(client, OV490_ISP_HSIZE_LOW, &val);
++ priv->max_width = (priv->max_width << 8) | val;
++ reg16_read(client, OV490_ISP_VSIZE_HIGH, &val);
++ priv->max_height = val;
++ reg16_read(client, OV490_ISP_VSIZE_LOW, &val);
++ priv->max_height = (priv->max_height << 8) | val;
++ /* Program wizard registers */
++ ov490_set_regs(client, ov490_regs_wizard, ARRAY_SIZE(ov490_regs_wizard));
++ /* Set DVP bit swap */
++ reg16_write(client, 0xFFFD, 0x80);
++ reg16_write(client, 0xFFFE, 0x28);
++ usleep_range(100, 150); /* wait 100 us */
++ reg16_write(client, 0x6009, priv->dvp_order << 4);
++ /* Read OTP IDs */
++ ov490_otp_id_read(client);
++
++out:
++ dev_info(&client->dev, "ov490-10640 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id ov490_id[] = {
++ { "ov490", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ov490_id);
++
++static const struct of_device_id ov490_of_ids[] = {
++ { .compatible = "ovti,ov490", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ov490_of_ids);
++
++static int ov490_parse_dt(struct device_node *np, struct ov490_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ if (of_property_read_u32(np, "dvp-order", &priv->dvp_order))
++ priv->dvp_order = 0;
++ if (of_property_read_u32(np, "reset-gpio", &priv->reset_gpio))
++ priv->reset_gpio = 1;
++ if (of_property_read_u32(np, "group", &priv->group))
++ priv->group = 0;
++
++ /* module params override dts */
++ if (dvp_order)
++ priv->dvp_order = dvp_order;
++ if (group)
++ priv->group = group;
++
++ return 0;
++}
++
++static int ov490_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ov490_priv *priv;
++ struct v4l2_ctrl *ctrl;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ov490_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ priv->exposure = 0x100;
++ priv->gain = 0x100;
++ priv->autogain = 1;
++ priv->red = 0x400;
++ priv->blue = 0x400;
++ priv->green_r = priv->red / 2;
++ priv->green_b = priv->blue / 2;
++ priv->awb = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_RED_BALANCE, 2, 0xf, 1, priv->red >> 8);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_BLUE_BALANCE, 2, 0xf, 1, priv->blue >> 8);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 1);
++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9);
++ if (ctrl)
++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ov490_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ov490_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = priv->max_width;
++ priv->rect.height = priv->max_height;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov490) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ov490_remove(struct i2c_client *client)
++{
++ struct ov490_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ov490);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ov490_i2c_driver = {
++ .driver = {
++ .name = "ov490",
++ .of_match_table = ov490_of_ids,
++ },
++ .probe = ov490_probe,
++ .remove = ov490_remove,
++ .id_table = ov490_id,
++};
++
++module_i2c_driver(ov490_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for OV490");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.h b/drivers/media/i2c/soc_camera/imagers/ov490.h
+new file mode 100644
+index 0000000..6c39bdd
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ov490.h
+@@ -0,0 +1,102 @@
++/*
++ * OmniVision ov490-ov10640 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit
++ *
++ * Copyright (C) 2016-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define OV490_DISPLAY_PATTERN
++
++struct ov490_reg {
++ u16 reg;
++ u8 val;
++};
++
++static const struct ov490_reg ov490_regs_wizard[] = {
++/* The following registers should match firmware */
++{0xfffd, 0x80},
++{0xfffe, 0x82},
++{0x0071, 0x11},
++{0x0075, 0x11},
++{0xfffe, 0x29},
++{0x6010, 0x01},
++/* ov490 EMB line disable in YUV and RAW data, NOTE: EMB line is still used in ISP and sensor */
++{0xe000, 0x14},
++#if 0 /* do not disable EMB line in ISP! */
++{0x4017, 0x00},
++#endif
++{0xfffe, 0x28},
++{0x6000, 0x04},
++{0x6004, 0x00},
++//{0x6008, 0x000}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register
++{0x6008, 0x02}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register
++{0xfffe, 0x80},
++{0x0091, 0x00},
++{0x00bb, 0x1d}, // bit[3]=0 - PCLK polarity workaround
++/* ov10640 EMB line disable */
++#if 0 /* do not disable EMB line in sensor! */
++{0xfffe, 0x19},
++{0x5000, 0x00},
++{0x5001, 0x30},
++{0x5002, 0x91},
++{0x5003, 0x08},
++{0xfffe, 0x80},
++{0x00c0, 0xc1},
++#endif
++/* Ov490 FSIN: app_fsin_from_fsync */
++{0xfffe, 0x85},
++{0x0008, 0x00},
++{0x0009, 0x01},
++{0x000A, 0x05}, // fsin0 src
++{0x000B, 0x00},
++{0x0030, 0x02}, // fsin0_delay
++{0x0031, 0x00},
++{0x0032, 0x00},
++{0x0033, 0x00},
++{0x0038, 0x02}, // fsin1_delay
++{0x0039, 0x00},
++{0x003A, 0x00},
++{0x003B, 0x00},
++{0x0070, 0x2C}, // fsin0_length
++{0x0071, 0x01},
++{0x0072, 0x00},
++{0x0073, 0x00},
++{0x0074, 0x64}, // fsin1_length
++{0x0075, 0x00},
++{0x0076, 0x00},
++{0x0077, 0x00},
++{0x0000, 0x14},
++{0x0001, 0x00},
++{0x0002, 0x00},
++{0x0003, 0x00},
++{0x0004, 0x32}, // load fsin0,load fsin1,load other, it will be cleared automatically.
++{0x0005, 0x00},
++{0x0006, 0x00},
++{0x0007, 0x00},
++{0xfffe, 0x80},
++{0x0081, 0x00}, // 03;SENSOR FSIN
++/* ov10640 FSIN */
++{0xfffe, 0x19},
++{0x5000, 0x00},
++{0x5001, 0x30},
++{0x5002, 0x8c},
++{0x5003, 0xb2},
++{0xfffe, 0x80},
++{0x00c0, 0xc1},
++/* ov10640 HFLIP=1 by default */
++{0xfffe, 0x19},
++{0x5000, 0x01},
++{0x5001, 0x00},
++{0xfffe, 0x80},
++{0x00c0, 0xdc},
++#ifdef OV490_DISPLAY_PATTERN
++{0xfffe, 0x19},
++{0x5000, 0x02},
++{0xfffe, 0x80},
++{0x00c0, 0xd6},
++#endif
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch
new file mode 100644
index 00000000..89bf7716
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch
@@ -0,0 +1,165 @@
+From ae9686ecfbdb0af61975e1f501d83f9a488e2e7b Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 11:25:19 +0300
+Subject: [PATCH] media: i2c: soc_camera: rcar_csi2: adjust debugging
+
+This extends MIPI packets debugging.
+This adds possibility to enable debuuggin runtime via sysfs
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/platform/soc_camera/rcar_csi2.c | 84 ++++++++++++++++++++++-----
+ 1 file changed, 69 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/media/platform/soc_camera/rcar_csi2.c b/drivers/media/platform/soc_camera/rcar_csi2.c
+index ca47ba3..1f1beb8 100644
+--- a/drivers/media/platform/soc_camera/rcar_csi2.c
++++ b/drivers/media/platform/soc_camera/rcar_csi2.c
+@@ -293,10 +293,10 @@ MODULE_PARM_DESC(dump, " Dump CSI packets (default: disabled)");
+ #define RCAR_CSI2_CRCECM 0x150
+ #define RCAR_CSI2_LCNT(i) (0x160 + i * 0x04)
+ #define RCAR_CSI2_LCNTM(i) (0x168 + i * 0x04)
+-#define RCAR_CSI2_FCNTM 0x170
+-#define RCAR_CSI2_FCNTM2 0x174
++#define RCAR_CSI2_FCNTM(i) (0x170 + i * 0x04)
+ #define RCAR_CSI2_VINSM(i) (0x190 + i * 0x04)
+ #define RCAR_CSI2_PHM(i) (0x1C0 + i * 0x04)
++#define RCAR_CSI2_PPM(i) (0x1E0 + i * 0x04)
+
+ #define RCAR_CSI2_INTSTATE_ALL 0x3FFFFCDD
+
+@@ -309,8 +309,28 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv)
+ return;
+
+ dev_info(&priv->pdev->dev, "Debug registers:\n");
+- printk("FCNTM : 0x%08x\n", ioread32(priv->base + RCAR_CSI2_FCNTM));
+- printk("FCNTM2: 0x%08x\n", ioread32(priv->base + RCAR_CSI2_FCNTM2));
++ for (i = 0; i < 2; i++) {
++ reg0 = ioread32(priv->base + RCAR_CSI2_FCNTM(i));
++
++ printk("FCNTM%d: 0x%08x: "
++ "Ch%d: %d, Ch%d: %d\n",
++ i + 1, reg0,
++ i * 2, (reg0 >> 0) & 0xffff, i * 2 + 1, (reg0 >> 16) & 0xffff);
++ }
++ for (i = 0; i < 2; i++) {
++ reg0 = ioread32(priv->base + RCAR_CSI2_LCNTM(i));
++
++ printk("LCNTM%d: 0x%08x: "
++ "Ch%d: %d, Ch%d: %d\n",
++ i + 1, reg0,
++ i * 2, (reg0 >> 0) & 0xffff, i * 2 + 1, (reg0 >> 16) & 0xffff);
++ }
++ for (i = 0; i < 2; i++) {
++ reg0 = ioread32(priv->base + RCAR_CSI2_LCNT(i));
++
++ printk("LCNT%d: 0x%04x, 0x%04x\n",
++ i + 1, (reg0 >> 0) & 0xffff, (reg0 >> 16));
++ }
+
+ for (i = 0; i < 4; i++) {
+ reg0 = ioread32(priv->base + RCAR_CSI2_PHxM0(i));
+@@ -324,7 +344,7 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv)
+ for (i = 0; i < 3; i++) {
+ reg0 = ioread32(priv->base + RCAR_CSI2_PHRM(i));
+
+- printk("Packet header R %d dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n",
++ printk("Packet Header R Monitor Register %d dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n",
+ i,
+ reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff,
+ (reg0 >> 24) & 0xff);
+@@ -332,21 +352,36 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv)
+ for (i = 0; i < 2; i++) {
+ reg0 = ioread32(priv->base + RCAR_CSI2_PHCM(i));
+
+- printk("Packet header C %d: dt: 0x%02x, vc: %d, wc: %d, cal_parity: 0x%02x\n",
++ printk("Packet Header C Monitor Register %d: dt: 0x%02x, vc: %d, wc: %d, cal_parity: 0x%02x\n",
+ i,
+ reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff,
+ (reg0 >> 24) & 0xff);
+ }
+ for (i = 0; i < 8; i++) {
+ reg0 = ioread32(priv->base + RCAR_CSI2_PHM(i));
++ reg1 = ioread32(priv->base + RCAR_CSI2_PPM(i));
+
+- printk("Packet header Monitor %d: dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x\n",
+- i + 1,
++ printk("Packet Header Monitor Register %d: dt: 0x%02x, vc: %d, wc: %d, ecc: 0x%02x (period = 0x%08x)\n",
++ i,
+ reg0 & 0x3F, (reg0 >> 6) & 0x03, (reg0 >> 8) & 0xffff,
+- (reg0 >> 24) & 0xff);
++ (reg0 >> 24) & 0xff,
++ reg1);
+ }
+- for (i = 0; i < 3; i++)
+- printk("VINSM%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_VINSM(i)));
++ for (i = 0; i < 2; i++) {
++ reg0 = ioread32(priv->base + RCAR_CSI2_VINSM(i));
++
++ printk("VINSM%d: 0x%08x: "
++ "HD%d: %d, VD%d: %d, HD%d: %d, VD%d: %d\n",
++ i, reg0,
++ 2 * i, (reg0 >> 0) & 0x0fff, 2* i, (reg0 >> 12) & 0x000f,
++ 2 * i + 1, (reg0 >> 16) & 0x0fff, 2 * i + 1, (reg0 >> 28) & 0x000f);
++ }
++ reg0 = ioread32(priv->base + RCAR_CSI2_VINSM(2));
++ printk("VINSM3: 0x%08x: "
++ "PE: %d, PEB: %x, FLD: %x, TAG: %x, ERRC: %x, ERRE: %x\n",
++ reg0,
++ (reg0 >> 0) & 0x01, (reg0 >> 4) & 0x0f, (reg0 >> 8) & 0x0f, (reg0 >> 10) & 0x03,
++ (reg0 >> 14) & 0x01, (reg0 >> 15) & 0x01);
+ printk("SERCCNT: %d\n",
+ ioread32(priv->base + RCAR_CSI2_SERCCNT));
+ printk("SSERCCNT: %d\n",
+@@ -357,10 +392,6 @@ static void rcar_sci2_debug_show(struct rcar_csi2 *priv)
+ ioread32(priv->base + RCAR_CSI2_ECECM));
+ printk("CRCECM: %d\n",
+ ioread32(priv->base + RCAR_CSI2_CRCECM));
+- for (i = 0; i < 2; i++)
+- printk("LCNT%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_LCNT(i)));
+- for (i = 0; i < 2; i++)
+- printk("LCNTM%d: 0x%08x\n", i, ioread32(priv->base + RCAR_CSI2_LCNTM(i)));
+ }
+
+ static int rcar_csi2_set_phy_freq(struct rcar_csi2 *priv)
+@@ -669,6 +700,26 @@ static struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
+ .core = &rcar_csi2_subdev_core_ops,
+ };
+
++static ssize_t rcar_csi2_dump_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ u32 val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ dump = !!val;
++
++ return count;
++}
++
++static ssize_t rcar_csi2_dump_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, 4, "%d\n", dump);
++}
++
++static DEVICE_ATTR(dump, S_IRUGO|S_IWUSR, rcar_csi2_dump_show, rcar_csi2_dump_store);
++
+ #ifdef CONFIG_OF
+ static const struct of_device_id rcar_csi2_of_table[] = {
+ { .compatible = "renesas,r8a77980-csi2", .data = (void *)RCAR_GEN3 },
+@@ -832,6 +883,9 @@ static int rcar_csi2_probe(struct platform_device *pdev)
+
+ pm_runtime_enable(&pdev->dev);
+
++ if (device_create_file(&pdev->dev, &dev_attr_dump) != 0)
++ dev_err(&pdev->dev, "sysfs dump entry creation failed\n");
++
+ dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+ return 0;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch
new file mode 100644
index 00000000..b95f9cc6
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch
@@ -0,0 +1,135 @@
+From a7032bf42a9e8452ac2bc01a5bed0775ce80d4b3 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 11:33:26 +0300
+Subject: [PATCH] media: platform: soc_camera: rcar_vin: add max96712, max9296
+
+This adds MAX96712 and MAX9296 deserializers in VIN binding
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/platform/soc_camera/rcar_vin.c | 75 ++++++++++------------------
+ 1 file changed, 27 insertions(+), 48 deletions(-)
+
+diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
+index 93bc1e4..564c371 100644
+--- a/drivers/media/platform/soc_camera/rcar_vin.c
++++ b/drivers/media/platform/soc_camera/rcar_vin.c
+@@ -880,6 +880,14 @@ enum rcar_vin_state {
+ STOPPING,
+ };
+
++static const char *deser_names[] = {
++ "max9286",
++ "ti9x4",
++ "max9288",
++ "max9296",
++ "max96712"
++};
++
+ struct rcar_vin_async_client {
+ struct v4l2_async_subdev *sensor;
+ struct v4l2_async_notifier notifier;
+@@ -1571,23 +1579,15 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev)
+
+ static struct v4l2_subdev *find_deser(struct rcar_vin_priv *pcdev)
+ {
++ int i;
+ struct v4l2_subdev *sd;
+- char name[] = "max9286";
+- char name2[] = "ti9x4";
+- char name3[] = "max9288";
+
+ v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) {
+- if (!strncmp(name, sd->name, sizeof(name) - 1)) {
+- pcdev->deser_sd = sd;
+- return sd;
+- }
+- if (!strncmp(name2, sd->name, sizeof(name2) - 1)) {
+- pcdev->deser_sd = sd;
+- return sd;
+- }
+- if (!strncmp(name3, sd->name, sizeof(name3) - 1)) {
+- pcdev->deser_sd = sd;
+- return sd;
++ for (i = 0; i < ARRAY_SIZE(deser_names); i++) {
++ if (!strncmp(deser_names[i], sd->name, strlen(deser_names[i]))) {
++ pcdev->deser_sd = sd;
++ return sd;
++ }
+ }
+ }
+
+@@ -3054,13 +3054,11 @@ static int rcar_vin_probe(struct platform_device *pdev)
+ unsigned int pdata_flags;
+ int irq, ret;
+ const char *str;
+- unsigned int i;
++ unsigned int i, j;
+ struct device_node *epn = NULL, *ren = NULL;
+- struct device_node *csi2_ren = NULL, *max9286_ren = NULL, *ti9x4_ren = NULL, *max9288_ren = NULL;
++ struct device_node *csi2_ren = NULL;
++ struct device_node *deser_ren[ARRAY_SIZE(deser_names)] = {NULL};
+ bool csi_use = false;
+- bool max9286_use = false;
+- bool ti9x4_use = false;
+- bool max9288_use = false;
+
+ match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
+
+@@ -3092,19 +3090,10 @@ static int rcar_vin_probe(struct platform_device *pdev)
+ csi_use = true;
+ }
+
+- if (strcmp(ren->parent->name, "max9286") == 0) {
+- max9286_ren = of_parse_phandle(epn, "remote-endpoint", 0);
+- max9286_use = true;
+- }
+-
+- if (strcmp(ren->parent->name, "ti9x4") == 0) {
+- ti9x4_ren = of_parse_phandle(epn, "remote-endpoint", 0);
+- ti9x4_use = true;
+- }
+-
+- if (strcmp(ren->parent->name, "max9288") == 0) {
+- max9288_ren = of_parse_phandle(epn, "remote-endpoint", 0);
+- max9288_use = true;
++ for (j = 0; j < ARRAY_SIZE(deser_names); j++) {
++ if (strcmp(ren->parent->name, deser_names[j]) == 0) {
++ deser_ren[j] = of_parse_phandle(epn, "remote-endpoint", 0);
++ }
+ }
+
+ of_node_put(ren);
+@@ -3372,22 +3361,12 @@ static int rcar_vin_probe(struct platform_device *pdev)
+ goto cleanup;
+ }
+
+- if (max9286_use) {
+- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, max9286_ren);
+- if (ret)
+- goto cleanup;
+- }
+-
+- if (ti9x4_use) {
+- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ti9x4_ren);
+- if (ret)
+- goto cleanup;
+- }
+-
+- if (max9288_use) {
+- ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, max9288_ren);
+- if (ret)
+- goto cleanup;
++ for (j = 0; j < ARRAY_SIZE(deser_names); j++) {
++ if (deser_ren[j]) {
++ ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, deser_ren[j]);
++ if (ret)
++ goto cleanup;
++ }
+ }
+
+ vin_debug = 0;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch
new file mode 100644
index 00000000..6e1a3e8f
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0499-regulator-add-MAX2008X-camera-protector.patch
@@ -0,0 +1,579 @@
+From 7cbcf44f887641e2d15b9b15c5aadd1850bc63ed Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 11:51:14 +0300
+Subject: [PATCH] regulator: add MAX2008X camera protector
+
+This adds MAX20086-MAX20089 camera protector regulator
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/regulator/Kconfig | 6 +
+ drivers/regulator/Makefile | 1 +
+ drivers/regulator/max2008x-regulator.c | 526 +++++++++++++++++++++++++++++++++
+ 3 files changed, 533 insertions(+)
+ create mode 100644 drivers/regulator/max2008x-regulator.c
+
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
+index 0fd6195..2ff9b57 100644
+--- a/drivers/regulator/Kconfig
++++ b/drivers/regulator/Kconfig
+@@ -495,6 +495,12 @@ config REGULATOR_MAX8998
+ via I2C bus. The provided regulator is suitable for S3C6410
+ and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
+
++config REGULATOR_MAX2008X
++ tristate "Maxim 20086-20089 Dual/Quad Camera Power Protector reguator"
++ help
++ This driver controls MAX20086-MAX20089 dual/quad camera power
++ protector IC.
++
+ config REGULATOR_MAX77686
+ tristate "Maxim 77686 regulator"
+ depends on MFD_MAX77686
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
+index 80ffc57..eb05d35 100644
+--- a/drivers/regulator/Makefile
++++ b/drivers/regulator/Makefile
+@@ -65,6 +65,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
+ obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
+ obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o
+ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
++obj-$(CONFIG_REGULATOR_MAX2008X) += max2008x-regulator.o
+ obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
+ obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
+ obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
+diff --git a/drivers/regulator/max2008x-regulator.c b/drivers/regulator/max2008x-regulator.c
+new file mode 100644
+index 0000000..70f9fb3
+--- /dev/null
++++ b/drivers/regulator/max2008x-regulator.c
+@@ -0,0 +1,526 @@
++/*
++ * gpio-regulator.c
++ *
++ * Copyright 2019 Andrey Gusakov <andrey.gusakov@cogentembedded.com>
++ *
++ * based on gpio-regulator.c
++ *
++ * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
++ *
++ * 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 (at your option) any later version.
++ *
++ * This is useful for systems with mixed controllable and
++ * non-controllable regulators, as well as for allowing testing on
++ * systems with no controllable regulators.
++ */
++
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/mutex.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/driver.h>
++#include <linux/regulator/machine.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/iio/iio.h>
++#include <linux/regulator/of_regulator.h>
++#include <linux/regmap.h>
++
++/* Register definitions */
++#define REG_MASK 0x00
++#define REG_CONFIG 0x01
++#define REG_ID 0x02
++#define REG_STAT1 0x03
++/* 16 bit register: 0x04 + 0x05 */
++#define REG_STAT2 0x04
++/* ADC1..ADC4 */
++#define REG_ADC(n) (0x06 + ((n) & 0x03))
++
++#define REG_CONFIG_ADC_MUX_CUR 0x00
++#define REG_CONFIG_ADC_MUX_VOUT 0x40
++#define REG_CONFIG_ADC_MUX_MISC 0x80
++#define REG_CONFIG_ADC_MUX_MASK 0xc0
++
++struct max2008x_regulator_data {
++ int id;
++ const char *name;
++ struct regulator_init_data *init_data;
++ struct device_node *of_node;
++};
++
++struct max2008x_data {
++ struct regmap *regmap;
++ struct max2008x_regulator_data *regulators;
++ struct iio_dev *iio_dev;
++
++ unsigned char id;
++ unsigned char rev;
++ unsigned char num_regulators;
++
++ unsigned char adc_mux;
++};
++
++static int max2008x_set_adc_mux(struct max2008x_data *max, int mux)
++{
++ int ret;
++ unsigned int reg;
++
++ mux = mux & REG_CONFIG_ADC_MUX_MASK;
++ if (mux > REG_CONFIG_ADC_MUX_MISC)
++ return -EINVAL;
++
++ /* do we need this? or we can relay on regmap? */
++ if (mux == max->adc_mux)
++ return 0;
++
++ ret = regmap_write_bits(max->regmap, REG_CONFIG,
++ REG_CONFIG_ADC_MUX_MASK, mux);
++ if (ret)
++ return ret;
++
++ max->adc_mux = mux;
++
++ /* Read ADC1 register to clear ACC bit in STAT1 register */
++ ret = regmap_read(max->regmap, REG_ADC(0), &reg);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int max2008x_read_adc(struct max2008x_data *max, int channel, int *value)
++{
++ int ret;
++ int timeout = 100;
++ unsigned int reg;
++
++ /* shift 3:2 bits to 7:6 */
++ ret = max2008x_set_adc_mux(max, channel << 4);
++ if (ret)
++ return ret;
++
++ do {
++ ret = regmap_read(max->regmap, REG_STAT1, &reg);
++ if (ret)
++ return ret;
++ } while ((!(reg & BIT(4))) && (--timeout));
++
++ if (timeout <= 0)
++ return -ETIMEDOUT;
++
++ ret = regmap_read(max->regmap, REG_ADC(channel & 0x03), &reg);
++ if (ret)
++ return ret;
++ *value = reg;
++
++ return 0;
++}
++
++static int max2008x_get_voltage(struct regulator_dev *dev)
++{
++ int ret;
++ int value = 0;
++ struct max2008x_data *max = rdev_get_drvdata(dev);
++
++ /* voltage channels starts from 4 */
++ ret = max2008x_read_adc(max, dev->desc->id + 4, &value);
++ if (ret)
++ return ret;
++
++ /* in 70mV units */
++ return (value * 70000);
++}
++
++static struct regulator_ops max2008x_ops = {
++ .enable = regulator_enable_regmap,
++ .disable = regulator_disable_regmap,
++ .is_enabled = regulator_is_enabled_regmap,
++ .get_voltage = max2008x_get_voltage,
++};
++
++static struct of_regulator_match max2008x_matches[] = {
++ [0] = { .name = "SW0"},
++ [1] = { .name = "SW1"},
++ [2] = { .name = "SW2"},
++ [3] = { .name = "SW3"},
++};
++
++static int of_get_max2008x_pdata(struct device *dev,
++ struct max2008x_data *pdata)
++{
++ int matched, i;
++ struct device_node *np;
++ struct max2008x_regulator_data *regulator;
++
++ np = of_get_child_by_name(dev->of_node, "regulators");
++ if (!np) {
++ dev_err(dev, "missing 'regulators' subnode in DT\n");
++ return -EINVAL;
++ }
++
++ matched = of_regulator_match(dev, np, max2008x_matches,
++ pdata->num_regulators);
++ of_node_put(np);
++ if (matched <= 0)
++ return matched;
++
++ pdata->regulators = devm_kzalloc(dev,
++ sizeof(struct max2008x_regulator_data) *
++ pdata->num_regulators, GFP_KERNEL);
++ if (!pdata->regulators)
++ return -ENOMEM;
++
++ regulator = pdata->regulators;
++
++ for (i = 0; i < pdata->num_regulators; i++) {
++ regulator->id = i;
++ regulator->name = max2008x_matches[i].name;
++ regulator->init_data = max2008x_matches[i].init_data;
++ regulator->of_node = max2008x_matches[i].of_node;
++ regulator++;
++ }
++
++ return 0;
++}
++
++static struct max2008x_regulator_data *max2008x_get_regulator_data(
++ int id, struct max2008x_data *data)
++{
++ int i;
++
++ if (!data)
++ return NULL;
++
++ for (i = 0; i < data->num_regulators; i++) {
++ if (data->regulators[i].id == id)
++ return &data->regulators[i];
++ }
++
++ return NULL;
++}
++
++#define MAX2008X_REG(_name, _id, _supply) \
++ { \
++ .name = _name, \
++ .supply_name = _supply, \
++ .id = _id, \
++ .type = REGULATOR_VOLTAGE, \
++ .ops = &max2008x_ops, \
++ .enable_reg = REG_CONFIG, \
++ .enable_mask = BIT(_id), \
++ .owner = THIS_MODULE, \
++ }
++
++static const struct regulator_desc max2008x_regulators[] = {
++ MAX2008X_REG("SW0", 0, "out0"),
++ MAX2008X_REG("SW1", 1, "out1"),
++ MAX2008X_REG("SW2", 2, "out2"),
++ MAX2008X_REG("SW3", 3, "out3"),
++};
++
++static const char *max2008x_devnames[] = {
++ "max20089",
++ "max20088",
++ "max20087",
++ "max20086"
++};
++
++static int max2008x_adc_read_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int *val, int *val2, long mask)
++{
++ int ret;
++ struct max2008x_data *max = iio_device_get_drvdata(indio_dev);
++
++ switch (mask) {
++ case IIO_CHAN_INFO_RAW:
++ ret = iio_device_claim_direct_mode(indio_dev);
++ if (ret)
++ return ret;
++
++ ret = max2008x_read_adc(max, chan->channel, val);
++ iio_device_release_direct_mode(indio_dev);
++
++ if (ret)
++ return ret;
++
++ return IIO_VAL_INT;
++ case IIO_CHAN_INFO_SCALE:
++ if (chan->type == IIO_VOLTAGE) {
++ /* Vout1..Vout4 and Vin */
++ if (chan->channel <= 8)
++ *val = 70;
++ /* Vdd */
++ else if (chan->channel == 9)
++ *val = 25;
++ /* Viset */
++ else
++ *val = 5;
++ } else if (chan->type == IIO_CURRENT) {
++ *val = 3;
++ *val2 = 0;
++ }
++
++ return IIO_VAL_INT;
++ }
++
++ return 0;
++}
++
++#define MAX2008X_ADC_C_CHAN(_chan, _addr, _name) { \
++ .type = IIO_CURRENT, \
++ .indexed = 1, \
++ .address = _addr, \
++ .channel = _chan, \
++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
++ BIT(IIO_CHAN_INFO_SCALE), \
++ .scan_index = _addr, \
++ .scan_type = { \
++ .sign = 'u', \
++ .realbits = 8, \
++ .storagebits = 8, \
++ .endianness = IIO_CPU, \
++ }, \
++ .datasheet_name = _name, \
++}
++
++#define MAX2008X_ADC_V_CHAN(_chan, _addr, _name) { \
++ .type = IIO_VOLTAGE, \
++ .indexed = 1, \
++ .address = _addr, \
++ .channel = _chan, \
++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
++ BIT(IIO_CHAN_INFO_SCALE), \
++ .scan_index = _addr, \
++ .scan_type = { \
++ .sign = 'u', \
++ .realbits = 8, \
++ .storagebits = 8, \
++ .endianness = IIO_CPU, \
++ }, \
++ .datasheet_name = _name, \
++}
++
++static const struct iio_chan_spec max2008x_adc_channels[] =
++{
++ MAX2008X_ADC_C_CHAN( 0, 0, "out0"),
++ MAX2008X_ADC_C_CHAN( 1, 1, "out1"),
++ MAX2008X_ADC_C_CHAN( 2, 2, "out2"),
++ MAX2008X_ADC_C_CHAN( 3, 3, "out3"),
++ MAX2008X_ADC_V_CHAN( 4, 4, "out0"),
++ MAX2008X_ADC_V_CHAN( 5, 5, "out1"),
++ MAX2008X_ADC_V_CHAN( 6, 6, "out2"),
++ MAX2008X_ADC_V_CHAN( 7, 7, "out3"),
++ MAX2008X_ADC_V_CHAN( 8, 8, "Vin"),
++ MAX2008X_ADC_V_CHAN( 9, 9, "Vdd"),
++ MAX2008X_ADC_V_CHAN(10, 10, "Viset"),
++};
++
++static const struct iio_info max2008x_adc_info = {
++ .driver_module = THIS_MODULE,
++ .read_raw = max2008x_adc_read_raw,
++};
++
++#if defined(CONFIG_OF)
++static const struct of_device_id max2008x_of_match[] = {
++ { .compatible = "maxim,max2008x" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max2008x_of_match);
++#endif
++
++
++static const struct regmap_range max2008x_reg_ranges[] = {
++ regmap_reg_range(REG_MASK, REG_ADC(3)),
++};
++
++static const struct regmap_range max2008x_reg_ro_ranges[] = {
++ regmap_reg_range(REG_ID, REG_ADC(3)),
++};
++
++static const struct regmap_range max2008x_reg_volatile_ranges[] = {
++ regmap_reg_range(REG_STAT1, REG_ADC(3)),
++};
++
++static const struct regmap_access_table max2008x_write_ranges_table = {
++ .yes_ranges = max2008x_reg_ranges,
++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_ranges),
++ .no_ranges = max2008x_reg_ro_ranges,
++ .n_no_ranges = ARRAY_SIZE(max2008x_reg_ro_ranges),
++};
++
++static const struct regmap_access_table max2008x_read_ranges_table = {
++ .yes_ranges = max2008x_reg_ranges,
++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_ranges),
++};
++
++static const struct regmap_access_table max2008x_volatile_ranges_table = {
++ .yes_ranges = max2008x_reg_volatile_ranges,
++ .n_yes_ranges = ARRAY_SIZE(max2008x_reg_volatile_ranges),
++};
++
++static const struct regmap_config max2008x_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = REG_ADC(3),
++ .wr_table = &max2008x_write_ranges_table,
++ .rd_table = &max2008x_read_ranges_table,
++ .volatile_table = &max2008x_volatile_ranges_table,
++};
++
++static int max2008x_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct device *dev = &client->dev;
++ struct device_node *np = dev->of_node;
++ struct max2008x_data *max;
++ struct gpio_desc *enable_gpio;
++ unsigned int reg;
++ int i, ret;
++
++ max = devm_kzalloc(&client->dev, sizeof(struct max2008x_data),
++ GFP_KERNEL);
++ if (max == NULL)
++ return -ENOMEM;
++
++ enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
++
++ /* regmap */
++ max->regmap = devm_regmap_init_i2c(client, &max2008x_regmap_config);
++ if (IS_ERR(max->regmap)) {
++ ret = PTR_ERR(max->regmap);
++ dev_err(&client->dev,
++ "regmap allocation failed with err %d\n", ret);
++ return ret;
++ }
++ i2c_set_clientdata(client, max);
++
++ ret = regmap_read(max->regmap, REG_ID, &reg);
++ if (ret)
++ return ret;
++
++ max->id = (reg >> 4) & 0x03;
++ max->rev = reg & 0x0f;
++ /* MAX20086 and MAX20087 have 4 outputs */
++ max->num_regulators = ((max->id == 0x2) || (max->id == 0x3)) ? 4 : 2;
++
++ /* Disable all */
++ ret = regmap_write_bits(max->regmap, REG_CONFIG, BIT(max->num_regulators) - 1, 0x00);
++ if (ret)
++ return ret;
++
++ /* to update mux on first access */
++ max->adc_mux = 0xff;
++
++ /* set autoconvertion mode for ADC */
++ ret = regmap_write_bits(max->regmap, REG_CONFIG, BIT(5), BIT(5));
++ if (ret)
++ return ret;
++
++ dev_info(&client->dev, "%s rev %d found (%d channels)\n",
++ max2008x_devnames[max->id], max->rev, max->num_regulators);
++
++ if (np) {
++ ret = of_get_max2008x_pdata(&client->dev, max);
++ if (ret) {
++ dev_err(&client->dev,
++ "dt parse error %d\n", ret);
++ return ret;
++ }
++ }
++
++ /* Finally register devices */
++ for (i = 0; i < max->num_regulators; i++) {
++ const struct regulator_desc *desc = &max2008x_regulators[i];
++ struct regulator_config config = { };
++ struct max2008x_regulator_data *rdata;
++ struct regulator_dev *rdev;
++
++ config.dev = dev;
++ config.driver_data = max;
++ config.regmap = max->regmap;
++
++ rdata = max2008x_get_regulator_data(desc->id, max);
++ if (rdata) {
++ config.init_data = rdata->init_data;
++ config.of_node = rdata->of_node;
++ }
++
++ rdev = devm_regulator_register(dev, desc, &config);
++ if (IS_ERR(rdev)) {
++ dev_err(dev, "failed to register %s\n", desc->name);
++ return PTR_ERR(rdev);
++ }
++ }
++
++ /* IIO device */
++ max->iio_dev = devm_iio_device_alloc(dev, 0);
++ if (!max->iio_dev)
++ return -ENOMEM;
++
++ max->iio_dev->info = &max2008x_adc_info;
++ max->iio_dev->dev.parent = dev;
++ max->iio_dev->dev.of_node = dev->of_node;
++ max->iio_dev->name = "max2008x-adc";
++ max->iio_dev->modes = INDIO_DIRECT_MODE;
++
++ max->iio_dev->channels = max2008x_adc_channels;
++ /* only ASIL can measure voltages */
++ if ((max->id == 0x00) || (max->id == 0x02))
++ max->iio_dev->num_channels = ARRAY_SIZE(max2008x_adc_channels);
++ else
++ max->iio_dev->num_channels = 4;
++
++ iio_device_set_drvdata(max->iio_dev, max);
++
++ ret = iio_device_register(max->iio_dev);
++ if (ret < 0) {
++ dev_err(&client->dev, "Failed to register IIO device: %d\n", ret);
++ return ret;
++ }
++
++ i2c_set_clientdata(client, max);
++
++ if (!IS_ERR(enable_gpio))
++ gpiod_set_value_cansleep(enable_gpio, 1);
++
++ return 0;
++}
++
++static const struct i2c_device_id max2008x_id[] = {
++ { "maxim,max2008x" },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max2008x_id);
++
++static struct i2c_driver max2008x_driver = {
++ .driver = {
++ .name = "max2008x",
++ .of_match_table = of_match_ptr(max2008x_of_match),
++ },
++ .probe = max2008x_probe,
++ .id_table = max2008x_id,
++};
++
++static int __init max2008x_init(void)
++{
++ return i2c_add_driver(&max2008x_driver);
++}
++subsys_initcall(max2008x_init);
++
++static void __exit max2008x_exit(void)
++{
++ i2c_del_driver(&max2008x_driver);
++}
++module_exit(max2008x_exit);
++
++MODULE_AUTHOR("Andrey Gusakov <andrey.gusakov@cogentembedded.com>");
++MODULE_DESCRIPTION("max2008x Dual/Quad Camera Power Protector");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:max2008x");
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch
new file mode 100644
index 00000000..4e58b2d8
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch
@@ -0,0 +1,1445 @@
+From bcba64742b957d8a6f7303abf05c4e586522c89b Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 18:53:42 +0300
+Subject: [PATCH] arm64: dts: renesas: add V3H GMSL2 Videoboxes
+
+This adds Quad and Dual GMSL Videoboxes on V3H
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/Makefile | 2 +
+ .../dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 717 +++++++++++++++++++++
+ .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 683 ++++++++++++++++++++
+ 3 files changed, 1402 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index 89da50c..a1373ba 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -43,6 +43,8 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v2.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb
++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-2x2.dtb
++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-4.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+new file mode 100644
+index 0000000..155b73f
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+@@ -0,0 +1,717 @@
++/*
++ * Device Tree Source for the V3HSK Videobox Mini board on r8a7798
++ *
++ * Copyright (C) 2018 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk.dts"
++#include <dt-bindings/gpio/gpio.h>
++/* FDPLink output */
++//#include "vb-fdplink-output.dtsi"
++
++#define COMPATIBLE_CAMERAS \
++"onsemi,ar0140", \
++"onsemi,ar0143", \
++"onsemi,ar0147", \
++"onsemi,ar0231", \
++"onsemi,ar0233", \
++"onsemi,ap0101", \
++"onsemi,ap0201", \
++"ovti,ov10635", \
++"ovti,ov10640", \
++"ovti,ov2311", \
++"ovti,ov2775", \
++"ovti,ov490", \
++"ovti,ov495", \
++"ovti,ox01d10", \
++"ovti,ox03a", \
++"sony,imx390", \
++"sony,isx016", \
++"sony,isx019", \
++"dummy,camera"
++
++/ {
++ model = "Renesas V3HSK 2x2ch GMSL2 Videobox board based on r8a7798";
++
++ aliases {
++ serial1 = &scif3;
++ ethernet1 = &avb;
++ };
++
++ cs2300_ref_clk: cs2300_ref_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <25000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led0 {
++ label = "board:status";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "none";
++ };
++ };
++
++ mpcie_1v8: regulator2 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ mpcie_3v3: regulator3 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ common_3v3: regulator4 {
++ compatible = "regulator-fixed";
++ regulator-name = "main 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ regulator_poc_0: regulator-poc-0 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "POC 0";
++ regulator-min-microvolt = <9000000>;
++ regulator-max-microvolt = <9000000>;
++ startup-delay-us = <50>;
++
++ gpio = <&gpio_exp_ch0 10 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ regulator_poc_1: regulator-poc-1 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "POC 1";
++ regulator-min-microvolt = <9000000>;
++ regulator-max-microvolt = <9000000>;
++ startup-delay-us = <50>;
++
++ gpio = <&gpio_exp_ch0 11 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ regulator_poc_2: regulator-poc-2 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "POC 2";
++ regulator-min-microvolt = <9000000>;
++ regulator-max-microvolt = <9000000>;
++ startup-delay-us = <50>;
++
++ gpio = <&gpio_exp_ch0 14 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ regulator_poc_3: regulator-poc-3 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "POC 3";
++ regulator-min-microvolt = <9000000>;
++ regulator-max-microvolt = <9000000>;
++ startup-delay-us = <50>;
++
++ gpio = <&gpio_exp_ch0 15 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++};
++
++&canfd {
++ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++&avb {
++ pinctrl-0 = <&avb_pins>;
++ pinctrl-names = "default";
++ renesas,no-ether-link;
++ phy-handle = <&avb_phy0>;
++ status = "okay";
++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>;
++
++ avb_phy0: eavb-phy@0 {
++ rxc-skew-ps = <1500>;
++ rxdv-skew-ps = <420>; /* default */
++ rxd0-skew-ps = <420>; /* default */
++ rxd1-skew-ps = <420>; /* default */
++ rxd2-skew-ps = <420>; /* default */
++ rxd3-skew-ps = <420>; /* default */
++ txc-skew-ps = <900>; /* default */
++ txen-skew-ps = <420>; /* default */
++ txd0-skew-ps = <420>; /* default */
++ txd1-skew-ps = <420>; /* default */
++ txd2-skew-ps = <420>; /* default */
++ txd3-skew-ps = <420>; /* default */
++ reg = <3>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++ max-speed = <1000>;
++ };
++};
++
++&csi40 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi40_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <1200>;
++ };
++ };
++};
++
++&csi41 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi41_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <1200>;
++ };
++ };
++};
++
++&i2c1 {
++ pinctrl-0 = <&i2c1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ clock-frequency = <400000>;
++
++ i2cswitch1: i2c-switch@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
++
++ /* CCTRL_SDA and CCTRL_SCL */
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ gpio_exp_ch0: gpio_ch0@76 {
++ compatible = "nxp,pca9539";
++ reg = <0x76>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ cmr_pwr_en {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CmrPEn";
++ };
++ };
++
++ /* CS2300 node @0x4e */
++ cs2300: clk_multiplier@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam: dac_vcam@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ vdd-supply = <&common_3v3>;
++ };
++ };
++
++ /* DS0_SDA and DS0_SCL */
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ max9296@48 {
++ compatible = "maxim,max9296";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x48>;
++ clocks = <&cs2300>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>;
++
++ maxim,link-mipi-map = <1 1>;
++
++ poc0-supply = <&regulator_poc_0>;
++ poc1-supply = <&regulator_poc_1>;
++
++ port@0 {
++ max9296_des0ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in0>;
++ };
++ max9296_des0ep1: endpoint@1 {
++ ser-addr = <0x0d>;
++ remote-endpoint = <&camera_in1>;
++ };
++ };
++
++ port@1 {
++ max9296_des0mipi1: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@60 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ camera_max9296_des0ep0: endpoint@1 {
++ remote-endpoint = <&max9296_des0ep0>;
++ };
++ };
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@61 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0d>;
++
++ port@0 {
++ camera_in1: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin1ep0>;
++ };
++ };
++ port@1 {
++ camera_max9296_des0ep1: endpoint@1 {
++ remote-endpoint = <&max9296_des0ep1>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* DS1_SDA and DS1_SCL */
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ max9296@48 {
++ compatible = "maxim,max9296";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x48>;
++ clocks = <&cs2300>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_ch0 0 GPIO_ACTIVE_LOW>;
++
++ maxim,link-mipi-map = <1 1>;
++
++ poc0-supply = <&regulator_poc_2>;
++ poc1-supply = <&regulator_poc_3>;
++
++ port@0 {
++ max9296_des1ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in2>;
++ };
++ max9296_des1ep1: endpoint@1 {
++ ser-addr = <0x51>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++
++ port@1 {
++ max9296_des1mipi1: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@60 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in2: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin4ep0>;
++ };
++ };
++ port@1 {
++ camera_max9296_des1ep0: endpoint@1 {
++ remote-endpoint = <&max9296_des1ep0>;
++ };
++ };
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@61 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0c>;
++
++ port@0 {
++ camera_in3: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin5ep0>;
++ };
++ };
++ port@1 {
++ camera_max9296_des1ep1: endpoint@1 {
++ remote-endpoint = <&max9296_des1ep1>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* Disp_SDA and Disp_SCL */
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++
++ /* fan node - lm96063 */
++ fan_ctrl: lm96063@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ /* ESDA and ESCL */
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++
++ /* ext connector nodes here */
++ };
++ };
++};
++
++&gpio0 {
++ fpdl_shdn {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "FPDL_SHDN";
++ };
++
++ cam_pwr_en {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIPWR_En";
++ };
++
++ wake_pin_8 {
++ gpio-hog;
++ gpios = <0 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 8";
++ };
++};
++
++&gpio1 {
++ md_buf_en {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CPLD_If_En";
++ };
++};
++
++&gpio2 {
++ m2_rst {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 RST#";
++ };
++
++ cctrl_rstn {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CCTRL_RSTn";
++ };
++
++ can0_stby {
++ gpio-hog;
++ gpios = <27 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN0STBY";
++ };
++
++ can1_load {
++ gpio-hog;
++ gpios = <29 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1Loff";
++ };
++
++ can1_stby {
++ gpio-hog;
++ gpios = <22 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1STBY";
++ };
++
++ wake_pin_7 {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 7";
++ };
++
++ vi1_gpioext_rst {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP1_RST";
++ };
++};
++
++&gpio3 {
++ vi0_gpioext_rst {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP0_RST";
++ };
++};
++
++&pcie_bus_clk {
++ clock-frequency = <100000000>;
++ status = "okay";
++};
++
++&pciec {
++ pcie3v3-supply = <&mpcie_3v3>;
++ pcie1v8-supply = <&mpcie_1v8>;
++ status = "okay";
++};
++
++&pcie_phy {
++ status = "okay";
++};
++
++&pfc {
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data_a";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ avb_pins: avb {
++ groups = "avb_mdio", "avb_rgmii";
++ function = "avb";
++ };
++
++ i2c1_pins: i2c1 {
++ groups = "i2c1";
++ function = "i2c1";
++ };
++
++ scif3_pins: scif3 {
++ groups = "scif3_data";
++ function = "scif3";
++ };
++};
++
++&scif3 {
++ pinctrl-0 = <&scif3_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&tpu {
++ status = "disabled";
++};
++
++&vin0 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin0ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in0>;
++ };
++ };
++ port@1 {
++ csi0ep0: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin0_max9296_des0ep0: endpoint@1 {
++ remote-endpoint = <&max9296_des0ep0>;
++ };
++ };
++ };
++};
++
++&vin1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin1ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in1>;
++ };
++ };
++ port@1 {
++ csi0ep1: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin1_max9296_des0ep1: endpoint@1 {
++ remote-endpoint = <&max9296_des0ep1>;
++ };
++ };
++ };
++};
++
++&vin4 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin4ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in2>;
++ };
++ };
++ port@1 {
++ csi1ep0: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin4_max9296_des1ep0: endpoint@1 {
++ remote-endpoint = <&max9296_des1ep0>;
++ };
++ };
++ };
++};
++
++&vin5 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin5ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++ port@1 {
++ csi1ep1: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin5_max9296_des1ep1: endpoint@1 {
++ remote-endpoint = <&max9296_des1ep1>;
++ };
++ };
++ };
++};
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+new file mode 100644
+index 0000000..310061f
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+@@ -0,0 +1,683 @@
++/*
++ * Device Tree Source for the V3HSK GMSL2 Quad Videobox Mini board on r8a7798
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk.dts"
++#include <dt-bindings/gpio/gpio.h>
++/* FDPLink output */
++//#include "vb-fdplink-output.dtsi"
++
++#define COMPATIBLE_CAMERAS \
++"onsemi,ar0140", \
++"onsemi,ar0143", \
++"onsemi,ar0147", \
++"onsemi,ar0231", \
++"onsemi,ar0233", \
++"onsemi,ap0101", \
++"onsemi,ap0201", \
++"ovti,ov10635", \
++"ovti,ov10640", \
++"ovti,ov2311", \
++"ovti,ov2775", \
++"ovti,ov490", \
++"ovti,ov495", \
++"ovti,ox01d10", \
++"ovti,ox03a", \
++"sony,imx390", \
++"sony,isx016", \
++"sony,isx019", \
++"dummy,camera"
++
++/ {
++ model = "Renesas V3HSK 4ch GMSL2 Videobox board based on r8a77980";
++
++ aliases {
++ serial1 = &scif3;
++ ethernet1 = &avb;
++ };
++
++ cs2300_ref_clk: cs2300_ref_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <25000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led0 {
++ label = "board:status";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "none";
++ };
++ };
++
++ mpcie_1v8: regulator2 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ mpcie_3v3: regulator3 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ common_3v3: regulator4 {
++ compatible = "regulator-fixed";
++ regulator-name = "main 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ iio_hwmon: hwmon@1 {
++ compatible = "iio-hwmon";
++ io-channels =
++ /* current */
++ <&max2008x 0>,
++ <&max2008x 2>,
++ /* voltage */
++ <&max2008x 4>,
++ <&max2008x 6>,
++ /* misc voltages */
++ <&max2008x 8>,
++ <&max2008x 9>;
++ io-channel-names =
++ "camera-0-Iout",
++ "camera-1-Iout",
++ "camera-0-Vout",
++ "camera-1-Vout",
++ "cameras-Vregulator",
++ "cameras-3v3";
++ };
++};
++
++&canfd {
++ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++&avb {
++ pinctrl-0 = <&avb_pins>;
++ pinctrl-names = "default";
++ renesas,no-ether-link;
++ phy-handle = <&avb_phy0>;
++ status = "okay";
++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>;
++
++ avb_phy0: eavb-phy@0 {
++ rxc-skew-ps = <1500>;
++ rxdv-skew-ps = <420>; /* default */
++ rxd0-skew-ps = <420>; /* default */
++ rxd1-skew-ps = <420>; /* default */
++ rxd2-skew-ps = <420>; /* default */
++ rxd3-skew-ps = <420>; /* default */
++ txc-skew-ps = <900>; /* default */
++ txen-skew-ps = <420>; /* default */
++ txd0-skew-ps = <420>; /* default */
++ txd1-skew-ps = <420>; /* default */
++ txd2-skew-ps = <420>; /* default */
++ txd3-skew-ps = <420>; /* default */
++ reg = <3>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++ max-speed = <1000>;
++ };
++};
++
++&csi40 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi40_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <1200>;
++ };
++ };
++};
++
++&i2c1 {
++ pinctrl-0 = <&i2c1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ clock-frequency = <400000>;
++
++ i2cswitch1: i2c-switch@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
++
++ /* CCTRL_SDA and CCTRL_SCL */
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ gpio_exp_ch0: gpio_ch0@76 {
++ compatible = "nxp,pca9539";
++ reg = <0x76>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ cmr_pwr_en {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CmrPEn";
++ };
++ };
++
++ cs2300: clk_multiplier@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam: dac_vcam@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ vdd-supply = <&common_3v3>;
++ };
++
++ max2008x: vcam_switch@28 {
++ compatible = "maxim,max2008x";
++ reg = <0x28>;
++ #io-channel-cells = <1>;
++ enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>;
++
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ vdd_cam0: SW0 {
++ reg = <0>;
++ regulator-name = "Camera-0";
++ };
++ vdd_cam1: SW1 {
++ reg = <1>;
++ regulator-name = "Camera-1";
++ };
++ vdd_cam2: SW2 {
++ reg = <2>;
++ regulator-name = "Camera-2";
++ };
++ vdd_cam3: SW3 {
++ reg = <3>;
++ regulator-name = "Camera-3";
++ };
++ };
++ };
++ };
++
++ /* DS0_SDA and DS0_SCL */
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ max96712@29 {
++ compatible = "maxim,max96712";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x29>;
++ clocks = <&cs2300>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>;
++
++ maxim,links-mipi-map = <2 2 2 2>;
++
++ poc0-supply = <&vdd_cam3>;
++ poc1-supply = <&vdd_cam1>;
++ poc2-supply = <&vdd_cam0>;
++ poc3-supply = <&vdd_cam2>;
++
++ port@0 {
++ max96712_des0ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in0>;
++ };
++ max96712_des0ep1: endpoint@1 {
++ ser-addr = <0x0d>;
++ remote-endpoint = <&camera_in1>;
++ };
++ max96712_des0ep2: endpoint@2 {
++ ser-addr = <0x0e>;
++ remote-endpoint = <&camera_in2>;
++ };
++ max96712_des0ep3: endpoint@3 {
++ ser-addr = <0x0f>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++
++ port@1 {
++ max96712_mipi2: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@60 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@61 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0d>;
++
++ port@0 {
++ camera_in1: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin1ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++ };
++
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ camera@62 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x62 0x0e>;
++
++ port@0 {
++ camera_in2: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin2ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ camera@63 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x63 0x0f>;
++
++ port@0 {
++ camera_in3: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin3ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* CTL0_SDA and CTL0_SCL */
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ };
++
++ /* Disp_SDA and Disp_SCL */
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++
++ /* fan node - lm96063 */
++ fan_ctrl: lm96063@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ /* ESDA and ESCL */
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++
++ rtc: mcp79411@6f {
++ compatible = "microchip,mcp7941x";
++ reg = <0x6f>;
++ };
++ };
++ };
++};
++
++&gpio0 {
++ fpdl_shdn {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "FPDL_SHDN";
++ };
++
++ cam_pwr_en {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIPWR_En";
++ };
++
++ wake_pin_8 {
++ gpio-hog;
++ gpios = <0 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 8";
++ };
++};
++
++&gpio1 {
++ md_buf_en {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CPLD_If_En";
++ };
++};
++
++&gpio2 {
++ m2_rst {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 RST#";
++ };
++
++ cctrl_rstn {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CCTRL_RSTn";
++ };
++
++ can0_stby {
++ gpio-hog;
++ gpios = <27 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN0STBY";
++ };
++
++ can1_load {
++ gpio-hog;
++ gpios = <29 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1Loff";
++ };
++
++ can1_stby {
++ gpio-hog;
++ gpios = <22 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1STBY";
++ };
++
++ wake_pin_7 {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 7";
++ };
++
++ vi1_gpioext_rst {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP1_RST";
++ };
++};
++
++&gpio3 {
++ vi0_gpioext_rst {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP0_RST";
++ };
++};
++
++&pcie_bus_clk {
++ clock-frequency = <100000000>;
++ status = "okay";
++};
++
++&pciec {
++ pcie3v3-supply = <&mpcie_3v3>;
++ pcie1v8-supply = <&mpcie_1v8>;
++ status = "okay";
++};
++
++&pcie_phy {
++ status = "okay";
++};
++
++&pfc {
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data_a";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ avb_pins: avb {
++ groups = "avb_mdio", "avb_rgmii";
++ function = "avb";
++ };
++
++ i2c1_pins: i2c1 {
++ groups = "i2c1";
++ function = "i2c1";
++ };
++
++ scif3_pins: scif3 {
++ groups = "scif3_data";
++ function = "scif3";
++ };
++};
++
++&scif3 {
++ pinctrl-0 = <&scif3_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&tpu {
++ status = "disabled";
++};
++
++&vin0 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin0ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in0>;
++ };
++ };
++ port@1 {
++ csi1ep0: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin0_max96712_des0ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++};
++
++&vin1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin1ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in1>;
++ };
++ };
++ port@1 {
++ csi1ep1: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin1_max96712_des0ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++};
++
++&vin2 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin2ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in2>;
++ };
++ };
++ port@1 {
++ csi1ep2: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin2_max96712_des0ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++};
++
++&vin3 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin3ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++ port@1 {
++ csi1ep3: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin3_max96712_des0ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch
new file mode 100644
index 00000000..1d6af948
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch
@@ -0,0 +1,52 @@
+From 7bb14f5fe5ab6c00c48dc879767b3def79bcef17 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 18:55:09 +0300
+Subject: [PATCH] media: i2c: ap0101: fix fsin on AP0102
+
+AP0101 and AP0102 hav different FSIN setup
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/ap0101_ar014x.c | 9 ++++++++-
+ drivers/media/i2c/soc_camera/ap0101_ar014x.h | 8 ++++++++
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+index 8a2d2a6..55cff3f 100644
+--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.c
+@@ -477,7 +477,14 @@ static int ap0101_initialize(struct i2c_client *client)
+ priv->max_height = AP0101_MAX_HEIGHT;
+ #endif
+ /* Program wizard registers */
+- ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard));
++ switch (pid) {
++ case AP0101_VERSION_REG:
++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard));
++ break;
++ case AP0102_VERSION_REG:
++ ap0101_set_regs(client, ap0102_regs_wizard, ARRAY_SIZE(ap0102_regs_wizard));
++ break;
++ }
+ /* Read OTP IDs */
+ ap0101_otp_id_read(client);
+
+diff --git a/drivers/media/i2c/soc_camera/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/ap0101_ar014x.h
+index 16599a1..d72ebfe 100644
+--- a/drivers/media/i2c/soc_camera/ap0101_ar014x.h
++++ b/drivers/media/i2c/soc_camera/ap0101_ar014x.h
+@@ -26,3 +26,11 @@ static const struct ap0101_reg ap0101_regs_wizard[] = {
+ {0x0040, 0x8100},
+ {AP0101_DELAY, 100},
+ };
++
++static const struct ap0101_reg ap0102_regs_wizard[] = {
++/* enable FSIN */
++{0xc890, 0x0303},
++{0xfc00, 0x2800},
++{0x0040, 0x8100},
++{AP0101_DELAY, 100},
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch
new file mode 100644
index 00000000..6f1d59e0
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch
@@ -0,0 +1,189 @@
+From 73714bd64b9beb6af9a4e00b85a4d2e6d8933143 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 29 Apr 2020 01:27:08 +0300
+Subject: [PATCH 1/3] media: i2c: max96712: add MIPI GMSL2 support
+
+This adds MIPI stream from serializer
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/max9295.h | 10 ++++
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 75 ++++++++++++++++------------
+ drivers/media/i2c/soc_camera/gmsl/max96712.h | 6 +--
+ 3 files changed, 57 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9295.h b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+index cf12d3c..864c441 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9295.h
++++ b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+@@ -27,3 +27,13 @@
+ #define MAX9295_VIDEO_TX_BASE(n) (0x100 + (0x8 * n))
+ #define MAX9295_VIDEO_TX0(n) (MAX9295_VIDEO_TX_BASE(n) + 0)
+ #define MAX9295_VIDEO_TX1(n) (MAX9295_VIDEO_TX_BASE(n) + 1)
++
++#define MAX9295_FRONTTOP_0 0x308
++#define MAX9295_FRONTTOP_9 0x311
++#define MAX9295_FRONTTOP_12 0x314
++#define MAX9295_FRONTTOP_13 0x315
++
++#define MAX9295_MIPI_RX0 0x330
++#define MAX9295_MIPI_RX1 0x331
++#define MAX9295_MIPI_RX2 0x332
++#define MAX9295_MIPI_RX3 0x333
+\ No newline at end of file
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+index af5e1d7..02ccc38 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -94,7 +94,7 @@ static int gmsl = MODE_GMSL2;
+ module_param(gmsl, int, 0644);
+ MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
+
+-static char *mbus = "dvp";
++static char *mbus = mbus_default;
+ module_param(mbus, charp, 0644);
+ MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
+
+@@ -161,7 +161,7 @@ static void max96712_reset_oneshot(struct max96712_priv *priv, int mask)
+ if (!(reg & mask))
+ break;
+
+- msleep(1);
++ mdelay(1);
+ }
+
+ if (reg & mask)
+@@ -741,9 +741,12 @@ static int max96712_gmsl2_reverse_channel_setup(struct max96712_priv *priv, int
+ des_write(MAX96712_REG6, 0xf0 | BIT(link_n)); /* GMSL2 mode, enable GMSL link# */
+ max96712_reset_oneshot(priv, BIT(link_n));
+
+- /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
+- while ((!max96712_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
+- msleep(1);
++ /* wait the link to be established, indicated when status bit LOCKED goes high */
++ for (; timeout > 0; timeout--) {
++ if (max96712_gmsl2_get_link_lock(priv, link_n))
++ break;
++ mdelay(1);
++ }
+
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+@@ -781,36 +784,42 @@ static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int
+ struct max96712_link *link = priv->link[link_n];
+ int i;
+
+- //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
+- //msleep(100);
+- ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
+-
+ if (strcmp(priv->mbus, "dvp") == 0) {
+- ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
+ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
+ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
+ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
+- }
+-
+- ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
+
+- switch (priv->dt) {
+- case MIPI_DT_YUV8:
+- case MIPI_DT_RAW12:
+- /* setup crossbar: strait DVP mapping */
+- ser_write(MAX9295_CROSS(0), priv->cb[0]);
+- ser_write(MAX9295_CROSS(1), priv->cb[1]);
+- ser_write(MAX9295_CROSS(2), priv->cb[2]);
+- ser_write(MAX9295_CROSS(3), priv->cb[3]);
+- ser_write(MAX9295_CROSS(4), priv->cb[4]);
+- ser_write(MAX9295_CROSS(5), priv->cb[5]);
+- ser_write(MAX9295_CROSS(6), priv->cb[6]);
+- ser_write(MAX9295_CROSS(7), priv->cb[7]);
+- ser_write(MAX9295_CROSS(8), priv->cb[8]);
+- ser_write(MAX9295_CROSS(9), priv->cb[9]);
+- ser_write(MAX9295_CROSS(10), priv->cb[10]);
+- ser_write(MAX9295_CROSS(11), priv->cb[11]);
+- break;
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++ } else {
++ /* defaults:
++ * REG2 - video enable Pipex X,Z
++ * MIPI_RX0 - 1x4 mode (1-port x 4-lanes)
++ * MIPI_RX1 - 4-lanes
++ * MIPI_RX2, MIPI_RX3 - merge PHY1,PHY2 to 1x4-mode
++ * FRONTTOP_9 - start Pipes X,Z from CSI_A,CSI_B
++ */
++
++ ser_write(MAX9295_FRONTTOP_0, 0x71); /* enable Pipe X from from CSI_A,CSI_B */
++ ser_write(MAX9295_FRONTTOP_12, BIT(6) | priv->dt); /* primary DT for Pipe X */
++ ser_write(MAX9295_FRONTTOP_13, BIT(6) | MIPI_DT_EMB); /* secondary DT for Pipe X */
+ }
+
+ for (i = 0; i < 11; i++) {
+@@ -852,7 +861,9 @@ static struct {
+ } gmsl2_pipe_maps[] = {
+ {0x00, 0x00}, /* FS */
+ {0x01, 0x01}, /* FE */
+- {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8}, /* payload data */
++ {MIPI_DT_RAW8, MIPI_DT_RAW8},
++ {MIPI_DT_RAW12, MIPI_DT_RAW12},
+ };
+
+ static void max96712_gmsl2_pipe_set_source(struct max96712_priv *priv, int pipe, int phy, int in_pipe)
+@@ -1193,6 +1204,8 @@ static int max96712_parse_dt(struct i2c_client *client)
+ priv->gpio[7] = gpio7;
+ if (gpio8 >= 0)
+ priv->gpio[8] = gpio8;
++ if (strcmp(mbus, "dvp"))
++ priv->mbus = mbus;
+
+ /* parse serializer crossbar setup */
+ for (i = 0; i < 16; i++) {
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+index 2976027..b648bdc 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.h
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+@@ -236,11 +236,11 @@ static inline int max96712_ser_write(struct max96712_link *link, int reg, int va
+ return ret;
+ }
+
+-static inline int max96712_ser_read(struct max96712_link *link, int reg, u8 *val)
++static inline int max96712_ser_read(struct max96712_link *link, int reg, int *val)
+ {
+ int ret;
+
+- ret = regmap_read(link->regmap, reg, (int *)val);
++ ret = regmap_read(link->regmap, reg, val);
+ if (ret)
+ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
+
+@@ -258,6 +258,6 @@ static inline int max96712_ser_update_bits(struct max96712_link *link, int reg,
+ return ret;
+ }
+
+-#define ser_read(reg, val) max96712_ser_read(link, reg, val)
++#define ser_read(reg, val) max96712_ser_read(link, reg, (int *)val)
+ #define ser_write(reg, val) max96712_ser_write(link, reg, val)
+ #define ser_update_bits(reg, mask, bits) max96712_ser_update_bits(link, reg, mask, bits)
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch
new file mode 100644
index 00000000..478f36f2
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0503-media-i2c-ov2311-add-GMSL2-support.patch
@@ -0,0 +1,83 @@
+From fa1d9aeccd9d3244d48ded2dc9e9405aab949513 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 29 Apr 2020 01:28:16 +0300
+Subject: [PATCH] media: i2c: ov2311: add GMSL2 support
+
+This add GMSL2 camera with this imager
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/ov2311.c | 21 ++++++++++++++-------
+ drivers/media/i2c/soc_camera/imagers/ov2311.h | 2 +-
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+index ce4999b..764c261 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ov2311.c
++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+@@ -1,7 +1,7 @@
+ /*
+ * OmniVision ov2311 sensor camera driver
+ *
+- * Copyright (C) 2015-2019 Cogent Embedded, Inc.
++ * Copyright (C) 2015-2020 Cogent Embedded, Inc.
+ *
+ * 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
+@@ -25,8 +25,8 @@
+
+ #define OV2311_I2C_ADDR 0x60
+
+-#define OV2311_PID_REGA 0x300a
+-#define OV2311_PID_REGB 0x300b
++#define OV2311_PIDA_REG 0x300a
++#define OV2311_PIDB_REG 0x300b
+ #define OV2311_REV_REG 0x300c
+ #define OV2311_PID 0x2311
+
+@@ -397,9 +397,9 @@ static int ov2311_initialize(struct i2c_client *client)
+
+ setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2);
+
+- reg16_read(client, OV2311_PID_REGA, &val);
++ reg16_read(client, OV2311_PIDA_REG, &val);
+ pid = val;
+- reg16_read(client, OV2311_PID_REGB, &val);
++ reg16_read(client, OV2311_PIDB_REG, &val);
+ pid = (pid << 8) | val;
+
+ if (pid != OV2311_PID) {
+@@ -407,8 +407,15 @@ static int ov2311_initialize(struct i2c_client *client)
+ return -ENODEV;
+ }
+
+- if (get_des_id(client) == UB960_ID)
+- reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */
++ switch (get_des_id(client)) {
++ case UB960_ID:
++ reg8_write_addr(client, priv->ser_addr, 0x02, 0x13); /* MIPI 2-lanes */
++ break;
++ case MAX9296A_ID:
++ case MAX96712_ID:
++ reg16_write_addr(client, priv->ser_addr, MAX9295_MIPI_RX1, 0x11); /* MIPI 2-lanes */
++ break;
++ }
+
+ /* check revision */
+ reg16_read(client, OV2311_REV_REG, &rev);
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.h b/drivers/media/i2c/soc_camera/imagers/ov2311.h
+index 3a56b0b..f76662a 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ov2311.h
++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.h
+@@ -30,7 +30,7 @@ struct ov2311_reg {
+ u8 val;
+ };
+
+-/* R1600x1300 RAW10 MIPI 60fps */
++/* R1600x1300 RAW8 MIPI 60fps */
+ static const struct ov2311_reg ov2311_regs_wizard_r1c[] = {
+ {0x0103, 0x01},
+ {0x0100, 0x00},
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch
new file mode 100644
index 00000000..5301e0a3
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch
@@ -0,0 +1,169 @@
+From ebdaf5ec6d7040c1c7c9a3486ea16ea60f5f127f Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 29 Apr 2020 01:31:03 +0300
+Subject: [PATCH] media: i2c: max9296: add MIPI GMSL2 support
+
+This adds MIPI stream from serializer
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/max9296.c | 75 +++++++++++++++++------------
+ drivers/media/i2c/soc_camera/gmsl/max9296.h | 6 +--
+ 2 files changed, 47 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+index a6d286f..85b45ca 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+@@ -94,7 +94,7 @@ static int gmsl = MODE_GMSL2;
+ module_param(gmsl, int, 0644);
+ MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
+
+-static char *mbus = "dvp";
++static char *mbus = mbus_default;
+ module_param(mbus, charp, 0644);
+ MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
+
+@@ -165,7 +165,7 @@ static void max9296_reset_oneshot(struct max9296_priv *priv)
+ if (!(reg & BIT(5)))
+ break;
+
+- msleep(1);
++ mdelay(1);
+ }
+
+ if (reg & BIT(5))
+@@ -745,9 +745,12 @@ static int max9296_gmsl2_reverse_channel_setup(struct max9296_priv *priv, int li
+ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */
+ max9296_reset_oneshot(priv);
+
+- /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
+- while ((!max9296_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
+- msleep(1);
++ /* wait the link to be established, indicated when status bit LOCKED goes high */
++ for (; timeout > 0; timeout--) {
++ if (max9296_gmsl2_get_link_lock(priv, link_n))
++ break;
++ mdelay(1);
++ }
+
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+@@ -785,36 +788,42 @@ static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int li
+ struct max9296_link *link = priv->link[link_n];
+ int i;
+
+- //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
+- //msleep(100);
+- ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
+-
+ if (strcmp(priv->mbus, "dvp") == 0) {
+- ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
+ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
+ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
+ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
+- }
+-
+- ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
+
+- switch (priv->dt) {
+- case MIPI_DT_YUV8:
+- case MIPI_DT_RAW12:
+- /* setup crossbar: strait DVP mapping */
+- ser_write(MAX9295_CROSS(0), priv->cb[0]);
+- ser_write(MAX9295_CROSS(1), priv->cb[1]);
+- ser_write(MAX9295_CROSS(2), priv->cb[2]);
+- ser_write(MAX9295_CROSS(3), priv->cb[3]);
+- ser_write(MAX9295_CROSS(4), priv->cb[4]);
+- ser_write(MAX9295_CROSS(5), priv->cb[5]);
+- ser_write(MAX9295_CROSS(6), priv->cb[6]);
+- ser_write(MAX9295_CROSS(7), priv->cb[7]);
+- ser_write(MAX9295_CROSS(8), priv->cb[8]);
+- ser_write(MAX9295_CROSS(9), priv->cb[9]);
+- ser_write(MAX9295_CROSS(10), priv->cb[10]);
+- ser_write(MAX9295_CROSS(11), priv->cb[11]);
+- break;
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++ } else {
++ /* defaults:
++ * REG2 - video enable Pipex X,Z
++ * MIPI_RX0 - 1x4 mode (1-port x 4-lanes)
++ * MIPI_RX1 - 4-lanes
++ * MIPI_RX2, MIPI_RX3 - merge PHY1,PHY2 to 1x4-mode
++ * FRONTTOP_9 - start Pipes X,Z from CSI_A,CSI_B
++ */
++
++ ser_write(MAX9295_FRONTTOP_0, 0x71); /* enable Pipe X from from CSI_A,CSI_B */
++ ser_write(MAX9295_FRONTTOP_12, BIT(6) | priv->dt); /* primary DT for Pipe X */
++ ser_write(MAX9295_FRONTTOP_13, BIT(6) | MIPI_DT_EMB); /* secondary DT for Pipe X */
+ }
+
+ for (i = 0; i < 11; i++) {
+@@ -856,7 +865,9 @@ static struct {
+ } gmsl2_pipe_maps[] = {
+ {0x00, 0x00}, /* FS */
+ {0x01, 0x01}, /* FE */
+- {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8}, /* payload data */
++ {MIPI_DT_RAW8, MIPI_DT_RAW8},
++ {MIPI_DT_RAW12, MIPI_DT_RAW12},
+ };
+
+ static void max9296_gmsl2_pipe_set_source(struct max9296_priv *priv, int pipe, int phy, int in_pipe)
+@@ -1193,6 +1204,8 @@ static int max9296_parse_dt(struct i2c_client *client)
+ priv->gpio[7] = gpio7;
+ if (gpio8 >= 0)
+ priv->gpio[8] = gpio8;
++ if (strcmp(mbus, "dvp"))
++ priv->mbus = mbus;
+
+ /* parse serializer crossbar setup */
+ for (i = 0; i < 16; i++) {
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+index 800df43..985b77e 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9296.h
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+@@ -254,11 +254,11 @@ static inline int max9296_ser_write(struct max9296_link *link, int reg, int val)
+ return ret;
+ }
+
+-static inline int max9296_ser_read(struct max9296_link *link, int reg, u8 *val)
++static inline int max9296_ser_read(struct max9296_link *link, int reg, int *val)
+ {
+ int ret;
+
+- ret = regmap_read(link->regmap, reg, (int *)val);
++ ret = regmap_read(link->regmap, reg, val);
+ if (ret)
+ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
+
+@@ -276,6 +276,6 @@ static inline int max9296_ser_update_bits(struct max9296_link *link, int reg, in
+ return ret;
+ }
+
+-#define ser_read(reg, val) max9296_ser_read(link, reg, val)
++#define ser_read(reg, val) max9296_ser_read(link, reg, (int *)val)
+ #define ser_write(reg, val) max9296_ser_write(link, reg, val)
+ #define ser_update_bits(reg, mask, bits) max9296_ser_update_bits(link, reg, mask, bits)
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch
new file mode 100644
index 00000000..21edaa0a
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch
@@ -0,0 +1,118 @@
+From afbb91288b32731dcf5249dcddeee019994364e2 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 29 Apr 2020 02:33:17 +0300
+Subject: [PATCH] media: i2c: gmsl: parse gmsl_mode from deserializer
+
+The gmsl1/2 mode needs to be parsed from deserizlier to
+access 16 or 8 bit remote serializer. If not done then
+imager may try to make 16 bit writes to 8 bit serizlier and
+hence it will change it's address at reg=0
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/common.h | 13 +++++++++++--
+ drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c | 2 +-
+ drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 2 +-
+ drivers/media/i2c/soc_camera/imagers/ov10635.c | 2 +-
+ drivers/media/i2c/soc_camera/imagers/ov2311.c | 2 +-
+ drivers/media/i2c/soc_camera/imagers/ov490.c | 2 +-
+ 6 files changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/common.h b/drivers/media/i2c/soc_camera/gmsl/common.h
+index 98bb1c0..346db3ca 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/common.h
++++ b/drivers/media/i2c/soc_camera/gmsl/common.h
+@@ -473,14 +473,23 @@ static inline int get_des_addr(struct i2c_client *client)
+ return to_i2c_client(mux_priv->muxc->dev)->addr;
+ }
+
+-static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr, int gmsl_mode)
++static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr)
+ {
++ int gmsl_mode = MODE_GMSL2;
++
+ switch (get_des_id(client)) {
+ case MAX9286_ID:
+ case MAX9288_ID:
+- case MAX9296A_ID:
+ case MAX96706_ID:
++ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */
++ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */
++ break;
++ case MAX9296A_ID:
+ case MAX96712_ID:
++ /* parse gmsl mode from deserializer */
++ reg16_read_addr(client, get_des_addr(client), 6, &gmsl_mode);
++ gmsl_mode = !!(gmsl_mode & BIT(7)) + 1;
++
+ if (gmsl_mode == MODE_GMSL1) {
+ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */
+ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+index 1df3f3b..d2a6ff9 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+@@ -409,7 +409,7 @@ static int ap0101_initialize(struct i2c_client *client)
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ap0101_i2c_addr); i++) {
+- setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i], MODE_GMSL1);
++ setup_i2c_translator(client, priv->ser_addr, ap0101_i2c_addr[i]);
+
+ /* check model ID */
+ reg16_read16(client, AP0101_PID_REG, &pid);
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+index 35169b8..7b274ce 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+@@ -405,7 +405,7 @@ static int ap0201_initialize(struct i2c_client *client)
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ap0201_i2c_addr); i++) {
+- setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i], MODE_GMSL2);
++ setup_i2c_translator(client, priv->ser_addr, ap0201_i2c_addr[i]);
+
+ /* check product ID */
+ reg16_read16(client, AP0201_PID_REG, &pid);
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov10635.c b/drivers/media/i2c/soc_camera/imagers/ov10635.c
+index b9813f7..d21d357 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ov10635.c
++++ b/drivers/media/i2c/soc_camera/imagers/ov10635.c
+@@ -506,7 +506,7 @@ static int ov10635_initialize(struct i2c_client *client)
+ u8 val = 0;
+ u16 pid = 0;
+
+- setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR, MODE_GMSL1);
++ setup_i2c_translator(client, priv->ser_addr, OV10635_I2C_ADDR);
+ udelay(100);
+
+ reg16_read(client, OV10635_PID_REGA, &val);
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov2311.c b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+index 764c261..d49ca96 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ov2311.c
++++ b/drivers/media/i2c/soc_camera/imagers/ov2311.c
+@@ -395,7 +395,7 @@ static int ov2311_initialize(struct i2c_client *client)
+ u8 val = 0, rev = 0;
+ int ret = 0;
+
+- setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR, MODE_GMSL2);
++ setup_i2c_translator(client, priv->ser_addr, OV2311_I2C_ADDR);
+
+ reg16_read(client, OV2311_PIDA_REG, &val);
+ pid = val;
+diff --git a/drivers/media/i2c/soc_camera/imagers/ov490.c b/drivers/media/i2c/soc_camera/imagers/ov490.c
+index 3c47398..ff0d122 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ov490.c
++++ b/drivers/media/i2c/soc_camera/imagers/ov490.c
+@@ -767,7 +767,7 @@ static int ov490_initialize(struct i2c_client *client)
+ u16 pid = 0;
+ int timeout, retry_timeout = 3;
+
+- setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR, MODE_GMSL1);
++ setup_i2c_translator(client, priv->ser_addr, OV490_I2C_ADDR);
+
+ reg16_write(client, 0xFFFD, 0x80);
+ reg16_write(client, 0xFFFE, 0x80);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch
new file mode 100644
index 00000000..c75293ae
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch
@@ -0,0 +1,1843 @@
+From f113d62d104a24b6035d969bad8cb04af54d7534 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 10:54:49 +0300
+Subject: [PATCH] media: i2c: imagers: add AR0231 for new LVDS support
+
+This adds AR0231 into new LVDS drivers that support all enabled
+serializers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/Makefile | 1 +
+ drivers/media/i2c/soc_camera/imagers/ar0231.c | 604 +++++++++++++++++++++
+ drivers/media/i2c/soc_camera/imagers/ar0231.h | 35 ++
+ drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h | 344 ++++++++++++
+ drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h | 343 ++++++++++++
+ drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h | 445 +++++++++++++++
+ 5 files changed, 1771 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile
+index 0d0ff32..eeb36fd 100644
+--- a/drivers/media/i2c/soc_camera/imagers/Makefile
++++ b/drivers/media/i2c/soc_camera/imagers/Makefile
+@@ -1,7 +1,8 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ar0231.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o
+-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o
+-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += dummy.o
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+new file mode 100644
+index 0000000..fc08793
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+@@ -0,0 +1,604 @@
++/*
++ * ON Semiconductor AR0231 sensor camera driver
++ *
++ * Copyright (C) 2018-220 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "ar0231.h"
++
++static const int ar0231_i2c_addr[] = {0x10, 0x20};
++
++#define AR0231_PID_REG 0x3000
++#define AR0231_REV_REG 0x31FE
++#define AR0231_PID 0x0354
++
++#define AR0231_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12
++
++struct ar0231_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int init_complete;
++ u8 id[6];
++ /* serializers */
++ int ser_addr;
++ int trigger;
++};
++
++static int trigger = 0;
++module_param(trigger, int, 0644);
++MODULE_PARM_DESC(trigger, " Trigger gpio number (default: 0 - GPIO0) ");
++
++static inline struct ar0231_priv *to_ar0231(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ar0231_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct ar0231_priv, hdl)->sd;
++}
++
++static int ar0231_set_regs(struct i2c_client *client,
++ const struct ar0231_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == AR0231_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write16(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static void ar0231_otp_id_read(struct i2c_client *client)
++{
++ struct ar0231_priv *priv = to_ar0231(client);
++ int i;
++ u16 val = 0;
++
++ /* read camera id from ar014x OTP memory */
++ reg16_write16(client, 0x3054, 0x400);
++ reg16_write16(client, 0x304a, 0x110);
++ usleep_range(25000, 25500); /* wait 25 ms */
++
++ for (i = 0; i < 6; i += 2) {
++ /* first 4 bytes are equal on all ar014x */
++ reg16_read16(client, 0x3800 + i + 4, &val);
++ priv->id[i] = val >> 8;
++ priv->id[i + 1] = val & 0xff;
++ }
++}
++
++
++static int ar0231_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ar0231_set_window(struct v4l2_subdev *sd)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ dev_dbg(&client->dev, "L=%d T=%d %dx%d\n", priv->rect.left, priv->rect.top, priv->rect.width, priv->rect.height);
++
++ /* horiz crop start */
++ reg16_write16(client, 0x3004, priv->rect.left + AR0231_X_START);
++ /* horiz crop end */
++ reg16_write16(client, 0x3008, priv->rect.left + priv->rect.width - 1 + AR0231_X_START);
++ /* vert crop start */
++ reg16_write16(client, 0x3002, priv->rect.top + AR0231_Y_START);
++ /* vert crop end */
++ reg16_write16(client, 0x3006, priv->rect.top + priv->rect.height - 1 + AR0231_Y_START);
++
++ return 0;
++};
++
++static int ar0231_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = AR0231_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int ar0231_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = AR0231_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ar0231_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = AR0231_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int ar0231_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = AR0231_PID >> 8;
++ edid->edid[9] = AR0231_PID & 0xff;
++
++ return 0;
++}
++
++static int ar0231_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > AR0231_MAX_WIDTH) ||
++ (rect->top + rect->height > AR0231_MAX_HEIGHT))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ ar0231_set_window(sd);
++
++ return 0;
++}
++
++static int ar0231_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = AR0231_MAX_WIDTH;
++ sel->r.height = AR0231_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = AR0231_MAX_WIDTH;
++ sel->r.height = AR0231_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ar0231_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int ar0231_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ __be64 be_val;
++
++ if (!reg->size)
++ reg->size = sizeof(u16);
++ if (reg->size > sizeof(reg->val))
++ reg->size = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&be_val, reg->size);
++ be_val = be_val << ((sizeof(be_val) - reg->size) * 8);
++ reg->val = be64_to_cpu(be_val);
++
++ return ret;
++}
++
++static int ar0231_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 size = reg->size;
++ int ret;
++ __be64 be_val;
++
++ if (!size)
++ size = sizeof(u16);
++ if (size > sizeof(reg->val))
++ size = sizeof(reg->val);
++
++ be_val = cpu_to_be64(reg->val);
++ be_val = be_val >> ((sizeof(be_val) - size) * 8);
++ ret = reg16_write_n(client, (u16)reg->reg, (u8*)&be_val, size);
++
++ return ret;
++}
++#endif
++
++static struct v4l2_subdev_core_ops ar0231_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = ar0231_g_register,
++ .s_register = ar0231_s_register,
++#endif
++};
++
++static int ar0231_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++ int ret = -EINVAL;
++ u16 val = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ break;
++ case V4L2_CID_GAIN:
++ /* Digital gain */
++ ret = reg16_write16(client, 0x3308, ctrl->val);
++ break;
++ case V4L2_CID_ANALOGUE_GAIN:
++ /* Analog gain */
++ ret = reg16_write16(client, 0x3366, (ctrl->val << 8) | (ctrl->val << 4) | ctrl->val);
++ break;
++ case V4L2_CID_EXPOSURE:
++ /* T1 exposure */
++ ret = reg16_write16(client, 0x3012, ctrl->val);
++ break;
++ case V4L2_CID_HFLIP:
++ ret = reg16_read16(client, 0x3040, &val);
++ if (ctrl->val)
++ val |= (1 << 14);
++ else
++ val &= ~(1 << 14);
++ ret |= reg16_write16(client, 0x3040, val);
++ break;
++ case V4L2_CID_VFLIP:
++ ret = reg16_read16(client, 0x3040, &val);
++ if (ctrl->val)
++ val |= (1 << 15);
++ else
++ val &= ~(1 << 15);
++ ret |= reg16_write16(client, 0x3040, val);
++ break;
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ret = 0;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops ar0231_ctrl_ops = {
++ .s_ctrl = ar0231_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ar0231_video_ops = {
++ .s_stream = ar0231_s_stream,
++ .g_mbus_config = ar0231_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops ar0231_subdev_pad_ops = {
++ .get_edid = ar0231_get_edid,
++ .enum_mbus_code = ar0231_enum_mbus_code,
++ .get_selection = ar0231_get_selection,
++ .set_selection = ar0231_set_selection,
++ .get_fmt = ar0231_get_fmt,
++ .set_fmt = ar0231_set_fmt,
++};
++
++static struct v4l2_subdev_ops ar0231_subdev_ops = {
++ .core = &ar0231_core_ops,
++ .video = &ar0231_video_ops,
++ .pad = &ar0231_subdev_pad_ops,
++};
++
++static ssize_t ar0231_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct ar0231_priv *priv = to_ar0231(client);
++
++ ar0231_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_ar0231, S_IRUGO, ar0231_otp_id_show, NULL);
++
++static int ar0231_initialize(struct i2c_client *client)
++{
++ struct ar0231_priv *priv = to_ar0231(client);
++ u16 val = 0, pid = 0, rev = 0;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ar0231_i2c_addr); i++) {
++ setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i] << 1);
++
++ /* check model ID */
++ reg16_read16(client, AR0231_PID_REG, &pid);
++ if (pid == AR0231_PID)
++ break;
++ }
++
++ if (pid != AR0231_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ /* check revision */
++ reg16_read16(client, AR0231_REV_REG, &rev);
++ /* Read OTP IDs */
++ ar0231_otp_id_read(client);
++ /* Program wizard registers */
++ switch (get_des_id(client)) {
++ case UB960_ID:
++ ar0231_set_regs(client, ar0231_regs_wizard_rev7, ARRAY_SIZE(ar0231_regs_wizard_rev7));
++ break;
++ case MAX9286_ID:
++ case MAX9296A_ID:
++ case MAX96712_ID:
++ ar0231_set_regs(client, ar0231_regs_wizard_rev6_dvp, ARRAY_SIZE(ar0231_regs_wizard_rev6_dvp));
++ break;
++ }
++ /* Enable trigger */
++ if (priv->trigger >= 0 && priv->trigger < 4) {
++ reg16_write16(client, 0x340A, (~(BIT(priv->trigger) << 4)) & 0xf0);/* GPIO_CONTROL1: GPIOn input enable */
++ reg16_write16(client, 0x340C, (0x2 << 2*priv->trigger)); /* GPIO_CONTROL2: GPIOn is trigger */
++ reg16_write16(client, 0x30CE, 0x0120); /* TRIGGER_MODE */
++ //reg16_write16(client, 0x30DC, 0x0120); /* TRIGGER_DELAY */
++ }
++ /* Enable stream */
++ reg16_read16(client, 0x301a, &val);
++ val |= (1 << 8); /* GPI pins enable */
++ val |= (1 << 2);
++ reg16_write16(client, 0x301a, val);
++
++ dev_info(&client->dev, "ar0231 PID %x (rev%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, rev & 0xf, AR0231_MAX_WIDTH, AR0231_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id ar0231_id[] = {
++ { "ar0231", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, ar0231_id);
++
++static const struct of_device_id ar0231_of_ids[] = {
++ { .compatible = "onnn,ar0231", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ar0231_of_ids);
++
++static int ar0231_parse_dt(struct device_node *np, struct ar0231_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ if (of_property_read_u32(np, "trigger", &priv->trigger))
++ priv->trigger = 0;
++
++ /* module params override dts */
++ if (trigger)
++ priv->trigger = trigger;
++
++ return 0;
++}
++
++static int ar0231_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ar0231_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ar0231_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &ar0231_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = ar0231_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ar0231_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = AR0231_MAX_WIDTH;
++ priv->rect.height = AR0231_MAX_HEIGHT;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0231) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int ar0231_remove(struct i2c_client *client)
++{
++ struct ar0231_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_ar0231);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver ar0231_i2c_driver = {
++ .driver = {
++ .name = "ar0231",
++ .of_match_table = ar0231_of_ids,
++ },
++ .probe = ar0231_probe,
++ .remove = ar0231_remove,
++ .id_table = ar0231_id,
++};
++
++module_i2c_driver(ar0231_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for AR0231");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.h b/drivers/media/i2c/soc_camera/imagers/ar0231.h
+new file mode 100644
+index 0000000..e455b38
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.h
+@@ -0,0 +1,35 @@
++/*
++ * ON Semiconductor AR0231 sensor camera wizard 1928x1208@30/BGGR/BT601
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define AR0231_DISPLAY_PATTERN_FIXED
++//#define AR0231_DISPLAY_PATTERN_COLOR_BAR
++
++#define AR0231_MAX_WIDTH 1920
++#define AR0231_MAX_HEIGHT 1200
++
++#define AR0231_DELAY 0xffff
++
++#define AR0231_SENSOR_WIDTH 1928
++#define AR0231_SENSOR_HEIGHT 1208
++
++#define AR0231_X_START ((AR0231_SENSOR_WIDTH - AR0231_MAX_WIDTH) / 2)
++#define AR0231_Y_START ((AR0231_SENSOR_HEIGHT - AR0231_MAX_HEIGHT) / 2)
++#define AR0231_X_END (AR0231_X_START + AR0231_MAX_WIDTH - 1)
++#define AR0231_Y_END (AR0231_Y_START + AR0231_MAX_HEIGHT - 1)
++
++struct ar0231_reg {
++ u16 reg;
++ u16 val;
++};
++
++#include "ar0231_rev4.h"
++#include "ar0231_rev6.h"
++#include "ar0231_rev7.h"
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h
+new file mode 100644
+index 0000000..e18b96d
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev4.h
+@@ -0,0 +1,344 @@
++/*
++ * ON Semiconductor AR0231 sensor camera wizard 1920x1080@30/BGGR/MIPI
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++static const struct ar0231_reg ar0231_regs_wizard_rev4_dvp[] = {
++{0x301A, 0x0001}, // reset
++{0x301A, 0x10D8}, // Stream off and setup parallel
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#ifdef AR0231_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++#endif
++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++
++//Recommended Settings
++{0x3366, 0x6666}, // ANALOG_GAIN
++{0x3056, 0x0080}, // GREEN1_GAIN
++{0x305C, 0x0080}, // GREEN2_GAIN
++{0x3058, 0x0080}, // BLUE_GAIN
++{0x305A, 0x0080}, // RED_GAIN
++{0x3044, 0x0400}, // DARK_CONTROL
++{0x30BA, 0x1021}, // DIGITAL_CTRL
++{0x318E, 0x0200}, // DLO_CONTROL0
++{0x32EA, 0x3C0A}, // RESERVED_MFR_32EA
++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA
++{0x3362, 0x0000}, // DC_GAIN
++{0x3364, 0x0060}, // RESERVED_MFR_3364
++{0x3370, 0x0231}, // DBLC_CONTROL
++{0x3372, 0x700F}, // RESERVED_MFR_3372
++{0x3386, 0x0000}, // RESERVED_MFR_3386
++{0x3C04, 0x0E80}, // RESERVED_MFR_3C04
++{0x3F90, 0x06E1}, // TEMPVSENS0_TMG_CTRL
++{0x3F92, 0x06E1}, // TEMPVSENS1_TMG_CTRL
++{0x3502, 0x0808}, // RESERVED_MFR_3502
++{0x3502, 0x0808}, // RESERVED_MFR_3502
++{0x350E, 0xFF10}, // RESERVED_MFR_350E
++{0x3506, 0x4444}, // RESERVED_MFR_3506
++{0x3508, 0x4444}, // RESERVED_MFR_3508
++{0x350A, 0x4465}, // RESERVED_MFR_350A
++{0x350C, 0x055F}, // RESERVED_MFR_350C
++{0x3230, 0x0317}, // FINE_CORRECTION
++{0x3232, 0x0552}, // FINE_CORRECTION2
++{0x3234, 0x078D}, // FINE_CORRECTION3
++{0x3566, 0x9D38}, // RESERVED_MFR_3566
++{0x3518, 0x1FFE}, // RESERVED_MFR_3518
++{0x3520, 0xC688}, // RESERVED_MFR_3520
++{0x3522, 0x88C0}, // RESERVED_MFR_3522
++{0x3524, 0xC0C6}, // RESERVED_MFR_3524
++{0x352C, 0xC6C6}, // RESERVED_MFR_352C
++{0x3528, 0x0900}, // RESERVED_MFR_3528
++{0x3528, 0x9900}, // RESERVED_MFR_3528
++{0x3528, 0x9909}, // RESERVED_MFR_3528
++{0x3528, 0x9999}, // RESERVED_MFR_3528
++{0x352A, 0x081F}, // RESERVED_MFR_352A
++{0x352E, 0x0001}, // RESERVED_MFR_352E
++{0x352E, 0x0011}, // RESERVED_MFR_352E
++{0x3530, 0x0400}, // RESERVED_MFR_3530
++{0x3530, 0x4400}, // RESERVED_MFR_3530
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF02}, // RESERVED_MFR_3536
++{0x3536, 0xFF06}, // RESERVED_MFR_3536
++{0x3536, 0xFF06}, // RESERVED_MFR_3536
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x353A, 0x9000}, // RESERVED_MFR_353A
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3542, 0x584B}, // RESERVED_MFR_3542
++{0x3542, 0x464B}, // RESERVED_MFR_3542
++{0x3544, 0x565A}, // RESERVED_MFR_3544
++{0x3544, 0x4B5A}, // RESERVED_MFR_3544
++{0x3546, 0x545A}, // RESERVED_MFR_3546
++{0x3546, 0x5A5A}, // RESERVED_MFR_3546
++{0x3548, 0x6430}, // RESERVED_MFR_3548
++{0x3556, 0x101F}, // RESERVED_MFR_3556
++{0x3566, 0x9D38}, // RESERVED_MFR_3566
++{0x3566, 0x1D38}, // RESERVED_MFR_3566
++{0x3566, 0x1D28}, // RESERVED_MFR_3566
++{0x3566, 0x1128}, // RESERVED_MFR_3566
++{0x3566, 0x1328}, // RESERVED_MFR_3566
++{0x3566, 0x3328}, // RESERVED_MFR_3566
++
++//Sequencer Update
++{0x2512, 0x8000}, // SEQ_CTRL_PORT
++{0x2510, 0x0905}, // SEQ_DATA_PORT
++{0x2510, 0x3350}, // SEQ_DATA_PORT
++{0x2510, 0x2004}, // SEQ_DATA_PORT
++{0x2510, 0x1460}, // SEQ_DATA_PORT
++{0x2510, 0x1578}, // SEQ_DATA_PORT
++{0x2510, 0x1360}, // SEQ_DATA_PORT
++{0x2510, 0x7B24}, // SEQ_DATA_PORT
++{0x2510, 0xFF24}, // SEQ_DATA_PORT
++{0x2510, 0xFF24}, // SEQ_DATA_PORT
++{0x2510, 0xEA24}, // SEQ_DATA_PORT
++{0x2510, 0x1022}, // SEQ_DATA_PORT
++{0x2510, 0x2410}, // SEQ_DATA_PORT
++{0x2510, 0x155A}, // SEQ_DATA_PORT
++{0x2510, 0x1342}, // SEQ_DATA_PORT
++{0x2510, 0x1400}, // SEQ_DATA_PORT
++{0x2510, 0x24FF}, // SEQ_DATA_PORT
++{0x2510, 0x24FF}, // SEQ_DATA_PORT
++{0x2510, 0x24EA}, // SEQ_DATA_PORT
++{0x2510, 0x2324}, // SEQ_DATA_PORT
++{0x2510, 0x647A}, // SEQ_DATA_PORT
++{0x2510, 0x2404}, // SEQ_DATA_PORT
++{0x2510, 0x052C}, // SEQ_DATA_PORT
++{0x2510, 0x400A}, // SEQ_DATA_PORT
++{0x2510, 0xFF0A}, // SEQ_DATA_PORT
++{0x2510, 0xFF0A}, // SEQ_DATA_PORT
++{0x2510, 0x0408}, // SEQ_DATA_PORT
++{0x2510, 0x3851}, // SEQ_DATA_PORT
++{0x2510, 0x1440}, // SEQ_DATA_PORT
++{0x2510, 0x0004}, // SEQ_DATA_PORT
++{0x2510, 0x0801}, // SEQ_DATA_PORT
++{0x2510, 0x0408}, // SEQ_DATA_PORT
++{0x2510, 0x1180}, // SEQ_DATA_PORT
++{0x2510, 0x15DC}, // SEQ_DATA_PORT
++{0x2510, 0x134C}, // SEQ_DATA_PORT
++{0x2510, 0x1002}, // SEQ_DATA_PORT
++{0x2510, 0x1016}, // SEQ_DATA_PORT
++{0x2510, 0x1181}, // SEQ_DATA_PORT
++{0x2510, 0x1189}, // SEQ_DATA_PORT
++{0x2510, 0x1056}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x0D08}, // SEQ_DATA_PORT
++{0x2510, 0x0913}, // SEQ_DATA_PORT
++{0x2510, 0x13C8}, // SEQ_DATA_PORT
++{0x2510, 0x092B}, // SEQ_DATA_PORT
++{0x2510, 0x1588}, // SEQ_DATA_PORT
++{0x2510, 0x1388}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x11D9}, // SEQ_DATA_PORT
++{0x2510, 0x091D}, // SEQ_DATA_PORT
++{0x2510, 0x1441}, // SEQ_DATA_PORT
++{0x2510, 0x0903}, // SEQ_DATA_PORT
++{0x2510, 0x1214}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x10D6}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x1212}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x11DD}, // SEQ_DATA_PORT
++{0x2510, 0x11D9}, // SEQ_DATA_PORT
++{0x2510, 0x1056}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x11DB}, // SEQ_DATA_PORT
++{0x2510, 0x0915}, // SEQ_DATA_PORT
++{0x2510, 0x119B}, // SEQ_DATA_PORT
++{0x2510, 0x090F}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x121A}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x1460}, // SEQ_DATA_PORT
++{0x2510, 0x1250}, // SEQ_DATA_PORT
++{0x2510, 0x1076}, // SEQ_DATA_PORT
++{0x2510, 0x10E6}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x15AB}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x13A8}, // SEQ_DATA_PORT
++{0x2510, 0x1240}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x0923}, // SEQ_DATA_PORT
++{0x2510, 0x158D}, // SEQ_DATA_PORT
++{0x2510, 0x138D}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x0B09}, // SEQ_DATA_PORT
++{0x2510, 0x0108}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x1440}, // SEQ_DATA_PORT
++{0x2510, 0x091D}, // SEQ_DATA_PORT
++{0x2510, 0x1588}, // SEQ_DATA_PORT
++{0x2510, 0x1388}, // SEQ_DATA_PORT
++{0x2510, 0x092D}, // SEQ_DATA_PORT
++{0x2510, 0x1066}, // SEQ_DATA_PORT
++{0x2510, 0x0905}, // SEQ_DATA_PORT
++{0x2510, 0x0C08}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x1441}, // SEQ_DATA_PORT
++{0x2510, 0x090D}, // SEQ_DATA_PORT
++{0x2510, 0x10E6}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x1262}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x11BF}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x1066}, // SEQ_DATA_PORT
++{0x2510, 0x11FB}, // SEQ_DATA_PORT
++{0x2510, 0x0935}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x1263}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x1400}, // SEQ_DATA_PORT
++{0x2510, 0x1510}, // SEQ_DATA_PORT
++{0x2510, 0x11B8}, // SEQ_DATA_PORT
++{0x2510, 0x12A0}, // SEQ_DATA_PORT
++{0x2510, 0x1200}, // SEQ_DATA_PORT
++{0x2510, 0x1026}, // SEQ_DATA_PORT
++{0x2510, 0x1000}, // SEQ_DATA_PORT
++{0x2510, 0x1342}, // SEQ_DATA_PORT
++{0x2510, 0x1100}, // SEQ_DATA_PORT
++{0x2510, 0x7A06}, // SEQ_DATA_PORT
++{0x2510, 0x0926}, // SEQ_DATA_PORT
++{0x2510, 0x0507}, // SEQ_DATA_PORT
++{0x2510, 0x0841}, // SEQ_DATA_PORT
++{0x2510, 0x3750}, // SEQ_DATA_PORT
++{0x2510, 0x2C2C}, // SEQ_DATA_PORT
++{0x2510, 0xFE02}, // SEQ_DATA_PORT
++{0x2510, 0xFE14}, // SEQ_DATA_PORT
++{0x3566, 0x3328}, // RESERVED_MFR_3566
++{0x350C, 0x055F}, // RESERVED_MFR_350C
++{0x32D0, 0x3A02}, // RESERVED_MFR_32D0
++{0x32D2, 0x3508}, // RESERVED_MFR_32D2
++{0x32D4, 0x3702}, // RESERVED_MFR_32D4
++{0x32D6, 0x3C04}, // RESERVED_MFR_32D6
++{0x32DC, 0x370A}, // RESERVED_MFR_32DC
++
++//Parallel Timing Setup
++{0x302A, 0x0009}, // VT_PIX_CLK_DIV
++{0x302C, 0x0001}, // VT_SYS_CLK_DIV
++{0x302E, 0x0003}, // PRE_PLL_CLK_DIV
++{0x3030, 0x0058}, // PLL_MULTIPLIER
++{0x3036, 0x0008}, // OP_WORD_CLK_DIV
++{0x3038, 0x0001}, // OP_SYS_CLK_DIV
++{0x30B0, 0x0A00}, // DIGITAL_TEST
++
++//Readout Mode Configuration
++{0x30A2, 0x0001}, // X_ODD_INC_
++{0x30A6, 0x0001}, // Y_ODD_INC_
++{0x3040, 0x0000}, // READ_MODE
++{0x3044, 0x0400}, // DARK_CONTROL
++#ifdef AR0231_EMBEDDED_LINE
++{0x3064, 0x1982}, // SMIA_TEST
++#else
++{0x3064, 0x1802}, // SMIA_TEST
++#endif
++{0x33E0, 0x0880}, // RESERVED_MFR_33E0
++{0x3180, 0x0080}, // RESERVED_MFR_3180
++{0x33E4, 0x0080}, // RESERVED_MFR_33E4
++
++#if 1
++{0x3004, AR0231_X_START}, // X_ADDR_START_
++{0x3008, AR0231_X_END}, // X_ADDR_END_
++{0x3002, AR0231_Y_START}, // Y_ADDR_START_
++{0x3006, AR0231_Y_END}, // Y_ADDR_END_
++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL
++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL
++#else
++{0x3004, 0}, // X_ADDR_START_
++{0x3008, 0x0787}, // X_ADDR_END_
++{0x3002, 0x0000}, // Y_ADDR_START_
++{0x3006, 0x04B7}, // Y_ADDR_END_
++{0x3402, 0x0788}, // RESERVED_MFR_3402
++{0x3402, 0x0F10}, // RESERVED_MFR_3402
++{0x3404, 0x0440}, // RESERVED_MFR_3404
++{0x3404, 0x0970}, // RESERVED_MFR_3404
++#endif
++{0x3032, 0x0000}, // SCALING_MODE
++{0x3400, 0x0010}, // RESERVED_MFR_3400
++
++//3exp Timing and Exposure
++{0x3082, 0x0008}, // OPERATION_MODE_CTRL
++{0x30BA, 0x11E2}, // DIGITAL_CTRL
++{0x300A, 0x05AF}, // FRAME_LENGTH_LINES_
++{0x300C, 0x07BA}, // LINE_LENGTH_PCK_
++{0x3042, 0x0000}, // EXTRA_DELAY
++{0x3238, 0x0222}, // EXPOSURE_RATIO
++{0x1008, 0x0374}, // FINE_INTEGRATION_TIME_MIN
++{0x100C, 0x05AF}, // FINE_INTEGRATION_TIME2_MIN
++{0x100E, 0x07EA}, // FINE_INTEGRATION_TIME3_MIN
++{0x1010, 0x0139}, // FINE_INTEGRATION_TIME4_MIN
++{0x3012, 0x0163}, // COARSE_INTEGRATION_TIME_
++{0x3014, 0x06A6}, // FINE_INTEGRATION_TIME_
++{0x321E, 0x06A6}, // FINE_INTEGRATION_TIME2
++{0x3222, 0x06A6}, // FINE_INTEGRATION_TIME3
++{0x30B0, 0x0B02}, // DIGITAL_TEST
++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA
++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC
++
++//Parallel HDR 12 bit Output
++{0x31D0, 0x0001}, // COMPANDING
++{0x31AE, 0x0001}, // SERIAL_FORMAT
++{0x31AC, 0x140C}, // DATA_FORMAT_BITS
++
++#if 0 // no need for front only camera
++/* Enable trigger input */
++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO1 is trigger
++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO1 is trigger
++{0x30CE, 0x0120}, // TRIGGER_MODE
++//{0x30DC, 0x0120}, // TRIGGER_DELAY
++{0x301A, 0x01D8}, // GPI pins enable
++#endif
++
++{0x301A, 0x01DC}, // RESET_REGISTER - stream on
++
++#if 1
++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // FRAME_LENGTH_LINES_
++{0x300C, AR0231_SENSOR_WIDTH + 120}, // LINE_LENGTH_PCK_
++/* the sequence must be updated to use following timings, now it is a hack */
++{0x1008, 0x0fff}, // FINE_INTEGRATION_TIME_MIN
++{0x100C, 0x0fff}, // FINE_INTEGRATION_TIME2_MIN
++{0x100E, 0x0fff}, // FINE_INTEGRATION_TIME3_MIN
++{0x1010, 0x0fff}, // FINE_INTEGRATION_TIME4_MIN
++#endif
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h
+new file mode 100644
+index 0000000..b5b8cb2
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev6.h
+@@ -0,0 +1,343 @@
++/*
++ * ON Semiconductor AR0231 sensor camera wizard 1920x1080@30/BGGR/MIPI
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++/* Parallel Timing Setup 27MHz In 88 MHz Out */
++static const struct ar0231_reg ar0231_regs_wizard_rev6_dvp[] = {
++{0x301A, 0x0001}, // reset
++{0x301A, 0x10D8}, // Stream off and setup parallel
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#ifdef AR0231_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++#endif
++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++
++//Recommended Settings
++{0x3056, 0x0080}, // GREEN1_GAIN
++{0x305C, 0x0080}, // GREEN2_GAIN
++{0x3058, 0x0080}, // BLUE_GAIN
++{0x305A, 0x0080}, // RED_GAIN
++{0x3138, 0x000B}, // OTPM_TCFG_OPT
++{0x3372, 0xF54F}, // RESERVED_MFR_3372
++{0x337A, 0x0D70}, // RESERVED_MFR_337A
++{0x337E, 0x1FFD}, // RESERVED_MFR_337E
++{0x3382, 0x00C0}, // RESERVED_MFR_3382
++{0x3C04, 0x0E80}, // RESERVED_MFR_3C04
++{0x3F90, 0x06E1}, // RESERVED_MFR_3F90
++{0x3F92, 0x06E1}, // RESERVED_MFR_3F92
++{0x350E, 0x1F14}, // RESERVED_MFR_350E
++{0x350E, 0xFF10}, // RESERVED_MFR_350E
++{0x3506, 0x4444}, // RESERVED_MFR_3506
++{0x3508, 0x4444}, // RESERVED_MFR_3508
++{0x350A, 0x4465}, // RESERVED_MFR_350A
++{0x350C, 0x055F}, // RESERVED_MFR_350C
++{0x3566, 0x9D38}, // RESERVED_MFR_3566
++{0x3518, 0x1FFE}, // RESERVED_MFR_3518
++{0x3520, 0xC688}, // RESERVED_MFR_3520
++{0x3522, 0x88C0}, // RESERVED_MFR_3522
++{0x3524, 0xC0C6}, // RESERVED_MFR_3524
++{0x352C, 0xC6C6}, // RESERVED_MFR_352C
++{0x3528, 0x0900}, // RESERVED_MFR_3528
++{0x3528, 0x9900}, // RESERVED_MFR_3528
++{0x3528, 0x9909}, // RESERVED_MFR_3528
++{0x3528, 0x9999}, // RESERVED_MFR_3528
++{0x352A, 0x089F}, // RESERVED_MFR_352A
++{0x352E, 0x0001}, // RESERVED_MFR_352E
++{0x352E, 0x0011}, // RESERVED_MFR_352E
++{0x3530, 0x0400}, // RESERVED_MFR_3530
++{0x3530, 0x4400}, // RESERVED_MFR_3530
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF00}, // RESERVED_MFR_3536
++{0x3536, 0xFF02}, // RESERVED_MFR_3536
++{0x3536, 0xFF06}, // RESERVED_MFR_3536
++{0x3536, 0xFF06}, // RESERVED_MFR_3536
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x3538, 0xFFFF}, // RESERVED_MFR_3538
++{0x353A, 0x9000}, // RESERVED_MFR_353A
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x353C, 0x3F00}, // RESERVED_MFR_353C
++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3540, 0xC637}, // RESERVED_MFR_3540
++{0x3542, 0x584B}, // RESERVED_MFR_3542
++{0x3542, 0x464B}, // RESERVED_MFR_3542
++{0x3544, 0x565A}, // RESERVED_MFR_3544
++{0x3544, 0x4B5A}, // RESERVED_MFR_3544
++{0x3546, 0x545A}, // RESERVED_MFR_3546
++{0x3546, 0x5A5A}, // RESERVED_MFR_3546
++{0x3548, 0x6400}, // RESERVED_MFR_3548
++{0x3556, 0x101F}, // RESERVED_MFR_3556
++{0x3566, 0x9D38}, // RESERVED_MFR_3566
++{0x3566, 0x1D38}, // RESERVED_MFR_3566
++{0x3566, 0x1D28}, // RESERVED_MFR_3566
++{0x3566, 0x1128}, // RESERVED_MFR_3566
++{0x3566, 0x1328}, // RESERVED_MFR_3566
++{0x3566, 0x3328}, // RESERVED_MFR_3566
++{0x3528, 0xDDDD}, // RESERVED_MFR_3528
++
++//Sequencer Update
++{0x2512, 0x8000}, // SEQ_CTRL_PORT
++{0x2510, 0x0905}, // SEQ_DATA_PORT
++{0x2510, 0x3350}, // SEQ_DATA_PORT
++{0x2510, 0x2004}, // SEQ_DATA_PORT
++{0x2510, 0x1460}, // SEQ_DATA_PORT
++{0x2510, 0x1578}, // SEQ_DATA_PORT
++{0x2510, 0x1360}, // SEQ_DATA_PORT
++{0x2510, 0x7B24}, // SEQ_DATA_PORT
++{0x2510, 0xFF24}, // SEQ_DATA_PORT
++{0x2510, 0xFF24}, // SEQ_DATA_PORT
++{0x2510, 0xEA24}, // SEQ_DATA_PORT
++{0x2510, 0x1022}, // SEQ_DATA_PORT
++{0x2510, 0x2410}, // SEQ_DATA_PORT
++{0x2510, 0x155A}, // SEQ_DATA_PORT
++{0x2510, 0x1342}, // SEQ_DATA_PORT
++{0x2510, 0x1400}, // SEQ_DATA_PORT
++{0x2510, 0x24FF}, // SEQ_DATA_PORT
++{0x2510, 0x24FF}, // SEQ_DATA_PORT
++{0x2510, 0x24EA}, // SEQ_DATA_PORT
++{0x2510, 0x2324}, // SEQ_DATA_PORT
++{0x2510, 0x647A}, // SEQ_DATA_PORT
++{0x2510, 0x2404}, // SEQ_DATA_PORT
++{0x2510, 0x052C}, // SEQ_DATA_PORT
++{0x2510, 0x400A}, // SEQ_DATA_PORT
++{0x2510, 0xFF0A}, // SEQ_DATA_PORT
++{0x2510, 0xFF0A}, // SEQ_DATA_PORT
++{0x2510, 0x1808}, // SEQ_DATA_PORT
++{0x2510, 0x3851}, // SEQ_DATA_PORT
++{0x2510, 0x1440}, // SEQ_DATA_PORT
++{0x2510, 0x0004}, // SEQ_DATA_PORT
++{0x2510, 0x0801}, // SEQ_DATA_PORT
++{0x2510, 0x0408}, // SEQ_DATA_PORT
++{0x2510, 0x1180}, // SEQ_DATA_PORT
++{0x2510, 0x15DC}, // SEQ_DATA_PORT
++{0x2510, 0x134C}, // SEQ_DATA_PORT
++{0x2510, 0x1002}, // SEQ_DATA_PORT
++{0x2510, 0x1016}, // SEQ_DATA_PORT
++{0x2510, 0x1181}, // SEQ_DATA_PORT
++{0x2510, 0x1189}, // SEQ_DATA_PORT
++{0x2510, 0x1056}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x0D08}, // SEQ_DATA_PORT
++{0x2510, 0x0913}, // SEQ_DATA_PORT
++{0x2510, 0x13C8}, // SEQ_DATA_PORT
++{0x2510, 0x092B}, // SEQ_DATA_PORT
++{0x2510, 0x1588}, // SEQ_DATA_PORT
++{0x2510, 0x1388}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x11D9}, // SEQ_DATA_PORT
++{0x2510, 0x091D}, // SEQ_DATA_PORT
++{0x2510, 0x1441}, // SEQ_DATA_PORT
++{0x2510, 0x0903}, // SEQ_DATA_PORT
++{0x2510, 0x1214}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x10D6}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x1212}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x11DD}, // SEQ_DATA_PORT
++{0x2510, 0x11D9}, // SEQ_DATA_PORT
++{0x2510, 0x1056}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x11DB}, // SEQ_DATA_PORT
++{0x2510, 0x0915}, // SEQ_DATA_PORT
++{0x2510, 0x119B}, // SEQ_DATA_PORT
++{0x2510, 0x090F}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x121A}, // SEQ_DATA_PORT
++{0x2510, 0x1210}, // SEQ_DATA_PORT
++{0x2510, 0x1460}, // SEQ_DATA_PORT
++{0x2510, 0x1250}, // SEQ_DATA_PORT
++{0x2510, 0x1076}, // SEQ_DATA_PORT
++{0x2510, 0x10E6}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x15AB}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x13A8}, // SEQ_DATA_PORT
++{0x2510, 0x1240}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x0923}, // SEQ_DATA_PORT
++{0x2510, 0x158D}, // SEQ_DATA_PORT
++{0x2510, 0x138D}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x0B09}, // SEQ_DATA_PORT
++{0x2510, 0x0108}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x1440}, // SEQ_DATA_PORT
++{0x2510, 0x091D}, // SEQ_DATA_PORT
++{0x2510, 0x1588}, // SEQ_DATA_PORT
++{0x2510, 0x1388}, // SEQ_DATA_PORT
++{0x2510, 0x092D}, // SEQ_DATA_PORT
++{0x2510, 0x1066}, // SEQ_DATA_PORT
++{0x2510, 0x0905}, // SEQ_DATA_PORT
++{0x2510, 0x0C08}, // SEQ_DATA_PORT
++{0x2510, 0x090B}, // SEQ_DATA_PORT
++{0x2510, 0x1441}, // SEQ_DATA_PORT
++{0x2510, 0x090D}, // SEQ_DATA_PORT
++{0x2510, 0x10E6}, // SEQ_DATA_PORT
++{0x2510, 0x0901}, // SEQ_DATA_PORT
++{0x2510, 0x1262}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x11BF}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x1066}, // SEQ_DATA_PORT
++{0x2510, 0x11FB}, // SEQ_DATA_PORT
++{0x2510, 0x0935}, // SEQ_DATA_PORT
++{0x2510, 0x11BB}, // SEQ_DATA_PORT
++{0x2510, 0x1263}, // SEQ_DATA_PORT
++{0x2510, 0x1260}, // SEQ_DATA_PORT
++{0x2510, 0x1400}, // SEQ_DATA_PORT
++{0x2510, 0x1510}, // SEQ_DATA_PORT
++{0x2510, 0x11B8}, // SEQ_DATA_PORT
++{0x2510, 0x12A0}, // SEQ_DATA_PORT
++{0x2510, 0x1200}, // SEQ_DATA_PORT
++{0x2510, 0x1026}, // SEQ_DATA_PORT
++{0x2510, 0x1000}, // SEQ_DATA_PORT
++{0x2510, 0x1342}, // SEQ_DATA_PORT
++{0x2510, 0x1100}, // SEQ_DATA_PORT
++{0x2510, 0x7A06}, // SEQ_DATA_PORT
++{0x2510, 0x0915}, // SEQ_DATA_PORT
++{0x2510, 0x0507}, // SEQ_DATA_PORT
++{0x2510, 0x0841}, // SEQ_DATA_PORT
++{0x2510, 0x3750}, // SEQ_DATA_PORT
++{0x2510, 0x2C2C}, // SEQ_DATA_PORT
++{0x2510, 0xFE05}, // SEQ_DATA_PORT
++{0x2510, 0xFE13}, // SEQ_DATA_PORT
++{0x1008, 0x0361}, // FINE_INTEGRATION_TIME_MIN
++{0x100C, 0x0589}, // FINE_INTEGRATION_TIME2_MIN
++{0x100E, 0x07B1}, // FINE_INTEGRATION_TIME3_MIN
++{0x1010, 0x0139}, // FINE_INTEGRATION_TIME4_MIN
++{0x3230, 0x0304}, // FINE_CORRECTION
++{0x3232, 0x052C}, // FINE_CORRECTION2
++{0x3234, 0x0754}, // FINE_CORRECTION3
++{0x3236, 0x00DC}, // FINE_CORRECTION4
++{0x3566, 0x3328}, // RESERVED_MFR_3566
++{0x350C, 0x055F}, // RESERVED_MFR_350C
++{0x32D0, 0x3A02}, // RESERVED_MFR_32D0
++{0x32D2, 0x3508}, // RESERVED_MFR_32D2
++{0x32D4, 0x3702}, // RESERVED_MFR_32D4
++{0x32D6, 0x3C04}, // RESERVED_MFR_32D6
++{0x32DC, 0x370A}, // RESERVED_MFR_32DC
++
++//Parallel Timing Setup 27MHz In 88 MHz Out
++{0x302A, 0x0009}, // VT_PIX_CLK_DIV
++{0x302C, 0x0001}, // VT_SYS_CLK_DIV
++{0x302E, 0x0003}, // PRE_PLL_CLK_DIV
++{0x3030, 0x0058}, // PLL_MULTIPLIER
++{0x3036, 0x0008}, // OP_WORD_CLK_DIV
++{0x3038, 0x0001}, // OP_SYS_CLK_DIV
++{0x30B0, 0x0B02}, // DIGITAL_TEST
++
++//Readout Mode Configuration
++{0x30A2, 0x0001}, // X_ODD_INC_
++{0x30A6, 0x0001}, // Y_ODD_INC_
++{0x3040, 0x0000}, // READ_MODE
++{0x3082, 0x0008}, // OPERATION_MODE_CTRL
++{0x30BA, 0x11E2}, // DIGITAL_CTRL
++{0x3044, 0x0400}, // DARK_CONTROL
++#ifdef AR0231_EMBEDDED_LINE
++{0x3064, 0x1982}, // SMIA_TEST
++#else
++{0x3064, 0x1802}, // SMIA_TEST
++#endif
++{0x33E0, 0x0880}, // RESERVED_MFR_33E0
++{0x3180, 0x0080}, // RESERVED_MFR_3180
++{0x33E4, 0x0080}, // RESERVED_MFR_33E4
++{0x33E0, 0x0C80}, // RESERVED_MFR_33E0
++
++#if 1
++{0x3004, AR0231_X_START}, // X_ADDR_START_
++{0x3008, AR0231_X_END}, // X_ADDR_END_
++{0x3002, AR0231_Y_START}, // Y_ADDR_START_
++{0x3006, AR0231_Y_END}, // Y_ADDR_END_
++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL
++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL
++#else
++{0x3004, 0}, // X_ADDR_START_
++{0x3008, 0x0787}, // X_ADDR_END_
++{0x3002, 0x0000}, // Y_ADDR_START_
++{0x3006, 0x04B7}, // Y_ADDR_END_
++{0x3402, 0x0788}, // RESERVED_MFR_3402
++{0x3402, 0x0F10}, // RESERVED_MFR_3402
++{0x3404, 0x0440}, // RESERVED_MFR_3404
++{0x3404, 0x0970}, // RESERVED_MFR_3404
++#endif
++{0x3032, 0x0000}, // SCALING_MODE
++{0x3400, 0x0010}, // RESERVED_MFR_3400
++
++//3exp Timing and Exposure
++{0x3082, 0x0008}, // OPERATION_MODE_CTRL
++{0x30BA, 0x11E2}, // DIGITAL_CTRL
++{0x300A, 0x05CA}, // FRAME_LENGTH_LINES_
++{0x300C, 0x07BA}, // LINE_LENGTH_PCK_
++{0x3042, 0x0000}, // EXTRA_DELAY
++{0x3238, 0x0222}, // EXPOSURE_RATIO
++{0x3012, 0x0163}, // COARSE_INTEGRATION_TIME_
++{0x3014, 0x08CC}, // FINE_INTEGRATION_TIME_
++{0x321E, 0x08CC}, // FINE_INTEGRATION_TIME2
++{0x3222, 0x0254}, // FINE_INTEGRATION_TIME3
++{0x30B0, 0x0A00}, // DIGITAL_TEST
++{0x32EA, 0x3C0E}, // RESERVED_MFR_32EA
++{0x32EC, 0x72A1}, // RESERVED_MFR_32EC
++
++//Parallel HDR 12 bit Output
++{0x31D0, 0x0001}, // COMPANDING
++{0x31AE, 0x0001}, // SERIAL_FORMAT
++{0x31AC, 0x140C}, // DATA_FORMAT_BITS
++
++#if 0 // no need for front only camera
++/* Enable trigger input */
++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO1 is trigger
++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO1 is trigger
++{0x30CE, 0x0120}, // TRIGGER_MODE
++//{0x30DC, 0x0120}, // TRIGGER_DELAY
++{0x301A, 0x01D8}, // GPI pins enable
++#endif
++
++{0x301A, 0x01DC}, // RESET_REGISTER - stream on
++
++#if 1
++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // FRAME_LENGTH_LINES_
++{0x300C, AR0231_SENSOR_WIDTH + 120}, // LINE_LENGTH_PCK_
++/* the sequence must be updated to use following timings, now it is a hack */
++{0x1008, 0x0fff}, // FINE_INTEGRATION_TIME_MIN
++{0x100C, 0x0fff}, // FINE_INTEGRATION_TIME2_MIN
++{0x100E, 0x0fff}, // FINE_INTEGRATION_TIME3_MIN
++{0x1010, 0x0fff}, // FINE_INTEGRATION_TIME4_MIN
++#endif
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
+new file mode 100644
+index 0000000..f3485f5
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
+@@ -0,0 +1,445 @@
++/*
++ * ON Semiconductor AR0231 sensor camera wizard 1928x1208@30/BGGR/MIPI
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++/* 3Exp HDR Full Resolution Mode MIPI 4lane 12bit 30FPS, XCLK=27MHz */
++static const struct ar0231_reg ar0231_regs_wizard_rev7[] = {
++{0x301A, 0x18}, // MIPI, stream OFF
++{AR0231_DELAY, 200}, // Wait 200ms
++
++{0x3070, 0x0000}, // 1: Solid color test pattern,
++ // 2: Full color bar test pattern,
++ // 3: Fade to grey color bar test pattern,
++ //256: Walking 1 test pattern (12 bit)
++{0x3072, 0x0123}, // R
++{0x3074, 0x0456}, // G(GR row)
++{0x3076, 0x0abc}, // B
++{0x3078, 0x0def}, // G(GB row)
++#ifdef AR0231_DISPLAY_PATTERN_FIXED
++{0x3070, 0x0001},
++#endif
++#ifdef AR0231_DISPLAY_PATTERN_COLOR_BAR
++{0x3070, 0x0002},
++#endif
++{AR0231_DELAY, 100}, // Wait 100ms
++
++#if 1 /* Sensor Setup */
++#if 1 /* Recommended Settings */
++{0x3092, 0x0C24},
++{0x337A, 0x0C80},
++{0x3520, 0x1288},
++{0x3522, 0x880C},
++{0x3524, 0x0C12},
++{0x352C, 0x1212},
++{0x354A, 0x007F},
++{0x350C, 0x055C},
++{0x3506, 0x3333},
++{0x3508, 0x3333},
++{0x3100, 0x4000},
++{0x3280, 0x0FA0},
++{0x3282, 0x0FA0},
++{0x3284, 0x0FA0},
++{0x3286, 0x0FA0},
++{0x3288, 0x0FA0},
++{0x328A, 0x0FA0},
++{0x328C, 0x0FA0},
++{0x328E, 0x0FA0},
++{0x3290, 0x0FA0},
++{0x3292, 0x0FA0},
++{0x3294, 0x0FA0},
++{0x3296, 0x0FA0},
++{0x3298, 0x0FA0},
++{0x329A, 0x0FA0},
++{0x329C, 0x0FA0},
++{0x329E, 0x0FA0},
++#endif /* Recommended Settings */
++
++#if 1 /* Sequencer Update */
++{0x2512, 0x8000},
++{0x2510, 0x0905},
++{0x2510, 0x3350},
++{0x2510, 0x2004},
++{0x2510, 0x1460},
++{0x2510, 0x1578},
++{0x2510, 0x0901},
++{0x2510, 0x7B24},
++{0x2510, 0xFF24},
++{0x2510, 0xFF24},
++{0x2510, 0xEA24},
++{0x2510, 0x1022},
++{0x2510, 0x2410},
++{0x2510, 0x155A},
++{0x2510, 0x0901},
++{0x2510, 0x1400},
++{0x2510, 0x24FF},
++{0x2510, 0x24FF},
++{0x2510, 0x24EA},
++{0x2510, 0x2324},
++{0x2510, 0x647A},
++{0x2510, 0x2404},
++{0x2510, 0x052C},
++{0x2510, 0x400A},
++{0x2510, 0xFF0A},
++{0x2510, 0xFF0A},
++{0x2510, 0x1008},
++{0x2510, 0x3851},
++{0x2510, 0x1440},
++{0x2510, 0x0004},
++{0x2510, 0x0801},
++{0x2510, 0x0408},
++{0x2510, 0x1180},
++{0x2510, 0x2652},
++{0x2510, 0x1518},
++{0x2510, 0x0906},
++{0x2510, 0x1348},
++{0x2510, 0x1002},
++{0x2510, 0x1016},
++{0x2510, 0x1181},
++{0x2510, 0x1189},
++{0x2510, 0x1056},
++{0x2510, 0x1210},
++{0x2510, 0x0901},
++{0x2510, 0x0D09},
++{0x2510, 0x1413},
++{0x2510, 0x8809},
++{0x2510, 0x2B15},
++{0x2510, 0x8809},
++{0x2510, 0x0311},
++{0x2510, 0xD909},
++{0x2510, 0x1214},
++{0x2510, 0x4109},
++{0x2510, 0x0312},
++{0x2510, 0x1409},
++{0x2510, 0x0110},
++{0x2510, 0xD612},
++{0x2510, 0x1012},
++{0x2510, 0x1212},
++{0x2510, 0x1011},
++{0x2510, 0xDD11},
++{0x2510, 0xD910},
++{0x2510, 0x5609},
++{0x2510, 0x1511},
++{0x2510, 0xDB09},
++{0x2510, 0x1511},
++{0x2510, 0x9B09},
++{0x2510, 0x0F11},
++{0x2510, 0xBB12},
++{0x2510, 0x1A12},
++{0x2510, 0x1014},
++{0x2510, 0x6012},
++{0x2510, 0x5010},
++{0x2510, 0x7610},
++{0x2510, 0xE609},
++{0x2510, 0x0812},
++{0x2510, 0x4012},
++{0x2510, 0x6009},
++{0x2510, 0x290B},
++{0x2510, 0x0904},
++{0x2510, 0x1440},
++{0x2510, 0x0923},
++{0x2510, 0x15C8},
++{0x2510, 0x13C8},
++{0x2510, 0x092C},
++{0x2510, 0x1588},
++{0x2510, 0x1388},
++{0x2510, 0x0C09},
++{0x2510, 0x0C14},
++{0x2510, 0x4109},
++{0x2510, 0x1112},
++{0x2510, 0x6212},
++{0x2510, 0x6011},
++{0x2510, 0xBF11},
++{0x2510, 0xBB10},
++{0x2510, 0x6611},
++{0x2510, 0xFB09},
++{0x2510, 0x3511},
++{0x2510, 0xBB12},
++{0x2510, 0x6312},
++{0x2510, 0x6014},
++{0x2510, 0x0015},
++{0x2510, 0x0011},
++{0x2510, 0xB812},
++{0x2510, 0xA012},
++{0x2510, 0x0010},
++{0x2510, 0x2610},
++{0x2510, 0x0013},
++{0x2510, 0x0011},
++{0x2510, 0x0008},
++{0x2510, 0x3053},
++{0x2510, 0x4215},
++{0x2510, 0x4013},
++{0x2510, 0x4010},
++{0x2510, 0x0210},
++{0x2510, 0x1611},
++{0x2510, 0x8111},
++{0x2510, 0x8910},
++{0x2510, 0x5612},
++{0x2510, 0x1009},
++{0x2510, 0x010D},
++{0x2510, 0x0815},
++{0x2510, 0xC015},
++{0x2510, 0xD013},
++{0x2510, 0x5009},
++{0x2510, 0x1313},
++{0x2510, 0xD009},
++{0x2510, 0x0215},
++{0x2510, 0xC015},
++{0x2510, 0xC813},
++{0x2510, 0xC009},
++{0x2510, 0x0515},
++{0x2510, 0x8813},
++{0x2510, 0x8009},
++{0x2510, 0x0213},
++{0x2510, 0x8809},
++{0x2510, 0x0411},
++{0x2510, 0xC909},
++{0x2510, 0x0814},
++{0x2510, 0x0109},
++{0x2510, 0x0B11},
++{0x2510, 0xD908},
++{0x2510, 0x1400},
++{0x2510, 0x091A},
++{0x2510, 0x1440},
++{0x2510, 0x0903},
++{0x2510, 0x1214},
++{0x2510, 0x0901},
++{0x2510, 0x10D6},
++{0x2510, 0x1210},
++{0x2510, 0x1212},
++{0x2510, 0x1210},
++{0x2510, 0x11DD},
++{0x2510, 0x11D9},
++{0x2510, 0x1056},
++{0x2510, 0x0917},
++{0x2510, 0x11DB},
++{0x2510, 0x0913},
++{0x2510, 0x11FB},
++{0x2510, 0x0905},
++{0x2510, 0x11BB},
++{0x2510, 0x121A},
++{0x2510, 0x1210},
++{0x2510, 0x1460},
++{0x2510, 0x1250},
++{0x2510, 0x1076},
++{0x2510, 0x10E6},
++{0x2510, 0x0901},
++{0x2510, 0x15A8},
++{0x2510, 0x0901},
++{0x2510, 0x13A8},
++{0x2510, 0x1240},
++{0x2510, 0x1260},
++{0x2510, 0x0925},
++{0x2510, 0x13AD},
++{0x2510, 0x0902},
++{0x2510, 0x0907},
++{0x2510, 0x1588},
++{0x2510, 0x0901},
++{0x2510, 0x138D},
++{0x2510, 0x0B09},
++{0x2510, 0x0914},
++{0x2510, 0x4009},
++{0x2510, 0x0B13},
++{0x2510, 0x8809},
++{0x2510, 0x1C0C},
++{0x2510, 0x0920},
++{0x2510, 0x1262},
++{0x2510, 0x1260},
++{0x2510, 0x11BF},
++{0x2510, 0x11BB},
++{0x2510, 0x1066},
++{0x2510, 0x090A},
++{0x2510, 0x11FB},
++{0x2510, 0x093B},
++{0x2510, 0x11BB},
++{0x2510, 0x1263},
++{0x2510, 0x1260},
++{0x2510, 0x1400},
++{0x2510, 0x1508},
++{0x2510, 0x11B8},
++{0x2510, 0x12A0},
++{0x2510, 0x1200},
++{0x2510, 0x1026},
++{0x2510, 0x1000},
++{0x2510, 0x1300},
++{0x2510, 0x1100},
++{0x2510, 0x437A},
++{0x2510, 0x0609},
++{0x2510, 0x0B05},
++{0x2510, 0x0708},
++{0x2510, 0x4137},
++{0x2510, 0x502C},
++{0x2510, 0x2CFE},
++{0x2510, 0x15FE},
++{0x2510, 0x0C2C},
++
++{0x32e6, 0xe0},
++{0x1008, 0x36f},
++{0x100c, 0x58f},
++{0x100e, 0x7af},
++{0x1010, 0x14f},
++
++{0x3230, 0x312},
++{0x3232, 0x532},
++{0x3234, 0x752},
++{0x3236, 0xf2},
++#endif /* Sequencer Update */
++
++//{0x3566, 0x3328}, // clear bit6
++{0x32D0, 0x3A02},
++{0x32D2, 0x3508},
++{0x32D4, 0x3702},
++{0x32D6, 0x3C04},
++{0x32DC, 0x370A},
++{0x30B0, 0x800}, // clear bit9
++#endif /* Sensor Setup */
++
++#if 1 /* Serial 12-bit Timing Setup */
++/* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
++/* PCLK=24Mhz/2 *44/1/12 *2= 88Mhz - TI serializers */
++{0x302E, 2}, // pre_pll_clk_div
++{0x3030, 44}, // pll_multiplier
++{0x302C, 1}, // vt_sys_clk_div (P1 divider)
++{0x302A, 6}, // vt_pix_clk_div (P2 divider)
++{0x3038, 1}, // op_sys_clk_div (P3 divider)
++{0x3036, 12}, // op_word_clk_div (P4 divider)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++#endif /* Serial 12-bit Timing Setup */
++
++#if 1 /* Readout Mode Configuration */
++{0x30A2, 1}, // x_odd_inc_
++{0x30A6, 1}, // y_odd_inc_
++{0x3040, 0}, // read_mode
++//{0x3082, 0x8}, // operation_mode_ctrl
++//{0x30BA, 0x11E2}, // digital_ctrl
++{0x3044, 0x400}, // dark_control
++#ifdef AR0231_EMBEDDED_LINE
++{0x3064, 0x1982}, // SMIA_TEST
++#else
++{0x3064, 0x1802}, // SMIA_TEST
++#endif
++//{0x33E0, 0xC80},
++//{0x3180, 0x80},
++//{0x33E4, 0x80},
++#endif /* Readout Mode Configuration */
++
++#if 1 /* Full Res FOV */
++{0x3004, AR0231_X_START}, // X_ADDR_START_
++{0x3008, AR0231_X_END}, // X_ADDR_END_
++{0x3002, AR0231_Y_START}, // Y_ADDR_START_
++{0x3006, AR0231_Y_END}, // Y_ADDR_END_
++{0x3032, 0x0}, // scaling_mode
++{0x3400, 0x10},
++{0x3402, 0x0000 | AR0231_MAX_WIDTH}, // X_OUTPUT_CONTROL
++{0x3404, 0x0000 | AR0231_MAX_HEIGHT}, // Y_OUTPUT_CONTROL
++#endif /* Full Res FOV */
++
++#if 1 /* 3exp Timing and Exposure */
++{0x3082, 0x8}, // operation_mode_ctrl
++{0x30BA, 0x11E2}, // digital_ctrl: num_exp_max=2
++
++/* Row and Pixel Timing */
++{0x300C, 1674}, // line_length_pck_
++{0x300A, 1314}, // frame_length_lines_
++{0x3042, 0}, // extra_delay
++
++/* Exposure Settings */
++//{0x3238, 0x222}, // exposure_ratio
++{0x3012, 355}, // coarse_integration_time_
++{0x3014, 1874}, // fine_integration_time_
++{0x321E, 1874}, // fine_integration_time2
++{0x3222, 1874}, // fine_integration_time3
++{0x30B0, 0x800}, // digital_test: set bit11
++{0x32EA, 0x3C0E},
++{0x32EC, 0x72A1},
++#endif /* 3exp Timing and Exposure - Serial */
++
++#if 1 /* HDR 12 bit Output */
++{0x31D0, 1}, // companding
++{0x31AC, 0x140C}, // data_format_bits: RAW20, OUT12
++#endif /* HDR 12 bit Output */
++
++#if 1 /* MIPI 12 bit Settings */
++{0x31AE, 0x204}, // serial_format: MIPI 4 lanes
++{0x3342, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x3346, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334A, 0x2c2c}, // default, DT=0x12, DT=0x2C
++{0x334E, 0x2c2c}, // default, DT=0x12, DT=0x2C
++//{0x3344, 0x0011}, // default, VC=0
++//{0x3348, 0x0111}, // default, VC=1
++//{0x334C, 0x0211}, // default, VC=2
++//{0x3350, 0x0311}, // default, VC=3
++//{0x31B0, 0x49}, // frame_preamble
++//{0x31B2, 0x33}, // line_preamble
++{0x31B4, 0x2185},
++{0x31B6, 0x1146},
++{0x31B8, 0x3047},
++{0x31BA, 0x186},
++{0x31BC, 0x805},
++#endif /* MIPI 12 bit Settings */
++
++/* FPS = 105MHz / reg0x300A / reg0x300C * (DES_XTAL/27MHz), DES_XTAL=23.5MHz */
++{0x300A, AR0231_SENSOR_HEIGHT + 100}, // Frame_length_Lines
++{0x300C, AR0231_SENSOR_WIDTH + 550}, // Line_length_pck
++{0x3012, 0x144}, //Integration_time
++
++#if 0 /* Enable trigger input */
++{0x340A, 0x00E0}, // GPIO_CONTROL1: GPIO0 is trigger
++{0x340C, 0x0002}, // GPIO_CONTROL2: GPIO0 is trigger
++{0x30CE, 0x0120}, // TRIGGER_MODE
++//{0x30DC, 0x0120}, // TRIGGER_DELAY
++{0x301A, 0x0118}, // GPI pins enable
++#endif
++};
++
++/* 3Exp HDR Full Resolution Mode Parallel 12bit 30FPS, XCLK=24MHz */
++static const struct ar0231_reg ar0231_regs_wizard_rev7_dvp[] = {
++#if 1 /* Parallel Timing Setup */
++/* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 */
++/* PCLK=24Mhz/3 *88/1/8 = 88Mhz - TI serializers */
++{0x302A, 8}, // vt_pix_clk_div (P2 divider)
++{0x302C, 1}, // vt_sys_clk_div (P1 divider)
++{0x302E, 3}, // pre_pll_clk_div
++{0x3030, 88}, // pll_multiplier
++{0x3036, 8}, // op_word_clk_div (P4 divider)
++{0x3038, 1}, // op_sys_clk_div (P3 divider)
++{0x30B0, 0x800}, // digital_test: pll_complete_bypass=0
++#endif
++
++#if 1 /* 3exp Timing and Exposure - Parallel */
++{0x3082, 0x8}, // operation_mode_ctrl
++{0x30BA, 0x11E2}, // digital_ctrl: num_exp_max=2
++
++/* Row and Pixel Timing */
++#if 1
++{0x300A, AR0231_SENSOR_HEIGHT + 225}, // frame_length_lines_
++{0x300C, AR0231_SENSOR_WIDTH + 120}, // line_length_pck_
++#else
++{0x300C, 1978}, // line_length_pck_
++{0x300A, 1482}, // frame_length_lines_
++#endif
++{0x3042, 0}, // extra_delay
++
++/* Exposure Settings */
++//{0x3238, 0x222}, // exposure_ratio
++//{0x3012, 355}, // coarse_integration_time_
++{0x3014, 2178}, // fine_integration_time_
++{0x321E, 2178}, // fine_integration_time2
++{0x3222, 2178}, // fine_integration_time3
++{0x30B0, 0x800}, // digital_test: set bit11
++{0x32EA, 0x3C0E},
++{0x32EC, 0x72A1},
++#endif /* 3exp Timing and Exposure - Parallel */
++
++#if 1 /* Parallel HDR 12 bit Output */
++{0x31AE, 0x001}, // serial_format:
++#endif
++
++{0x301A, 0x01d8}, // RESET_REGISTER parallel pins enable
++};
+--
+2.7.4
+
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch
new file mode 100644
index 00000000..45b07d44
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch
@@ -0,0 +1,97 @@
+From 9d8155ae4fbf9f480c993447f6f4753ec2f9c3bf Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 11:03:16 +0300
+Subject: [PATCH] media: i2c: ap0101,ap0201: fix vendor name, fsin fix on ap0102
+
+This fixes vendor name, fix fsync on ap0102
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c | 14 ++++++++++++--
+ drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h | 8 ++++++++
+ drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 6 ++++--
+ 3 files changed, 24 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+index d2a6ff9..526d4ea 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.c
+@@ -27,7 +27,9 @@ static const int ap0101_i2c_addr[] = {0x5d, 0x48};
+
+ #define AP0101_PID_REG 0x0000
+ #define AP0101_REV_REG 0x0058
++#define AP0100_PID 0x0062
+ #define AP0101_PID 0x0160
++#define AP0102_PID 0x0064
+
+ #define AP0101_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8
+
+@@ -434,7 +436,15 @@ static int ap0101_initialize(struct i2c_client *client)
+ priv->max_height = AP0101_MAX_HEIGHT;
+ #endif
+ /* Program wizard registers */
+- ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard));
++ switch (pid) {
++ case AP0100_PID:
++ case AP0101_PID:
++ ap0101_set_regs(client, ap0101_regs_wizard, ARRAY_SIZE(ap0101_regs_wizard));
++ break;
++ case AP0102_PID:
++ ap0101_set_regs(client, ap0102_regs_wizard, ARRAY_SIZE(ap0102_regs_wizard));
++ break;
++ }
+ /* Read OTP IDs */
+ ap0101_otp_id_read(client);
+
+@@ -471,7 +481,7 @@ static const struct i2c_device_id ap0101_id[] = {
+ MODULE_DEVICE_TABLE(i2c, ap0101_id);
+
+ static const struct of_device_id ap0101_of_ids[] = {
+- { .compatible = "onsemi,ap0101", },
++ { .compatible = "onnn,ap0101", },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, ap0101_of_ids);
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
+index d0d6205..5755b87 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
++++ b/drivers/media/i2c/soc_camera/imagers/ap0101_ar014x.h
+@@ -26,3 +26,11 @@ static const struct ap0101_reg ap0101_regs_wizard[] = {
+ {0x0040, 0x8100},
+ {AP0101_DELAY, 100},
+ };
++
++static const struct ap0101_reg ap0102_regs_wizard[] = {
++/* enable FSIN */
++{0xc890, 0x0303},
++{0xfc00, 0x2800},
++{0x0040, 0x8100},
++{AP0101_DELAY, 100},
++};
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+index 7b274ce..10bf6f7 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+@@ -27,7 +27,9 @@ static const int ap0201_i2c_addr[] = {0x5d, 0x48};
+
+ #define AP0201_PID_REG 0x0000
+ #define AP0201_REV_REG 0x0058
+-#define AP0201_PID 0x0064
++#define AP0200_PID 0x0062
++#define AP0201_PID 0x0160
++#define AP0202_PID 0x0064
+
+ #define AP0201_MEDIA_BUS_FMT MEDIA_BUS_FMT_YUYV8_2X8
+
+@@ -446,7 +448,7 @@ static const struct i2c_device_id ap0201_id[] = {
+ MODULE_DEVICE_TABLE(i2c, ap0201_id);
+
+ static const struct of_device_id ap0201_of_ids[] = {
+- { .compatible = "onsemi,ap0201", },
++ { .compatible = "onnn,ap0201", },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, ap0201_of_ids);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch
new file mode 100644
index 00000000..98a00d29
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0508-media-i2c-fix-indentation.patch
@@ -0,0 +1,46 @@
+From b6a59d9176b872d7247b5829f5d3112376fc4877 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 11:05:05 +0300
+Subject: [PATCH] media: i2c: fix indentation
+
+Indentation fixes
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/fpdlink/ti9x4.c | 2 +-
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+index a50201d..56b5ed8a 100644
+--- a/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
++++ b/drivers/media/i2c/soc_camera/fpdlink/ti9x4.c
+@@ -218,7 +218,7 @@ static void ti9x4_initial_setup(struct i2c_client *client)
+ #else
+ reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */
+ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */
+- reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
++ reg8_write(client, 0x1b, priv->fs_time >> 8); /* FrameSync low time MSB */
+ reg8_write(client, 0x1c, priv->fs_time & 0xff); /* FrameSync low time LSB */
+ reg8_write(client, 0x18, 0x00); /* Disable FrameSync - must be enabled after all cameras are set up */
+ #endif
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+index 02ccc38..c4cdf0e 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -494,9 +494,9 @@ static int max96712_gmsl1_link_serializer_setup(struct max96712_priv *priv, int
+ /* GMSL setup */
+ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
+ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
+- (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
+- (0x80) | /* DBL=1 in serializer */
+- (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
+ usleep_range(2000, 2500);
+ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
+ usleep_range(2000, 2500);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch
new file mode 100644
index 00000000..4bd48b82
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0509-media-i2c-fix-broken-old-LVDS-imagers.patch
@@ -0,0 +1,33 @@
+From e24f11423cea901af73faaacbd3c1614f4be2954 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 11:06:12 +0300
+Subject: [PATCH] media: i2c: fix broken old LVDS imagers
+
+This fixes broken old LVDS imagers from support.
+We temporary need to support these
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/Makefile | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile
+index 5e08254..8640bac 100644
+--- a/drivers/media/i2c/soc_camera/Makefile
++++ b/drivers/media/i2c/soc_camera/Makefile
+@@ -11,10 +11,11 @@ obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
+ obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
+ obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
+ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+-obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o
+ obj-$(CONFIG_SOC_CAMERA_IMX219) += imx219.o
+
+ obj-$(CONFIG_SOC_CAMERA_AR0147) += ar0147.o
+ obj-y += imagers/
+ obj-y += gmsl/
+ obj-y += fpdlink/
++
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov106xx.o
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch
new file mode 100644
index 00000000..eda17d66
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0510-arm64-dts-renesas-add-camera-dtsi-file.patch
@@ -0,0 +1,120 @@
+From 048fcef8ad30f5a5158b3f3d2c2cf1c63fe51b90 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 11:15:37 +0300
+Subject: [PATCH] arm64: dts: renesas: add camera dtsi file
+
+This adds camera dtsi file for common data
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/camera.dtsi | 30 ++++++++++++++++++++++
+ .../dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 22 +---------------
+ .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 22 +---------------
+ 3 files changed, 32 insertions(+), 42 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/renesas/camera.dtsi
+
+diff --git a/arch/arm64/boot/dts/renesas/camera.dtsi b/arch/arm64/boot/dts/renesas/camera.dtsi
+new file mode 100644
+index 0000000..0216327
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/camera.dtsi
+@@ -0,0 +1,30 @@
++/*
++ * Device Tree Source for the LVDS cameras
++ *
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#define COMPATIBLE_CAMERAS \
++ "onnn,ar0140", \
++ "onnn,ar0143", \
++ "onnn,ar0147", \
++ "onnn,ar0231", \
++ "onnn,ar0233", \
++ "onnn,ap0101", \
++ "onnn,ap0201", \
++ "ovti,ov10635", \
++ "ovti,ov10640", \
++ "ovti,ov2311", \
++ "ovti,ov2775", \
++ "ovti,ov490", \
++ "ovti,ov495", \
++ "ovti,ox01d10", \
++ "ovti,ox03a", \
++ "sony,imx390", \
++ "sony,isx016", \
++ "sony,isx019", \
++ "dummy,camera"
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+index 155b73f..4d284b1 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+@@ -12,27 +12,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+ /* FDPLink output */
+ //#include "vb-fdplink-output.dtsi"
+-
+-#define COMPATIBLE_CAMERAS \
+-"onsemi,ar0140", \
+-"onsemi,ar0143", \
+-"onsemi,ar0147", \
+-"onsemi,ar0231", \
+-"onsemi,ar0233", \
+-"onsemi,ap0101", \
+-"onsemi,ap0201", \
+-"ovti,ov10635", \
+-"ovti,ov10640", \
+-"ovti,ov2311", \
+-"ovti,ov2775", \
+-"ovti,ov490", \
+-"ovti,ov495", \
+-"ovti,ox01d10", \
+-"ovti,ox03a", \
+-"sony,imx390", \
+-"sony,isx016", \
+-"sony,isx019", \
+-"dummy,camera"
++#include "camera.dtsi"
+
+ / {
+ model = "Renesas V3HSK 2x2ch GMSL2 Videobox board based on r8a7798";
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+index 310061f..ac2d825 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+@@ -12,27 +12,7 @@
+ #include <dt-bindings/gpio/gpio.h>
+ /* FDPLink output */
+ //#include "vb-fdplink-output.dtsi"
+-
+-#define COMPATIBLE_CAMERAS \
+-"onsemi,ar0140", \
+-"onsemi,ar0143", \
+-"onsemi,ar0147", \
+-"onsemi,ar0231", \
+-"onsemi,ar0233", \
+-"onsemi,ap0101", \
+-"onsemi,ap0201", \
+-"ovti,ov10635", \
+-"ovti,ov10640", \
+-"ovti,ov2311", \
+-"ovti,ov2775", \
+-"ovti,ov490", \
+-"ovti,ov495", \
+-"ovti,ox01d10", \
+-"ovti,ox03a", \
+-"sony,imx390", \
+-"sony,isx016", \
+-"sony,isx019", \
+-"dummy,camera"
++#include "camera.dtsi"
+
+ / {
+ model = "Renesas V3HSK 4ch GMSL2 Videobox board based on r8a77980";
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch
new file mode 100644
index 00000000..dccf8c03
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0511-media-i2c-ap0201-detect-AP0200-AP0202.patch
@@ -0,0 +1,85 @@
+From bc27eaaaddb5ebc94daa3a7f91d753162de944b9 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 16:33:49 +0300
+Subject: [PATCH 1/2] media: i2c: ap0201: detect AP0200, AP0202
+
+This allows to detect AP0200 and AP0202 imagers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ .../media/i2c/soc_camera/imagers/ap0201_ar023x.c | 6 +++---
+ drivers/media/i2c/soc_camera/imagers/dummy.c | 24 +++++++++++-----------
+ 2 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+index 10bf6f7..ad18e2e 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+@@ -411,11 +411,11 @@ static int ap0201_initialize(struct i2c_client *client)
+
+ /* check product ID */
+ reg16_read16(client, AP0201_PID_REG, &pid);
+- if (pid == AP0201_PID)
++ if (pid == AP0200_PID || pid == AP0201_PID || pid == AP0202_PID)
+ break;
+ }
+
+- if (pid != AP0201_PID) {
++ if (pid != AP0200_PID && pid != AP0201_PID && pid != AP0202_PID) {
+ dev_dbg(&client->dev, "Product ID error %x\n", pid);
+ return -ENODEV;
+ }
+@@ -436,7 +436,7 @@ static int ap0201_initialize(struct i2c_client *client)
+ /* Read OTP IDs */
+ ap0201_otp_id_read(client);
+
+- dev_info(&client->dev, "ap0201 PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ dev_info(&client->dev, "ap020X PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ return 0;
+ }
+diff --git a/drivers/media/i2c/soc_camera/imagers/dummy.c b/drivers/media/i2c/soc_camera/imagers/dummy.c
+index d213fff..e4070fc 100644
+--- a/drivers/media/i2c/soc_camera/imagers/dummy.c
++++ b/drivers/media/i2c/soc_camera/imagers/dummy.c
+@@ -343,6 +343,18 @@ static int dummy_initialize(struct i2c_client *client)
+ return 0;
+ }
+
++static const struct i2c_device_id dummy_id[] = {
++ { "dummy-camera", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, dummy_id);
++
++static const struct of_device_id dummy_of_ids[] = {
++ { .compatible = "dummy,camera", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, dummy_of_ids);
++
+ static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv)
+ {
+ if (of_property_read_u32(np, "dummy,width", &priv->max_width))
+@@ -463,18 +475,6 @@ static int dummy_remove(struct i2c_client *client)
+ return 0;
+ }
+
+-static const struct i2c_device_id dummy_id[] = {
+- { "dummy-camera", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(i2c, dummy_id);
+-
+-static const struct of_device_id dummy_of_ids[] = {
+- { .compatible = "dummy-camera", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, dummy_of_ids);
+-
+ static struct i2c_driver dummy_i2c_driver = {
+ .driver = {
+ .name = "dummy-camera",
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch
new file mode 100644
index 00000000..198d1daf
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch
@@ -0,0 +1,1949 @@
+From fabd912331128d45339dd6f9282aa623c1b92bb1 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Thu, 30 Apr 2020 16:34:44 +0300
+Subject: [PATCH 2/2] arm64: dts: renesas: add H3 GMSL2 Videobox
+
+This is GMSL2 RCAR H3 Videobox 2.1 support
+This is interim support since all serializers soon will
+be integrated to PnP.
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/Makefile | 1 +
+ .../renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts | 68 +
+ .../dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts | 68 +
+ arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi | 1662 ++++++++++++++++++++
+ arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi | 90 ++
+ 5 files changed, 1889 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts
+ create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi
+ create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index f18c742..cd53aaf 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -26,6 +26,7 @@ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-kf.dtb r8a7795-h3ulcb-4x2g-kf.dtb r
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb.dtb r8a7795-es1-h3ulcb-vb.dtb r8a7795-h3ulcb-4x2g-vb.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.dtb r8a7795-es1-h3ulcb-vb2.dtb r8a7795-h3ulcb-4x2g-vb2.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.1.dtb r8a7795-h3ulcb-4x2g-vb2.1.dtb
++dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vb2.1-gmsl2.dtb r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-vbm.dtb r8a7795-es1-h3ulcb-vbm.dtb r8a7795-h3ulcb-4x2g-vbm.dtb
+ dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-m3nulcb-kf.dtb
+ dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle-function.dtb
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts
+new file mode 100644
+index 0000000..54170c9
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-4x2g-vb2.1-gmsl2.dts
+@@ -0,0 +1,68 @@
++/*
++ * Device Tree Source for the 8GB H3ULCB Videobox board V2.1 on r8a7795
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a7795-h3ulcb-4x2g.dts"
++#include "ulcb-vb2.1-gmsl2.dtsi"
++
++/ {
++ model = "Renesas H3ULCB Videobox V2.1 board based on r8a7795 with 8GiB (4 x 2 GiB)";
++
++ hdmi1-out {
++ compatible = "hdmi-connector";
++ type = "a";
++
++ port {
++ hdmi1_con: endpoint {
++ remote-endpoint = <&rcar_dw_hdmi1_out>;
++ };
++ };
++ };
++};
++
++&du {
++ ports {
++ port@2 {
++ endpoint {
++ remote-endpoint = <&rcar_dw_hdmi1_in>;
++ };
++ };
++ port@3 {
++ endpoint {
++ remote-endpoint = <&lvds_in>;
++ };
++ };
++ };
++};
++
++&hdmi1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++ rcar_dw_hdmi1_in: endpoint {
++ remote-endpoint = <&du_out_hdmi1>;
++ };
++ };
++ port@1 {
++ reg = <1>;
++ rcar_dw_hdmi1_out: endpoint {
++ remote-endpoint = <&hdmi1_con>;
++ };
++ };
++ };
++};
++
++&hsusb {
++ status = "okay";
++};
+diff --git a/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts
+new file mode 100644
+index 0000000..144b035
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.1-gmsl2.dts
+@@ -0,0 +1,68 @@
++/*
++ * Device Tree Source for the H3ULCB Videobox board V2.1 on r8a7795
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a7795-h3ulcb.dts"
++#include "ulcb-vb2.1-gmsl2.dtsi"
++
++/ {
++ model = "Renesas H3ULCB Videobox V2.1 board based on r8a7795";
++
++ hdmi1-out {
++ compatible = "hdmi-connector";
++ type = "a";
++
++ port {
++ hdmi1_con: endpoint {
++ remote-endpoint = <&rcar_dw_hdmi1_out>;
++ };
++ };
++ };
++};
++
++&du {
++ ports {
++ port@2 {
++ endpoint {
++ remote-endpoint = <&rcar_dw_hdmi1_in>;
++ };
++ };
++ port@3 {
++ endpoint {
++ remote-endpoint = <&lvds_in>;
++ };
++ };
++ };
++};
++
++&hdmi1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ reg = <0>;
++ rcar_dw_hdmi1_in: endpoint {
++ remote-endpoint = <&du_out_hdmi1>;
++ };
++ };
++ port@1 {
++ reg = <1>;
++ rcar_dw_hdmi1_out: endpoint {
++ remote-endpoint = <&hdmi1_con>;
++ };
++ };
++ };
++};
++
++&hsusb {
++ status = "okay";
++};
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi
+new file mode 100644
+index 0000000..64f54f5
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2-gmsl2.dtsi
+@@ -0,0 +1,1662 @@
++/*
++ * Device Tree Source for the ULCB Videobox V2 board
++ *
++ * Copyright (C) 2018 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "camera.dtsi"
++
++/ {
++ cs2300_ref_clk: cs2300_ref_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <25000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led5 {
++ gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>;
++ };
++ led6 {
++ gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>;
++ };
++ /* D13 - status 0 */
++ led_ext00 {
++ gpios = <&gpio_ext_led 0 GPIO_ACTIVE_LOW>;
++ /* linux,default-trigger = "heartbeat"; */
++ };
++ /* D14 - status 1 */
++ led_ext01 {
++ gpios = <&gpio_ext_led 1 GPIO_ACTIVE_LOW>;
++ /* linux,default-trigger = "mmc1"; */
++ };
++ /* D16 - HDMI0 */
++ led_ext02 {
++ gpios = <&gpio_ext_led 2 GPIO_ACTIVE_LOW>;
++ };
++ /* D18 - HDMI1 */
++ led_ext03 {
++ gpios = <&gpio_ext_led 3 GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ vcc_sdhi3: regulator-vcc-sdhi3 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "SDHI3 Vcc";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++
++ gpio = <&gpio4 17 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ vccq_sdhi3: regulator-vccq-sdhi3 {
++ compatible = "regulator-fixed";
++
++ regulator-name = "SDHI3 VccQ";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ fpdlink_switch: regulator@8 {
++ compatible = "regulator-fixed";
++ regulator-name = "fpdlink_on";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio1 20 0>;
++ enable-active-high;
++ regulator-always-on;
++ };
++
++ can2_power: regulator@9 {
++ compatible = "regulator-fixed";
++ regulator-name = "can2_power";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio_ext_pwr 8 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ can3_power: regulator@10 {
++ compatible = "regulator-fixed";
++ regulator-name = "can3_power";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio_ext_pwr 9 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ lvds {
++ compatible = "panel-lvds";
++
++ width-mm = <210>;
++ height-mm = <158>;
++
++ data-mapping = "jeida-24";
++
++ panel-timing {
++ /* 1280x800 @60Hz */
++ clock-frequency = <65000000>;
++ hactive = <1280>;
++ vactive = <800>;
++ hsync-len = <40>;
++ hfront-porch = <80>;
++ hback-porch = <40>;
++ vfront-porch = <14>;
++ vback-porch = <14>;
++ vsync-len = <4>;
++ };
++
++ port {
++ lvds_in: endpoint {
++ remote-endpoint = <&du_out_lvds0>;
++ };
++ };
++ };
++
++ excan_ref_clk: excan-ref-clock {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <16000000>;
++ };
++
++ spi_gpio_sw {
++ compatible = "spi-gpio";
++ #address-cells = <0x1>;
++ #size-cells = <0x0>;
++ gpio-sck = <&gpio0 8 GPIO_ACTIVE_HIGH>;
++ gpio-miso = <&gpio0 10 GPIO_ACTIVE_HIGH>;
++ gpio-mosi = <&gpio0 11 GPIO_ACTIVE_HIGH>;
++ cs-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
++ num-chipselects = <1>;
++
++ spidev: spidev@0 {
++ compatible = "spidev", "spi-gpio";
++ reg = <0>;
++ spi-max-frequency = <25000000>;
++ spi-cpha;
++ spi-cpol;
++ };
++ };
++
++ spi_gpio_can {
++ compatible = "spi-gpio";
++ #address-cells = <0x1>;
++ #size-cells = <0x0>;
++ gpio-sck = <&gpio1 2 GPIO_ACTIVE_HIGH>;
++ gpio-miso = <&gpio1 3 GPIO_ACTIVE_HIGH>;
++ gpio-mosi = <&gpio1 1 GPIO_ACTIVE_HIGH>;
++ cs-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH
++ &gpio1 4 GPIO_ACTIVE_HIGH>;
++ num-chipselects = <2>;
++
++ spican0: spidev@0 {
++ compatible = "microchip,mcp2515";
++ reg = <0>;
++ clocks = <&excan_ref_clk>;
++ interrupt-parent = <&gpio0>;
++ interrupts = <15 GPIO_ACTIVE_LOW>;
++ spi-max-frequency = <10000000>;
++ vdd-supply = <&can2_power>;
++ };
++ spican1: spidev@1 {
++ compatible = "microchip,mcp2515";
++ reg = <1>;
++ clocks = <&excan_ref_clk>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <5 GPIO_ACTIVE_LOW>;
++ spi-max-frequency = <10000000>;
++ vdd-supply = <&can3_power>;
++ };
++ };
++
++ /* camera slot A */
++ iio_hwmon_a: hwmon_a@1 {
++ compatible = "iio-hwmon";
++ io-channels =
++ /* current */
++ <&max2008x_a 0>,
++ <&max2008x_a 2>,
++ /* voltage */
++ <&max2008x_a 4>,
++ <&max2008x_a 6>,
++ /* misc voltages */
++ <&max2008x_a 8>,
++ <&max2008x_a 9>;
++ io-channel-names =
++ "camera-A-0-Iout",
++ "camera-A-1-Iout",
++ "camera-A-0-Vout",
++ "camera-A-1-Vout",
++ "cameras-A-Vregulator",
++ "cameras-A-3v3";
++ };
++};
++
++&pfc {
++ hscif4_pins: hscif4 {
++ groups = "hscif4_data_a", "hscif4_ctrl";
++ function = "hscif4";
++ };
++
++ usb0_pins: usb0 {
++ groups = "usb0";
++ function = "usb0";
++ };
++
++ usb2_pins: usb2 {
++ groups = "usb2";
++ function = "usb2";
++ };
++
++ usb30_pins: usb30 {
++ groups = "usb30";
++ function = "usb30";
++ };
++
++ can0_pins: can0 {
++ groups = "can0_data_a";
++ function = "can0";
++ };
++
++ can1_pins: can1 {
++ groups = "can1_data";
++ function = "can1";
++ };
++
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data_a";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ sdhi3_pins: sd3 {
++ groups = "sdhi3_data4", "sdhi3_ctrl";
++ function = "sdhi3";
++ power-source = <3300>;
++ };
++
++ sdhi3_pins_uhs: sd3_uhs {
++ groups = "sdhi3_data4", "sdhi3_ctrl";
++ function = "sdhi3";
++ power-source = <1800>;
++ };
++};
++
++&gpio0 {
++ video_a_irq {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-A irq";
++ };
++
++ video_b_irq {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-B irq";
++ };
++
++ video_c_irq {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C irq";
++ };
++ can2_irq {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "CAN2 irq";
++ };
++};
++
++&gpio1 {
++ can3_irq {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "CAN3 irq";
++ };
++ gpioext_4_22_irq {
++ gpio-hog;
++ gpios = <25 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "0x22@i2c4 irq";
++ };
++ m2_0_sleep {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M2 0 SLEEP#";
++ };
++ m2_1_sleep {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M2 1 SLEEP#";
++ };
++ m2_0_pcie_det {
++ gpio-hog;
++ gpios = <18 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 0 PCIe/SATA";
++ };
++ m2_1_pcie_det {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 1 PCIe/SATA";
++ };
++ m2_1_rst {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 1 RST#";
++ };
++ switch_ext_phy_reset {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR ext phy reset";
++ };
++ switch_sw_reset {
++ gpio-hog;
++ gpios = <17 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR switch reset";
++ };
++ switch_1v2_en {
++ gpio-hog;
++ gpios = <27 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR 1.2V en";
++ };
++};
++
++&gpio2 {
++ m2_0_wake {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 0 WAKE#";
++ };
++ m2_0_clkreq {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 0 CLKREQ#";
++ };
++ switch_3v3_en {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR 3.3V en";
++ };
++};
++
++&gpio3 {
++ switch_int_phy_reset {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR int phy reset";
++ };
++};
++
++&gpio5 {
++ switch_2v5_en {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR 2.5V en";
++ };
++ switch_25mhz_en {
++ gpio-hog;
++ gpios = <8 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "BR 25MHz clk en";
++ };
++};
++
++&gpio6 {
++ m2_1_wake {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 1 WAKE#";
++ };
++ m2_1_clkreq {
++ gpio-hog;
++ gpios = <10 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "M.2 1 CLKREQ#";
++ };
++
++ m2_0_rst {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 0 RST#";
++ };
++};
++
++&i2c2 {
++ clock-frequency = <400000>;
++
++ i2cswitch2: pca9548@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios = <&gpio6 5 GPIO_ACTIVE_LOW>;
++
++ i2c@4 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <4>;
++ /* USB3.0 HUB node(s) */
++ tusb8041_44@44 {
++ compatible = "ti,tusb8041";
++ reg = <0x44>;
++ reset-gpios = <&gpio5 5 0>;
++ ti,registers = /bits/ 8 <
++ 0x05 0x10
++ 0x06 0x0f
++ 0x07 0x8f
++ 0x08 0x0f
++ 0x0a 0x20
++ 0x0b 0x80>;
++ };
++ tusb8041_45@45 {
++ compatible = "ti,tusb8041";
++ reg = <0x45>;
++ reset-gpios = <&gpio5 5 0>;
++ ti,registers = /bits/ 8 <
++ 0x05 0x10
++ 0x06 0x0f
++ 0x07 0x8f
++ 0x08 0x0f
++ 0x0a 0x20
++ 0x0b 0x80>;
++ };
++ };
++
++ /* Slot A (CN10) */
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ max96712@29 {
++ compatible = "maxim,max96712";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x29>;
++ clocks = <&cs2300_a>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_a_5c 13 GPIO_ACTIVE_LOW>;
++
++ maxim,link-mipi-map = <1 1 1 1>;
++
++ poc0-supply = <&vdd_cam_a_0>;
++ poc1-supply = <&vdd_cam_a_1>;
++ poc2-supply = <&vdd_cam_a_2>;
++ poc3-supply = <&vdd_cam_a_3>;
++
++ port@0 {
++ reg = <4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ max96712_des0ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in0>;
++ };
++ max96712_des0ep1: endpoint@1 {
++ ser-addr = <0x0d>;
++ remote-endpoint = <&camera_in1>;
++ };
++ max96712_des0ep2: endpoint@2 {
++ ser-addr = <0x0e>;
++ remote-endpoint = <&camera_in2>;
++ };
++ max96712_des0ep3: endpoint@3 {
++ ser-addr = <0x0f>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++
++ port@1 {
++ max96712_des0csi0ep0: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++
++
++ i2c_des@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@0 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep0: endpoint {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++ };
++
++ i2c_des@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@1 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0d>;
++
++ port@0 {
++ camera_in1: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin1ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep1: endpoint {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++ };
++
++ i2c_des@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ camera@2 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x62 0x0e>;
++
++ port@0 {
++ camera_in2: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin2ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep2: endpoint {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++ };
++
++ i2c_des@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ camera@3 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x63 0x0f>;
++
++ port@0 {
++ camera_in3: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin3ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep3: endpoint {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* Slot B (CN11) */
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ max96712@29 {
++ compatible = "maxim,max96712_XX";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x29>;
++ clocks = <&cs2300_b>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_b_5c 13 GPIO_ACTIVE_LOW>;
++
++ maxim,link-mipi-map = <1 1 1 1>;
++
++ poc0-supply = <&vdd_cam_b_0>;
++ poc1-supply = <&vdd_cam_b_1>;
++ poc2-supply = <&vdd_cam_b_2>;
++ poc3-supply = <&vdd_cam_b_3>;
++
++ port@0 {
++ reg = <4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ max96712_des1ep0: endpoint@0 {
++ ser-addr = <0x1c>;
++ remote-endpoint = <&camera_in4>;
++ };
++ max96712_des1ep1: endpoint@1 {
++ ser-addr = <0x1d>;
++ remote-endpoint = <&camera_in5>;
++ };
++ max96712_des1ep2: endpoint@2 {
++ ser-addr = <0x1e>;
++ remote-endpoint = <&camera_in6>;
++ };
++ max96712_des1ep3: endpoint@3 {
++ ser-addr = <0x1f>;
++ remote-endpoint = <&camera_in7>;
++ };
++ };
++
++ port@1 {
++ reg = <5>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ max96712_des1csi0ep0: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++
++ i2c_des@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@0 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x64 0x1c>;
++
++ port@0 {
++ camera_in4: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin4ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep0: endpoint {
++ remote-endpoint = <&max96712_des1ep0>;
++ };
++ };
++ };
++ };
++
++ i2c_des@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@1 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x65 0x1d>;
++
++ port@0 {
++ camera_in5: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin5ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep1: endpoint {
++ remote-endpoint = <&max96712_des1ep1>;
++ };
++ };
++ };
++ };
++
++ i2c_des@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ camera@2 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x66 0x1e>;
++
++ port@0 {
++ camera_in6: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin6ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep2: endpoint {
++ remote-endpoint = <&max96712_des1ep2>;
++ };
++ };
++ };
++ };
++
++ i2c_des@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ camera@3 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x67 0x1f>;
++
++ port@0 {
++ camera_in7: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin7ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep3: endpoint {
++ remote-endpoint = <&max96712_des1ep3>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* Slot A (CN10) */
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ /* PCA9535 is a redundant/deprecated card */
++ gpio_exp_a_26: gpio@26 {
++ compatible = "nxp,pca9535";
++ reg = <0x26>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_a_pwr_shdn {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR_SHDN";
++ };
++ video_a_cam_pwr0 {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR0";
++ };
++ video_a_cam_pwr1 {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR1";
++ };
++ video_a_cam_pwr2 {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR2";
++ };
++ video_a_cam_pwr3 {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR3";
++ };
++ video_a_des_shdn {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A DES_SHDN";
++ };
++ video_a_des_led {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-A led";
++ };
++ };
++
++ gpio_exp_a_5c: gpio@5c {
++ compatible = "maxim,max7325";
++ reg = <0x5c>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_a_des_cfg0 {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-A cfg0";
++ };
++ video_a_pwr_shdn {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A PWR_SHDN";
++ };
++/*
++ video_a_des_shdn {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-A DES_SHDN";
++ };
++*/
++ video_a_led {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-A LED";
++ };
++ };
++
++ cs2300_a: clk_multiplier_a@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300_a>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam_a: dac_vcam_a@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ };
++
++ max2008x_a: vcam_switch_a@28 {
++ compatible = "maxim,max2008x";
++ reg = <0x28>;
++ #io-channel-cells = <1>;
++
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ vdd_cam_a_0: SW0 {
++ reg = <0>;
++ regulator-name = "Camera-A-0";
++ };
++ vdd_cam_a_3: SW1 {
++ reg = <1>;
++ regulator-name = "Camera-A-3";
++ };
++ vdd_cam_a_1: SW2 {
++ reg = <2>;
++ regulator-name = "Camera-A-1";
++ };
++ vdd_cam_a_2: SW3 {
++ reg = <3>;
++ regulator-name = "Camera-A-2";
++ };
++ };
++ };
++ };
++
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ /* Slot B (CN11) */
++
++ /* PCA9535 is a redundant/deprecated card */
++ gpio_exp_b_26: gpio@26 {
++ compatible = "nxp,pca9535";
++ reg = <0x26>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_b_des_cfg1 {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-B cfg1";
++ };
++ video_b_des_cfg0 {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-B cfg0";
++ };
++ video_b_pwr_shdn {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR_SHDN";
++ };
++ video_b_cam_pwr0 {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR0";
++ };
++ video_b_cam_pwr1 {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR1";
++ };
++ video_b_cam_pwr2 {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR2";
++ };
++ video_b_cam_pwr3 {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR3";
++ };
++ video_b_des_shdn {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B DES_SHDN";
++ };
++ video_b_des_led {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-B led";
++ };
++ };
++
++ gpio_exp_b_5c: gpio@5c {
++ compatible = "maxim,max7325";
++ reg = <0x5c>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_b_des_cfg0 {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-B cfg0";
++ };
++ video_b_pwr_shdn {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B PWR_SHDN";
++ };
++/*
++ video_b_des_shdn {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-B DES_SHDN";
++ };
++*/
++ video_b_led {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-B LED";
++ };
++ };
++
++ cs2300_b: clk_multiplier_b@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300_b>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam_b: dac_vcam_b@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ };
++
++ max2008x_b: vcam_switch_b@28 {
++ compatible = "maxim,max2008x";
++ reg = <0x28>;
++ #io-channel-cells = <1>;
++
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ vdd_cam_b_0: SW0 {
++ reg = <0>;
++ regulator-name = "Camera-B-0";
++ };
++ vdd_cam_b_3: SW1 {
++ reg = <1>;
++ regulator-name = "Camera-B-3";
++ };
++ vdd_cam_b_1: SW2 {
++ reg = <2>;
++ regulator-name = "Camera-B-1";
++ };
++ vdd_cam_b_2: SW3 {
++ reg = <3>;
++ regulator-name = "Camera-B-2";
++ };
++ };
++ };
++ };
++
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++ /* Slot C (CN12) */
++
++ gpio_exp_c_5c: gpio@5c {
++ compatible = "maxim,max7325";
++ reg = <0x5c>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ video_c_des_cfg0 {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "Video-C cfg0";
++ };
++ video_c_pwr_shdn {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C PWR_SHDN";
++ };
++/*
++ video_c_des_shdn {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "Video-C DES_SHDN";
++ };
++*/
++ video_c_led {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "Video-C LED";
++ };
++ };
++
++ cs2300_c: clk_multiplier_c@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300_c>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam_c: dac_vcam_c@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ };
++
++ max2008x_c: vcam_switch_c@28 {
++ compatible = "maxim,max2008x";
++ reg = <0x28>;
++ #io-channel-cells = <1>;
++
++ regulators {
++ vdd_cam_c_0: SW0 {
++ regulator-name = "Camera-C-0";
++ };
++ vdd_cam_c_1: SW2 {
++ regulator-name = "Camera-C-1";
++ };
++ };
++ };
++ };
++ };
++};
++
++&i2c4 {
++ i2cswitch4: pca9548@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios= <&gpio5 15 GPIO_ACTIVE_LOW>;
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++ /* FAN1 node - lm96063 */
++ fan_ctrl_1:lm96063-1@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ i2c@6 {
++ /* FAN2 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <6>;
++ /* FAN2 node - lm96063 */
++ fan_ctrl_2:lm96063-2@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ /* Power nodes - 2 x TPS544x20 */
++ tps_5v: tps544c20@0x2a {
++ compatible = "tps544c20";
++ reg = <0x2c>;
++ status = "disabled";
++ };
++ tps_3v3: tps544c20@0x22 {
++ compatible = "tps544c20";
++ reg = <0x24>;
++ status = "disabled";
++ };
++ };
++
++ i2c_power: i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++ /* CAN and power board nodes */
++
++ gpio_ext_pwr: pca9535@22 {
++ compatible = "nxp,pca9535";
++ reg = <0x22>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ interrupt-parent = <&gpio1>;
++ interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
++
++ /* enable input DCDC after wake-up signal released */
++ pwr_hold {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "pwr_hold";
++ };
++ pwr_5v_out {
++ gpio-hog;
++ gpios = <14 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "pwr_5v_out";
++ };
++ pwr_5v_oc {
++ gpio-hog;
++ gpios = <15 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "pwr_5v_oc";
++ };
++ pwr_wake8 {
++ gpio-hog;
++ gpios = <12 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "wake8";
++ };
++ pwr_wake7 {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "wake7";
++ };
++
++ /* CAN0 */
++ can0_stby {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "can0_stby";
++ };
++ can0_load {
++ gpio-hog;
++ gpios = <0 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "can0_120R_load";
++ };
++ /* CAN1 */
++ can1_stby {
++ gpio-hog;
++ gpios = <5 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "can1_stby";
++ };
++ can1_load {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "can1_120R_load";
++ };
++ /* CAN2 */
++ can2_stby {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "can2_stby";
++ };
++ can2_load {
++ gpio-hog;
++ gpios = <2 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "can2_120R_load";
++ };
++ /* CAN3 */
++ can3_stby {
++ gpio-hog;
++ gpios = <7 GPIO_ACTIVE_HIGH>;
++ output-low;
++ line-name = "can3_stby";
++ };
++ can3_load {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "can3_120R_load";
++ };
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++ /* FPDLink output node - DS90UH947 */
++ };
++
++ i2c@4 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <4>;
++ /* BCM switch node */
++ };
++
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++ /* LED board node(s) */
++
++ gpio_ext_led: pca9535@22 {
++ compatible = "nxp,pca9535";
++ reg = <0x22>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ /* gpios 0..7 are used for indication LEDs, low-active */
++ };
++ rtc: mcp79411@6f {
++ compatible = "microchip,mcp7941x";
++ reg = <0x6f>;
++ };
++ };
++
++ /* port 7 is not used */
++ };
++};
++
++&pcie_bus_clk {
++ clock-frequency = <100000000>;
++ status = "okay";
++};
++
++&pciec0 {
++ status = "okay";
++};
++
++&pciec1 {
++ status = "okay";
++};
++
++&vin0 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin0ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in0>;
++ };
++ };
++ port@1 {
++ csi40ep0: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin0_mmax96712_des0ep0: endpoint {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++};
++
++&vin1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin1ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in1>;
++ };
++ };
++ port@1 {
++ csi40ep1: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin1_max96712_des0ep1: endpoint {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++};
++
++&vin2 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin2ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in2>;
++ };
++ };
++ port@1 {
++ csi40ep2: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin2_max96712_des0ep2: endpoint {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++};
++
++&vin3 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin3ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++ port@1 {
++ csi40ep3: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin3_max96712_des0ep3: endpoint {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++};
++
++&vin4 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin4ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <0>;
++ remote-endpoint = <&camera_in4>;
++ data-lanes = <1 2 3 4>;
++ };
++ };
++ port@1 {
++ csi41ep0: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin4_max96712_des0ep1: endpoint {
++ remote-endpoint = <&max96712_des1ep0>;
++ };
++ };
++ };
++};
++
++&vin5 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin5ep0: endpoint@0 {
++ csi,select = "csi41";
++ virtual,channel = <1>;
++ remote-endpoint = <&camera_in5>;
++ data-lanes = <1 2 3 4>;
++ };
++ };
++ port@1 {
++ csi41ep1: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin5_max96712_des0ep1: endpoint {
++ remote-endpoint = <&max96712_des1ep1>;
++ };
++ };
++ };
++};
++
++&vin6 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin6ep0: endpoint@0 {
++ csi,select = "csi41";
++ virtual,channel = <2>;
++ remote-endpoint = <&camera_in6>;
++ data-lanes = <1 2 3 4>;
++ };
++ };
++ port@1 {
++ csi41ep2: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin6_max96712_des2ep2: endpoint {
++ remote-endpoint = <&max96712_des1ep2>;
++ };
++ };
++ };
++};
++
++&vin7 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin7ep0: endpoint@0 {
++ csi,select = "csi41";
++ virtual,channel = <3>;
++ remote-endpoint = <&camera_in7>;
++ data-lanes = <1 2 3 4>;
++ };
++ };
++ port@1 {
++ csi41ep3: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin7_max96712_des2ep3: endpoint {
++ remote-endpoint = <&max96712_des1ep3>;
++ };
++ };
++ };
++};
++
++&csi40 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi40_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <300>;
++ };
++ };
++};
++
++&csi41 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi41_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <300>;
++ };
++ };
++};
++
++&ssi1 {
++ /delete-property/shared-pin;
++};
++
++&sdhi3 {
++ pinctrl-0 = <&sdhi3_pins>;
++ pinctrl-1 = <&sdhi3_pins_uhs>;
++ pinctrl-names = "default", "state_uhs";
++
++ vmmc-supply = <&vcc_sdhi3>;
++ vqmmc-supply = <&vccq_sdhi3>;
++ cd-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
++ wp-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;
++ bus-width = <4>;
++ sd-uhs-sdr50;
++ status = "okay";
++};
++
++&msiof1 {
++ status = "disabled";
++};
++
++&usb2_phy0 {
++ pinctrl-0 = <&usb0_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&usb2_phy2 {
++ pinctrl-0 = <&usb2_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&xhci0 {
++ pinctrl-0 = <&usb30_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&ehci0 {
++ status = "okay";
++};
++
++&ehci2 {
++ status = "okay";
++};
++
++&ohci0 {
++ status = "okay";
++};
++
++&ohci2 {
++ status = "okay";
++};
++
++&can0 {
++ pinctrl-0 = <&can0_pins>;
++ pinctrl-names = "default";
++ status = "disabled";
++};
++
++&can1 {
++ pinctrl-0 = <&can1_pins>;
++ pinctrl-names = "default";
++ status = "disabled";
++};
++
++&canfd {
++ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++/* uncomment to enable CN12 on VIN4-7 */
++//#include "ulcb-vb2-cn12.dtsi"
+diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi
+new file mode 100644
+index 0000000..7334a5e
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.1-gmsl2.dtsi
+@@ -0,0 +1,90 @@
++/*
++ * Device Tree Source for the ULCB Videobox V2.1 board
++ *
++ * Copyright (C) 2019 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "ulcb-vb2-gmsl2.dtsi"
++
++/{
++ leds {
++ led_button {
++ gpios = <&gpio_ext_led 9 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "cpu";
++ };
++ };
++
++ gpio_keys_polled {
++ compatible = "gpio-keys-polled";
++ poll-interval = <100>;
++ autorepeat;
++
++ button_pwr {
++ label = "GPIO Key POWER";
++ linux,code = <116>;
++ gpios = <&gpio_ext_led 8 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
++
++&i2c_power {
++ adc@48 {
++ reg = <0x48>;
++ compatible = "ti,ads1115";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ wake7_voltage: channel@4 {
++ /* single endded AIN0 */
++ reg = <4>;
++ };
++ wake8_voltage: channel@5 {
++ /* single endded AIN1 */
++ reg = <5>;
++ };
++ dc_prot_voltage: channel@6 {
++ /* single endded AIN2 */
++ reg = <6>;
++ };
++ dcdc_voltage: channel@7 {
++ /* single endded AIN3 */
++ reg = <7>;
++ };
++ };
++};
++
++&gpio6 {
++ /delete-node/m2_0_rst;
++
++ m2_0_rst {
++ gpio-hog;
++ gpios = <6 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 0 RST#";
++ };
++};
++
++&pfc {
++ usb1_pins: usb1 {
++ groups = "usb1";
++ function = "usb1";
++ };
++};
++
++&usb2_phy1 {
++ pinctrl-0 = <&usb1_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&ohci1 {
++ status = "okay";
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch
new file mode 100644
index 00000000..fe348084
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0513-MTD-renesas-rpc-fix-dummy-cycles.patch
@@ -0,0 +1,30 @@
+From 09381afbd95859e22aad7d0647b202eba7bb2cae Mon Sep 17 00:00:00 2001
+From: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Date: Thu, 5 Dec 2019 17:30:15 +0300
+Subject: [PATCH] MTD: renesas-rpc: fix dummy cycles
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+---
+ drivers/mtd/spi-nor/renesas-rpc-qspi.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/spi-nor/renesas-rpc-qspi.c b/drivers/mtd/spi-nor/renesas-rpc-qspi.c
+index 3d2d5dbe03e0..f4abdac10670 100644
+--- a/drivers/mtd/spi-nor/renesas-rpc-qspi.c
++++ b/drivers/mtd/spi-nor/renesas-rpc-qspi.c
+@@ -458,7 +458,11 @@ static ssize_t rpc_read_flash(struct spi_nor *nor, loff_t from, size_t len,
+
+ /* ...setup read sequence */
+ val = rpc_readl(rpc, RPC_DRENR);
+- val |= RPC_DRENR_DME | RPC_DRENR_CDE;
++ if (nor->read_dummy)
++ val |= RPC_DRENR_DME;
++ else
++ val &= ~RPC_DRENR_DME;
++ val |= RPC_DRENR_CDE;
+ rpc_writel(rpc, RPC_DRENR, val);
+
+ rpc_do_read_flash(rpc, from, len, buf, nor->addr_width > 3);
+--
+2.17.1
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch
new file mode 100644
index 00000000..49b66489
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0514-media-i2c-gmsl2-add-fsync-support.patch
@@ -0,0 +1,102 @@
+From 848b902979b3d10b6104bdae5a73285351b98a3a Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 5 May 2020 00:31:31 +0300
+Subject: [PATCH 1/3] media: i2c: gmsl2: add fsync support
+
+This add FSYNC support on GMSL2 serializers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/max9296.c | 12 ++++++++++--
+ drivers/media/i2c/soc_camera/gmsl/max9296.h | 1 +
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 12 ++++++++++--
+ drivers/media/i2c/soc_camera/gmsl/max96712.h | 1 +
+ 4 files changed, 22 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+index 85b45ca..daa2201 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+@@ -840,7 +840,7 @@ static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int li
+ if (priv->gpio[i] == 2) {
+ /* GPIO FSIN */
+ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
+- ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ ser_write(MAX9295_GPIO_C(i), 0x08); /* pull-none, GPIO ID=8 assosiated with FSYNC transmission */
+ }
+ if (priv->gpio[i] == 3) {
+ /* GPIO Interrupt */
+@@ -919,7 +919,15 @@ static void max9296_gmsl2_link_crossbar_setup(struct max9296_priv *priv, int lin
+
+ static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv)
+ {
+- /* TODO */
++ des_write(MAX9296_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX9296_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX9296_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ des_write(MAX9296_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX9296_FSYNC_11, 0x00);
++
++ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */
++ des_write(MAX9296_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */
++ des_write(MAX9296_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */
+ }
+
+ /* -----------------------------------------------------------------------------
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+index 985b77e..87fa05ee 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9296.h
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+@@ -153,6 +153,7 @@ struct max9296_priv {
+ #define MAX9296_FSYNC_10 0x3aa
+ #define MAX9296_FSYNC_11 0x3ab
+ #define MAX9296_FSYNC_15 0x3af
++#define MAX9296_FSYNC_17 0x3b1
+
+ #define MAX_MIPI_PHY_BASE 0x8a0
+ #define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+index c4cdf0e..17eed0b 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -836,7 +836,7 @@ static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int
+ if (priv->gpio[i] == 2) {
+ /* GPIO FSIN */
+ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
+- ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ ser_write(MAX9295_GPIO_C(i), 0x08); /* pull-none, GPIO ID=8 assosiated with FSYNC transmission */
+ }
+ if (priv->gpio[i] == 3) {
+ /* GPIO Interrupt */
+@@ -918,7 +918,15 @@ static void max96712_gmsl2_link_crossbar_setup(struct max96712_priv *priv, int l
+
+ static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv)
+ {
+- /* TODO */
++ des_write(MAX96712_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX96712_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX96712_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ des_write(MAX96712_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX96712_FSYNC_11, 0x00);
++
++ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */
++ des_write(MAX96712_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */
++ des_write(MAX96712_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */
+ }
+
+ /* -----------------------------------------------------------------------------
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+index b648bdc..609da2f 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.h
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+@@ -135,6 +135,7 @@ struct max96712_priv {
+ #define MAX96712_FSYNC_10 0x4aa
+ #define MAX96712_FSYNC_11 0x4ab
+ #define MAX96712_FSYNC_15 0x4af
++#define MAX96712_FSYNC_17 0x4b1
+
+ #define MAX_MIPI_PHY_BASE 0x8a0
+ #define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch
new file mode 100644
index 00000000..84088d7c
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0515-media-i2c-ap020x-add-fsync-support.patch
@@ -0,0 +1,74 @@
+From e5c437ef218ca86640a3c80c5e6a75602748ae5e Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 5 May 2020 00:35:42 +0300
+Subject: [PATCH 2/3] media: i2c: ap020x: add fsync support
+
+This adds fsync support
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c | 19 +++++++++++++------
+ drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h | 12 ++++++++++++
+ 2 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+index ad18e2e..8dfad4a 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.c
+@@ -421,6 +421,18 @@ static int ap0201_initialize(struct i2c_client *client)
+ }
+
+ reg16_read16(client, AP0201_REV_REG, &rev);
++ /* Program wizard registers */
++ switch (pid) {
++ case AP0200_PID:
++ case AP0201_PID:
++ ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard));
++ break;
++ case AP0202_PID:
++ ap0201_set_regs(client, ap0202_regs_wizard, ARRAY_SIZE(ap0202_regs_wizard));
++ break;
++ }
++ /* Read OTP IDs */
++ ap0201_otp_id_read(client);
+ #if 1
+ /* read resolution used by current firmware */
+ reg16_read16(client, 0xcae4, &val);
+@@ -431,12 +443,7 @@ static int ap0201_initialize(struct i2c_client *client)
+ priv->max_width = AP0201_MAX_WIDTH;
+ priv->max_height = AP0201_MAX_HEIGHT;
+ #endif
+- /* Program wizard registers */
+- ap0201_set_regs(client, ap0201_regs_wizard, ARRAY_SIZE(ap0201_regs_wizard));
+- /* Read OTP IDs */
+- ap0201_otp_id_read(client);
+-
+- dev_info(&client->dev, "ap020X PID %x (%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ dev_info(&client->dev, "ap020X PID %x (rev%x), res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, rev, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+ return 0;
+ }
+diff --git a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
+index c857edc..daf6bd6 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
++++ b/drivers/media/i2c/soc_camera/imagers/ap0201_ar023x.h
+@@ -21,4 +21,16 @@ struct ap0201_reg {
+
+ static const struct ap0201_reg ap0201_regs_wizard[] = {
+ /* enable FSIN */
++{0xc88c, 0x0303},
++{0xfc00, 0x2800},
++{0x0040, 0x8100},
++{AP0201_DELAY, 100},
++};
++
++static const struct ap0201_reg ap0202_regs_wizard[] = {
++/* enable FSIN */
++{0xc890, 0x0303},
++{0xfc00, 0x2800},
++{0x0040, 0x8100},
++{AP0201_DELAY, 100},
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch
new file mode 100644
index 00000000..3c276931
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0516-media-i2c-ar0231-fix-translator.patch
@@ -0,0 +1,37 @@
+From 104e7ee4ee011b6050dc9b55b993c811e3efc959 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 5 May 2020 00:36:27 +0300
+Subject: [PATCH 3/3] media: i2c: ar0231: fix translator
+
+This fixes translator imager address
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/ar0231.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+index fc08793..42f125c 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ar0231.c
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+@@ -27,7 +27,7 @@ static const int ar0231_i2c_addr[] = {0x10, 0x20};
+
+ #define AR0231_PID_REG 0x3000
+ #define AR0231_REV_REG 0x31FE
+-#define AR0231_PID 0x0354
++#define AR0231_PID 0x0354
+
+ #define AR0231_MEDIA_BUS_FMT MEDIA_BUS_FMT_SGRBG12_1X12
+
+@@ -403,7 +403,7 @@ static int ar0231_initialize(struct i2c_client *client)
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ar0231_i2c_addr); i++) {
+- setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i] << 1);
++ setup_i2c_translator(client, priv->ser_addr, ar0231_i2c_addr[i]);
+
+ /* check model ID */
+ reg16_read16(client, AR0231_PID_REG, &pid);
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch
new file mode 100644
index 00000000..b9c0b8e1
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch
@@ -0,0 +1,43 @@
+From bc3d7daebf2a0e35d859d847bbe3f9e648cb1c71 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 5 May 2020 00:52:41 +0300
+Subject: [PATCH] media: i2c: gmsl2: fix fsync in manual mode
+
+disable back control from pipes, since this is needed only for
+automatic mode, that we do not use
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/max9296.c | 2 +-
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+index daa2201..a2a30ef 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max9296.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+@@ -926,7 +926,7 @@ static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv)
+ des_write(MAX9296_FSYNC_11, 0x00);
+
+ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */
+- des_write(MAX9296_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */
++ des_write(MAX9296_FSYNC_15, 0x80); /* GMSL2 Type Fsync, Disable all pipes for manual mode */
+ des_write(MAX9296_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */
+ }
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+index 17eed0b..80e26d0 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/max96712.c
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -925,7 +925,7 @@ static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv)
+ des_write(MAX96712_FSYNC_11, 0x00);
+
+ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL2 generator mode */
+- des_write(MAX96712_FSYNC_15, 0x9f); /* GMSL2 Type Fsync, Enable all pipes */
++ des_write(MAX96712_FSYNC_15, 0x80); /* GMSL2 Type Fsync, Disable all pipes for manual mode */
+ des_write(MAX96712_FSYNC_17, 8 << 3); /* GPIO ID=8 assosiated with FSYNC transmission */
+ }
+
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch
new file mode 100644
index 00000000..e6aab0b5
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0518-media-i2c-imagers-ar0231-fix-GMSL2.patch
@@ -0,0 +1,55 @@
+From 92c2f541b19b139a4457383c634b142457ca3df3 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 6 May 2020 17:19:02 +0300
+Subject: [PATCH 1/2] media: i2c: imagers: ar0231: fix GMSL2
+
+This fixes imager MIPI setup over GMSL2
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/ar0231.c | 4 ++--
+ drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h | 3 ++-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231.c b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+index 42f125c..fd8fe94 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ar0231.c
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231.c
+@@ -423,11 +423,11 @@ static int ar0231_initialize(struct i2c_client *client)
+ /* Program wizard registers */
+ switch (get_des_id(client)) {
+ case UB960_ID:
++ case MAX9296A_ID:
++ case MAX96712_ID:
+ ar0231_set_regs(client, ar0231_regs_wizard_rev7, ARRAY_SIZE(ar0231_regs_wizard_rev7));
+ break;
+ case MAX9286_ID:
+- case MAX9296A_ID:
+- case MAX96712_ID:
+ ar0231_set_regs(client, ar0231_regs_wizard_rev6_dvp, ARRAY_SIZE(ar0231_regs_wizard_rev6_dvp));
+ break;
+ }
+diff --git a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
+index f3485f5..96dd2c4 100644
+--- a/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
++++ b/drivers/media/i2c/soc_camera/imagers/ar0231_rev7.h
+@@ -303,6 +303,7 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = {
+ #if 1 /* Serial 12-bit Timing Setup */
+ /* PCLK=24Mhz/PRE_PLL_CLK_DIV *PLL_MULTIPLIER /P1 /P4 *2 */
+ /* PCLK=24Mhz/2 *44/1/12 *2= 88Mhz - TI serializers */
++/* MIPI 528MBPS */
+ {0x302E, 2}, // pre_pll_clk_div
+ {0x3030, 44}, // pll_multiplier
+ {0x302C, 1}, // vt_sys_clk_div (P1 divider)
+@@ -381,7 +382,7 @@ static const struct ar0231_reg ar0231_regs_wizard_rev7[] = {
+ {0x31B6, 0x1146},
+ {0x31B8, 0x3047},
+ {0x31BA, 0x186},
+-{0x31BC, 0x805},
++{0x31BC, 0x805 | BIT(15)},
+ #endif /* MIPI 12 bit Settings */
+
+ /* FPS = 105MHz / reg0x300A / reg0x300C * (DES_XTAL/27MHz), DES_XTAL=23.5MHz */
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch
new file mode 100644
index 00000000..b4e8848e
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch
@@ -0,0 +1,4377 @@
+From f901052c8130b621fa1a94facb375ac9a5bc8a2e Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 27 May 2020 12:34:28 +0300
+Subject: [PATCH] media: i2c: imagers: add IMX390 for new LVDS support
+
+This adds IMX390 into new LVDS drivers that support all enabled
+serializers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+media: i2c: imagers: add IMX390 for new LVDS support
+
+This adds IMX390 into new LVDS drivers that support all enabled
+serializers
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/imagers/Makefile | 1 +
+ drivers/media/i2c/soc_camera/imagers/imx390.c | 655 +++++
+ drivers/media/i2c/soc_camera/imagers/imx390.h | 3672 +++++++++++++++++++++++++
+ 3 files changed, 4328 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/imx390.c
+ create mode 100644 drivers/media/i2c/soc_camera/imagers/imx390.h
+
+diff --git a/drivers/media/i2c/soc_camera/imagers/Makefile b/drivers/media/i2c/soc_camera/imagers/Makefile
+index eeb36fd..66c9237 100644
+--- a/drivers/media/i2c/soc_camera/imagers/Makefile
++++ b/drivers/media/i2c/soc_camera/imagers/Makefile
+@@ -2,6 +2,7 @@
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0101_ar014x.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ap0201_ar023x.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ar0231.o
++obj-$(CONFIG_SOC_CAMERA_OV106XX) += imx390.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov10635.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov2311.o
+ obj-$(CONFIG_SOC_CAMERA_OV106XX) += ov490.o
+diff --git a/drivers/media/i2c/soc_camera/imagers/imx390.c b/drivers/media/i2c/soc_camera/imagers/imx390.c
+new file mode 100644
+index 0000000..c326aa6
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/imx390.c
+@@ -0,0 +1,655 @@
++/*
++ * Sony IMX390 sensor camera driver
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#include "../gmsl/common.h"
++#include "imx390.h"
++
++static const int imx390_i2c_addr[] = {0x21, 0x1a};
++
++#define IMX390_PID_REG 0x0330
++#define IMX390_PID 0x0015
++
++#define IMX390_MEDIA_BUS_FMT MEDIA_BUS_FMT_SRGGB12_1X12
++
++struct imx390_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ int fps_denominator;
++ int fps_numerator;
++ int init_complete;
++ u8 id[6];
++ int exposure;
++ int gain;
++ int autogain;
++ /* serializers */
++ int ser_addr;
++ int vts;
++};
++
++static inline struct imx390_priv *to_imx390(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct imx390_priv, sd);
++}
++
++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct imx390_priv, hdl)->sd;
++}
++
++static int imx390_set_regs(struct i2c_client *client,
++ const struct imx390_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == IMX390_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static void imx390_otp_id_read(struct i2c_client *client)
++{
++ struct imx390_priv *priv = to_imx390(client);
++ int i;
++ u8 val = 0;
++
++ /* read camera id from imx390 OTP memory */
++ for (i = 0; i < 6; i++) {
++ reg16_read(client, 0x3050 + i, &val);
++ priv->id[i] = val;
++ }
++}
++
++static int imx390_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int imx390_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = IMX390_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int imx390_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = IMX390_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int imx390_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = IMX390_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++static int imx390_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = IMX390_PID >> 8;
++ edid->edid[9] = IMX390_PID & 0xff;
++
++ return 0;
++}
++
++static int imx390_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > IMX390_MAX_WIDTH) ||
++ (rect->top + rect->height > IMX390_MAX_HEIGHT))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int imx390_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = IMX390_MAX_WIDTH;
++ sel->r.height = IMX390_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = IMX390_MAX_WIDTH;
++ sel->r.height = IMX390_MAX_HEIGHT;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int imx390_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++static int imx390_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ memset(cp, 0, sizeof(struct v4l2_captureparm));
++ cp->capability = V4L2_CAP_TIMEPERFRAME;
++ cp->timeperframe.numerator = priv->fps_numerator;
++ cp->timeperframe.denominator = priv->fps_denominator;
++
++ return 0;
++}
++
++static int imx390_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++ struct v4l2_captureparm *cp = &parms->parm.capture;
++ int ret = 0, timeout;
++ u8 val;
++
++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++ if (cp->extendedmode != 0)
++ return -EINVAL;
++
++ if (priv->fps_denominator != cp->timeperframe.denominator ||
++ priv->fps_numerator != cp->timeperframe.numerator) {
++ priv->vts = (IMX390_SENSOR_HEIGHT + 29) * 30 * cp->timeperframe.numerator / cp->timeperframe.denominator;
++
++ reg16_write(client, 0x0, 1);
++ for (timeout = 100; timeout > 0; timeout--) {
++ reg16_read(client, 0x5001, &val);
++ if (val == 1)
++ break;
++ mdelay(1);
++ }
++ if (!timeout)
++ dev_err(&client->dev, "timeout enter standby\n");
++
++ reg16_write(client, 0x2008, priv->vts & 0xff);
++ reg16_write(client, 0x2009, (priv->vts >> 8) & 0xff);
++ reg16_write(client, 0x200A, priv->vts >> 16);
++ ret = reg16_write(client, 0x0, 0);
++
++ priv->fps_numerator = cp->timeperframe.numerator;
++ priv->fps_denominator = cp->timeperframe.denominator;
++ }
++
++ return ret;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int imx390_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 s = reg->size;
++ int ret;
++
++ if (!s)
++ s = 1;
++ if (s > sizeof(reg->val))
++ s = sizeof(reg->val);
++
++ ret = reg16_read_n(client, (u16)reg->reg, (u8*)&reg->val, s);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static int imx390_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ u32 s = reg->size;
++
++ if (!s)
++ s = 1;
++ if (s > sizeof(reg->val))
++ s = sizeof(reg->val);
++
++ return reg16_write_n(client, (u16)reg->reg, (u8*)&reg->val, s);
++}
++#endif
++
++static struct v4l2_subdev_core_ops imx390_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = imx390_g_register,
++ .s_register = imx390_s_register,
++#endif
++};
++
++static int imx390_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++ int ret = -EINVAL;
++ int val;
++ uint8_t val8 = 0;
++
++ if (!priv->init_complete)
++ return 0;
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ break;
++ case V4L2_CID_GAIN:
++ /* Digital gain */
++ /* Set PGA_GAIN_SP1H as Normal SP1 HCG mode is configured in wizard */
++ val8 = ctrl->val & 0xff;
++ ret = reg16_write(client, 0x24, val8);
++#if 0 // stubs for other normal modes and HDR
++ /* Set PGA_GAIN_SP1L as Normal SP1 LCG mode is configured in wizard */
++ val8 = ctrl->val & 0xff;
++ ret = reg16_write(client, 0x26, val8);
++
++ /* Set PGA_GAIN_SP2 as Normal SP2 mode is configured in wizard */
++ val8 = ctrl->val & 0xff;
++ ret = reg16_write(client, 0x28, val8);
++#endif
++ break;
++ case V4L2_CID_ANALOGUE_GAIN:
++ /* Analog gain */
++ /* Set AGAIN_SP1H as Normal SP1 HCG mode is configured in wizard */
++ val8 = ctrl->val & 0xff;
++ ret = reg16_write(client, 0x18, val8);
++#if 0 // stubs for other normal modes and HDR
++ /* Set AGAIN_SP1L as Normal SP1 LCG mode is configured in wizard */
++ val8 = ctrl->val & 0xff;
++ ret = reg16_write(client, 0x1A, val8);
++#endif
++ break;
++ case V4L2_CID_EXPOSURE:
++ val = 0xfff - ctrl->val;
++ reg16_write(client, 0x0c, val); /* LSB */
++ reg16_write(client, 0x0d, val >> 8);
++ ret = reg16_write(client, 0x0e, val >> 16); /* MSB */
++ break;
++ case V4L2_CID_HFLIP:
++ /* hflip */
++ ret = reg16_read(client, 0x74, &val8);
++ if (ctrl->val)
++ val8 |= (1 << 1);
++ else
++ val8 &= ~(1 << 1);
++ ret |= reg16_write(client, 0x74, val8);
++
++ /* hflip app lock */
++ ret = reg16_read(client, 0x3c0, &val8);
++ if (ctrl->val)
++ val8 |= (1 << 3);
++ else
++ val8 &= ~(1 << 3);
++ ret |= reg16_write(client, 0x3c0, val8);
++ break;
++ case V4L2_CID_VFLIP:
++ /* vflip */
++ ret = reg16_read(client, 0x74, &val8);
++ if (ctrl->val)
++ val8 |= (1 << 0);
++ else
++ val8 &= ~(1 << 0);
++ ret |= reg16_write(client, 0x74, val8);
++
++ /* vflip app lock */
++ ret = reg16_read(client, 0x3c0, &val8);
++ if (ctrl->val)
++ val8 |= (1 << 2);
++ else
++ val8 &= ~(1 << 2);
++ ret |= reg16_write(client, 0x3c0, val8);
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ctrl_ops imx390_ctrl_ops = {
++ .s_ctrl = imx390_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops imx390_video_ops = {
++ .s_stream = imx390_s_stream,
++ .g_mbus_config = imx390_g_mbus_config,
++ .g_parm = imx390_g_parm,
++ .s_parm = imx390_s_parm,
++};
++
++static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = {
++ .get_edid = imx390_get_edid,
++ .enum_mbus_code = imx390_enum_mbus_code,
++ .get_selection = imx390_get_selection,
++ .set_selection = imx390_set_selection,
++ .get_fmt = imx390_get_fmt,
++ .set_fmt = imx390_set_fmt,
++};
++
++static struct v4l2_subdev_ops imx390_subdev_ops = {
++ .core = &imx390_core_ops,
++ .video = &imx390_video_ops,
++ .pad = &imx390_subdev_pad_ops,
++};
++
++static ssize_t imx390_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct imx390_priv *priv = to_imx390(client);
++
++ imx390_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_imx390, S_IRUGO, imx390_otp_id_show, NULL);
++
++static int imx390_initialize(struct i2c_client *client)
++{
++ struct imx390_priv *priv = to_imx390(client);
++ u8 pid = 0;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(imx390_i2c_addr); i++) {
++ setup_i2c_translator(client, priv->ser_addr, imx390_i2c_addr[i]);
++
++ /* check model ID */
++ reg16_read(client, IMX390_PID_REG, &pid);
++ if (pid == IMX390_PID)
++ break;
++ }
++
++ if (pid != IMX390_PID) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ return -ENODEV;
++ }
++
++ switch (get_des_id(client)) {
++ case UB960_ID:
++ /* Setup XCLK:
++ * CLK_OUT=23MHz*160*M/N/CLKDIV
++ * CLK_OUT=24MHz (desired), CLKDIV=4, M=6, N=230
++ * 23*160/4*6/230 = 24MHz = CLK_OUT
++ */
++ reg8_write_addr(client, priv->ser_addr, 0x06, 0x46); /* Set CLKDIV and M */
++ reg8_write_addr(client, priv->ser_addr, 0x07, 0xe6); /* Set N */
++ break;
++ case MAX9296A_ID:
++ case MAX96712_ID:
++// reg16_write_addr(client, priv->ser_addr, MAX9295_MIPI_RX1, 0x11); /* MIPI 2-lanes */
++ break;
++ }
++
++ /* Read OTP IDs */
++ imx390_otp_id_read(client);
++ /* Program wizard registers */
++ imx390_set_regs(client, imx390_regs_wizard, ARRAY_SIZE(imx390_regs_wizard));
++
++ dev_info(&client->dev, "imx390 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, IMX390_MAX_WIDTH, IMX390_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++ return 0;
++}
++
++static const struct i2c_device_id imx390_id[] = {
++ { "imx390", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, imx390_id);
++
++static const struct of_device_id imx390_of_ids[] = {
++ { .compatible = "sony,imx390", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, imx390_of_ids);
++
++static int imx390_parse_dt(struct device_node *np, struct imx390_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ u32 addrs[2], naddrs;
++
++ naddrs = of_property_count_elems_of_size(np, "reg", sizeof(u32));
++ if (naddrs != 2) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ if (of_property_read_u32_array(client->dev.of_node, "reg", addrs, naddrs) < 0) {
++ dev_err(&client->dev, "Invalid DT reg property\n");
++ return -EINVAL;
++ }
++
++ priv->ser_addr = addrs[1];
++
++ return 0;
++}
++
++static int imx390_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct imx390_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &imx390_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++ priv->fps_numerator = 1;
++ priv->fps_denominator = 30;
++
++ priv->exposure = 0x100;
++ priv->gain = 0;
++ priv->autogain = 1;
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_GAIN, 0, 140, 1, priv->gain);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0x15);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_EXPOSURE, 0, 0xff0, 1, 0xfff - 0x2f2);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &imx390_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = imx390_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = imx390_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = IMX390_MAX_WIDTH;
++ priv->rect.height = IMX390_MAX_HEIGHT;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_imx390) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ priv->init_complete = 1;
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ return ret;
++}
++
++static int imx390_remove(struct i2c_client *client)
++{
++ struct imx390_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_imx390);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
++
++static struct i2c_driver imx390_i2c_driver = {
++ .driver = {
++ .name = "imx390",
++ .of_match_table = imx390_of_ids,
++ },
++ .probe = imx390_probe,
++ .remove = imx390_remove,
++ .id_table = imx390_id,
++};
++
++module_i2c_driver(imx390_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for IMX390");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/imagers/imx390.h b/drivers/media/i2c/soc_camera/imagers/imx390.h
+new file mode 100644
+index 0000000..8f27447
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/imagers/imx390.h
+@@ -0,0 +1,3672 @@
++/*
++ * Sony IMX390 sensor camera wizard 1920x1080@30/BGGR/MIPI
++ *
++ * Copyright (C) 2018-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++//#define IMX390_DISPLAY_PATTERN_COLOR_BAR
++
++#define IMX390_MAX_WIDTH 1920
++#define IMX390_MAX_HEIGHT 1080
++
++#define IMX390_SENSOR_WIDTH 1936
++#define IMX390_SENSOR_HEIGHT 1096
++
++#define IMX390_DELAY 0xffff
++#define IMX390_DT 0x2c /* MIPI Data Type RAW12 */
++
++struct imx390_reg {
++ u16 reg;
++ u8 val;
++};
++
++/* wizard: MIPI 1920x1080 RAW12 Linear 30fps 700Mbps */
++static const struct imx390_reg imx390_regs_wizard[] = {
++{0x000C, 0xF2},
++{0x000D, 0x02},
++{0x000E, 0x00},
++{0x0010, 0xF2},
++{0x0011, 0x02},
++{0x0012, 0x00},
++{0x0018, 0x15},
++{0x0019, 0x00},
++{0x001A, 0x0C},
++{0x001B, 0x00},
++{0x0038, 0x00},
++{0x003C, 0x00},
++{0x003D, 0x00},
++{0x003E, 0x00},
++{0x0040, 0x00},
++{0x0041, 0x00},
++{0x0042, 0x00},
++{0x0044, 0x00},
++{0x0045, 0x00},
++{0x0046, 0x00},
++{0x0048, 0x00},
++{0x0049, 0x00},
++{0x004A, 0x00},
++{0x004C, 0x00},
++{0x004D, 0x00},
++{0x004E, 0x00},
++{0x0050, 0x00},
++{0x0051, 0x00},
++{0x0052, 0x00},
++{0x0054, 0x00},
++{0x0055, 0x00},
++{0x0056, 0x00},
++{0x0058, 0x00},
++{0x0059, 0x00},
++{0x005A, 0x00},
++{0x005C, 0x00},
++{0x005D, 0x00},
++{0x005E, 0x00},
++{0x0060, 0x00},
++{0x0061, 0x00},
++{0x0062, 0x00},
++{0x0064, 0x00},
++{0x0065, 0x00},
++{0x0066, 0x00},
++{0x0068, 0x00},
++{0x0069, 0x00},
++{0x006A, 0x00},
++{0x0078, 0x00},
++{0x007C, 0x00},
++{0x007D, 0x00},
++{0x0080, 0x00},
++{0x0081, 0x00},
++{0x00F4, 0x1C},
++{0x00F5, 0xF8},
++{0x00F6, 0x01},
++{0x00F8, 0x03},
++{0x00F9, 0x00}, // non-HDR
++//{0x00F9, 0x01}, // HDR
++{0x00FA, 0x00},
++{0x00FB, 0x00},
++{0x0114, 0x00},
++{0x0115, 0x01},
++{0x0118, 0x20},
++{0x0119, 0x03},
++{0x011A, 0x00},
++{0x011B, 0x41},
++{0x011C, 0x80},
++{0x011D, 0x00},
++{0x0120, 0x20},
++{0x0121, 0x00},
++{0x0122, 0x00},
++{0x0123, 0x44},
++{0x0124, 0x00},
++{0x0125, 0x01},
++{0x0128, 0xAC},
++{0x0129, 0x0D},
++{0x012A, 0x00},
++{0x012B, 0xA4},
++{0x012C, 0x00},
++{0x012D, 0x01},
++{0x0130, 0xC4},
++{0x0131, 0x09},
++{0x0132, 0x00},
++{0x0133, 0xDA},
++{0x013B, 0x01},
++{0x01C4, 0x00},
++{0x01C5, 0x00},
++{0x01CC, 0x01},
++{0x01D0, 0x09},
++{0x01D4, 0x01},
++{0x0232, 0x7E},
++{0x0233, 0x00},
++{0x0390, 0x00},
++{0x0391, 0x00},
++{0x0392, 0x00},
++#ifdef IMX390_DISPLAY_PATTERN_COLOR_BAR
++{0x01DB, 0x32},
++{0x03C0, 0x02},
++#else
++{0x03C0, 0x00},
++#endif
++{0x2000, 0x55},
++{0x2001, 0x55},
++{0x2002, 0x55},
++{0x2003, 0x05},
++{0x2004, 0x02},
++{0x2008, (IMX390_SENSOR_HEIGHT + 29) & 0xff},
++{0x2009, ((IMX390_SENSOR_HEIGHT + 29) >> 8) & 0xff},
++{0x200A, (IMX390_SENSOR_HEIGHT + 29) >> 16},
++{0x200C, 0x30},
++{0x200D, 0x11},
++{0x2010, 0x04},
++{0x2014, 0x01},
++{0x2018, 0x02},
++{0x2019, 0x04},
++{0x201A, 0x00},
++{0x201C, 0x21},
++{0x201D, 0x11},
++{0x201E, 0x00},
++{0x201F, 0x00},
++{0x2020, 0xBC},
++{0x2021, 0x00},
++{0x2022, 0x7F},
++{0x2023, 0x00},
++{0x2024, 0xBA},
++{0x2025, 0x00},
++{0x2026, 0x81},
++{0x2027, 0x00},
++{0x2028, 0x7D},
++{0x2029, 0x90},
++{0x202A, 0x05},
++{0x202C, 0xFC},
++{0x202D, 0x02},
++{0x202E, 0x25},
++{0x202F, 0x03},
++{0x2030, 0x05},
++{0x2031, 0x02},
++{0x2032, 0xCA},
++{0x2033, 0x02},
++{0x2034, 0xFC},
++{0x2035, 0x02},
++{0x2036, 0x25},
++{0x2037, 0x03},
++{0x2038, 0x25},
++{0x2039, 0x97},
++{0x203A, 0xEC},
++{0x203B, 0x01},
++{0x203C, 0xF5},
++{0x203D, 0x8E},
++{0x203E, 0x0C},
++{0x203F, 0x2D},
++{0x2040, 0x69},
++{0x2041, 0x01},
++{0x2042, 0x8E},
++{0x2043, 0x01},
++{0x2044, 0x0C},
++{0x2045, 0x02},
++{0x2046, 0x31},
++{0x2047, 0x02},
++{0x2048, 0x6A},
++{0x2049, 0x01},
++{0x204A, 0x8E},
++{0x204B, 0x01},
++{0x204C, 0x0D},
++{0x204D, 0x02},
++{0x204E, 0x31},
++{0x204F, 0x02},
++{0x2050, 0x7B},
++{0x2051, 0x00},
++{0x2052, 0x7D},
++{0x2053, 0x00},
++{0x2054, 0x95},
++{0x2055, 0x00},
++{0x2056, 0x97},
++{0x2057, 0x00},
++{0x2058, 0xAD},
++{0x2059, 0x00},
++{0x205A, 0xAF},
++{0x205B, 0x00},
++{0x205C, 0x92},
++{0x205D, 0x00},
++{0x205E, 0x94},
++{0x205F, 0x00},
++{0x2060, 0x8E},
++{0x2061, 0x00},
++{0x2062, 0x90},
++{0x2063, 0x00},
++{0x2064, 0xB1},
++{0x2065, 0x00},
++{0x2066, 0xB3},
++{0x2067, 0x00},
++{0x2068, 0x08},
++{0x2069, 0x00},
++{0x206A, 0x04},
++{0x206B, 0x00},
++{0x206C, 0x84},
++{0x206D, 0x00},
++{0x206E, 0x80},
++{0x206F, 0x00},
++{0x2070, 0x04},
++{0x2071, 0x00},
++{0x2072, 0x46},
++{0x2073, 0x00},
++{0x2074, 0xE9},
++{0x2075, 0x01},
++{0x2076, 0x74},
++{0x2077, 0x02},
++{0x2078, 0x80},
++{0x2079, 0x00},
++{0x207A, 0xC1},
++{0x207B, 0x00},
++{0x207C, 0xFF},
++{0x207D, 0x03},
++{0x207E, 0xFF},
++{0x207F, 0x03},
++{0x2080, 0x78},
++{0x2081, 0x00},
++{0x2082, 0x6A},
++{0x2083, 0x01},
++{0x2084, 0xE4},
++{0x2085, 0x01},
++{0x2086, 0x2B},
++{0x2087, 0x03},
++{0x2088, 0x00},
++{0x2089, 0x00},
++{0x208A, 0xFF},
++{0x208B, 0x03},
++{0x208C, 0xFF},
++{0x208D, 0x03},
++{0x208E, 0xFF},
++{0x208F, 0x03},
++{0x2090, 0x7D},
++{0x2091, 0x00},
++{0x2092, 0x62},
++{0x2093, 0x01},
++{0x2094, 0xE9},
++{0x2095, 0x01},
++{0x2096, 0x00},
++{0x2097, 0x00},
++{0x2098, 0x7C},
++{0x2099, 0x00},
++{0x209A, 0x21},
++{0x209B, 0x03},
++{0x209C, 0xE9},
++{0x209D, 0x01},
++{0x209E, 0x21},
++{0x209F, 0x03},
++{0x20A0, 0xFF},
++{0x20A1, 0x03},
++{0x20A2, 0xFF},
++{0x20A3, 0x03},
++{0x20A4, 0xFF},
++{0x20A5, 0x03},
++{0x20A6, 0xFF},
++{0x20A7, 0x03},
++{0x20A8, 0xFF},
++{0x20A9, 0x03},
++{0x20AA, 0xFF},
++{0x20AB, 0x03},
++{0x20AC, 0xFF},
++{0x20AD, 0x03},
++{0x20AE, 0xFF},
++{0x20AF, 0x03},
++{0x20B0, 0xFF},
++{0x20B1, 0x03},
++{0x20B2, 0xFF},
++{0x20B3, 0x03},
++{0x20B4, 0x87},
++{0x20B5, 0xCC},
++{0x20B6, 0x87},
++{0x20B7, 0x08},
++{0x20B8, 0xF4},
++{0x20B9, 0xA5},
++{0x20BA, 0x07},
++{0x20BC, 0x1F},
++{0x20BD, 0x01},
++{0x20BE, 0xF6},
++{0x20BF, 0x00},
++{0x20C0, 0x90},
++{0x20C1, 0x01},
++{0x20C2, 0x67},
++{0x20C3, 0x01},
++{0x20C4, 0xFF},
++{0x20C5, 0x03},
++{0x20C6, 0xFF},
++{0x20C7, 0x03},
++{0x20C8, 0x33},
++{0x20C9, 0x02},
++{0x20CA, 0x0A},
++{0x20CB, 0x02},
++{0x20CC, 0x7F},
++{0x20CD, 0x00},
++{0x20CE, 0xD2},
++{0x20CF, 0x00},
++{0x20D0, 0x81},
++{0x20D1, 0x00},
++{0x20D2, 0x87},
++{0x20D3, 0x00},
++{0x20D4, 0x09},
++{0x20D5, 0x00},
++{0x20D8, 0x7F},
++{0x20D9, 0x00},
++{0x20DA, 0x62},
++{0x20DB, 0x01},
++{0x20DC, 0x7F},
++{0x20DD, 0x00},
++{0x20DE, 0x62},
++{0x20DF, 0x01},
++{0x20E0, 0x65},
++{0x20E1, 0x00},
++{0x20E2, 0x75},
++{0x20E3, 0x00},
++{0x20E4, 0xE0},
++{0x20E5, 0x00},
++{0x20E6, 0xF0},
++{0x20E7, 0x00},
++{0x20E8, 0x4C},
++{0x20E9, 0x01},
++{0x20EA, 0x5C},
++{0x20EB, 0x01},
++{0x20EC, 0xD1},
++{0x20ED, 0x01},
++{0x20EE, 0xE1},
++{0x20EF, 0x01},
++{0x20F0, 0x93},
++{0x20F1, 0x02},
++{0x20F2, 0xA3},
++{0x20F3, 0x02},
++{0x20F4, 0x0D},
++{0x20F5, 0x03},
++{0x20F6, 0x1D},
++{0x20F7, 0x03},
++{0x20F8, 0x57},
++{0x20F9, 0x00},
++{0x20FA, 0x7B},
++{0x20FB, 0x00},
++{0x20FC, 0xD2},
++{0x20FD, 0x00},
++{0x20FE, 0xF6},
++{0x20FF, 0x00},
++{0x2100, 0x3E},
++{0x2101, 0x01},
++{0x2102, 0x60},
++{0x2103, 0x01},
++{0x2104, 0xC3},
++{0x2105, 0x01},
++{0x2106, 0xE5},
++{0x2107, 0x01},
++{0x2108, 0x85},
++{0x2109, 0x02},
++{0x210A, 0xA9},
++{0x210B, 0x02},
++{0x210C, 0xFF},
++{0x210D, 0x02},
++{0x210E, 0x21},
++{0x210F, 0x03},
++{0x2110, 0xFF},
++{0x2111, 0x03},
++{0x2112, 0x00},
++{0x2113, 0x00},
++{0x2114, 0xFF},
++{0x2115, 0x03},
++{0x2116, 0xFF},
++{0x2117, 0x03},
++{0x2118, 0xFF},
++{0x2119, 0x03},
++{0x211A, 0xFF},
++{0x211B, 0x03},
++{0x211C, 0xFF},
++{0x211D, 0x03},
++{0x211E, 0xFF},
++{0x211F, 0x03},
++{0x2120, 0xFF},
++{0x2121, 0x03},
++{0x2122, 0xFF},
++{0x2123, 0x03},
++{0x2124, 0xFF},
++{0x2125, 0x03},
++{0x2126, 0xFF},
++{0x2127, 0x03},
++{0x2128, 0x7D},
++{0x2129, 0x90},
++{0x212A, 0xD5},
++{0x212B, 0x07},
++{0x212C, 0x64},
++{0x212D, 0x01},
++{0x2130, 0x5F},
++{0x2131, 0x7D},
++{0x2132, 0x05},
++{0x2134, 0x78},
++{0x2135, 0x00},
++{0x2136, 0x76},
++{0x2137, 0x00},
++{0x2138, 0xF3},
++{0x2139, 0x00},
++{0x213A, 0xF1},
++{0x213B, 0x00},
++{0x213C, 0xA6},
++{0x213D, 0x02},
++{0x213E, 0xA4},
++{0x213F, 0x02},
++{0x2140, 0x7D},
++{0x2141, 0x00},
++{0x2142, 0x8D},
++{0x2143, 0x00},
++{0x2144, 0xA1},
++{0x2145, 0x01},
++{0x2146, 0xB1},
++{0x2147, 0x01},
++{0x2148, 0xAB},
++{0x2149, 0x02},
++{0x214A, 0xBB},
++{0x214B, 0x02},
++{0x214C, 0x17},
++{0x214D, 0x5C},
++{0x214E, 0x00},
++{0x2150, 0x00},
++{0x2151, 0x00},
++{0x2152, 0xF8},
++{0x2153, 0x00},
++{0x2154, 0xBE},
++{0x2155, 0x00},
++{0x2156, 0x7D},
++{0x2157, 0x00},
++{0x2158, 0x25},
++{0x2159, 0x00},
++{0x215A, 0x7D},
++{0x215B, 0x00},
++{0x215C, 0x62},
++{0x215D, 0x01},
++{0x215E, 0xFF},
++{0x215F, 0x03},
++{0x2160, 0x26},
++{0x2161, 0x00},
++{0x2162, 0x7D},
++{0x2163, 0x00},
++{0x2164, 0x63},
++{0x2165, 0x01},
++{0x2166, 0xFF},
++{0x2167, 0x03},
++{0x2168, 0xCB},
++{0x2169, 0x02},
++{0x216A, 0xCF},
++{0x216B, 0x02},
++{0x216C, 0xFF},
++{0x216D, 0x03},
++{0x216E, 0xFF},
++{0x216F, 0x03},
++{0x2170, 0xFF},
++{0x2171, 0x03},
++{0x2172, 0xFF},
++{0x2173, 0x03},
++{0x2174, 0xFF},
++{0x2175, 0x03},
++{0x2176, 0xFF},
++{0x2177, 0x03},
++{0x2178, 0x7E},
++{0x2179, 0x00},
++{0x217A, 0xBD},
++{0x217B, 0x00},
++{0x217C, 0xEC},
++{0x217D, 0x01},
++{0x217E, 0x7B},
++{0x217F, 0x02},
++{0x2180, 0xD1},
++{0x2181, 0x02},
++{0x2182, 0x25},
++{0x2183, 0x03},
++{0x2184, 0x7F},
++{0x2185, 0x00},
++{0x2186, 0xBD},
++{0x2187, 0x00},
++{0x2188, 0xED},
++{0x2189, 0x01},
++{0x218A, 0x7B},
++{0x218B, 0x02},
++{0x218C, 0xD2},
++{0x218D, 0x02},
++{0x218E, 0x25},
++{0x218F, 0x03},
++{0x2190, 0xFF},
++{0x2191, 0x03},
++{0x2192, 0xFF},
++{0x2193, 0x03},
++{0x2194, 0xE9},
++{0x2195, 0x01},
++{0x2196, 0x21},
++{0x2197, 0x03},
++{0x2198, 0x17},
++{0x2199, 0xFC},
++{0x219A, 0x7F},
++{0x219B, 0x01},
++{0x219C, 0xFF},
++{0x219D, 0x03},
++{0x21A0, 0x1B},
++{0x21A1, 0x1B},
++{0x21A2, 0x1B},
++{0x21A3, 0x1B},
++{0x21A4, 0x2E},
++{0x21A5, 0x80},
++{0x21A6, 0x00},
++{0x21A8, 0x04},
++{0x21A9, 0x98},
++{0x21AA, 0x60},
++{0x21AB, 0x03},
++{0x21AC, 0x7F},
++{0x21AD, 0x80},
++{0x21AE, 0x09},
++{0x21B0, 0x1C},
++{0x21B1, 0x00},
++{0x21B2, 0xA0},
++{0x21B3, 0x00},
++{0x21B4, 0x0C},
++{0x21B5, 0x00},
++{0x21B6, 0x2D},
++{0x21B7, 0x00},
++{0x21B8, 0x20},
++{0x21B9, 0x00},
++{0x21BA, 0x02},
++{0x21BB, 0x00},
++{0x21BC, 0xCC},
++{0x21BD, 0x00},
++{0x21BE, 0x4A},
++{0x21BF, 0x00},
++{0x21C0, 0xD0},
++{0x21C1, 0x00},
++{0x21C2, 0x44},
++{0x21C3, 0x00},
++{0x21C4, 0x00},
++{0x21C5, 0xE0},
++{0x21C6, 0x00},
++{0x21C8, 0x11},
++{0x21C9, 0x00},
++{0x21CA, 0x02},
++{0x21CC, 0x08},
++{0x21CD, 0xC0},
++{0x21CE, 0x0C},
++{0x21D0, 0x44},
++{0x21D1, 0x00},
++{0x21D2, 0x02},
++{0x21D4, 0x02},
++{0x21D5, 0x20},
++{0x21D6, 0x2C},
++{0x21D8, 0xFE},
++{0x21D9, 0x9D},
++{0x21DA, 0xDF},
++{0x21DB, 0x03},
++{0x21DC, 0x62},
++{0x21DD, 0x01},
++{0x21DE, 0x7F},
++{0x21DF, 0x00},
++{0x21E0, 0xB7},
++{0x21E1, 0x01},
++{0x21E2, 0xB5},
++{0x21E3, 0x01},
++{0x21E4, 0xC1},
++{0x21E5, 0x02},
++{0x21E6, 0xBF},
++{0x21E7, 0x02},
++{0x21E8, 0xB3},
++{0x21E9, 0x0D},
++{0x21EA, 0x00},
++{0x21EB, 0x04},
++#if 1
++{0x21EC, 0x90},
++{0x21ED, 0x07},
++{0x21EE, 0x58},
++{0x21EF, 0x04},
++#else
++{0x21EC, 0x80},
++{0x21ED, 0x07},
++{0x21EE, 0x38},
++{0x21EF, 0x04},
++#endif
++{0x21F0, 0x54},
++{0x21F1, 0x04},
++{0x21F4, 0x02},
++{0x21F5, 0x00},
++{0x21F6, 0x00},
++{0x21F8, 0x3C},
++{0x21F9, 0x00},
++{0x21FC, 0x28},
++{0x21FD, 0x00},
++{0x21FE, 0x3C},
++{0x21FF, 0x00},
++{0x2200, 0x00},
++{0x2204, 0x4C},
++{0x2205, 0x04},
++{0x2206, 0x65},
++{0x2207, 0x04},
++{0x2208, 0x0A},
++{0x2209, 0x00},
++{0x220C, 0x47},
++{0x220D, 0x00},
++{0x220E, 0x1F},
++{0x220F, 0x00},
++{0x2210, 0x17},
++{0x2211, 0x00},
++{0x2212, 0x0F},
++{0x2213, 0x00},
++{0x2214, 0x17},
++{0x2215, 0x00},
++{0x2216, 0x47},
++{0x2217, 0x00},
++{0x2218, 0x0F},
++{0x2219, 0x00},
++{0x221A, 0x0F},
++{0x221B, 0x00},
++{0x221C, 0x03},
++{0x2220, 0x20},
++{0x2221, 0x20},
++{0x2222, 0x22},
++{0x2223, 0x02},
++{0x2224, 0xA7},
++{0x2225, 0xAA},
++{0x2226, 0x80},
++{0x2227, 0x08},
++{0x2228, 0x01},
++{0x22B2, 0x92},
++{0x22B4, 0x20},
++{0x22B5, 0x00},
++{0x22B6, 0x20},
++{0x22B7, 0x00},
++{0x22B8, 0x20},
++{0x22B9, 0x00},
++{0x22BA, 0x20},
++{0x22BB, 0x00},
++{0x22BC, 0x20},
++{0x22BD, 0x00},
++{0x22BE, 0x20},
++{0x22BF, 0x00},
++{0x22C0, 0x20},
++{0x22C1, 0x00},
++{0x22C2, 0x20},
++{0x22C3, 0x00},
++{0x22C4, 0x20},
++{0x22C5, 0x00},
++{0x22C6, 0x20},
++{0x22C7, 0x00},
++{0x22C8, 0x20},
++{0x22C9, 0x00},
++{0x22CA, 0x20},
++{0x22CB, 0x00},
++{0x22CC, 0x20},
++{0x22CD, 0x00},
++{0x22CE, 0x20},
++{0x22CF, 0x00},
++{0x22DA, 0x00},
++{0x2308, 0x01},
++{0x2311, 0x09},
++{0x2318, 0x40},
++{0x2319, 0xCD},
++{0x231A, 0x54},
++{0x2324, 0x20},
++{0x2325, 0x00},
++{0x2328, 0x00},
++{0x2354, 0x0C},
++{0x23C0, 0x5D},
++{0x244C, 0x00},
++{0x244D, 0x02},
++{0x244E, 0x54},
++{0x244F, 0x02},
++{0x24A0, 0x00},
++{0x24DA, 0x6F},
++{0x24DB, 0x00},
++{0x24DC, 0x62},
++{0x24DD, 0x01},
++{0x24EA, 0x32},
++{0x24EB, 0x00},
++{0x24EC, 0xDC},
++{0x24ED, 0x00},
++{0x24FA, 0x32},
++{0x24FB, 0x00},
++{0x24FC, 0xDD},
++{0x24FD, 0x00},
++{0x254A, 0x15},
++{0x254B, 0x01},
++{0x255A, 0x15},
++{0x255B, 0x01},
++{0x2560, 0x01},
++{0x2561, 0x00},
++{0x2562, 0x2A},
++{0x2563, 0x00},
++{0x2564, 0xF8},
++{0x2565, 0x00},
++{0x2566, 0x15},
++{0x2567, 0x01},
++{0x2568, 0x0C},
++{0x2569, 0x02},
++{0x256A, 0x31},
++{0x256B, 0x02},
++{0x2578, 0x90},
++{0x2579, 0x01},
++{0x257A, 0x92},
++{0x257B, 0x01},
++{0x257C, 0xB8},
++{0x257D, 0x02},
++{0x257E, 0xBA},
++{0x257F, 0x02},
++{0x2584, 0x90},
++{0x2585, 0x01},
++{0x2586, 0x92},
++{0x2587, 0x01},
++{0x2588, 0xB8},
++{0x2589, 0x02},
++{0x258A, 0xBA},
++{0x258B, 0x02},
++{0x26B8, 0x10},
++{0x26B9, 0x00},
++{0x26BA, 0x33},
++{0x26BB, 0x00},
++{0x26BC, 0x89},
++{0x26BD, 0x00},
++{0x26BE, 0xB0},
++{0x26BF, 0x00},
++{0x26C4, 0x4E},
++{0x26C5, 0x00},
++{0x26C8, 0xC9},
++{0x26C9, 0x00},
++{0x26CC, 0x35},
++{0x26CD, 0x01},
++{0x26D0, 0xBA},
++{0x26D1, 0x01},
++{0x26D4, 0x7C},
++{0x26D5, 0x02},
++{0x26D8, 0xF6},
++{0x26D9, 0x02},
++{0x26DE, 0x51},
++{0x26DF, 0x00},
++{0x26E0, 0x7F},
++{0x26E1, 0x00},
++{0x26E2, 0xCC},
++{0x26E3, 0x00},
++{0x26E4, 0xF8},
++{0x26E5, 0x00},
++{0x26E6, 0x38},
++{0x26E7, 0x01},
++{0x26E8, 0x65},
++{0x26E9, 0x01},
++{0x26EA, 0xBD},
++{0x26EB, 0x01},
++{0x26EE, 0x7F},
++{0x26EF, 0x02},
++{0x26F0, 0xAB},
++{0x26F1, 0x02},
++{0x26F2, 0xF9},
++{0x26F3, 0x02},
++{0x2722, 0x59},
++{0x2723, 0x02},
++{0x2938, 0x55},
++{0x2939, 0x00},
++{0x293A, 0x17},
++{0x293B, 0x00},
++{0x293C, 0xD0},
++{0x293D, 0x00},
++{0x293E, 0x91},
++{0x293F, 0x00},
++{0x2940, 0x3C},
++{0x2941, 0x01},
++{0x2942, 0x0C},
++{0x2943, 0x01},
++{0x2944, 0xC1},
++{0x2945, 0x01},
++{0x2946, 0x76},
++{0x2947, 0x01},
++{0x2948, 0x83},
++{0x2949, 0x02},
++{0x294A, 0xFB},
++{0x294B, 0x01},
++{0x294C, 0xFD},
++{0x294D, 0x02},
++{0x294E, 0xBF},
++{0x294F, 0x02},
++{0x2A06, 0xFF},
++{0x2A07, 0x03},
++{0x2A20, 0x00},
++{0x2A21, 0x00},
++{0x2A22, 0x7D},
++{0x2A23, 0x00},
++{0x2B11, 0x19},
++{0x2B13, 0x15},
++{0x2B14, 0x14},
++{0x2B15, 0x13},
++{0x2B16, 0x12},
++{0x2B17, 0x11},
++{0x2B18, 0x10},
++{0x2B19, 0x0F},
++{0x2B1A, 0x0E},
++{0x2B1B, 0x0D},
++{0x2B1C, 0x0C},
++{0x2B1D, 0x0B},
++{0x2B1E, 0x0A},
++{0x2B1F, 0x09},
++{0x2B20, 0x08},
++{0x2B21, 0x07},
++{0x2B22, 0x06},
++{0x2B23, 0x05},
++{0x2B24, 0x04},
++{0x2B25, 0x03},
++{0x2B26, 0x03},
++{0x2B38, 0x01},
++{0x2B45, 0xE3},
++{0x2B50, 0x01},
++{0x2B51, 0x00},
++{0x2B6D, 0x47},
++{0x2B70, 0x02},
++{0x2B71, 0x02},
++{0x2B72, 0x02},
++{0x2B7F, 0x7F},
++{0x2B80, 0x94},
++{0x2B81, 0x06},
++{0x2B87, 0x1B},
++{0x2B88, 0x1B},
++{0x2B89, 0x17},
++{0x2B8A, 0x12},
++{0x2B8B, 0x12},
++{0x2B8D, 0x2B},
++{0x2B8E, 0x2B},
++{0x2B8F, 0x2B},
++{0x2B90, 0x7F},
++{0x2B91, 0x1F},
++{0x2B94, 0x7F},
++{0x2B95, 0x27},
++{0x2B98, 0x7F},
++{0x2B99, 0x57},
++{0x2BA8, 0xBC},
++{0x2BA9, 0x62},
++{0x2BC1, 0x70},
++{0x2BC5, 0x80},
++{0x2BD5, 0x30},
++{0x2BD6, 0xF0},
++{0x2BD8, 0xDB},
++{0x2BD9, 0xF6},
++{0x2BDA, 0x63},
++{0x2BDB, 0x0C},
++{0x2BDC, 0x5C},
++{0x2C98, 0xE1},
++{0x2C99, 0x2E},
++{0x2C9B, 0x86},
++{0x2CA9, 0x80},
++{0x2CAA, 0x01},
++{0x2D39, 0x0E},
++{0x2D54, 0x00},
++{0x2D5B, 0x58},
++{0x3000, 0x00},
++{0x3001, 0x40},
++{0x3002, 0x23},
++{0x3003, 0xA1},
++{0x3004, 0x00},
++{0x3005, 0x20},
++{0x3006, 0x94},
++{0x3007, 0x00},
++{0x3008, 0x06},
++{0x3009, 0xB4},
++{0x300A, 0x1F},
++{0x300B, 0x28},
++{0x300C, 0x00},
++{0x300D, 0x18},
++{0x300E, 0x90},
++{0x300F, 0x97},
++{0x3010, 0x00},
++{0x3011, 0x40},
++{0x3012, 0x21},
++{0x3013, 0x21},
++{0x3014, 0x00},
++{0x3015, 0x20},
++{0x3016, 0x94},
++{0x3017, 0x00},
++{0x3018, 0x00},
++{0x3019, 0x09},
++{0x301A, 0x46},
++{0x301B, 0x28},
++{0x3070, 0xC1},
++{0x3071, 0x81},
++{0x3072, 0x29},
++{0x3073, 0x81},
++#if 1
++{0x3410, 0x90},
++{0x3411, 0x07},
++{0x3418, 0x48},
++{0x3419, 0x04},
++#else
++{0x3410, 0x80},
++{0x3411, 0x07},
++{0x3418, 0x38},
++{0x3419, 0x04},
++#endif
++{0x3584, 0x00},
++{0x3586, 0x00},
++{0x3587, 0x01},
++{0x3588, 0xE6},
++{0x3589, 0x00},
++{0x3590, 0x00},
++{0x3591, 0x00},
++{0x3594, 0x40},
++{0x3598, 0x03},
++{0x3599, 0x00},
++{0x359A, 0x80},
++{0x359B, 0x00},
++{0x359C, 0x00},
++{0x359D, 0x01},
++{0x359E, 0x00},
++{0x359F, 0x02},
++{0x35A0, 0x00},
++{0x35A1, 0x04},
++{0x35A2, 0x20},
++{0x35A3, 0x00},
++{0x35A4, 0x40},
++{0x35A5, 0x00},
++{0x35A6, 0x80},
++{0x35A7, 0x00},
++{0x35A8, 0x00},
++{0x35A9, 0x01},
++{0x35AA, 0x3A},
++{0x35AB, 0x00},
++{0x35AC, 0x80},
++{0x35AD, 0x00},
++{0x35AE, 0x00},
++{0x35AF, 0x01},
++{0x35B0, 0x00},
++{0x35B1, 0x02},
++{0x35B2, 0x00},
++{0x35B3, 0x04},
++{0x35B4, 0x02},
++{0x35B5, 0x00},
++{0x35B6, 0x04},
++{0x35B7, 0x00},
++{0x35B8, 0x08},
++{0x35B9, 0x00},
++{0x35BA, 0x10},
++{0x35BB, 0x00},
++{0x35BC, 0x03},
++{0x35BD, 0x00},
++{0x35C8, 0x00},
++{0x35C9, 0x01},
++{0x35CA, 0x00},
++{0x35CB, 0x04},
++{0x35CC, 0x00},
++{0x35CD, 0x10},
++{0x35CE, 0x00},
++{0x35CF, 0x40},
++{0x35D0, 0x00},
++{0x35D1, 0x0C},
++{0x35D2, 0x00},
++{0x35D3, 0x0C},
++{0x35D4, 0x00},
++{0x35D5, 0x0C},
++{0x35D6, 0x00},
++{0x35D7, 0x0C},
++{0x35D8, 0x00},
++{0x35D9, 0x00},
++{0x35DA, 0x08},
++{0x35DB, 0x00},
++{0x35DC, 0xD8},
++{0x35DD, 0x0E},
++{0x35F0, 0x00},
++{0x35F1, 0x10},
++{0x35F2, 0x00},
++{0x35F3, 0x10},
++{0x35F4, 0x00},
++{0x35F5, 0x10},
++{0x35F6, 0x00},
++{0x35F7, 0x03},
++{0x35F8, 0x00},
++{0x35F9, 0x01},
++{0x35FA, 0x38},
++{0x35FB, 0x00},
++{0x35FC, 0xB3},
++{0x35FD, 0x01},
++{0x35FE, 0x00},
++{0x35FF, 0x00},
++{0x3600, 0x04},
++{0x3601, 0x06},
++{0x3604, 0x03},
++{0x3605, 0x00},
++{0x3608, 0x03},
++{0x3609, 0x00},
++{0x360C, 0x00},
++{0x360D, 0x00},
++{0x3610, 0x10},
++{0x3611, 0x01},
++{0x3612, 0x00},
++{0x3613, 0x00},
++{0x3614, 0x00},
++{0x3615, 0x00},
++{0x361C, 0x00},
++{0x361D, 0x01},
++{0x361E, 0x00},
++{0x361F, 0x01},
++{0x3620, 0x01},
++{0x3621, 0x00},
++{0x3622, 0xB0},
++{0x3623, 0x04},
++{0x3624, 0xDC},
++{0x3625, 0x05},
++{0x3626, 0x00},
++{0x3627, 0x01},
++{0x3628, 0xFF},
++{0x3629, 0x0F},
++{0x362A, 0x00},
++{0x362B, 0x10},
++{0x362C, 0x00},
++{0x362D, 0x01},
++{0x36C4, 0x99},
++{0x36C5, 0x09},
++{0x36C6, 0x18},
++{0x36C7, 0x07},
++{0x36C8, 0x65},
++{0x36C9, 0x0E},
++{0x36CC, 0x99},
++{0x36CD, 0x01},
++{0x36CE, 0x47},
++{0x36CF, 0x00},
++{0x36D0, 0x04},
++{0x36D1, 0x00},
++{0x36D4, 0x65},
++{0x36D5, 0x0E},
++{0x36D6, 0xA4},
++{0x36D7, 0x0A},
++{0x36D8, 0x65},
++{0x36D9, 0x0E},
++{0x36DC, 0x65},
++{0x36DD, 0x0E},
++{0x36DE, 0xA4},
++{0x36DF, 0x0A},
++{0x36E0, 0x65},
++{0x36E1, 0x0E},
++{0x36E4, 0x65},
++{0x36E5, 0x0E},
++{0x36E6, 0xA4},
++{0x36E7, 0x0A},
++{0x36E8, 0x65},
++{0x36E9, 0x0E},
++{0x36EE, 0x00},
++{0x36EF, 0x00},
++{0x36F0, 0x00},
++{0x36F1, 0x80},
++{0x36F8, 0x00},
++{0x3702, 0x03},
++{0x3703, 0x04},
++{0x3704, 0x08},
++{0x370E, 0x0E},
++{0x3718, 0x62},
++{0x3719, 0x4A},
++{0x371A, 0x38},
++{0x371B, 0x20},
++{0x371C, 0x64},
++{0x371D, 0x42},
++{0x371E, 0x32},
++{0x371F, 0x1B},
++{0x3720, 0x98},
++{0x3721, 0xA0},
++{0x3722, 0xA8},
++{0x3723, 0xB0},
++{0x3748, 0xA5},
++{0x3749, 0x9B},
++{0x374A, 0x91},
++{0x374B, 0x7D},
++{0x37C0, 0x00},
++{0x37C1, 0x00},
++{0x37C2, 0x00},
++{0x37C4, 0x00},
++{0x37C5, 0x00},
++{0x37C6, 0x00},
++{0x37C8, 0x00},
++{0x37C9, 0x00},
++{0x37CA, 0x00},
++{0x37CC, 0x00},
++{0x37CD, 0x00},
++{0x37CE, 0x00},
++{0x37D0, 0x00},
++{0x37D1, 0x00},
++{0x37D2, 0x00},
++{0x37D4, 0x00},
++{0x37D5, 0x00},
++{0x37D6, 0x00},
++{0x37D8, 0x00},
++{0x37D9, 0x00},
++{0x37DA, 0x00},
++{0x37DC, 0x00},
++{0x37DD, 0x00},
++{0x37DE, 0x00},
++{0x37E0, 0x00},
++{0x37E1, 0x00},
++{0x37E2, 0x00},
++{0x37E4, 0x00},
++{0x37E5, 0x00},
++{0x37E6, 0x00},
++{0x37E8, 0x00},
++{0x37E9, 0x00},
++{0x37EA, 0x00},
++{0x37EC, 0x00},
++{0x37ED, 0x00},
++{0x37EE, 0x00},
++{0x37F0, 0x00},
++{0x37F4, 0x00},
++{0x37F5, 0x1E},
++{0x37F6, 0x34},
++{0x37F7, 0x00},
++{0x37F8, 0xFF},
++{0x37F9, 0xFF},
++{0x37FA, 0x03},
++{0x37FC, 0x00},
++{0x37FD, 0x00},
++{0x37FE, 0x04},
++{0x3800, 0xFF},
++{0x3801, 0xFF},
++{0x3802, 0x03},
++{0x3804, 0x00},
++{0x3805, 0x00},
++{0x3806, 0x04},
++{0x3808, 0x00},
++{0x3809, 0x00},
++{0x380A, 0x00},
++{0x380C, 0x00},
++{0x380D, 0x00},
++{0x380E, 0x00},
++{0x3810, 0x00},
++{0x3811, 0x00},
++{0x3812, 0x00},
++{0x3814, 0x00},
++{0x3815, 0x00},
++{0x3816, 0x00},
++{0x3818, 0x00},
++{0x3819, 0x00},
++{0x381A, 0x00},
++{0x381C, 0x00},
++{0x381D, 0x00},
++{0x381E, 0x00},
++{0x3820, 0x00},
++{0x3821, 0x00},
++{0x3822, 0x00},
++{0x3824, 0x00},
++{0x3825, 0x00},
++{0x3826, 0x00},
++{0x3828, 0x00},
++{0x3829, 0x00},
++{0x382A, 0x00},
++{0x382C, 0x00},
++{0x382D, 0x00},
++{0x382E, 0x00},
++{0x3830, 0x00},
++{0x3831, 0x00},
++{0x3832, 0x00},
++{0x3834, 0x00},
++{0x3835, 0x00},
++{0x3836, 0x00},
++{0x3838, 0x22},
++{0x3839, 0x00},
++{0x383A, 0x25},
++{0x383B, 0x00},
++{0x383C, 0x1A},
++{0x383D, 0x00},
++{0x383E, 0x26},
++{0x383F, 0x00},
++{0x3840, 0x07},
++{0x3841, 0x00},
++{0x3842, 0x06},
++{0x3843, 0x00},
++{0x3844, 0x03},
++{0x3845, 0x00},
++{0x3846, 0x02},
++{0x3847, 0x00},
++{0x3848, 0xFB},
++{0x3849, 0xFF},
++{0x384A, 0xFF},
++{0x384B, 0xFF},
++{0x384C, 0xF3},
++{0x384D, 0xFF},
++{0x384E, 0xF2},
++{0x384F, 0xFF},
++{0x3850, 0xFF},
++{0x3851, 0x0F},
++{0x3852, 0x00},
++{0x3853, 0x10},
++{0x3854, 0xFF},
++{0x3855, 0x0F},
++{0x3856, 0x00},
++{0x3857, 0x10},
++{0x3858, 0xFF},
++{0x3859, 0x0F},
++{0x385A, 0x00},
++{0x385B, 0x10},
++{0x385C, 0x02},
++{0x385D, 0x00},
++{0x385E, 0x06},
++{0x385F, 0x00},
++{0x3860, 0x06},
++{0x3861, 0x00},
++{0x3862, 0x08},
++{0x3863, 0x00},
++{0x3864, 0x02},
++{0x3865, 0x00},
++{0x38A0, 0x01},
++{0x38A1, 0x01},
++{0x38A2, 0x00},
++{0x38A3, 0x01},
++{0x38A4, 0x07},
++{0x38A5, 0x00},
++{0x38A6, 0x04},
++{0x38A7, 0x05},
++{0x38A8, 0x00},
++{0x38A9, 0x00},
++{0x38AC, 0x00},
++{0x38AD, 0x00},
++{0x38AE, 0x01},
++{0x38B0, 0x02},
++{0x38B2, 0x22},
++{0x38B3, 0x00},
++{0x38B4, 0x17},
++{0x38B5, 0x00},
++{0x38B6, 0x11},
++{0x38B7, 0x00},
++{0x38B8, 0x0E},
++{0x38B9, 0x00},
++{0x38BA, 0x2A},
++{0x38BB, 0x00},
++{0x38BC, 0x1C},
++{0x38BD, 0x00},
++{0x38BE, 0x14},
++{0x38BF, 0x00},
++{0x38C0, 0x10},
++{0x38C1, 0x00},
++{0x38C2, 0x31},
++{0x38C3, 0x00},
++{0x38C4, 0x21},
++{0x38C5, 0x00},
++{0x38C6, 0x18},
++{0x38C7, 0x00},
++{0x38C8, 0x12},
++{0x38C9, 0x00},
++{0x38CA, 0x3C},
++{0x38CB, 0x00},
++{0x38CC, 0x29},
++{0x38CD, 0x00},
++{0x38CE, 0x1D},
++{0x38CF, 0x00},
++{0x38D0, 0x15},
++{0x38D1, 0x00},
++{0x38D2, 0x4E},
++{0x38D3, 0x00},
++{0x38D4, 0x35},
++{0x38D5, 0x00},
++{0x38D6, 0x26},
++{0x38D7, 0x00},
++{0x38D8, 0x1A},
++{0x38D9, 0x00},
++{0x38DA, 0x69},
++{0x38DB, 0x00},
++{0x38DC, 0x48},
++{0x38DD, 0x00},
++{0x38DE, 0x33},
++{0x38DF, 0x00},
++{0x38E0, 0x22},
++{0x38E1, 0x00},
++{0x38E2, 0x93},
++{0x38E3, 0x00},
++{0x38E4, 0x64},
++{0x38E5, 0x00},
++{0x38E6, 0x48},
++{0x38E7, 0x00},
++{0x38E8, 0x30},
++{0x38E9, 0x00},
++{0x38EA, 0xD3},
++{0x38EB, 0x00},
++{0x38EC, 0x90},
++{0x38ED, 0x00},
++{0x38EE, 0x69},
++{0x38EF, 0x00},
++{0x38F0, 0x49},
++{0x38F1, 0x00},
++{0x38F2, 0x39},
++{0x38F3, 0x01},
++{0x38F4, 0xD5},
++{0x38F5, 0x00},
++{0x38F6, 0x9F},
++{0x38F7, 0x00},
++{0x38F8, 0x75},
++{0x38F9, 0x00},
++{0x38FA, 0x00},
++{0x38FB, 0x01},
++{0x38FC, 0x00},
++{0x38FD, 0x01},
++{0x38FE, 0x00},
++{0x38FF, 0x01},
++{0x3900, 0x00},
++{0x3901, 0x01},
++{0x3902, 0x60},
++{0x3903, 0x00},
++{0x3904, 0x25},
++{0x3905, 0x00},
++{0x3906, 0x18},
++{0x3907, 0x00},
++{0x3908, 0x10},
++{0x3909, 0x00},
++{0x390A, 0xFF},
++{0x390B, 0x00},
++{0x390C, 0xD5},
++{0x390D, 0x00},
++{0x390E, 0xAA},
++{0x390F, 0x00},
++{0x3910, 0x85},
++{0x3911, 0x00},
++{0x3912, 0xFF},
++{0x3913, 0x00},
++{0x3914, 0xD5},
++{0x3915, 0x00},
++{0x3916, 0xAA},
++{0x3917, 0x00},
++{0x3918, 0x85},
++{0x3919, 0x00},
++{0x391A, 0xFF},
++{0x391B, 0x00},
++{0x391C, 0xD5},
++{0x391D, 0x00},
++{0x391E, 0xAA},
++{0x391F, 0x00},
++{0x3920, 0x85},
++{0x3921, 0x00},
++{0x3922, 0x40},
++{0x3923, 0x00},
++{0x3924, 0x40},
++{0x3925, 0x00},
++{0x3926, 0x40},
++{0x3927, 0x00},
++{0x3928, 0x40},
++{0x3929, 0x00},
++{0x392A, 0x80},
++{0x392B, 0x00},
++{0x392C, 0x80},
++{0x392D, 0x00},
++{0x392E, 0x80},
++{0x392F, 0x00},
++{0x3930, 0x80},
++{0x3931, 0x00},
++{0x3932, 0x4C},
++{0x3933, 0x4C},
++{0x3934, 0x4C},
++{0x3940, 0x01},
++{0x3941, 0x01},
++{0x3942, 0x00},
++{0x3943, 0x01},
++{0x3944, 0x07},
++{0x3945, 0x00},
++{0x3946, 0x04},
++{0x3947, 0x05},
++{0x3948, 0x00},
++{0x3949, 0x00},
++{0x394C, 0x00},
++{0x394D, 0x00},
++{0x394E, 0x01},
++{0x3950, 0x03},
++{0x3952, 0x14},
++{0x3953, 0x00},
++{0x3954, 0x0F},
++{0x3955, 0x00},
++{0x3956, 0x0E},
++{0x3957, 0x00},
++{0x3958, 0x0E},
++{0x3959, 0x00},
++{0x395A, 0x19},
++{0x395B, 0x00},
++{0x395C, 0x11},
++{0x395D, 0x00},
++{0x395E, 0x0F},
++{0x395F, 0x00},
++{0x3960, 0x0E},
++{0x3961, 0x00},
++{0x3962, 0x1C},
++{0x3963, 0x00},
++{0x3964, 0x13},
++{0x3965, 0x00},
++{0x3966, 0x0F},
++{0x3967, 0x00},
++{0x3968, 0x0E},
++{0x3969, 0x00},
++{0x396A, 0x23},
++{0x396B, 0x00},
++{0x396C, 0x15},
++{0x396D, 0x00},
++{0x396E, 0x11},
++{0x396F, 0x00},
++{0x3970, 0x0E},
++{0x3971, 0x00},
++{0x3972, 0x2E},
++{0x3973, 0x00},
++{0x3974, 0x1A},
++{0x3975, 0x00},
++{0x3976, 0x14},
++{0x3977, 0x00},
++{0x3978, 0x0F},
++{0x3979, 0x00},
++{0x397A, 0x3E},
++{0x397B, 0x00},
++{0x397C, 0x23},
++{0x397D, 0x00},
++{0x397E, 0x1A},
++{0x397F, 0x00},
++{0x3980, 0x12},
++{0x3981, 0x00},
++{0x3982, 0x56},
++{0x3983, 0x00},
++{0x3984, 0x31},
++{0x3985, 0x00},
++{0x3986, 0x25},
++{0x3987, 0x00},
++{0x3988, 0x1A},
++{0x3989, 0x00},
++{0x398A, 0x7B},
++{0x398B, 0x00},
++{0x398C, 0x49},
++{0x398D, 0x00},
++{0x398E, 0x39},
++{0x398F, 0x00},
++{0x3990, 0x2C},
++{0x3991, 0x00},
++{0x3992, 0xB4},
++{0x3993, 0x00},
++{0x3994, 0x75},
++{0x3995, 0x00},
++{0x3996, 0x61},
++{0x3997, 0x00},
++{0x3998, 0x53},
++{0x3999, 0x00},
++{0x399A, 0x00},
++{0x399B, 0x01},
++{0x399C, 0x00},
++{0x399D, 0x01},
++{0x399E, 0x00},
++{0x399F, 0x01},
++{0x39A0, 0x00},
++{0x39A1, 0x01},
++{0x39A2, 0x60},
++{0x39A3, 0x00},
++{0x39A4, 0x20},
++{0x39A5, 0x00},
++{0x39A6, 0x15},
++{0x39A7, 0x00},
++{0x39A8, 0x10},
++{0x39A9, 0x00},
++{0x39AA, 0xFF},
++{0x39AB, 0x00},
++{0x39AC, 0xD5},
++{0x39AD, 0x00},
++{0x39AE, 0xAA},
++{0x39AF, 0x00},
++{0x39B0, 0x85},
++{0x39B1, 0x00},
++{0x39B2, 0xFF},
++{0x39B3, 0x00},
++{0x39B4, 0xD5},
++{0x39B5, 0x00},
++{0x39B6, 0xAA},
++{0x39B7, 0x00},
++{0x39B8, 0x85},
++{0x39B9, 0x00},
++{0x39BA, 0xFF},
++{0x39BB, 0x00},
++{0x39BC, 0xD5},
++{0x39BD, 0x00},
++{0x39BE, 0xAA},
++{0x39BF, 0x00},
++{0x39C0, 0x85},
++{0x39C1, 0x00},
++{0x39C2, 0x40},
++{0x39C3, 0x00},
++{0x39C4, 0x40},
++{0x39C5, 0x00},
++{0x39C6, 0x40},
++{0x39C7, 0x00},
++{0x39C8, 0x40},
++{0x39C9, 0x00},
++{0x39CA, 0x80},
++{0x39CB, 0x00},
++{0x39CC, 0x80},
++{0x39CD, 0x00},
++{0x39CE, 0x80},
++{0x39CF, 0x00},
++{0x39D0, 0x80},
++{0x39D1, 0x00},
++{0x39D2, 0x4C},
++{0x39D3, 0x4C},
++{0x39D4, 0x4C},
++{0x39E0, 0x01},
++{0x39E1, 0x00},
++{0x39E4, 0x40},
++{0x39E5, 0x01},
++{0x39E6, 0x01},
++{0x39E8, 0x00},
++{0x39E9, 0x01},
++{0x39EA, 0x00},
++{0x39EB, 0x00},
++{0x39EC, 0x01},
++{0x39ED, 0x00},
++{0x39EE, 0x01},
++{0x39F0, 0x03},
++{0x39F1, 0x04},
++{0x39F2, 0x0E},
++{0x39F4, 0x1C},
++{0x39F5, 0x00},
++{0x39F6, 0x13},
++{0x39F7, 0x00},
++{0x39F8, 0x0D},
++{0x39F9, 0x00},
++{0x39FA, 0x07},
++{0x39FB, 0x00},
++{0x39FC, 0x38},
++{0x39FD, 0x00},
++{0x39FE, 0x1C},
++{0x39FF, 0x00},
++{0x3A00, 0x11},
++{0x3A01, 0x00},
++{0x3A02, 0x08},
++{0x3A03, 0x00},
++{0x3A04, 0x4A},
++{0x3A05, 0x00},
++{0x3A06, 0x23},
++{0x3A07, 0x00},
++{0x3A08, 0x15},
++{0x3A09, 0x00},
++{0x3A0A, 0x09},
++{0x3A0B, 0x00},
++{0x3A0C, 0x65},
++{0x3A0D, 0x00},
++{0x3A0E, 0x2D},
++{0x3A0F, 0x00},
++{0x3A10, 0x1A},
++{0x3A11, 0x00},
++{0x3A12, 0x0B},
++{0x3A13, 0x00},
++{0x3A14, 0x8D},
++{0x3A15, 0x00},
++{0x3A16, 0x3D},
++{0x3A17, 0x00},
++{0x3A18, 0x23},
++{0x3A19, 0x00},
++{0x3A1A, 0x0E},
++{0x3A1B, 0x00},
++{0x3A1C, 0xC5},
++{0x3A1D, 0x00},
++{0x3A1E, 0x55},
++{0x3A1F, 0x00},
++{0x3A20, 0x30},
++{0x3A21, 0x00},
++{0x3A22, 0x13},
++{0x3A23, 0x00},
++{0x3A24, 0x16},
++{0x3A25, 0x01},
++{0x3A26, 0x76},
++{0x3A27, 0x00},
++{0x3A28, 0x42},
++{0x3A29, 0x00},
++{0x3A2A, 0x1A},
++{0x3A2B, 0x00},
++{0x3A2C, 0x88},
++{0x3A2D, 0x01},
++{0x3A2E, 0xA7},
++{0x3A2F, 0x00},
++{0x3A30, 0x5D},
++{0x3A31, 0x00},
++{0x3A32, 0x24},
++{0x3A33, 0x00},
++{0x3A34, 0x2A},
++{0x3A35, 0x02},
++{0x3A36, 0xEB},
++{0x3A37, 0x00},
++{0x3A38, 0x83},
++{0x3A39, 0x00},
++{0x3A3A, 0x32},
++{0x3A3B, 0x00},
++{0x3A3C, 0x00},
++{0x3A3D, 0x01},
++{0x3A3E, 0x00},
++{0x3A3F, 0x01},
++{0x3A40, 0x00},
++{0x3A41, 0x01},
++{0x3A42, 0x00},
++{0x3A43, 0x01},
++{0x3A44, 0x70},
++{0x3A45, 0x00},
++{0x3A46, 0x25},
++{0x3A47, 0x00},
++{0x3A48, 0x18},
++{0x3A49, 0x00},
++{0x3A4A, 0x10},
++{0x3A4B, 0x00},
++{0x3A4C, 0xFF},
++{0x3A4D, 0x00},
++{0x3A4E, 0xD5},
++{0x3A4F, 0x00},
++{0x3A50, 0xAA},
++{0x3A51, 0x00},
++{0x3A52, 0x85},
++{0x3A53, 0x00},
++{0x3A54, 0xFF},
++{0x3A55, 0x00},
++{0x3A56, 0xD5},
++{0x3A57, 0x00},
++{0x3A58, 0xAA},
++{0x3A59, 0x00},
++{0x3A5A, 0x85},
++{0x3A5B, 0x00},
++{0x3A5C, 0xFF},
++{0x3A5D, 0x00},
++{0x3A5E, 0xD5},
++{0x3A5F, 0x00},
++{0x3A60, 0xAA},
++{0x3A61, 0x00},
++{0x3A62, 0x85},
++{0x3A63, 0x00},
++{0x3A64, 0x1C},
++{0x3A65, 0x00},
++{0x3A66, 0x13},
++{0x3A67, 0x00},
++{0x3A68, 0x0D},
++{0x3A69, 0x00},
++{0x3A6A, 0x07},
++{0x3A6B, 0x00},
++{0x3A6C, 0x0D},
++{0x3A6D, 0x00},
++{0x3A6E, 0x0B},
++{0x3A6F, 0x00},
++{0x3A70, 0x06},
++{0x3A71, 0x00},
++{0x3A72, 0x05},
++{0x3A73, 0x00},
++{0x3A74, 0x19},
++{0x3A75, 0x00},
++{0x3A76, 0x14},
++{0x3A77, 0x00},
++{0x3A78, 0x0F},
++{0x3A79, 0x00},
++{0x3A7A, 0x0A},
++{0x3A7B, 0x00},
++{0x3A7C, 0x80},
++{0x3A7D, 0x00},
++{0x3A7E, 0x80},
++{0x3A7F, 0x00},
++{0x3A80, 0x80},
++{0x3A81, 0x00},
++{0x3A82, 0x80},
++{0x3A83, 0x00},
++{0x3A84, 0x08},
++{0x3A85, 0x00},
++{0x3A86, 0x05},
++{0x3A87, 0x00},
++{0x3A88, 0x04},
++{0x3A89, 0x00},
++{0x3A8A, 0x03},
++{0x3A8B, 0x00},
++{0x3A8C, 0xCD},
++{0x3A8D, 0x00},
++{0x3A8E, 0xAA},
++{0x3A8F, 0x00},
++{0x3A90, 0x8C},
++{0x3A91, 0x00},
++{0x3A92, 0x64},
++{0x3A93, 0x00},
++{0x3A94, 0xCD},
++{0x3A95, 0x00},
++{0x3A96, 0xAA},
++{0x3A97, 0x00},
++{0x3A98, 0x8C},
++{0x3A99, 0x00},
++{0x3A9A, 0x64},
++{0x3A9B, 0x00},
++{0x3A9C, 0x08},
++{0x3A9D, 0x10},
++{0x3A9E, 0x4C},
++{0x3A9F, 0x4C},
++{0x3AA0, 0x4C},
++{0x3AA1, 0x04},
++{0x3AA2, 0x05},
++{0x3AC0, 0x01},
++{0x3AC4, 0x81},
++{0x3AC5, 0x00},
++{0x3AC6, 0x00},
++{0x3AC7, 0x00},
++{0x3AC8, 0x00},
++{0x3AC9, 0x00},
++{0x3ACA, 0x00},
++{0x3ACB, 0x00},
++{0x3ACC, 0x02},
++{0x3ACD, 0x00},
++{0x3ACE, 0x81},
++{0x3ACF, 0x00},
++{0x3AD0, 0x00},
++{0x3AD1, 0x00},
++{0x3AD2, 0xFD},
++{0x3AD3, 0x03},
++{0x3AD4, 0x02},
++{0x3AD5, 0x00},
++{0x3AD6, 0x00},
++{0x3AD7, 0x00},
++{0x3AD8, 0x81},
++{0x3AD9, 0x00},
++{0x3ADA, 0xFD},
++{0x3ADB, 0x03},
++{0x3ADC, 0xFF},
++{0x3ADD, 0x03},
++{0x3ADE, 0x01},
++{0x3ADF, 0x00},
++{0x3AE0, 0x01},
++{0x3AE1, 0x00},
++{0x3AE2, 0x7E},
++{0x3AE3, 0x00},
++{0x3AF4, 0x00},
++{0x3AF6, 0x40},
++{0x3AF7, 0x1E},
++{0x3AF8, 0x01},
++{0x3AFA, 0x63},
++{0x3AFB, 0x09},
++{0x3AFC, 0x11},
++{0x3AFD, 0x09},
++{0x3AFE, 0x00},
++{0x3AFF, 0x00},
++{0x3B00, 0x00},
++{0x3B01, 0x00},
++{0x3B02, 0x84},
++{0x3B03, 0x06},
++{0x3B04, 0x30},
++{0x3B05, 0x06},
++{0x3B06, 0x00},
++{0x3B07, 0x00},
++{0x3B08, 0x00},
++{0x3B09, 0x00},
++{0x3B0A, 0x00},
++{0x3B0B, 0x00},
++{0x3B0C, 0x00},
++{0x3B0D, 0x00},
++{0x3B0E, 0x00},
++{0x3B0F, 0x00},
++{0x3B10, 0x00},
++{0x3B11, 0x00},
++{0x3B12, 0x00},
++{0x3B13, 0x00},
++{0x3B14, 0x00},
++{0x3B15, 0x00},
++{0x3B16, 0x00},
++{0x3B17, 0x00},
++{0x3B18, 0x00},
++{0x3B19, 0x00},
++{0x3B1A, 0x00},
++{0x3B1B, 0x00},
++{0x3B1C, 0x00},
++{0x3B1D, 0x00},
++{0x3B1E, 0x00},
++{0x3B1F, 0x00},
++{0x3B20, 0x00},
++{0x3B21, 0x00},
++{0x3B22, 0x00},
++{0x3B23, 0x00},
++{0x3B24, 0x00},
++{0x3B25, 0x00},
++{0x3B26, 0x00},
++{0x3B27, 0x00},
++{0x3B28, 0x00},
++{0x3B29, 0x00},
++{0x3B2A, 0x00},
++{0x3B2C, 0x00},
++{0x3B2E, 0x00},
++{0x3B30, 0x00},
++{0x3B32, 0x0C},
++{0x4000, 0xD1},
++{0x4001, 0xC0},
++{0x4002, 0xC0},
++{0x4003, 0xB8},
++{0x4004, 0xC0},
++{0x4005, 0xB8},
++{0x4006, 0xB9},
++{0x4007, 0xB7},
++{0x4008, 0xB0},
++{0x4009, 0xAB},
++{0x400A, 0xAC},
++{0x400B, 0xAB},
++{0x400C, 0xA8},
++{0x400D, 0xA6},
++{0x400E, 0xA6},
++{0x400F, 0xA5},
++{0x4010, 0xA2},
++{0x4011, 0xA0},
++{0x4012, 0xA0},
++{0x4013, 0x9F},
++{0x4014, 0xA4},
++{0x4015, 0xA2},
++{0x4016, 0xA2},
++{0x4017, 0x9C},
++{0x4018, 0xA8},
++{0x4019, 0xA6},
++{0x401A, 0xA8},
++{0x401B, 0xAA},
++{0x401C, 0xB0},
++{0x401D, 0xAE},
++{0x401E, 0xAE},
++{0x401F, 0xAE},
++{0x4020, 0xBA},
++{0x4021, 0xAE},
++{0x4022, 0xAF},
++{0x4023, 0xAE},
++{0x4024, 0xC6},
++{0x4025, 0xBD},
++{0x4026, 0xBD},
++{0x4027, 0xBA},
++{0x4028, 0xB0},
++{0x4029, 0xA9},
++{0x402A, 0xAA},
++{0x402B, 0xA8},
++{0x402C, 0x9F},
++{0x402D, 0x9C},
++{0x402E, 0x9C},
++{0x402F, 0x9B},
++{0x4030, 0x93},
++{0x4031, 0x91},
++{0x4032, 0x92},
++{0x4033, 0x91},
++{0x4034, 0x8D},
++{0x4035, 0x8C},
++{0x4036, 0x8C},
++{0x4037, 0x8C},
++{0x4038, 0x8F},
++{0x4039, 0x8E},
++{0x403A, 0x8E},
++{0x403B, 0x8E},
++{0x403C, 0x98},
++{0x403D, 0x96},
++{0x403E, 0x96},
++{0x403F, 0x95},
++{0x4040, 0xA4},
++{0x4041, 0xA0},
++{0x4042, 0xA0},
++{0x4043, 0x9E},
++{0x4044, 0xB3},
++{0x4045, 0xAE},
++{0x4046, 0xAF},
++{0x4047, 0xAB},
++{0x4048, 0xC2},
++{0x4049, 0xB7},
++{0x404A, 0xB8},
++{0x404B, 0xB5},
++{0x404C, 0xAB},
++{0x404D, 0xA4},
++{0x404E, 0xA5},
++{0x404F, 0xA3},
++{0x4050, 0x99},
++{0x4051, 0x96},
++{0x4052, 0x96},
++{0x4053, 0x96},
++{0x4054, 0x8B},
++{0x4055, 0x8A},
++{0x4056, 0x8A},
++{0x4057, 0x8A},
++{0x4058, 0x82},
++{0x4059, 0x81},
++{0x405A, 0x81},
++{0x405B, 0x81},
++{0x405C, 0x85},
++{0x405D, 0x86},
++{0x405E, 0x85},
++{0x405F, 0x85},
++{0x4060, 0x90},
++{0x4061, 0x90},
++{0x4062, 0x8F},
++{0x4063, 0x8F},
++{0x4064, 0x9D},
++{0x4065, 0x9B},
++{0x4066, 0x9B},
++{0x4067, 0x9A},
++{0x4068, 0xAF},
++{0x4069, 0xAA},
++{0x406A, 0xAC},
++{0x406B, 0xAA},
++{0x406C, 0xC2},
++{0x406D, 0xB7},
++{0x406E, 0xB8},
++{0x406F, 0xB5},
++{0x4070, 0xAB},
++{0x4071, 0xA4},
++{0x4072, 0xA4},
++{0x4073, 0xA3},
++{0x4074, 0x99},
++{0x4075, 0x96},
++{0x4076, 0x96},
++{0x4077, 0x96},
++{0x4078, 0x8B},
++{0x4079, 0x8A},
++{0x407A, 0x8A},
++{0x407B, 0x8A},
++{0x407C, 0x82},
++{0x407D, 0x82},
++{0x407E, 0x82},
++{0x407F, 0x82},
++{0x4080, 0x85},
++{0x4081, 0x86},
++{0x4082, 0x86},
++{0x4083, 0x86},
++{0x4084, 0x90},
++{0x4085, 0x90},
++{0x4086, 0x8F},
++{0x4087, 0x8F},
++{0x4088, 0x9D},
++{0x4089, 0x9B},
++{0x408A, 0x9B},
++{0x408B, 0x99},
++{0x408C, 0xAE},
++{0x408D, 0xAA},
++{0x408E, 0xAA},
++{0x408F, 0xA7},
++{0x4090, 0xC7},
++{0x4091, 0xBA},
++{0x4092, 0xBC},
++{0x4093, 0xB9},
++{0x4094, 0xB1},
++{0x4095, 0xA8},
++{0x4096, 0xA8},
++{0x4097, 0xA7},
++{0x4098, 0x9F},
++{0x4099, 0x9B},
++{0x409A, 0x9B},
++{0x409B, 0x9B},
++{0x409C, 0x93},
++{0x409D, 0x91},
++{0x409E, 0x91},
++{0x409F, 0x91},
++{0x40A0, 0x8D},
++{0x40A1, 0x8C},
++{0x40A2, 0x8C},
++{0x40A3, 0x8C},
++{0x40A4, 0x8E},
++{0x40A5, 0x8E},
++{0x40A6, 0x8D},
++{0x40A7, 0x8D},
++{0x40A8, 0x96},
++{0x40A9, 0x95},
++{0x40AA, 0x95},
++{0x40AB, 0x94},
++{0x40AC, 0xA2},
++{0x40AD, 0x9F},
++{0x40AE, 0x9F},
++{0x40AF, 0x9D},
++{0x40B0, 0xB1},
++{0x40B1, 0xAC},
++{0x40B2, 0xAB},
++{0x40B3, 0xAA},
++{0x40B4, 0xD3},
++{0x40B5, 0xBC},
++{0x40B6, 0xBD},
++{0x40B7, 0xBC},
++{0x40B8, 0xC1},
++{0x40B9, 0xB7},
++{0x40BA, 0xB7},
++{0x40BB, 0xB5},
++{0x40BC, 0xB0},
++{0x40BD, 0xAA},
++{0x40BE, 0xAA},
++{0x40BF, 0xAA},
++{0x40C0, 0xA8},
++{0x40C1, 0xA4},
++{0x40C2, 0xA4},
++{0x40C3, 0xA4},
++{0x40C4, 0xA2},
++{0x40C5, 0x9F},
++{0x40C6, 0x9F},
++{0x40C7, 0x9F},
++{0x40C8, 0xA3},
++{0x40C9, 0xA0},
++{0x40CA, 0xA0},
++{0x40CB, 0xA0},
++{0x40CC, 0xA6},
++{0x40CD, 0xA3},
++{0x40CE, 0xA3},
++{0x40CF, 0xA2},
++{0x40D0, 0xAF},
++{0x40D1, 0xAB},
++{0x40D2, 0xAA},
++{0x40D3, 0xA8},
++{0x40D4, 0xBA},
++{0x40D5, 0xAE},
++{0x40D6, 0xAE},
++{0x40D7, 0xAB},
++{0x4100, 0xBD},
++{0x4101, 0xBA},
++{0x4102, 0xBD},
++{0x4103, 0xB7},
++{0x4104, 0xB7},
++{0x4105, 0xB7},
++{0x4106, 0xB8},
++{0x4107, 0xB5},
++{0x4108, 0xAB},
++{0x4109, 0xAA},
++{0x410A, 0xAC},
++{0x410B, 0xAB},
++{0x410C, 0xA4},
++{0x410D, 0xA5},
++{0x410E, 0xA5},
++{0x410F, 0xA4},
++{0x4110, 0x9F},
++{0x4111, 0xA0},
++{0x4112, 0xA0},
++{0x4113, 0x9F},
++{0x4114, 0xA0},
++{0x4115, 0xA0},
++{0x4116, 0xA0},
++{0x4117, 0x9F},
++{0x4118, 0xA1},
++{0x4119, 0xA1},
++{0x411A, 0xA1},
++{0x411B, 0xA0},
++{0x411C, 0xA7},
++{0x411D, 0xA6},
++{0x411E, 0xA6},
++{0x411F, 0xA6},
++{0x4120, 0xA7},
++{0x4121, 0xA6},
++{0x4122, 0xA6},
++{0x4123, 0xA3},
++{0x4124, 0xB9},
++{0x4125, 0xB9},
++{0x4126, 0xBA},
++{0x4127, 0xB8},
++{0x4128, 0xA6},
++{0x4129, 0xA7},
++{0x412A, 0xA7},
++{0x412B, 0xA6},
++{0x412C, 0x9B},
++{0x412D, 0x9B},
++{0x412E, 0x9B},
++{0x412F, 0x9B},
++{0x4130, 0x91},
++{0x4131, 0x92},
++{0x4132, 0x92},
++{0x4133, 0x91},
++{0x4134, 0x8C},
++{0x4135, 0x8C},
++{0x4136, 0x8C},
++{0x4137, 0x8C},
++{0x4138, 0x8D},
++{0x4139, 0x8D},
++{0x413A, 0x8D},
++{0x413B, 0x8D},
++{0x413C, 0x93},
++{0x413D, 0x93},
++{0x413E, 0x93},
++{0x413F, 0x92},
++{0x4140, 0x9A},
++{0x4141, 0x9A},
++{0x4142, 0x9A},
++{0x4143, 0x99},
++{0x4144, 0xA7},
++{0x4145, 0xA5},
++{0x4146, 0xA6},
++{0x4147, 0xA6},
++{0x4148, 0xB8},
++{0x4149, 0xB4},
++{0x414A, 0xB4},
++{0x414B, 0xB3},
++{0x414C, 0xA3},
++{0x414D, 0xA2},
++{0x414E, 0xA3},
++{0x414F, 0xA2},
++{0x4150, 0x96},
++{0x4151, 0x96},
++{0x4152, 0x96},
++{0x4153, 0x96},
++{0x4154, 0x8A},
++{0x4155, 0x8A},
++{0x4156, 0x8A},
++{0x4157, 0x8A},
++{0x4158, 0x82},
++{0x4159, 0x82},
++{0x415A, 0x82},
++{0x415B, 0x82},
++{0x415C, 0x84},
++{0x415D, 0x85},
++{0x415E, 0x84},
++{0x415F, 0x84},
++{0x4160, 0x8D},
++{0x4161, 0x8D},
++{0x4162, 0x8D},
++{0x4163, 0x8D},
++{0x4164, 0x96},
++{0x4165, 0x96},
++{0x4166, 0x96},
++{0x4167, 0x95},
++{0x4168, 0xA5},
++{0x4169, 0xA2},
++{0x416A, 0xA3},
++{0x416B, 0xA2},
++{0x416C, 0xB7},
++{0x416D, 0xB3},
++{0x416E, 0xB5},
++{0x416F, 0xB4},
++{0x4170, 0xA4},
++{0x4171, 0xA2},
++{0x4172, 0xA3},
++{0x4173, 0xA2},
++{0x4174, 0x97},
++{0x4175, 0x96},
++{0x4176, 0x96},
++{0x4177, 0x96},
++{0x4178, 0x8B},
++{0x4179, 0x8A},
++{0x417A, 0x8A},
++{0x417B, 0x8A},
++{0x417C, 0x81},
++{0x417D, 0x81},
++{0x417E, 0x81},
++{0x417F, 0x81},
++{0x4180, 0x84},
++{0x4181, 0x84},
++{0x4182, 0x84},
++{0x4183, 0x84},
++{0x4184, 0x8C},
++{0x4185, 0x8D},
++{0x4186, 0x8D},
++{0x4187, 0x8D},
++{0x4188, 0x95},
++{0x4189, 0x96},
++{0x418A, 0x96},
++{0x418B, 0x95},
++{0x418C, 0xA1},
++{0x418D, 0xA1},
++{0x418E, 0xA1},
++{0x418F, 0xA0},
++{0x4190, 0xBC},
++{0x4191, 0xB8},
++{0x4192, 0xB8},
++{0x4193, 0xB9},
++{0x4194, 0xA8},
++{0x4195, 0xA5},
++{0x4196, 0xA6},
++{0x4197, 0xA5},
++{0x4198, 0x9C},
++{0x4199, 0x9A},
++{0x419A, 0x9A},
++{0x419B, 0x9A},
++{0x419C, 0x91},
++{0x419D, 0x91},
++{0x419E, 0x91},
++{0x419F, 0x91},
++{0x41A0, 0x8B},
++{0x41A1, 0x8B},
++{0x41A2, 0x8B},
++{0x41A3, 0x8B},
++{0x41A4, 0x8C},
++{0x41A5, 0x8C},
++{0x41A6, 0x8C},
++{0x41A7, 0x8C},
++{0x41A8, 0x91},
++{0x41A9, 0x92},
++{0x41AA, 0x91},
++{0x41AB, 0x91},
++{0x41AC, 0x98},
++{0x41AD, 0x99},
++{0x41AE, 0x99},
++{0x41AF, 0x98},
++{0x41B0, 0xA3},
++{0x41B1, 0xA3},
++{0x41B2, 0xA3},
++{0x41B3, 0xA2},
++{0x41B4, 0xC1},
++{0x41B5, 0xB8},
++{0x41B6, 0xB9},
++{0x41B7, 0xBA},
++{0x41B8, 0xB8},
++{0x41B9, 0xB4},
++{0x41BA, 0xB4},
++{0x41BB, 0xB4},
++{0x41BC, 0xAA},
++{0x41BD, 0xA7},
++{0x41BE, 0xA7},
++{0x41BF, 0xA8},
++{0x41C0, 0xA4},
++{0x41C1, 0xA2},
++{0x41C2, 0xA2},
++{0x41C3, 0xA3},
++{0x41C4, 0x9E},
++{0x41C5, 0x9D},
++{0x41C6, 0x9D},
++{0x41C7, 0x9D},
++{0x41C8, 0x9E},
++{0x41C9, 0x9D},
++{0x41CA, 0x9D},
++{0x41CB, 0x9D},
++{0x41CC, 0x9E},
++{0x41CD, 0x9E},
++{0x41CE, 0x9E},
++{0x41CF, 0x9E},
++{0x41D0, 0xA3},
++{0x41D1, 0xA3},
++{0x41D2, 0xA2},
++{0x41D3, 0xA1},
++{0x41D4, 0xA7},
++{0x41D5, 0xA7},
++{0x41D6, 0xA7},
++{0x41D7, 0xA3},
++{0x4200, 0xCE},
++{0x4201, 0xC0},
++{0x4202, 0xC1},
++{0x4203, 0xB9},
++{0x4204, 0xC3},
++{0x4205, 0xB9},
++{0x4206, 0xBC},
++{0x4207, 0xBD},
++{0x4208, 0xB3},
++{0x4209, 0xAE},
++{0x420A, 0xAF},
++{0x420B, 0xAE},
++{0x420C, 0xAA},
++{0x420D, 0xA8},
++{0x420E, 0xA8},
++{0x420F, 0xA6},
++{0x4210, 0xA4},
++{0x4211, 0xA2},
++{0x4212, 0xA2},
++{0x4213, 0xA0},
++{0x4214, 0xA4},
++{0x4215, 0xA3},
++{0x4216, 0xA2},
++{0x4217, 0xA0},
++{0x4218, 0xA7},
++{0x4219, 0xA5},
++{0x421A, 0xA3},
++{0x421B, 0xA1},
++{0x421C, 0xB0},
++{0x421D, 0xA8},
++{0x421E, 0xA8},
++{0x421F, 0xA6},
++{0x4220, 0xB4},
++{0x4221, 0xAA},
++{0x4222, 0xA5},
++{0x4223, 0xA3},
++{0x4224, 0xC7},
++{0x4225, 0xBC},
++{0x4226, 0xBE},
++{0x4227, 0xBC},
++{0x4228, 0xB0},
++{0x4229, 0xA9},
++{0x422A, 0xA9},
++{0x422B, 0xA8},
++{0x422C, 0xA0},
++{0x422D, 0x9D},
++{0x422E, 0x9D},
++{0x422F, 0x9C},
++{0x4230, 0x94},
++{0x4231, 0x93},
++{0x4232, 0x93},
++{0x4233, 0x92},
++{0x4234, 0x8E},
++{0x4235, 0x8D},
++{0x4236, 0x8D},
++{0x4237, 0x8C},
++{0x4238, 0x8F},
++{0x4239, 0x8E},
++{0x423A, 0x8E},
++{0x423B, 0x8D},
++{0x423C, 0x96},
++{0x423D, 0x94},
++{0x423E, 0x94},
++{0x423F, 0x92},
++{0x4240, 0xA1},
++{0x4241, 0x9C},
++{0x4242, 0x9C},
++{0x4243, 0x99},
++{0x4244, 0xB0},
++{0x4245, 0xA8},
++{0x4246, 0xAB},
++{0x4247, 0xA7},
++{0x4248, 0xC3},
++{0x4249, 0xB7},
++{0x424A, 0xB7},
++{0x424B, 0xBC},
++{0x424C, 0xAB},
++{0x424D, 0xA4},
++{0x424E, 0xA5},
++{0x424F, 0xA5},
++{0x4250, 0x9A},
++{0x4251, 0x97},
++{0x4252, 0x97},
++{0x4253, 0x98},
++{0x4254, 0x8C},
++{0x4255, 0x8B},
++{0x4256, 0x8B},
++{0x4257, 0x8B},
++{0x4258, 0x82},
++{0x4259, 0x82},
++{0x425A, 0x82},
++{0x425B, 0x82},
++{0x425C, 0x85},
++{0x425D, 0x85},
++{0x425E, 0x85},
++{0x425F, 0x84},
++{0x4260, 0x8F},
++{0x4261, 0x8E},
++{0x4262, 0x8E},
++{0x4263, 0x8D},
++{0x4264, 0x9B},
++{0x4265, 0x98},
++{0x4266, 0x98},
++{0x4267, 0x95},
++{0x4268, 0xAE},
++{0x4269, 0xA5},
++{0x426A, 0xA7},
++{0x426B, 0xA2},
++{0x426C, 0xC2},
++{0x426D, 0xB7},
++{0x426E, 0xB8},
++{0x426F, 0xB9},
++{0x4270, 0xAA},
++{0x4271, 0xA4},
++{0x4272, 0xA4},
++{0x4273, 0xA5},
++{0x4274, 0x99},
++{0x4275, 0x96},
++{0x4276, 0x97},
++{0x4277, 0x98},
++{0x4278, 0x8B},
++{0x4279, 0x8A},
++{0x427A, 0x8A},
++{0x427B, 0x8B},
++{0x427C, 0x81},
++{0x427D, 0x81},
++{0x427E, 0x81},
++{0x427F, 0x82},
++{0x4280, 0x84},
++{0x4281, 0x84},
++{0x4282, 0x84},
++{0x4283, 0x84},
++{0x4284, 0x8E},
++{0x4285, 0x8E},
++{0x4286, 0x8D},
++{0x4287, 0x8C},
++{0x4288, 0x9A},
++{0x4289, 0x97},
++{0x428A, 0x97},
++{0x428B, 0x95},
++{0x428C, 0xAA},
++{0x428D, 0xA3},
++{0x428E, 0xA3},
++{0x428F, 0xA2},
++{0x4290, 0xC7},
++{0x4291, 0xBA},
++{0x4292, 0xC0},
++{0x4293, 0xC3},
++{0x4294, 0xB0},
++{0x4295, 0xA7},
++{0x4296, 0xA7},
++{0x4297, 0xA9},
++{0x4298, 0x9F},
++{0x4299, 0x9B},
++{0x429A, 0x9B},
++{0x429B, 0x9D},
++{0x429C, 0x93},
++{0x429D, 0x91},
++{0x429E, 0x91},
++{0x429F, 0x92},
++{0x42A0, 0x8C},
++{0x42A1, 0x8B},
++{0x42A2, 0x8B},
++{0x42A3, 0x8C},
++{0x42A4, 0x8D},
++{0x42A5, 0x8C},
++{0x42A6, 0x8C},
++{0x42A7, 0x8C},
++{0x42A8, 0x94},
++{0x42A9, 0x93},
++{0x42AA, 0x92},
++{0x42AB, 0x91},
++{0x42AC, 0x9E},
++{0x42AD, 0x9B},
++{0x42AE, 0x9B},
++{0x42AF, 0x98},
++{0x42B0, 0xAC},
++{0x42B1, 0xA6},
++{0x42B2, 0xA6},
++{0x42B3, 0xA2},
++{0x42B4, 0xCE},
++{0x42B5, 0xBA},
++{0x42B6, 0xBC},
++{0x42B7, 0xB7},
++{0x42B8, 0xC5},
++{0x42B9, 0xB5},
++{0x42BA, 0xBA},
++{0x42BB, 0xC0},
++{0x42BC, 0xB1},
++{0x42BD, 0xA8},
++{0x42BE, 0xAE},
++{0x42BF, 0xAF},
++{0x42C0, 0xA7},
++{0x42C1, 0xA3},
++{0x42C2, 0xA3},
++{0x42C3, 0xA5},
++{0x42C4, 0xA0},
++{0x42C5, 0x9D},
++{0x42C6, 0x9D},
++{0x42C7, 0x9F},
++{0x42C8, 0xA0},
++{0x42C9, 0x9E},
++{0x42CA, 0x9E},
++{0x42CB, 0x9F},
++{0x42CC, 0xA2},
++{0x42CD, 0xA0},
++{0x42CE, 0xA0},
++{0x42CF, 0xA0},
++{0x42D0, 0xA8},
++{0x42D1, 0xA5},
++{0x42D2, 0xA5},
++{0x42D3, 0xA2},
++{0x42D4, 0xB3},
++{0x42D5, 0xAA},
++{0x42D6, 0xAB},
++{0x42D7, 0xA3},
++{0x42D8, 0x00},
++{0x42D9, 0x00},
++{0x4300, 0xA2},
++{0x4301, 0xAE},
++{0x4302, 0xAD},
++{0x4303, 0xB5},
++{0x4304, 0x95},
++{0x4305, 0x9A},
++{0x4306, 0x98},
++{0x4307, 0x9B},
++{0x4308, 0x8D},
++{0x4309, 0x90},
++{0x430A, 0x8F},
++{0x430B, 0x91},
++{0x430C, 0x86},
++{0x430D, 0x88},
++{0x430E, 0x87},
++{0x430F, 0x89},
++{0x4310, 0x86},
++{0x4311, 0x87},
++{0x4312, 0x86},
++{0x4313, 0x88},
++{0x4314, 0x89},
++{0x4315, 0x88},
++{0x4316, 0x88},
++{0x4317, 0x8E},
++{0x4318, 0x90},
++{0x4319, 0x8F},
++{0x431A, 0x8C},
++{0x431B, 0x8C},
++{0x431C, 0x9C},
++{0x431D, 0x99},
++{0x431E, 0x98},
++{0x431F, 0x99},
++{0x4320, 0xAB},
++{0x4321, 0xB0},
++{0x4322, 0xAD},
++{0x4323, 0xAF},
++{0x4324, 0x9B},
++{0x4325, 0x9F},
++{0x4326, 0x9E},
++{0x4327, 0xA1},
++{0x4328, 0x8E},
++{0x4329, 0x91},
++{0x432A, 0x90},
++{0x432B, 0x93},
++{0x432C, 0x86},
++{0x432D, 0x88},
++{0x432E, 0x87},
++{0x432F, 0x89},
++{0x4330, 0x82},
++{0x4331, 0x84},
++{0x4332, 0x83},
++{0x4333, 0x84},
++{0x4334, 0x82},
++{0x4335, 0x82},
++{0x4336, 0x82},
++{0x4337, 0x83},
++{0x4338, 0x85},
++{0x4339, 0x84},
++{0x433A, 0x84},
++{0x433B, 0x85},
++{0x433C, 0x8A},
++{0x433D, 0x89},
++{0x433E, 0x88},
++{0x433F, 0x89},
++{0x4340, 0x93},
++{0x4341, 0x91},
++{0x4342, 0x91},
++{0x4343, 0x93},
++{0x4344, 0xA0},
++{0x4345, 0x9E},
++{0x4346, 0x9D},
++{0x4347, 0xA1},
++{0x4348, 0x95},
++{0x4349, 0x9B},
++{0x434A, 0x9A},
++{0x434B, 0x9C},
++{0x434C, 0x8A},
++{0x434D, 0x8D},
++{0x434E, 0x8C},
++{0x434F, 0x8D},
++{0x4350, 0x83},
++{0x4351, 0x85},
++{0x4352, 0x84},
++{0x4353, 0x85},
++{0x4354, 0x80},
++{0x4355, 0x81},
++{0x4356, 0x81},
++{0x4357, 0x81},
++{0x4358, 0x80},
++{0x4359, 0x80},
++{0x435A, 0x80},
++{0x435B, 0x80},
++{0x435C, 0x82},
++{0x435D, 0x81},
++{0x435E, 0x81},
++{0x435F, 0x81},
++{0x4360, 0x85},
++{0x4361, 0x84},
++{0x4362, 0x84},
++{0x4363, 0x85},
++{0x4364, 0x8D},
++{0x4365, 0x8B},
++{0x4366, 0x8B},
++{0x4367, 0x8D},
++{0x4368, 0x98},
++{0x4369, 0x98},
++{0x436A, 0x95},
++{0x436B, 0x98},
++{0x436C, 0x95},
++{0x436D, 0x9A},
++{0x436E, 0x99},
++{0x436F, 0x9A},
++{0x4370, 0x8A},
++{0x4371, 0x8D},
++{0x4372, 0x8C},
++{0x4373, 0x8C},
++{0x4374, 0x83},
++{0x4375, 0x85},
++{0x4376, 0x84},
++{0x4377, 0x84},
++{0x4378, 0x80},
++{0x4379, 0x80},
++{0x437A, 0x80},
++{0x437B, 0x80},
++{0x437C, 0x7F},
++{0x437D, 0x7F},
++{0x437E, 0x7F},
++{0x437F, 0x7F},
++{0x4380, 0x81},
++{0x4381, 0x80},
++{0x4382, 0x80},
++{0x4383, 0x81},
++{0x4384, 0x84},
++{0x4385, 0x83},
++{0x4386, 0x83},
++{0x4387, 0x84},
++{0x4388, 0x8B},
++{0x4389, 0x8A},
++{0x438A, 0x8A},
++{0x438B, 0x8C},
++{0x438C, 0x97},
++{0x438D, 0x96},
++{0x438E, 0x96},
++{0x438F, 0x99},
++{0x4390, 0x99},
++{0x4391, 0x9F},
++{0x4392, 0x9E},
++{0x4393, 0x9D},
++{0x4394, 0x8D},
++{0x4395, 0x90},
++{0x4396, 0x90},
++{0x4397, 0x8F},
++{0x4398, 0x85},
++{0x4399, 0x87},
++{0x439A, 0x87},
++{0x439B, 0x86},
++{0x439C, 0x81},
++{0x439D, 0x83},
++{0x439E, 0x82},
++{0x439F, 0x82},
++{0x43A0, 0x80},
++{0x43A1, 0x81},
++{0x43A2, 0x81},
++{0x43A3, 0x81},
++{0x43A4, 0x82},
++{0x43A5, 0x82},
++{0x43A6, 0x82},
++{0x43A7, 0x82},
++{0x43A8, 0x86},
++{0x43A9, 0x85},
++{0x43AA, 0x85},
++{0x43AB, 0x87},
++{0x43AC, 0x8D},
++{0x43AD, 0x8D},
++{0x43AE, 0x8D},
++{0x43AF, 0x90},
++{0x43B0, 0x9A},
++{0x43B1, 0x9A},
++{0x43B2, 0x9B},
++{0x43B3, 0x9D},
++{0x43B4, 0xA0},
++{0x43B5, 0xAD},
++{0x43B6, 0xAC},
++{0x43B7, 0xAA},
++{0x43B8, 0x93},
++{0x43B9, 0x97},
++{0x43BA, 0x97},
++{0x43BB, 0x96},
++{0x43BC, 0x8B},
++{0x43BD, 0x8E},
++{0x43BE, 0x8E},
++{0x43BF, 0x8C},
++{0x43C0, 0x83},
++{0x43C1, 0x85},
++{0x43C2, 0x85},
++{0x43C3, 0x84},
++{0x43C4, 0x82},
++{0x43C5, 0x84},
++{0x43C6, 0x83},
++{0x43C7, 0x83},
++{0x43C8, 0x83},
++{0x43C9, 0x84},
++{0x43CA, 0x84},
++{0x43CB, 0x85},
++{0x43CC, 0x8A},
++{0x43CD, 0x8A},
++{0x43CE, 0x8A},
++{0x43CF, 0x8C},
++{0x43D0, 0x92},
++{0x43D1, 0x93},
++{0x43D2, 0x93},
++{0x43D3, 0x96},
++{0x43D4, 0x9F},
++{0x43D5, 0xA6},
++{0x43D6, 0xA5},
++{0x43D7, 0xAA},
++{0x4400, 0xA1},
++{0x4401, 0xAB},
++{0x4402, 0xA7},
++{0x4403, 0xB0},
++{0x4404, 0x91},
++{0x4405, 0x96},
++{0x4406, 0x94},
++{0x4407, 0x99},
++{0x4408, 0x8A},
++{0x4409, 0x8E},
++{0x440A, 0x8C},
++{0x440B, 0x8F},
++{0x440C, 0x85},
++{0x440D, 0x86},
++{0x440E, 0x86},
++{0x440F, 0x88},
++{0x4410, 0x85},
++{0x4411, 0x86},
++{0x4412, 0x85},
++{0x4413, 0x87},
++{0x4414, 0x88},
++{0x4415, 0x87},
++{0x4416, 0x87},
++{0x4417, 0x89},
++{0x4418, 0x91},
++{0x4419, 0x8F},
++{0x441A, 0x8F},
++{0x441B, 0x90},
++{0x441C, 0x9C},
++{0x441D, 0x9B},
++{0x441E, 0x9A},
++{0x441F, 0x9A},
++{0x4420, 0xB3},
++{0x4421, 0xB1},
++{0x4422, 0xB0},
++{0x4423, 0xB2},
++{0x4424, 0x96},
++{0x4425, 0x9C},
++{0x4426, 0x9A},
++{0x4427, 0x9E},
++{0x4428, 0x8B},
++{0x4429, 0x8F},
++{0x442A, 0x8E},
++{0x442B, 0x91},
++{0x442C, 0x84},
++{0x442D, 0x87},
++{0x442E, 0x86},
++{0x442F, 0x88},
++{0x4430, 0x82},
++{0x4431, 0x83},
++{0x4432, 0x82},
++{0x4433, 0x84},
++{0x4434, 0x82},
++{0x4435, 0x82},
++{0x4436, 0x82},
++{0x4437, 0x83},
++{0x4438, 0x84},
++{0x4439, 0x84},
++{0x443A, 0x84},
++{0x443B, 0x84},
++{0x443C, 0x8B},
++{0x443D, 0x89},
++{0x443E, 0x89},
++{0x443F, 0x89},
++{0x4440, 0x95},
++{0x4441, 0x93},
++{0x4442, 0x93},
++{0x4443, 0x93},
++{0x4444, 0xA2},
++{0x4445, 0xA2},
++{0x4446, 0xA1},
++{0x4447, 0xA0},
++{0x4448, 0x8F},
++{0x4449, 0x97},
++{0x444A, 0x97},
++{0x444B, 0x98},
++{0x444C, 0x87},
++{0x444D, 0x8B},
++{0x444E, 0x8A},
++{0x444F, 0x8B},
++{0x4450, 0x81},
++{0x4451, 0x83},
++{0x4452, 0x83},
++{0x4453, 0x84},
++{0x4454, 0x7F},
++{0x4455, 0x80},
++{0x4456, 0x80},
++{0x4457, 0x81},
++{0x4458, 0x80},
++{0x4459, 0x80},
++{0x445A, 0x80},
++{0x445B, 0x80},
++{0x445C, 0x82},
++{0x445D, 0x81},
++{0x445E, 0x81},
++{0x445F, 0x81},
++{0x4460, 0x87},
++{0x4461, 0x85},
++{0x4462, 0x85},
++{0x4463, 0x86},
++{0x4464, 0x90},
++{0x4465, 0x8E},
++{0x4466, 0x8E},
++{0x4467, 0x8E},
++{0x4468, 0x9B},
++{0x4469, 0x9C},
++{0x446A, 0x9A},
++{0x446B, 0x9A},
++{0x446C, 0x91},
++{0x446D, 0x97},
++{0x446E, 0x95},
++{0x446F, 0x95},
++{0x4470, 0x87},
++{0x4471, 0x8A},
++{0x4472, 0x8A},
++{0x4473, 0x89},
++{0x4474, 0x81},
++{0x4475, 0x83},
++{0x4476, 0x83},
++{0x4477, 0x83},
++{0x4478, 0x7F},
++{0x4479, 0x80},
++{0x447A, 0x80},
++{0x447B, 0x80},
++{0x447C, 0x80},
++{0x447D, 0x80},
++{0x447E, 0x80},
++{0x447F, 0x7F},
++{0x4480, 0x81},
++{0x4481, 0x81},
++{0x4482, 0x81},
++{0x4483, 0x81},
++{0x4484, 0x85},
++{0x4485, 0x85},
++{0x4486, 0x85},
++{0x4487, 0x85},
++{0x4488, 0x8E},
++{0x4489, 0x8D},
++{0x448A, 0x8D},
++{0x448B, 0x8E},
++{0x448C, 0x9D},
++{0x448D, 0x9C},
++{0x448E, 0x9C},
++{0x448F, 0x9C},
++{0x4490, 0x94},
++{0x4491, 0x9B},
++{0x4492, 0x9A},
++{0x4493, 0x97},
++{0x4494, 0x8A},
++{0x4495, 0x8E},
++{0x4496, 0x8E},
++{0x4497, 0x8C},
++{0x4498, 0x84},
++{0x4499, 0x86},
++{0x449A, 0x86},
++{0x449B, 0x84},
++{0x449C, 0x81},
++{0x449D, 0x83},
++{0x449E, 0x83},
++{0x449F, 0x81},
++{0x44A0, 0x81},
++{0x44A1, 0x82},
++{0x44A2, 0x82},
++{0x44A3, 0x81},
++{0x44A4, 0x83},
++{0x44A5, 0x83},
++{0x44A6, 0x83},
++{0x44A7, 0x83},
++{0x44A8, 0x88},
++{0x44A9, 0x88},
++{0x44AA, 0x88},
++{0x44AB, 0x88},
++{0x44AC, 0x91},
++{0x44AD, 0x91},
++{0x44AE, 0x91},
++{0x44AF, 0x92},
++{0x44B0, 0xA0},
++{0x44B1, 0xA0},
++{0x44B2, 0xA0},
++{0x44B3, 0xA0},
++{0x44B4, 0x9E},
++{0x44B5, 0xA9},
++{0x44B6, 0xA8},
++{0x44B7, 0xA3},
++{0x44B8, 0x90},
++{0x44B9, 0x95},
++{0x44BA, 0x95},
++{0x44BB, 0x92},
++{0x44BC, 0x8A},
++{0x44BD, 0x8E},
++{0x44BE, 0x8E},
++{0x44BF, 0x8B},
++{0x44C0, 0x84},
++{0x44C1, 0x86},
++{0x44C2, 0x86},
++{0x44C3, 0x84},
++{0x44C4, 0x84},
++{0x44C5, 0x85},
++{0x44C6, 0x85},
++{0x44C7, 0x84},
++{0x44C8, 0x86},
++{0x44C9, 0x87},
++{0x44CA, 0x87},
++{0x44CB, 0x86},
++{0x44CC, 0x8D},
++{0x44CD, 0x8E},
++{0x44CE, 0x8E},
++{0x44CF, 0x8D},
++{0x44D0, 0x98},
++{0x44D1, 0x98},
++{0x44D2, 0x99},
++{0x44D3, 0x9A},
++{0x44D4, 0xA9},
++{0x44D5, 0xAA},
++{0x44D6, 0xAA},
++{0x44D7, 0xAD},
++{0x4500, 0x9F},
++{0x4501, 0xA8},
++{0x4502, 0xA5},
++{0x4503, 0xAF},
++{0x4504, 0x8F},
++{0x4505, 0x96},
++{0x4506, 0x92},
++{0x4507, 0x94},
++{0x4508, 0x89},
++{0x4509, 0x8D},
++{0x450A, 0x8A},
++{0x450B, 0x8E},
++{0x450C, 0x84},
++{0x450D, 0x85},
++{0x450E, 0x84},
++{0x450F, 0x87},
++{0x4510, 0x84},
++{0x4511, 0x85},
++{0x4512, 0x84},
++{0x4513, 0x86},
++{0x4514, 0x87},
++{0x4515, 0x86},
++{0x4516, 0x86},
++{0x4517, 0x88},
++{0x4518, 0x8F},
++{0x4519, 0x8D},
++{0x451A, 0x8D},
++{0x451B, 0x8F},
++{0x451C, 0x9A},
++{0x451D, 0x9A},
++{0x451E, 0x98},
++{0x451F, 0x9A},
++{0x4520, 0xAF},
++{0x4521, 0xAF},
++{0x4522, 0xB2},
++{0x4523, 0xB1},
++{0x4524, 0x95},
++{0x4525, 0x9B},
++{0x4526, 0x97},
++{0x4527, 0x9C},
++{0x4528, 0x8A},
++{0x4529, 0x8E},
++{0x452A, 0x8D},
++{0x452B, 0x90},
++{0x452C, 0x84},
++{0x452D, 0x86},
++{0x452E, 0x85},
++{0x452F, 0x87},
++{0x4530, 0x81},
++{0x4531, 0x82},
++{0x4532, 0x82},
++{0x4533, 0x83},
++{0x4534, 0x81},
++{0x4535, 0x81},
++{0x4536, 0x81},
++{0x4537, 0x82},
++{0x4538, 0x84},
++{0x4539, 0x83},
++{0x453A, 0x83},
++{0x453B, 0x84},
++{0x453C, 0x8A},
++{0x453D, 0x88},
++{0x453E, 0x88},
++{0x453F, 0x89},
++{0x4540, 0x94},
++{0x4541, 0x92},
++{0x4542, 0x91},
++{0x4543, 0x92},
++{0x4544, 0xA1},
++{0x4545, 0xA0},
++{0x4546, 0x9C},
++{0x4547, 0x9D},
++{0x4548, 0x8F},
++{0x4549, 0x96},
++{0x454A, 0x95},
++{0x454B, 0x92},
++{0x454C, 0x87},
++{0x454D, 0x8A},
++{0x454E, 0x89},
++{0x454F, 0x8A},
++{0x4550, 0x81},
++{0x4551, 0x83},
++{0x4552, 0x82},
++{0x4553, 0x83},
++{0x4554, 0x7F},
++{0x4555, 0x80},
++{0x4556, 0x80},
++{0x4557, 0x81},
++{0x4558, 0x7F},
++{0x4559, 0x80},
++{0x455A, 0x7F},
++{0x455B, 0x80},
++{0x455C, 0x81},
++{0x455D, 0x81},
++{0x455E, 0x81},
++{0x455F, 0x81},
++{0x4560, 0x86},
++{0x4561, 0x85},
++{0x4562, 0x85},
++{0x4563, 0x85},
++{0x4564, 0x8F},
++{0x4565, 0x8D},
++{0x4566, 0x8D},
++{0x4567, 0x8D},
++{0x4568, 0x99},
++{0x4569, 0x9A},
++{0x456A, 0x97},
++{0x456B, 0x99},
++{0x456C, 0x90},
++{0x456D, 0x95},
++{0x456E, 0x93},
++{0x456F, 0x92},
++{0x4570, 0x87},
++{0x4571, 0x8A},
++{0x4572, 0x88},
++{0x4573, 0x87},
++{0x4574, 0x81},
++{0x4575, 0x83},
++{0x4576, 0x82},
++{0x4577, 0x82},
++{0x4578, 0x7F},
++{0x4579, 0x80},
++{0x457A, 0x80},
++{0x457B, 0x80},
++{0x457C, 0x80},
++{0x457D, 0x80},
++{0x457E, 0x80},
++{0x457F, 0x80},
++{0x4580, 0x81},
++{0x4581, 0x81},
++{0x4582, 0x81},
++{0x4583, 0x81},
++{0x4584, 0x85},
++{0x4585, 0x85},
++{0x4586, 0x84},
++{0x4587, 0x85},
++{0x4588, 0x8E},
++{0x4589, 0x8D},
++{0x458A, 0x8C},
++{0x458B, 0x8D},
++{0x458C, 0x9B},
++{0x458D, 0x9B},
++{0x458E, 0x9A},
++{0x458F, 0x98},
++{0x4590, 0x94},
++{0x4591, 0x9A},
++{0x4592, 0x94},
++{0x4593, 0x90},
++{0x4594, 0x8A},
++{0x4595, 0x8D},
++{0x4596, 0x8C},
++{0x4597, 0x89},
++{0x4598, 0x84},
++{0x4599, 0x86},
++{0x459A, 0x85},
++{0x459B, 0x83},
++{0x459C, 0x82},
++{0x459D, 0x83},
++{0x459E, 0x82},
++{0x459F, 0x80},
++{0x45A0, 0x81},
++{0x45A1, 0x82},
++{0x45A2, 0x81},
++{0x45A3, 0x80},
++{0x45A4, 0x83},
++{0x45A5, 0x83},
++{0x45A6, 0x83},
++{0x45A7, 0x83},
++{0x45A8, 0x88},
++{0x45A9, 0x87},
++{0x45AA, 0x87},
++{0x45AB, 0x88},
++{0x45AC, 0x91},
++{0x45AD, 0x90},
++{0x45AE, 0x90},
++{0x45AF, 0x91},
++{0x45B0, 0x9F},
++{0x45B1, 0x9F},
++{0x45B2, 0x9E},
++{0x45B3, 0x9F},
++{0x45B4, 0x9F},
++{0x45B5, 0xA8},
++{0x45B6, 0xA6},
++{0x45B7, 0xA7},
++{0x45B8, 0x8D},
++{0x45B9, 0x95},
++{0x45BA, 0x90},
++{0x45BB, 0x8A},
++{0x45BC, 0x89},
++{0x45BD, 0x8D},
++{0x45BE, 0x88},
++{0x45BF, 0x86},
++{0x45C0, 0x84},
++{0x45C1, 0x86},
++{0x45C2, 0x85},
++{0x45C3, 0x82},
++{0x45C4, 0x84},
++{0x45C5, 0x85},
++{0x45C6, 0x85},
++{0x45C7, 0x83},
++{0x45C8, 0x86},
++{0x45C9, 0x86},
++{0x45CA, 0x86},
++{0x45CB, 0x85},
++{0x45CC, 0x8E},
++{0x45CD, 0x8D},
++{0x45CE, 0x8D},
++{0x45CF, 0x8C},
++{0x45D0, 0x99},
++{0x45D1, 0x98},
++{0x45D2, 0x98},
++{0x45D3, 0x98},
++{0x45D4, 0xA6},
++{0x45D5, 0xA9},
++{0x45D6, 0xA7},
++{0x45D7, 0xAC},
++{0x7000, 0xAB},
++{0x7001, 0xBA},
++{0x7002, 0x40},
++{0x7003, 0x02},
++{0x7004, 0x00},
++{0x7005, 0x00},
++{0x7006, 0x00},
++{0x7007, 0x00},
++{0x7008, 0x00},
++{0x7009, 0x00},
++{0x700A, 0x00},
++{0x700B, 0x00},
++{0x700C, 0x00},
++{0x700D, 0x00},
++{0x700E, 0x00},
++{0x700F, 0x00},
++{0x7010, 0x55},
++{0x7011, 0x88},
++{0x7012, 0x40},
++{0x7013, 0x01},
++{0x7014, 0x72},
++{0x7015, 0xF1},
++{0x7016, 0x02},
++{0x7017, 0xF8},
++{0x7018, 0x00},
++{0x7019, 0x00},
++{0x701A, 0x00},
++{0x701B, 0x00},
++{0x701C, 0x00},
++{0x701D, 0x00},
++{0x701E, 0x00},
++{0x701F, 0x00},
++{0x7020, 0x00},
++{0x7021, 0x00},
++{0x7022, 0x00},
++{0x7023, 0x00},
++{0x7024, 0x00},
++{0x7025, 0x00},
++{0x7026, 0x00},
++{0x7027, 0x00},
++{0x7028, 0x00},
++{0x7029, 0x00},
++{0x702A, 0x00},
++{0x702B, 0x00},
++{0x702C, 0x00},
++{0x702D, 0x00},
++{0x702E, 0x00},
++{0x702F, 0x00},
++{0x7030, 0x00},
++{0x7031, 0x00},
++{0x7032, 0x00},
++{0x7033, 0x00},
++{0x7034, 0x00},
++{0x7035, 0x00},
++{0x7036, 0x00},
++{0x7037, 0x00},
++{0x7038, 0x00},
++{0x7039, 0x00},
++{0x703A, 0x00},
++{0x703B, 0x00},
++{0x703C, 0x00},
++{0x703D, 0x00},
++{0x703E, 0x00},
++{0x703F, 0x00},
++{0x7040, 0x00},
++{0x7041, 0x00},
++{0x7042, 0x00},
++{0x7043, 0x00},
++{0x7044, 0x00},
++{0x7045, 0x00},
++{0x7046, 0x00},
++{0x7047, 0x00},
++{0x7048, 0x00},
++{0x7049, 0x00},
++{0x704A, 0x00},
++{0x704B, 0x00},
++{0x704C, 0x00},
++{0x704D, 0x00},
++{0x704E, 0x00},
++{0x704F, 0x00},
++{0x7050, 0x00},
++{0x7051, 0x00},
++{0x7052, 0x00},
++{0x7053, 0x00},
++{0x7054, 0x00},
++{0x7055, 0x00},
++{0x7056, 0x00},
++{0x7057, 0x00},
++{0x7058, 0x00},
++{0x7059, 0x00},
++{0x705A, 0x00},
++{0x705B, 0x00},
++{0x705C, 0x00},
++{0x705D, 0x00},
++{0x705E, 0x00},
++{0x705F, 0x00},
++{0x7060, 0x00},
++{0x7061, 0x00},
++{0x7062, 0x00},
++{0x7063, 0x00},
++{0x7064, 0x00},
++{0x7065, 0x00},
++{0x7066, 0x00},
++{0x7067, 0x00},
++{0x7068, 0x00},
++{0x7069, 0x00},
++{0x706A, 0x00},
++{0x706B, 0x00},
++{0x706C, 0x00},
++{0x706D, 0x00},
++{0x706E, 0x00},
++{0x706F, 0x00},
++{0x7070, 0x00},
++{0x7071, 0x00},
++{0x7072, 0x00},
++{0x7073, 0x00},
++{0x7074, 0x00},
++{0x7075, 0x00},
++{0x7076, 0x00},
++{0x7077, 0x00},
++{0x7078, 0x00},
++{0x7079, 0x00},
++{0x707A, 0x00},
++{0x707B, 0x00},
++{0x707C, 0x00},
++{0x707D, 0x00},
++{0x707E, 0x00},
++{0x707F, 0x00},
++{0x7080, 0x00},
++{0x7081, 0x00},
++{0x7082, 0x00},
++{0x7083, 0x00},
++{0x7084, 0x00},
++{0x7085, 0x00},
++{0x7086, 0x00},
++{0x7087, 0x00},
++{0x7088, 0x00},
++{0x7089, 0x00},
++{0x708A, 0x00},
++{0x708B, 0x00},
++{0x708C, 0x00},
++{0x708D, 0x00},
++{0x708E, 0x00},
++{0x708F, 0x00},
++{0x7090, 0x00},
++{0x7091, 0xF0},
++{0x7092, 0x02},
++{0x7093, 0xF8},
++{0x7094, 0x8D},
++{0x7095, 0xF6},
++{0x7096, 0xFA},
++{0x7097, 0xFF},
++{0x7098, 0xF0},
++{0x7099, 0xB5},
++{0x709A, 0x04},
++{0x709B, 0x46},
++{0x709C, 0x8F},
++{0x709D, 0xB0},
++{0x709E, 0x5F},
++{0x709F, 0x48},
++{0x70A0, 0x0C},
++{0x70A1, 0x90},
++{0x70A2, 0x5F},
++{0x70A3, 0x48},
++{0x70A4, 0x06},
++{0x70A5, 0x90},
++{0x70A6, 0x20},
++{0x70A7, 0x46},
++{0x70A8, 0x34},
++{0x70A9, 0x30},
++{0x70AA, 0x0B},
++{0x70AB, 0x90},
++{0x70AC, 0x5B},
++{0x70AD, 0x48},
++{0x70AE, 0x5A},
++{0x70AF, 0x49},
++{0x70B0, 0x26},
++{0x70B1, 0x46},
++{0x70B2, 0x66},
++{0x70B3, 0x30},
++{0x70B4, 0x3A},
++{0x70B5, 0x31},
++{0x70B6, 0x3C},
++{0x70B7, 0x36},
++{0x70B8, 0x05},
++{0x70B9, 0x90},
++{0x70BA, 0x0A},
++{0x70BB, 0x30},
++{0x70BC, 0x04},
++{0x70BD, 0x90},
++{0x70BE, 0x59},
++{0x70BF, 0x48},
++{0x70C0, 0x55},
++{0x70C1, 0x4A},
++{0x70C2, 0x40},
++{0x70C3, 0x6E},
++{0x70C4, 0xC0},
++{0x70C5, 0x07},
++{0x70C6, 0x7D},
++{0x70C7, 0xD1},
++{0x70C8, 0x17},
++{0x70C9, 0x88},
++{0x70CA, 0x0A},
++{0x70CB, 0x5E},
++{0x70CC, 0x0D},
++{0x70CD, 0x92},
++{0x70CE, 0x53},
++{0x70CF, 0x49},
++{0x70D0, 0x55},
++{0x70D1, 0x48},
++{0x70D2, 0x94},
++{0x70D3, 0x31},
++{0x70D4, 0x89},
++{0x70D5, 0x6B},
++{0x70D6, 0x80},
++{0x70D7, 0x68},
++{0x70D8, 0x09},
++{0x70D9, 0x02},
++{0x70DA, 0x00},
++{0x70DB, 0x03},
++{0x70DC, 0x09},
++{0x70DD, 0x0E},
++{0x70DE, 0x00},
++{0x70DF, 0x0B},
++{0x70E0, 0x49},
++{0x70E1, 0x1C},
++{0x70E2, 0x48},
++{0x70E3, 0x43},
++{0x70E4, 0x4D},
++{0x70E5, 0x49},
++{0x70E6, 0x6C},
++{0x70E7, 0x39},
++{0x70E8, 0x8A},
++{0x70E9, 0x6A},
++{0x70EA, 0x07},
++{0x70EB, 0x92},
++{0x70EC, 0xCA},
++{0x70ED, 0x6A},
++{0x70EE, 0x00},
++{0x70EF, 0x21},
++{0x70F0, 0xC9},
++{0x70F1, 0x43},
++{0x70F2, 0x03},
++{0x70F3, 0x92},
++{0x70F4, 0x00},
++{0x70F5, 0x22},
++{0x70F6, 0x00},
++{0x70F7, 0x91},
++{0x70F8, 0x01},
++{0x70F9, 0x92},
++{0x70FA, 0x39},
++{0x70FB, 0x46},
++{0x70FC, 0x8F},
++{0x70FD, 0xF6},
++{0x70FE, 0xCE},
++{0x70FF, 0xFB},
++{0x7100, 0x01},
++{0x7101, 0x22},
++{0x7102, 0x00},
++{0x7103, 0x23},
++{0x7104, 0x8C},
++{0x7105, 0xF6},
++{0x7106, 0x02},
++{0x7107, 0xFA},
++{0x7108, 0x00},
++{0x7109, 0x21},
++{0x710A, 0x05},
++{0x710B, 0x46},
++{0x710C, 0x01},
++{0x710D, 0x91},
++{0x710E, 0x00},
++{0x710F, 0x90},
++{0x7110, 0x39},
++{0x7111, 0x46},
++{0x7112, 0x07},
++{0x7113, 0x98},
++{0x7114, 0x8F},
++{0x7115, 0xF6},
++{0x7116, 0xC2},
++{0x7117, 0xFB},
++{0x7118, 0x0D},
++{0x7119, 0x9A},
++{0x711A, 0xD3},
++{0x711B, 0x17},
++{0x711C, 0x80},
++{0x711D, 0x18},
++{0x711E, 0x59},
++{0x711F, 0x41},
++{0x7120, 0x01},
++{0x7121, 0x22},
++{0x7122, 0x00},
++{0x7123, 0x23},
++{0x7124, 0x8C},
++{0x7125, 0xF6},
++{0x7126, 0xCD},
++{0x7127, 0xF9},
++{0x7128, 0x07},
++{0x7129, 0x90},
++{0x712A, 0x00},
++{0x712B, 0x20},
++{0x712C, 0x01},
++{0x712D, 0x90},
++{0x712E, 0x00},
++{0x712F, 0x95},
++{0x7130, 0x39},
++{0x7131, 0x46},
++{0x7132, 0x03},
++{0x7133, 0x98},
++{0x7134, 0x8F},
++{0x7135, 0xF6},
++{0x7136, 0xB2},
++{0x7137, 0xFB},
++{0x7138, 0x01},
++{0x7139, 0x22},
++{0x713A, 0x00},
++{0x713B, 0x23},
++{0x713C, 0x8C},
++{0x713D, 0xF6},
++{0x713E, 0xE6},
++{0x713F, 0xF9},
++{0x7140, 0x02},
++{0x7141, 0x46},
++{0x7142, 0x07},
++{0x7143, 0x98},
++{0x7144, 0x00},
++{0x7145, 0x23},
++{0x7146, 0x81},
++{0x7147, 0x0B},
++{0x7148, 0x80},
++{0x7149, 0x04},
++{0x714A, 0x7A},
++{0x714B, 0xF6},
++{0x714C, 0x54},
++{0x714D, 0xF8},
++{0x714E, 0x37},
++{0x714F, 0x4A},
++{0x7150, 0x00},
++{0x7151, 0x23},
++{0x7152, 0x00},
++{0x7153, 0x92},
++{0x7154, 0x01},
++{0x7155, 0x93},
++{0x7156, 0x01},
++{0x7157, 0x22},
++{0x7158, 0x8C},
++{0x7159, 0xF6},
++{0x715A, 0xD8},
++{0x715B, 0xF9},
++{0x715C, 0x05},
++{0x715D, 0x46},
++{0x715E, 0x60},
++{0x715F, 0x68},
++{0x7160, 0x00},
++{0x7161, 0x23},
++{0x7162, 0x01},
++{0x7163, 0x0C},
++{0x7164, 0x00},
++{0x7165, 0x04},
++{0x7166, 0xE2},
++{0x7167, 0x68},
++{0x7168, 0x7A},
++{0x7169, 0xF6},
++{0x716A, 0x45},
++{0x716B, 0xF8},
++{0x716C, 0x00},
++{0x716D, 0x22},
++{0x716E, 0xD2},
++{0x716F, 0x43},
++{0x7170, 0x00},
++{0x7171, 0x23},
++{0x7172, 0x00},
++{0x7173, 0x92},
++{0x7174, 0x01},
++{0x7175, 0x93},
++{0x7176, 0x1A},
++{0x7177, 0x46},
++{0x7178, 0x8C},
++{0x7179, 0xF6},
++{0x717A, 0xC8},
++{0x717B, 0xF9},
++{0x717C, 0x29},
++{0x717D, 0x46},
++{0x717E, 0x8F},
++{0x717F, 0xF6},
++{0x7180, 0x8D},
++{0x7181, 0xFB},
++{0x7182, 0x8A},
++{0x7183, 0x03},
++{0x7184, 0x80},
++{0x7185, 0x0C},
++{0x7186, 0x10},
++{0x7187, 0x43},
++{0x7188, 0x00},
++{0x7189, 0x22},
++{0x718A, 0xD2},
++{0x718B, 0x43},
++{0x718C, 0x00},
++{0x718D, 0x23},
++{0x718E, 0x00},
++{0x718F, 0x92},
++{0x7190, 0x89},
++{0x7191, 0x0C},
++{0x7192, 0x01},
++{0x7193, 0x93},
++{0x7194, 0x1A},
++{0x7195, 0x46},
++{0x7196, 0x8C},
++{0x7197, 0xF6},
++{0x7198, 0xB9},
++{0x7199, 0xF9},
++{0x719A, 0x00},
++{0x719B, 0x24},
++{0x719C, 0x03},
++{0x719D, 0x90},
++{0x719E, 0x0C},
++{0x719F, 0x98},
++{0x71A0, 0x61},
++{0x71A1, 0x00},
++{0x71A2, 0x45},
++{0x71A3, 0x5A},
++{0x71A4, 0x06},
++{0x71A5, 0x98},
++{0x71A6, 0x22},
++{0x71A7, 0x4A},
++{0x71A8, 0x40},
++{0x71A9, 0x5A},
++{0x71AA, 0x00},
++{0x71AB, 0x21},
++{0x71AC, 0x8C},
++{0x71AD, 0xF6},
++{0x71AE, 0xBE},
++{0x71AF, 0xF9},
++{0x71B0, 0x07},
++{0x71B1, 0x46},
++{0x71B2, 0x28},
++{0x71B3, 0x46},
++{0x71B4, 0x03},
++{0x71B5, 0x99},
++{0x71B6, 0x8F},
++{0x71B7, 0xF6},
++{0x71B8, 0x71},
++{0x71B9, 0xFB},
++{0x71BA, 0x3A},
++{0x71BB, 0x46},
++{0x71BC, 0x00},
++{0x71BD, 0x23},
++{0x71BE, 0x79},
++{0x71BF, 0xF6},
++{0x71C0, 0xCA},
++{0x71C1, 0xFF},
++{0x71C2, 0x00},
++{0x71C3, 0xE0},
++{0x71C4, 0x0F},
++{0x71C5, 0xE0},
++{0x71C6, 0x8A},
++{0x71C7, 0x02},
++{0x71C8, 0x80},
++{0x71C9, 0x0D},
++{0x71CA, 0x10},
++{0x71CB, 0x43},
++{0x71CC, 0x19},
++{0x71CD, 0x4A},
++{0x71CE, 0x00},
++{0x71CF, 0x23},
++{0x71D0, 0x00},
++{0x71D1, 0x92},
++{0x71D2, 0x89},
++{0x71D3, 0x0D},
++{0x71D4, 0x01},
++{0x71D5, 0x93},
++{0x71D6, 0x40},
++{0x71D7, 0x22},
++{0x71D8, 0x8C},
++{0x71D9, 0xF6},
++{0x71DA, 0x98},
++{0x71DB, 0xF9},
++{0x71DC, 0xA1},
++{0x71DD, 0x00},
++{0x71DE, 0x64},
++{0x71DF, 0x1C},
++{0x71E0, 0x70},
++{0x71E1, 0x50},
++{0x71E2, 0x04},
++{0x71E3, 0x2C},
++{0x71E4, 0xDB},
++{0x71E5, 0xD3},
++{0x71E6, 0x14},
++{0x71E7, 0x4D},
++{0x71E8, 0x00},
++{0x71E9, 0x24},
++{0x71EA, 0x0B},
++{0x71EB, 0x98},
++{0x71EC, 0x67},
++{0x71ED, 0x00},
++{0x71EE, 0xC0},
++{0x71EF, 0x5B},
++{0x71F0, 0x2A},
++{0x71F1, 0x46},
++{0x71F2, 0x40},
++{0x71F3, 0x21},
++{0x71F4, 0x8C},
++{0x71F5, 0xF6},
++{0x71F6, 0x9A},
++{0x71F7, 0xF9},
++{0x71F8, 0x05},
++{0x71F9, 0x99},
++{0x71FA, 0x0E},
++{0x71FB, 0x4A},
++{0x71FC, 0xC8},
++{0x71FD, 0x53},
++{0x71FE, 0xA7},
++{0x71FF, 0x00},
++{0x7200, 0xF0},
++{0x7201, 0x59},
++{0x7202, 0x40},
++{0x7203, 0x21},
++{0x7204, 0x8C},
++{0x7205, 0xF6},
++{0x7206, 0x7B},
++{0x7207, 0xF9},
++{0x7208, 0x04},
++{0x7209, 0x99},
++{0x720A, 0x64},
++{0x720B, 0x1C},
++{0x720C, 0xC8},
++{0x720D, 0x51},
++{0x720E, 0x04},
++{0x720F, 0x2C},
++{0x7210, 0xEB},
++{0x7211, 0xD3},
++{0x7212, 0x0F},
++{0x7213, 0xB0},
++{0x7214, 0xF0},
++{0x7215, 0xBD},
++{0x7216, 0x00},
++{0x7217, 0x00},
++{0x7218, 0x76},
++{0x7219, 0x69},
++{0x721A, 0x18},
++{0x721B, 0x00},
++{0x721C, 0xEC},
++{0x721D, 0x58},
++{0x721E, 0x18},
++{0x721F, 0x00},
++{0x7220, 0x38},
++{0x7221, 0x36},
++{0x7222, 0x18},
++{0x7223, 0x00},
++{0x7224, 0x00},
++{0x7225, 0x35},
++{0x7226, 0x18},
++{0x7227, 0x00},
++{0x7228, 0x00},
++{0x7229, 0x20},
++{0x722A, 0x18},
++{0x722B, 0x00},
++{0x722C, 0xFF},
++{0x722D, 0xFF},
++{0x722E, 0xFF},
++{0x722F, 0x3F},
++{0x7230, 0xFF},
++{0x7231, 0x07},
++{0x7232, 0x00},
++{0x7233, 0x00},
++{0x7234, 0xFF},
++{0x7235, 0xFF},
++{0x7236, 0x07},
++{0x7237, 0x00},
++{0x7238, 0xFF},
++{0x7239, 0x1F},
++{0x723A, 0x00},
++{0x723B, 0x00},
++{0x723C, 0x01},
++{0x723D, 0xF6},
++{0x723E, 0x45},
++{0x723F, 0x12},
++{0x3450, 0x00}, /* use continuous clock */
++//{0x3448, 0x2f}, // RAW20 DT
++//{0x3449, 0x2c}, // RAW12 DT
++{0x0000, 0x00},
++};
++
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch
new file mode 100644
index 00000000..84a7e44e
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch
@@ -0,0 +1,620 @@
+From 0368ffc88e6aec7655d9b63c7ddc50c57714dd58 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Sat, 30 May 2020 00:48:18 +0300
+Subject: [PATCH] media: i2c: soc_camera: add dummy lvds sensor
+
+This adds sensor that is not detectable behind serializer
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/dummy.c | 539 +++++++++++++++++++++++++++++++++
+ drivers/media/i2c/soc_camera/max9286.h | 3 +
+ drivers/media/i2c/soc_camera/ov106xx.c | 11 +
+ 3 files changed, 553 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/dummy.c
+
+diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c
+new file mode 100644
+index 0000000..346b5dd
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/dummy.c
+@@ -0,0 +1,539 @@
++/*
++ * Dummy sensor camera driver
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * 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 (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/of_graph.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++struct dummy_priv {
++ struct v4l2_subdev sd;
++ struct v4l2_ctrl_handler hdl;
++ struct media_pad pad;
++ struct v4l2_rect rect;
++ u8 id[6];
++ int max_width;
++ int max_height;
++ const char * media_bus_format;
++ int mbus_format;
++ int dummy;
++ /* serializers */
++ int ti9x4_addr;
++ int ti9x3_addr;
++ int port;
++};
++
++static int width = 1920;
++module_param(width, int, 0644);
++MODULE_PARM_DESC(width, " width (default: 1920)");
++
++static int height = 1080;
++module_param(height, int, 0644);
++MODULE_PARM_DESC(height, " height (default: 1080)");
++
++static char *fmt = "yuyv";
++module_param(fmt, charp, 0644);
++MODULE_PARM_DESC(fmt, " MEDIA_BUS_FORMAT (default: YUYV)");
++
++static int dummy = 0;
++module_param(dummy, int, 0644);
++MODULE_PARM_DESC(dummy, " dummy force (0 - dummy imager disabled)");
++
++static inline struct dummy_priv *to_dummy(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct dummy_priv, sd);
++}
++
++static inline struct v4l2_subdev *dummy_to_sd(struct v4l2_ctrl *ctrl)
++{
++ return &container_of(ctrl->handler, struct dummy_priv, hdl)->sd;
++}
++
++static int dummy_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int dummy_get_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (format->pad)
++ return -EINVAL;
++
++ mf->width = priv->rect.width;
++ mf->height = priv->rect.height;
++ mf->code = priv->mbus_format;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ return 0;
++}
++
++static int dummy_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ mf->code = priv->mbus_format;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int dummy_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (code->pad || code->index > 0)
++ return -EINVAL;
++
++ code->code = priv->mbus_format;
++
++ return 0;
++}
++
++static int dummy_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ memcpy(edid->edid, priv->id, 6);
++
++ edid->edid[6] = 0xff;
++ edid->edid[7] = client->addr;
++ edid->edid[8] = 'D' >> 8;
++ edid->edid[9] = 'Y' & 0xff;
++
++ return 0;
++}
++
++static int dummy_set_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct v4l2_rect *rect = &sel->r;
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > priv->max_width) ||
++ (rect->top + rect->height > priv->max_height))
++ *rect = priv->rect;
++
++ priv->rect.left = rect->left;
++ priv->rect.top = rect->top;
++ priv->rect.width = rect->width;
++ priv->rect.height = rect->height;
++
++ return 0;
++}
++
++static int dummy_get_selection(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_selection *sel)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ switch (sel->target) {
++ case V4L2_SEL_TGT_CROP_BOUNDS:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP_DEFAULT:
++ sel->r.left = 0;
++ sel->r.top = 0;
++ sel->r.width = priv->max_width;
++ sel->r.height = priv->max_height;
++ return 0;
++ case V4L2_SEL_TGT_CROP:
++ sel->r = priv->rect;
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int dummy_g_mbus_config(struct v4l2_subdev *sd,
++ struct v4l2_mbus_config *cfg)
++{
++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
++ cfg->type = V4L2_MBUS_CSI2;
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int dummy_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ reg->val = 0;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int dummy_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ return 0;
++}
++#endif
++
++static struct v4l2_subdev_core_ops dummy_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = dummy_g_register,
++ .s_register = dummy_s_register,
++#endif
++};
++
++static int dummy_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ case V4L2_CID_CONTRAST:
++ case V4L2_CID_SATURATION:
++ case V4L2_CID_HUE:
++ case V4L2_CID_GAMMA:
++ case V4L2_CID_SHARPNESS:
++ case V4L2_CID_AUTOGAIN:
++ case V4L2_CID_GAIN:
++ case V4L2_CID_ANALOGUE_GAIN:
++ case V4L2_CID_EXPOSURE:
++ case V4L2_CID_HFLIP:
++ case V4L2_CID_VFLIP:
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ctrl_ops dummy_ctrl_ops = {
++ .s_ctrl = dummy_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops dummy_video_ops = {
++ .s_stream = dummy_s_stream,
++ .g_mbus_config = dummy_g_mbus_config,
++};
++
++static const struct v4l2_subdev_pad_ops dummy_subdev_pad_ops = {
++ .get_edid = dummy_get_edid,
++ .enum_mbus_code = dummy_enum_mbus_code,
++ .get_selection = dummy_get_selection,
++ .set_selection = dummy_set_selection,
++ .get_fmt = dummy_get_fmt,
++ .set_fmt = dummy_set_fmt,
++};
++
++static struct v4l2_subdev_ops dummy_subdev_ops = {
++ .core = &dummy_core_ops,
++ .video = &dummy_video_ops,
++ .pad = &dummy_subdev_pad_ops,
++};
++
++static void dummy_otp_id_read(struct i2c_client *client)
++{
++ struct dummy_priv *priv = to_dummy(client);
++
++ /* dummy camera id */
++ priv->id[0] = 'd';
++ priv->id[1] = 'u';
++ priv->id[2] = 'm';
++ priv->id[3] = 'm';
++ priv->id[4] = 'y';
++ priv->id[5] = '.';
++}
++
++static ssize_t dummy_otp_id_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev));
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ struct dummy_priv *priv = to_dummy(client);
++
++ dummy_otp_id_read(client);
++
++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++}
++
++static DEVICE_ATTR(otp_id_dummy, S_IRUGO, dummy_otp_id_show, NULL);
++
++static int dummy_initialize(struct i2c_client *client)
++{
++ struct dummy_priv *priv = to_dummy(client);
++ u8 pid = 0xff;
++ int tmp_addr;
++
++ tmp_addr = client->addr;
++ do {
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x3_addr;
++ /* check if UB953 ID */
++ reg8_read(client, 0xf1, &pid);
++ if (pid == 'U')
++ break;
++ /* check if UB913 ID */
++ reg8_read(client, 0x00, &pid);
++ if (pid == (TI913_ID << 1))
++ break;
++
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ client->addr = tmp_addr;
++ return -ENODEV;
++ }
++ } while(0);
++ client->addr = tmp_addr;
++
++ if (strcmp(priv->media_bus_format, "yuyv") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_YUYV8_2X8;
++ else if (strcmp(priv->media_bus_format, "uyvy") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_UYVY8_2X8;
++ else if (strcmp(priv->media_bus_format, "grey") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_Y8_1X8;
++ else if (strcmp(priv->media_bus_format, "rggb8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB8_1X8;
++ else if (strcmp(priv->media_bus_format, "bggr8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR8_1X8;
++ else if (strcmp(priv->media_bus_format, "grbg8") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG8_1X8;
++ else if (strcmp(priv->media_bus_format, "rggb12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB12_1X12;
++ else if (strcmp(priv->media_bus_format, "bggr12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR12_1X12;
++ else if (strcmp(priv->media_bus_format, "grbg12") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG12_1X12;
++ else if (strcmp(priv->media_bus_format, "rggb14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB14_1X14;
++ else if (strcmp(priv->media_bus_format, "bggr14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR14_1X14;
++ else if (strcmp(priv->media_bus_format, "grbg14") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG14_1X14;
++ else if (strcmp(priv->media_bus_format, "rggb16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SRGGB16_1X16;
++ else if (strcmp(priv->media_bus_format, "bggr16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SBGGR16_1X16;
++ else if (strcmp(priv->media_bus_format, "grbg16") == 0)
++ priv->mbus_format = MEDIA_BUS_FMT_SGRBG16_1X16;
++ else {
++ v4l_err(client, "failed to parse mbus format (%s)\n", priv->media_bus_format);
++ return -EINVAL;
++ }
++
++ /* Read OTP IDs */
++ dummy_otp_id_read(client);
++
++ dev_info(&client->dev, "Dummy camera PID %x, res %dx%d, fmt %s, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
++ pid, priv->max_width, priv->max_height, priv->media_bus_format, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
++
++ return 0;
++}
++
++static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd);
++ int i;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ int tmp_addr = 0;
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ of_property_read_u32(endpoint, "dummy", &priv->dummy);
++
++ if (of_property_read_u32(np, "dummy,width", &priv->max_width))
++ priv->max_width = width;
++ if (of_property_read_u32(np, "dummy,height", &priv->max_height))
++ priv->max_height = height;
++ if (of_property_read_string(np, "dummy,fmt", &priv->media_bus_format))
++ priv->media_bus_format = fmt;
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) &&
++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") &&
++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) &&
++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port))
++ break;
++ }
++
++ of_node_put(endpoint);
++
++ if (!priv->ti9x4_addr) {
++ dev_dbg(&client->dev, "deserializer does not present\n");
++ return -EINVAL;
++ }
++
++ /* setup I2C translator address */
++ tmp_addr = client->addr;
++ if (priv->ti9x4_addr) {
++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */
++
++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */
++ usleep_range(2000, 2500); /* wait 2ms */
++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */
++ }
++ client->addr = tmp_addr;
++
++ /* module params override dts */
++ if (strcmp(fmt, "yuyv"))
++ priv->media_bus_format = fmt;
++ if (width != 1920)
++ priv->max_width = width;
++ if (height != 1080)
++ priv->max_height = height;
++ if (dummy)
++ priv->dummy = dummy;
++
++ if (!priv->dummy)
++ return -ENODEV;
++
++ return 0;
++}
++
++static int dummy_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct dummy_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &dummy_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&priv->hdl, 4);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_CONTRAST, 0, 16, 1, 7);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_SATURATION, 0, 7, 1, 2);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_HUE, 0, 23, 1, 12);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_GAMMA, -128, 128, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_SHARPNESS, 0, 10, 1, 3);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_GAIN, 1, 0x7ff, 1, 0x200);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_ANALOGUE_GAIN, 1, 0xe, 1, 0xa);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_EXPOSURE, 1, 0x600, 1, 0x144);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_HFLIP, 0, 1, 1, 0);
++ v4l2_ctrl_new_std(&priv->hdl, &dummy_ctrl_ops,
++ V4L2_CID_VFLIP, 0, 1, 1, 0);
++ priv->sd.ctrl_handler = &priv->hdl;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ priv->pad.flags = MEDIA_PAD_FL_SOURCE;
++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad);
++ if (ret < 0)
++ goto cleanup;
++
++ ret = dummy_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = dummy_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = priv->max_width;
++ priv->rect.height = priv->max_height;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ if (device_create_file(&client->dev, &dev_attr_otp_id_dummy) != 0) {
++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n");
++ goto cleanup;
++ }
++
++ return 0;
++
++cleanup:
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n",
++ client->addr, client->adapter->name);
++ return ret;
++}
++
++static int dummy_remove(struct i2c_client *client)
++{
++ struct dummy_priv *priv = i2c_get_clientdata(client);
++
++ device_remove_file(&client->dev, &dev_attr_otp_id_dummy);
++ v4l2_async_unregister_subdev(&priv->sd);
++ media_entity_cleanup(&priv->sd.entity);
++ v4l2_ctrl_handler_free(&priv->hdl);
++ v4l2_device_unregister_subdev(&priv->sd);
++
++ return 0;
++}
+diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h
+index 3fe713f..48233e2 100644
+--- a/drivers/media/i2c/soc_camera/max9286.h
++++ b/drivers/media/i2c/soc_camera/max9286.h
+@@ -30,6 +30,9 @@
+ #define MAX9290_ID 0x2C
+ #define BROADCAST 0x6f
+
++#define TI913_ID 0x58
++#define TI953_ID 0x30
++
+ static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val)
+ {
+ int ret, retries;
+diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
+index cf97f28..b3d84a6 100644
+--- a/drivers/media/i2c/soc_camera/ov106xx.c
++++ b/drivers/media/i2c/soc_camera/ov106xx.c
+@@ -32,6 +32,7 @@ static enum {
+ ID_ISX016,
+ ID_ISX019,
+ ID_OV2311,
++ ID_DUMMY,
+ } chip_id;
+
+ #include "ov10635.c"
+@@ -55,6 +56,7 @@ static enum {
+ #include "isx019.c"
+ #include "ov2311.c"
+ #include "ar0147.c"
++#include "dummy.c"
+
+ static int ov106xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+@@ -62,6 +64,12 @@ static int ov106xx_probe(struct i2c_client *client,
+ int ret = -1;
+ chip_id = -EINVAL;
+
++ ret = dummy_probe(client, did);
++ if (!ret) {
++ chip_id = ID_DUMMY;
++ goto out;
++ }
++
+ ret = gw5200_probe(client, did);
+ if (!ret) {
+ chip_id = ID_GW5200_IMX390;
+@@ -258,6 +266,9 @@ static int ov106xx_remove(struct i2c_client *client)
+ case ID_OV2311:
+ ov2311_remove(client);
+ break;
++ case ID_DUMMY:
++ dummy_remove(client);
++ break;
+ default:
+ break;
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch
new file mode 100644
index 00000000..b3aef256
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch
@@ -0,0 +1,1014 @@
+From ed70167620fa94494ade3a3192a8517d8a47c55d Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 3 Jun 2020 18:42:39 +0300
+Subject: [PATCH] arm64: dts: renesas: add V3H GMSL2 8ch Videobox
+
+This adds V3H GMSL2 8ch Videobox
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/Makefile | 1 +
+ .../boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts | 979 +++++++++++++++++++++
+ 2 files changed, 980 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index da23cbb..558ea98 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -49,6 +49,7 @@ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vbm-v3.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-8ch.dtb r8a77980-v3hsk-vb-4ch.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-2x2.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-4.dtb
++dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl2-8.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-gmsl-8ch.dtb
+ dtb-$(CONFIG_ARCH_R8A77980) += r8a77980-v3hsk-vb-4ch-hdmi.dtb r8a77980-v3hsk-vb-8ch-hdmi.dtb
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts
+new file mode 100644
+index 0000000..9bf6cd3
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-8.dts
+@@ -0,0 +1,979 @@
++/*
++ * Device Tree Source for the V3HSK GMSL2 Quad Videobox Mini board on r8a7798
++ *
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include "r8a77980-v3hsk.dts"
++#include <dt-bindings/gpio/gpio.h>
++/* FDPLink output */
++//#include "vb-fdplink-output.dtsi"
++#include "camera.dtsi"
++
++/ {
++ model = "Renesas V3HSK 8ch GMSL2 Videobox board based on r8a77980";
++
++ aliases {
++ serial1 = &scif3;
++ ethernet1 = &avb;
++ };
++
++ cs2300_ref_clk: cs2300_ref_clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <25000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led0 {
++ label = "board:status";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "none";
++ };
++ };
++
++ mpcie_1v8: regulator2 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ mpcie_3v3: regulator3 {
++ compatible = "regulator-fixed";
++ regulator-name = "mPCIe 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ common_3v3: regulator4 {
++ compatible = "regulator-fixed";
++ regulator-name = "main 3v3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ iio_hwmon: hwmon@1 {
++ compatible = "iio-hwmon";
++ io-channels =
++ /* current */
++ <&max2008x 0>,
++ <&max2008x 2>,
++ /* voltage */
++ <&max2008x 4>,
++ <&max2008x 6>,
++ /* misc voltages */
++ <&max2008x 8>,
++ <&max2008x 9>;
++ io-channel-names =
++ "camera-0-Iout",
++ "camera-1-Iout",
++ "camera-0-Vout",
++ "camera-1-Vout",
++ "cameras-Vregulator",
++ "cameras-3v3";
++ };
++
++ iio_hwmon2: hwmon@2 {
++ compatible = "iio-hwmon";
++ io-channels =
++ /* current */
++ <&max2008x_2 0>,
++ <&max2008x_2 2>,
++ /* voltage */
++ <&max2008x_2 4>,
++ <&max2008x_2 6>,
++ /* misc voltages */
++ <&max2008x_2 8>,
++ <&max2008x_2 9>;
++ io-channel-names =
++ "camera-0-Iout",
++ "camera-1-Iout",
++ "camera-0-Vout",
++ "camera-1-Vout",
++ "cameras-Vregulator",
++ "cameras-3v3";
++ };
++};
++
++&canfd {
++ pinctrl-0 = <&canfd0_pins &canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++&avb {
++ pinctrl-0 = <&avb_pins>;
++ pinctrl-names = "default";
++ renesas,no-ether-link;
++ phy-handle = <&avb_phy0>;
++ status = "okay";
++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>;
++
++ avb_phy0: eavb-phy@0 {
++ rxc-skew-ps = <1500>;
++ rxdv-skew-ps = <420>; /* default */
++ rxd0-skew-ps = <420>; /* default */
++ rxd1-skew-ps = <420>; /* default */
++ rxd2-skew-ps = <420>; /* default */
++ rxd3-skew-ps = <420>; /* default */
++ txc-skew-ps = <900>; /* default */
++ txen-skew-ps = <420>; /* default */
++ txd0-skew-ps = <420>; /* default */
++ txd1-skew-ps = <420>; /* default */
++ txd2-skew-ps = <420>; /* default */
++ txd3-skew-ps = <420>; /* default */
++ reg = <3>;
++ interrupt-parent = <&gpio1>;
++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++ max-speed = <1000>;
++ };
++};
++
++&csi40 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi40_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <1200>;
++ };
++ };
++};
++
++&csi41 {
++ status = "okay";
++
++ port {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ csi41_ep: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ csi-rate = <1200>;
++ };
++ };
++};
++
++&i2c1 {
++ pinctrl-0 = <&i2c1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ clock-frequency = <400000>;
++
++ i2cswitch1: i2c-switch@74 {
++ compatible = "nxp,pca9548";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x74>;
++ reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>;
++
++ /* CCTRL_SDA and CCTRL_SCL */
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ gpio_exp_ch0: gpio_ch0@76 {
++ compatible = "nxp,pca9539";
++ reg = <0x76>;
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ cmr_pwr_en {
++ gpio-hog;
++ gpios = <3 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CmrPEn";
++ };
++ };
++
++ /* CS2300 node @0x4e */
++ cs2300: clk_multiplier@4e {
++ #clock-cells = <0>;
++ compatible = "cirrus,cs2300-cp";
++ reg = <0x4e>;
++ clocks = <&cs2300_ref_clk>;
++ clock-names = "clk_in";
++
++ assigned-clocks = <&cs2300>;
++ assigned-clock-rates = <25000000>;
++ };
++
++ dac_vcam: dac_vcam@60 {
++ compatible = "microchip,mcp4725";
++ reg = <0x60>;
++ vdd-supply = <&common_3v3>;
++ };
++
++ max2008x: vcam_switch@28 {
++ compatible = "maxim,max2008x";
++ reg = <0x28>;
++ #io-channel-cells = <1>;
++ enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>;
++
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ vdd_cam0: SW0 {
++ reg = <0>;
++ regulator-name = "Camera-0";
++ };
++ vdd_cam1: SW1 {
++ reg = <1>;
++ regulator-name = "Camera-1";
++ };
++ vdd_cam2: SW2 {
++ reg = <2>;
++ regulator-name = "Camera-2";
++ };
++ vdd_cam3: SW3 {
++ reg = <3>;
++ regulator-name = "Camera-3";
++ };
++ };
++ };
++
++ max2008x_2: vcam_switch@29 {
++ compatible = "maxim,max2008x";
++ reg = <0x29>;
++ #io-channel-cells = <1>;
++ /* enable-gpios = <&gpio_exp_ch0 5 GPIO_ACTIVE_HIGH>; */
++
++ regulators {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ vdd_cam4: SW0 {
++ reg = <0>;
++ regulator-name = "Camera-4";
++ };
++ vdd_cam5: SW1 {
++ reg = <1>;
++ regulator-name = "Camera-5";
++ };
++ vdd_cam6: SW2 {
++ reg = <2>;
++ regulator-name = "Camera-6";
++ };
++ vdd_cam7: SW3 {
++ reg = <3>;
++ regulator-name = "Camera-7";
++ };
++ };
++ };
++ };
++
++ /* DS0_SDA and DS0_SCL */
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ max96712@29 {
++ compatible = "maxim,max96712";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x29>;
++ clocks = <&cs2300>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>;
++
++ maxim,links-mipi-map = <2 2 2 2>;
++
++ poc0-supply = <&vdd_cam1>;
++ poc1-supply = <&vdd_cam4>;
++ poc2-supply = <&vdd_cam6>;
++ poc3-supply = <&vdd_cam3>;
++
++ port@0 {
++ max96712_des0ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in0>;
++ };
++ max96712_des0ep1: endpoint@1 {
++ ser-addr = <0x0d>;
++ remote-endpoint = <&camera_in1>;
++ };
++ max96712_des0ep2: endpoint@2 {
++ ser-addr = <0x0e>;
++ remote-endpoint = <&camera_in2>;
++ };
++ max96712_des0ep3: endpoint@3 {
++ ser-addr = <0x0f>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++
++ port@1 {
++ max96712_des0mipi2: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@60 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in0: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin0ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@61 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0d>;
++
++ port@0 {
++ camera_in1: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin1ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++ };
++
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ camera@62 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x62 0x0e>;
++
++ port@0 {
++ camera_in2: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin2ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ camera@63 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x63 0x0f>;
++
++ port@0 {
++ camera_in3: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin3ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des0ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ max96712@29 {
++ compatible = "maxim,max96712";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x29>;
++ clocks = <&cs2300>;
++ clock-names = "ref_clk";
++ shutdown-gpios = <&gpio_exp_ch0 2 GPIO_ACTIVE_LOW>;
++
++ maxim,links-mipi-map = <1 1 1 1>;
++
++ poc0-supply = <&vdd_cam0>;
++ poc1-supply = <&vdd_cam7>;
++ poc2-supply = <&vdd_cam5>;
++ poc3-supply = <&vdd_cam2>;
++
++ port@0 {
++ max96712_des1ep0: endpoint@0 {
++ ser-addr = <0x0c>;
++ remote-endpoint = <&camera_in4>;
++ };
++ max96712_des1ep1: endpoint@1 {
++ ser-addr = <0x0d>;
++ remote-endpoint = <&camera_in5>;
++ };
++ max96712_des1ep2: endpoint@2 {
++ ser-addr = <0x0e>;
++ remote-endpoint = <&camera_in6>;
++ };
++ max96712_des1ep3: endpoint@3 {
++ ser-addr = <0x0f>;
++ remote-endpoint = <&camera_in7>;
++ };
++ };
++
++ port@1 {
++ max96712_des1mipi2: endpoint {
++ csi-rate = <1200>;
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++
++ i2c@0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0>;
++
++ camera@60 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x60 0x0c>;
++
++ port@0 {
++ camera_in4: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin4ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep0>;
++ };
++ };
++ };
++ };
++
++ i2c@1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <1>;
++
++ camera@61 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x61 0x0d>;
++
++ port@0 {
++ camera_in5: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin5ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep1>;
++ };
++ };
++ };
++ };
++
++ i2c@2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <2>;
++
++ camera@62 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x62 0x0e>;
++
++ port@0 {
++ camera_in6: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin6ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep2>;
++ };
++ };
++ };
++ };
++
++ i2c@3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <3>;
++
++ camera@63 {
++ compatible = COMPATIBLE_CAMERAS;
++ reg = <0x63 0x0f>;
++
++ port@0 {
++ camera_in7: endpoint {
++ clock-lanes = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&vin7ep0>;
++ };
++ };
++ port@1 {
++ camera_max96712_des1ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep3>;
++ };
++ };
++ };
++ };
++ };
++ };
++
++ /* Disp_SDA and Disp_SCL */
++ i2c@5 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <5>;
++
++ /* fan node - lm96063 */
++ fan_ctrl: lm96063@4c {
++ compatible = "lm96163";
++ reg = <0x4c>;
++ };
++ };
++
++ /* ESDA and ESCL */
++ i2c@7 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <7>;
++
++ rtc: mcp79411@6f {
++ compatible = "microchip,mcp7941x";
++ reg = <0x6f>;
++ };
++ };
++ };
++};
++
++&gpio0 {
++ fpdl_shdn {
++ gpio-hog;
++ gpios = <1 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "FPDL_SHDN";
++ };
++
++ cam_pwr_en {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIPWR_En";
++ };
++
++ wake_pin_8 {
++ gpio-hog;
++ gpios = <0 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 8";
++ };
++};
++
++&gpio1 {
++ md_buf_en {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CPLD_If_En";
++ };
++};
++
++&gpio2 {
++ m2_rst {
++ gpio-hog;
++ gpios = <11 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "M.2 RST#";
++ };
++
++ cctrl_rstn {
++ gpio-hog;
++ gpios = <16 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CCTRL_RSTn";
++ };
++
++ can0_stby {
++ gpio-hog;
++ gpios = <27 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN0STBY";
++ };
++
++ can1_load {
++ gpio-hog;
++ gpios = <29 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1Loff";
++ };
++
++ can1_stby {
++ gpio-hog;
++ gpios = <22 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "CAN1STBY";
++ };
++
++ wake_pin_7 {
++ gpio-hog;
++ gpios = <19 GPIO_ACTIVE_HIGH>;
++ input;
++ line-name = "WAKE INPUT PIN 7";
++ };
++
++ vi1_gpioext_rst {
++ gpio-hog;
++ gpios = <13 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP1_RST";
++ };
++};
++
++&gpio3 {
++ vi0_gpioext_rst {
++ gpio-hog;
++ gpios = <4 GPIO_ACTIVE_HIGH>;
++ output-high;
++ line-name = "VIP0_RST";
++ };
++};
++
++&pcie_bus_clk {
++ clock-frequency = <100000000>;
++ status = "okay";
++};
++
++&pciec {
++ pcie3v3-supply = <&mpcie_3v3>;
++ pcie1v8-supply = <&mpcie_1v8>;
++ status = "okay";
++};
++
++&pcie_phy {
++ status = "okay";
++};
++
++&pfc {
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data_a";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ avb_pins: avb {
++ groups = "avb_mdio", "avb_rgmii";
++ function = "avb";
++ };
++
++ i2c1_pins: i2c1 {
++ groups = "i2c1";
++ function = "i2c1";
++ };
++
++ scif3_pins: scif3 {
++ groups = "scif3_data";
++ function = "scif3";
++ };
++};
++
++&scif3 {
++ pinctrl-0 = <&scif3_pins>;
++ pinctrl-names = "default";
++
++ status = "okay";
++};
++
++&tpu {
++ status = "disabled";
++};
++
++&vin0 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin0ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in0>;
++ };
++ };
++ port@1 {
++ csi0ep0: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin0_max96712_des0ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep0>;
++ };
++ };
++ };
++};
++
++&vin1 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin1ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in1>;
++ };
++ };
++ port@1 {
++ csi0ep1: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin1_max96712_des0ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep1>;
++ };
++ };
++ };
++};
++
++&vin2 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin2ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in2>;
++ };
++ };
++ port@1 {
++ csi0ep2: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin2_max96712_des0ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep2>;
++ };
++ };
++ };
++};
++
++&vin3 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin3ep0: endpoint {
++ csi,select = "csi40";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in3>;
++ };
++ };
++ port@1 {
++ csi0ep3: endpoint {
++ remote-endpoint = <&csi40_ep>;
++ };
++ };
++ port@2 {
++ vin3_max96712_des0ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des0ep3>;
++ };
++ };
++ };
++};
++
++&vin4 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin4ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <0>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in4>;
++ };
++ };
++ port@1 {
++ csi1ep0: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin4_max96712_des1ep0: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep0>;
++ };
++ };
++ };
++};
++
++&vin5 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin5ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <1>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in5>;
++ };
++ };
++ port@1 {
++ csi1ep1: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin5_max96712_des1ep1: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep1>;
++ };
++ };
++ };
++};
++
++&vin6 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin6ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <2>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in6>;
++ };
++ };
++ port@1 {
++ csi1ep2: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin6_max96712_des1ep2: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep2>;
++ };
++ };
++ };
++};
++
++&vin7 {
++ status = "okay";
++
++ ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port@0 {
++ vin7ep0: endpoint {
++ csi,select = "csi41";
++ virtual,channel = <3>;
++ data-lanes = <1 2 3 4>;
++ remote-endpoint = <&camera_in7>;
++ };
++ };
++ port@1 {
++ csi1ep3: endpoint {
++ remote-endpoint = <&csi41_ep>;
++ };
++ };
++ port@2 {
++ vin7_max96712_des1ep3: endpoint@1 {
++ remote-endpoint = <&max96712_des1ep3>;
++ };
++ };
++ };
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch
new file mode 100644
index 00000000..2272f48f
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch
@@ -0,0 +1,106 @@
+From b025c0676549f2a075269e09ca9fc88b62a1c5af Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 3 Jun 2020 18:44:06 +0300
+Subject: [PATCH] arm64: dts: renesas: vb-gmsl2: fix typos
+
+This fixes varius typos on GMSL2 Videobox ECUs
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts | 12 ++++++------
+ arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts | 8 ++++----
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+index 4d284b1..c56adc0 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-2x2.dts
+@@ -1,7 +1,7 @@
+ /*
+- * Device Tree Source for the V3HSK Videobox Mini board on r8a7798
++ * Device Tree Source for the V3HSK GMSL2 Dual Videobox Mini board on r8a7798
+ *
+- * Copyright (C) 2018 Cogent Embedded, Inc.
++ * Copyright (C) 2020 Cogent Embedded, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+@@ -254,7 +254,7 @@
+ clock-names = "ref_clk";
+ shutdown-gpios = <&gpio_exp_ch0 1 GPIO_ACTIVE_LOW>;
+
+- maxim,link-mipi-map = <1 1>;
++ maxim,links-mipi-map = <1 1>;
+
+ poc0-supply = <&regulator_poc_0>;
+ poc1-supply = <&regulator_poc_1>;
+@@ -342,7 +342,7 @@
+ clock-names = "ref_clk";
+ shutdown-gpios = <&gpio_exp_ch0 0 GPIO_ACTIVE_LOW>;
+
+- maxim,link-mipi-map = <1 1>;
++ maxim,links-mipi-map = <1 1>;
+
+ poc0-supply = <&regulator_poc_2>;
+ poc1-supply = <&regulator_poc_3>;
+@@ -353,7 +353,7 @@
+ remote-endpoint = <&camera_in2>;
+ };
+ max9296_des1ep1: endpoint@1 {
+- ser-addr = <0x51>;
++ ser-addr = <0x0d>;
+ remote-endpoint = <&camera_in3>;
+ };
+ };
+@@ -396,7 +396,7 @@
+
+ camera@61 {
+ compatible = COMPATIBLE_CAMERAS;
+- reg = <0x61 0x0c>;
++ reg = <0x61 0x0d>;
+
+ port@0 {
+ camera_in3: endpoint {
+diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+index ac2d825..919e775 100644
+--- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
++++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk-vb-gmsl2-4.dts
+@@ -566,7 +566,7 @@
+ };
+ };
+ port@1 {
+- csi1ep0: endpoint {
++ csi0ep0: endpoint {
+ remote-endpoint = <&csi40_ep>;
+ };
+ };
+@@ -594,7 +594,7 @@
+ };
+ };
+ port@1 {
+- csi1ep1: endpoint {
++ csi0ep1: endpoint {
+ remote-endpoint = <&csi40_ep>;
+ };
+ };
+@@ -622,7 +622,7 @@
+ };
+ };
+ port@1 {
+- csi1ep2: endpoint {
++ csi0ep2: endpoint {
+ remote-endpoint = <&csi40_ep>;
+ };
+ };
+@@ -650,7 +650,7 @@
+ };
+ };
+ port@1 {
+- csi1ep3: endpoint {
++ csi0ep3: endpoint {
+ remote-endpoint = <&csi40_ep>;
+ };
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch
new file mode 100644
index 00000000..a2c8870e
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0523-media-i2c-isx019-do-not-disable-embedded-line.patch
@@ -0,0 +1,32 @@
+From 4c72275148ef3cc02ca8c6dc8a22cb8e67724322 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Wed, 17 Jun 2020 23:13:26 +0300
+Subject: [PATCH] media: i2c: isx019: do not disable embedded line
+
+Skip disale the embedded line by default.
+Disableing of embedded line reduces the frame size by one line,
+that is truncated in the end of frame, hence this is useless to disable
+emb line
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/isx019.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/isx019.h b/drivers/media/i2c/soc_camera/isx019.h
+index c7072a3..c3c36ba 100644
+--- a/drivers/media/i2c/soc_camera/isx019.h
++++ b/drivers/media/i2c/soc_camera/isx019.h
+@@ -23,8 +23,8 @@ static const struct isx019_reg isx019_regs_wizard[] = {
+ #if 0
+ /* enable FSIN */
+ {ISX019_DELAY, 100},
+-#endif
+ /* disable embedded data */
+ {0x504c, 0x0},
+ {0x504e, 0x0},
++#endif
+ };
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch
new file mode 100644
index 00000000..f567d5df
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0524-media-i2c-dummy-fix-DT-parse.patch
@@ -0,0 +1,28 @@
+From 8e338812615c72dad0fe17ea5a135ffdcc7b25a7 Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Tue, 28 Jul 2020 21:12:51 +0300
+Subject: [PATCH] media: i2c: dummy: fix DT parse
+
+This fixes the parse of dummy field
+
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/dummy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/soc_camera/dummy.c b/drivers/media/i2c/soc_camera/dummy.c
+index 346b5dd..3be2728 100644
+--- a/drivers/media/i2c/soc_camera/dummy.c
++++ b/drivers/media/i2c/soc_camera/dummy.c
+@@ -386,7 +386,7 @@ static int dummy_parse_dt(struct device_node *np, struct dummy_priv *priv)
+ if (!endpoint)
+ break;
+
+- of_property_read_u32(endpoint, "dummy", &priv->dummy);
++ of_property_read_u32(np, "dummy", &priv->dummy);
+
+ if (of_property_read_u32(np, "dummy,width", &priv->max_width))
+ priv->max_width = width;
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch
new file mode 100644
index 00000000..1a727e37
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0525-arm64-dts-renesas-Add-r8a7796-m3ulcb-2x4g-kf.dts.patch
@@ -0,0 +1,74 @@
+From 20b0cce7e2407ab766e849851d832006cabf9f2d Mon Sep 17 00:00:00 2001
+From: Valentine Barshak <valentine.barshak@cogentembedded.com>
+Date: Wed, 8 Jul 2020 19:21:13 +0300
+Subject: [PATCH] arm64: dts: renesas: Add r8a7796-m3ulcb-2x4g-kf.dts
+
+This adds Kingfisher board support for M3 v3.0 8GiB (2x4GiB) SK.
+
+Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
+---
+ arch/arm64/boot/dts/renesas/Makefile | 2 +-
+ .../boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts | 38 ++++++++++++++++++++++
+ 2 files changed, 39 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts
+
+diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
+index 5680cde..45c555e 100644
+--- a/arch/arm64/boot/dts/renesas/Makefile
++++ b/arch/arm64/boot/dts/renesas/Makefile
+@@ -24,7 +24,7 @@ dtb-$(CONFIG_ARCH_R8A77995) += r8a77995-draak.dtb
+ # ADAS boards
+ dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-x-view.dtb
+ dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-view.dtb
+-dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb
++dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-m3ulcb-kf.dtb r8a7796-m3ulcb-2x4g.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-salvator-x-view.dtb r8a7795-es1-salvator-x-view.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-view.dtb r8a7795-es1-h3ulcb-view.dtb
+ dtb-$(CONFIG_ARCH_R8A7795) += r8a7795-h3ulcb-had-alfa.dtb r8a7795-h3ulcb-had-beta.dtb r8a7795-es1-h3ulcb-had-alfa.dtb r8a7795-es1-h3ulcb-had-beta.dtb
+diff --git a/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts
+new file mode 100644
+index 0000000..76e0e57
+--- /dev/null
++++ b/arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-2x4g-kf.dts
+@@ -0,0 +1,38 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Device Tree Source for the M3ULCB Kingfisher board
++ *
++ * Copyright (C) 2020 Renesas Electronics Corp.
++ * Copyright (C) 2020 Cogent Embedded, Inc.
++ */
++
++#include "r8a7796-m3ulcb-2x4g.dts"
++#include "ulcb-kf.dtsi"
++
++/ {
++ model = "Renesas M3ULCB Kingfisher board based on r8a7796 ES3.0+";
++ compatible = "shimafuji,kingfisher", "renesas,m3ulcb",
++ "renesas,r8a7796";
++};
++
++&du {
++ ports {
++ port@0 {
++ endpoint {
++ remote-endpoint = <&adv7513_in>;
++ };
++ };
++ };
++};
++
++&lvds0 {
++ status = "okay";
++
++ ports {
++ port@1 {
++ lvds0_out: endpoint {
++ remote-endpoint = <&lvds_in>;
++ };
++ };
++ };
++};
+--
+2.7.4
+
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg
new file mode 100644
index 00000000..abd0bd76
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/enable.cfg
@@ -0,0 +1,2 @@
+CONFIG_TMPFS=y
+CONFIG_REGULATOR=y
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg
index df45d5e9..b078e242 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/hyperflash.cfg
@@ -1,2 +1 @@
-CONFIG_MTD=y
-CONFIG_MTD_RPC_HYPERFLASH=y
+CONFIG_MTD_RENESAS_RPC_HYPERFLASH=y
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg
index 9a1c695e..a88472a8 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/qspi.cfg
@@ -1,3 +1,3 @@
-CONFIG_SPI_RENESAS_RPC=y
+CONFIG_MTD_RENESAS_RPC_QSPI=y
CONFIG_MTD_BLOCK=y
CONFIG_JFFS2_FS=y
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc
index 31146743..34855009 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/renesas.scc
@@ -291,7 +291,6 @@ patch 0351-arm64-dts-renesas-r8a77980-VB-4ch-and-8ch-Add-PCIE-p.patch
patch 0352-gpu-drm-rcar_du-Fix-physical-address-of-the-CMA-back.patch
patch 0353-media-soc_camera-rcar_csi2-add-dump-module-param.patch
patch 0354-media-rcar_csi2-Disable-data-type-matching.patch
-patch 0355-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch
patch 0356-media-platform-vsp1-Extend-DRM-VSP1-interface.patch
patch 0357-gpu-drm-rcar-du-rcar_du_vsp-Check-if-gem-buffer-has-.patch
patch 0358-media-platform-vsp1-Add-cropping-handling-to-VSP-alp.patch
@@ -355,3 +354,105 @@ patch 0416-arm64-dtb-renesas-vb2.1-enable-usb2-channel-3.patch
patch 0417-USB-tusb8041-add-simple-driver-to-start-device-over-.patch
patch 0418-arm64-dts-renesas-ulcb-vb2-fix-USB30-and-HUB.patch
patch 0419-phy-rcar-gen3-usb2-power-on-port-in-host-mode-to.patch
+patch 0420-media-i2c-ov2311-fix-otp-id-read.patch
+patch 0421-media-i2c-imx390-add-user-defined-size-for-register-.patch
+patch 0422-mmc-core-mmc-Try-other-timings-if-the-higher-one-fai.patch
+patch 0423-media-i2c-ap0101_ar014x-add-AP0102-chip.patch
+patch 0424-arm64-dts-renesas-ulcb-vb-Fix-lvds0-port-routing.patch
+patch 0425-arm64-dts-r8a7798-v3hsk-vb-4-8ch-change-i2c-rate-to-.patch
+patch 0426-media-i2c-ov106xx-change-order.patch
+patch 0427-media-i2c-gw5200-fix-imager-hang.patch
+patch 0428-arch64-dts-renesas-r8a77970-Fix-IPMMU-probe-order.patch
+patch 0429-arch64-dts-renesas-r8a77980-Fix-IPMMU-probe-order.patch
+patch 0430-media-i2c-ar0140-update-driver-to-use-rGPIO-and-dyna.patch
+patch 0431-media-i2c-ti9x4-update-remote-gpio-function.patch
+patch 0432-media-i2c-soc_camera-add-AR0220.patch
+patch 0433-media-i2c-ar0220-add-rev2-rev3.patch
+patch 0434-media-i2c-max9286-parse-crossbard-from-cmdline.patch
+patch 0435-clk-renesas-r8a7795-cpg-mssr-Add-RPC-clocks.patch
+patch 0436-clk-renesas-r8a7796-cpg-mssr-Add-RPC-clocks.patch
+patch 0437-clk-renesas-r8a77965-cpg-mssr-Add-RPC-clocks.patch
+patch 0438-clk-renesas-rcar-gen3-cpg-Allow-to-set-RPCD2-clock-p.patch
+patch 0439-mtd-Consolidate-Renesas-RPC-drivers.patch
+patch 0440-arm64-dts-renesas-r8a77970-Update-RPC-device-nodes.patch
+patch 0441-arm64-dts-renesas-r8a77980-Update-RPC-device-nodes.patch
+patch 0442-arm64-dts-renesas-r8a7795-Add-RPC-device-node.patch
+patch 0443-arm64-dts-renesas-r8a7796-Add-RPC-device-node.patch
+patch 0444-arm64-dts-renesas-r8a77965-Add-RPC-device-node.patch
+patch 0445-arm64-dts-renesas-ulcb-Add-RPC-HyperFlash-device-nod.patch
+patch 0446-arm64-dts-renesas-salvator-common-Add-RPC-HyperFlash.patch
+patch 0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch
+patch 0448-media-i2c-ar0xxx-append-embedded-data-stats-into-frame.patch
+patch 0449-media-i2c-soc_camera-ov495_ov2775-Remove-early_param.patch
+patch 0450-arm64-dts-renesas-ulcb-Add-tee-MTD-RPC-HyperFlash-pa.patch
+patch 0451-arm64-dts-renesas-salvator-common-Add-tee-MTD-RPC-Hy.patch
+patch 0452-arm64-dts-renesas-ulcb-Increase-U-Boot-partition-siz.patch
+patch 0453-arm64-dts-renesas-salvator-common-Increase-U-Boot-pa.patch
+patch 0454-media-i2c-imx390-fix-refclk.patch
+patch 0455-media-i2c-ox01d10-add-imager-support.patch
+patch 0456-media-i2c-max9286-fix-resetb-handling.patch
+patch 0457-media-i2c-ov10640-fix-dvp-order-and-soft-reset.patch
+patch 0458-arm64-dts-renesas-Add-V3x-VideoBox-GMSL-8ch-support.patch
+patch 0459-media-i2c-ov10640-support-different-revisions.patch
+patch 0460-media-ar0xxx-add-embedded-line-into-frame.patch
+patch 0461-v3hsk-Add-separate-dts-for-dummy-camera-1920x1080.patch
+patch 0462-media-i2c-ov10640-add-embedded-data-fix-crop.patch
+patch 0463-net-can-rcar_can-fix-possible-IRQ-storm-on-high-load.patch
+patch 0464-arm64-dts-renesas-ulcb-v2-use-CANFD-instead-CAN.patch
+patch 0465-arm64-dts-renesas-add-cn12-support-on-VB2-1.patch
+patch 0466-media-i2c-max9286-parse-crossbar-from-dt.patch
+patch 0467-media-i2c-isx016-add-fixed-sensor.patch
+patch 0468-imx390-Read-1-byte-registers-by-default.patch
+patch 0469-rcar_canfd-fix-one-more-interrupt-storm-window.patch
+patch 0470-media-i2c-add-fps-setup.patch
+patch 0471-media-i2c-ov10640-add-fps-setup.patch
+patch 0472-media-i2c-soc_camera-fix-compilation-warnings.patch
+patch 0473-media-i2c-ov10640-add-different-imager-addresses.patch
+patch 0474-media-i2c-soc_camera-add-V4L2_CID_MIN_BUFFERS_FOR_CA.patch
+patch 0475-media-i2c-ar0233-add-fps-setup.patch
+patch 0476-media-i2c-imx390-add-fps-setup.patch
+patch 0477-media-i2c-ar0231-fix-FSIN-pin-input.patch
+patch 0478-media-i2c-ti9x4-fix-framesync.patch
+patch 0479-media-soc_camera-rcar_csi2-add-interrupts.patch
+patch 0480-media-i2c-soc_camera-ov10640-fix-emb-lines-number.patch
+patch 0481-r8a779-78-sysc-don-t-poweroff-Cortex-R7-core.patch
+patch 0482-media-i2c-max9286-ti9x4-power-down-POCs-on-reboot.patch
+patch 0484-media-platform-soc_camera-disable-mutex-locking-for-.patch
+patch 0485-media-i2c-ov10640-compensate-disabled-mutex.patch
+patch 0487-i2c-busses-i2c-rcar-block-pm_runtime.patch
+patch 0488-arm64-dts-renesas-block-i2c-pm-runtime.patch
+patch 0490-media-i2c-ti9x4-increase-i2c-freq-on-master-bus.patch
+patch 0491-media-i2c-soc_camera-switch-to-u64-adv_debug-access.patch
+patch 0492-media-i2c-move-gmsl-fpdlink-drivers-to-separate-fold.patch
+patch 0493-media-i2c-add-max96712-and-max9296.patch
+patch 0494-media-i2c-max9286-max9288-use-common.h-file.patch
+patch 0495-media-i2c-ti9x4-fix-rebot_notify-and-gpiod_request.patch
+patch 0496-media-i2c-add-interim-LVDS-imager-drivers.patch
+patch 0497-media-i2c-soc_camera-rcar_csi2-adjust-debugging.patch
+patch 0498-media-platform-soc_camera-rcar_vin-add-max96712-max9.patch
+patch 0499-regulator-add-MAX2008X-camera-protector.patch
+patch 0500-arm64-dts-renesas-add-V3H-GMSL2-Videoboxes.patch
+patch 0501-media-i2c-ap0101-fix-fsin-on-AP0102.patch
+patch 0502-media-i2c-max96712-add-MIPI-GMSL2-support.patch
+patch 0503-media-i2c-ov2311-add-GMSL2-support.patch
+patch 0504-media-i2c-max9296-add-MIPI-GMSL2-support.patch
+patch 0505-media-i2c-gmsl-parse-gmsl_mode-from-deserializer.patch
+patch 0506-media-i2c-imagers-add-AR0231-for-new-LVDS-support.patch
+patch 0507-media-i2c-ap0101-ap0201-fix-vendor-name-fsin-fix-on-.patch
+patch 0508-media-i2c-fix-indentation.patch
+patch 0509-media-i2c-fix-broken-old-LVDS-imagers.patch
+patch 0510-arm64-dts-renesas-add-camera-dtsi-file.patch
+patch 0511-media-i2c-ap0201-detect-AP0200-AP0202.patch
+patch 0512-arm64-dts-renesas-add-H3-GMSL2-Videobox.patch
+patch 0513-MTD-renesas-rpc-fix-dummy-cycles.patch
+patch 0514-media-i2c-gmsl2-add-fsync-support.patch
+patch 0515-media-i2c-ap020x-add-fsync-support.patch
+patch 0516-media-i2c-ar0231-fix-translator.patch
+patch 0517-media-i2c-gmsl2-fix-fsync-in-manual-mode.patch
+patch 0518-media-i2c-imagers-ar0231-fix-GMSL2.patch
+patch 0519-media-i2c-imagers-add-IMX390-for-new-LVDS-support.patch
+patch 0520-media-i2c-soc_camera-add-dummy-lvds-sensor.patch
+patch 0521-arm64-dts-renesas-add-V3H-GMSL2-8ch-Videobox.patch
+patch 0522-arm64-dts-renesas-vb-gmsl2-fix-typos.patch
+patch 0523-media-i2c-isx019-do-not-disable-embedded-line.patch
+patch 0524-media-i2c-dummy-fix-DT-parse.patch
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
index e053969e..4cce75a8 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg
@@ -27,6 +27,8 @@ CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_SCALE_CROP=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
+CONFIG_SOC_CAMERA_MAX9296=y
+CONFIG_SOC_CAMERA_MAX96712=y
CONFIG_SOC_CAMERA_TI9X4=y
CONFIG_SOC_CAMERA_OV106XX=y
CONFIG_SOC_CAMERA_OV5647=y
@@ -85,3 +87,5 @@ CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_RAID0=y
CONFIG_GPIO_SYSFS=y
+CONFIG_USB_TUSB8041=y
+CONFIG_REGULATOR_MAX2008X=y
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
index c633e9ed..9baa6f0f 100644
--- a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3hsk.cfg
@@ -22,6 +22,8 @@ CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_SCALE_CROP=y
CONFIG_SOC_CAMERA_PLATFORM=y
CONFIG_SOC_CAMERA_MAX9286=y
+CONFIG_SOC_CAMERA_MAX9296=y
+CONFIG_SOC_CAMERA_MAX96712=y
CONFIG_SOC_CAMERA_TI9X4=y
CONFIG_SOC_CAMERA_OV106XX=y
CONFIG_INPUT_TOUCHSCREEN=y
@@ -41,3 +43,4 @@ CONFIG_GPIO_SYSFS=y
CONFIG_DRM_THINE_THC63LVD1024=y
CONFIG_MCP4725=y
CONFIG_PHY_RCAR_GEN3_PCIE=y
+CONFIG_REGULATOR_MAX2008X=y