* commit 'a2d0c7f12f': (49 commits)
  ASoC: rockchip: i2s: Use add_component_controls
  ASoC: rockchip: i2s-tdm: Add support for PCM R/W Wait Time
  ASoC: rockchip: i2s-tdm: Add support for PATHx controls
  ASoC: rockchip: i2s-tdm: Use add_component_controls
  ASoC: rockchip: multi-dais: Fix component's name_prefix
  ASoC: rockchip: sai: Fix Transmit SDOx Select
  ASoC: rockchip: sai: Reduce FIFO XRUN warning prompt
  media: rockchip: hdmirx: avoid PKTDEC_AVIIF_CHG_IRQ mistrigger.
  video: rockchip: mpp: rkvenc2: fix slice mode poll failed
  arm64: dts: rockchip: px30: Add reboot_mode label for Android
  ARM: dts: rockchip: add rv1106g-evb1-v11-nofastae-spi-nand
  PCI: rockchip: dw: Use handle_level_irq for legacy irq
  arm64: dts: rockchip: rk3562-amp: Move the rpmsg node backwards.
  arm64: dts: rockchip: rk3568-amp: Move the rpmsg node backwards.
  arm64: dts: rockchip: rk3588-amp: support ap rpmsg
  rpmsg: rockchip: use rockchip,rpmsg for all rockchip platform
  arm64: dts: rockchip: rk3588-vehicle-evb: add v22 dts files and use serdes-mfd-display default
  mailbox: rockchip: Add Rockchip MBOX Demo
  arm64: dts: rockchip: add rk3588 evb1 lp4 v10 linux amp dts
  arm64: dts: rockchip: rk3588-amp: support ap core for amp
  ...

Change-Id: I13bb9ab1c3def29f25b18c67ee73d915b17ec817

Conflicts:
	drivers/gpio/Kconfig
	drivers/media/i2c/maxim4c/Kconfig
This commit is contained in:
Tao Huang 2023-09-28 09:23:21 +08:00
commit dfd3eeaf2b
60 changed files with 11207 additions and 601 deletions

View file

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/novo,nca9539-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Novosense I2C GPIO controller
maintainers:
- Cody Xie <cody.xie@rock-chips.com>
description: |
This controller is A GPIO expander with I2C interface and one interrupt pin.
properties:
compatible:
const: novo,nca9539-gpio
reg:
items:
- description: the I2C address containing the GPIO controller registers.
gpio-controller: true
'#gpio-cells':
const: 2
ngpios:
minimum: 0
maximum: 32
interrupt-controller: true
'#interrupt-cells':
const: 2
interrupts:
maxItems: 1
vdd-supply:
- description: the regulator for the VDD supplier.
required:
- compatible
- reg
- "#gpio-cells"
- gpio-controller
- vdd-supply
additionalProperties: false
dependencies:
interrupt-controller: [ interrupts ]
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
nca9539_vdd: nca9539-vdd {
compatible = "regulator-fixed";
regulator-name = "nca9539_vdd";
enable-active-high;
regulator-boot-on;
regulator-always-on;
};
};
nca9539_gpio: gpio@74 {
compatible = "novo,nca9539-gpio";
reg = <0x74>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
vdd-supply = <&nca9539_vdd>;
};
...

View file

@ -1145,6 +1145,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1106g-evb1-v11-facial-gate.dtb \
rv1106g-evb1-v10-spi-nand.dtb \
rv1106g-evb1-v10-spi-nor.dtb \
rv1106g-evb1-v11-nofastae-spi-nand.dtb \
rv1106g-evb2-v10.dtb \
rv1106g-evb2-v10-dual-camera.dtb \
rv1106g-evb2-v11-emmc.dtb \

View file

@ -0,0 +1,29 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106g-evb1-v11.dts"
#include "rv1106-tb-nofastae.dtsi"
/ {
model = "Rockchip RV1106G EVB1 V11 Board";
compatible = "rockchip,rv1106g-evb1-v11", "rockchip,rv1106";
chosen {
bootargs = "loglevel=0 rootfstype=erofs rootflags=dax console=ttyFIQ0 root=/dev/rd0 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=0 driver_async_probe=dwmmc_rockchip";
};
};
&fiq_debugger {
rockchip,baudrate = <1500000>;
};
&ramdisk_r {
reg = <0x800000 (15 * 0x00100000)>;
};
&ramdisk_c {
reg = <0x1700000 (10 * 0x00100000)>;
};

View file

@ -145,6 +145,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-rk817-tablet-k108.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-rk817-tablet-rkg11.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-rk817-tablet-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-channel-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-camera.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux.dtb
@ -211,6 +213,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-dsi-dsc-MV2100UZ1.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-ipc-6x-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-linux-amp.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-linux-ipc.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-lp4-v10-lt6911uxe.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb2-lp4-v10.dtb
@ -248,6 +251,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v20.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v21.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v22.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-s66-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-lp4x-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-lp4x-v10-linux.dtb

View file

@ -652,7 +652,7 @@
status = "disabled";
};
reboot-mode {
reboot_mode: reboot-mode {
compatible = "syscon-reboot-mode";
offset = <0x200>;
mode-bootloader = <BOOT_BL_DOWNLOAD>;

View file

@ -22,18 +22,6 @@
status = "okay";
};
rpmsg: rpmsg@7c00000 {
compatible = "rockchip,rk3562-rpmsg";
mbox-names = "rpmsg-rx", "rpmsg-tx";
mboxes = <&mailbox 0 &mailbox 3>;
rockchip,vdev-nums = <1>;
rockchip,link-id = <0x04>;
reg = <0x0 0x7c00000 0x0 0x20000>;
memory-region = <&rpmsg_dma_reserved>;
status = "okay";
};
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@ -63,6 +51,18 @@
};
};
rpmsg: rpmsg@7c00000 {
compatible = "rockchip,rpmsg";
mbox-names = "rpmsg-rx", "rpmsg-tx";
mboxes = <&mailbox 0 &mailbox 3>;
rockchip,vdev-nums = <1>;
rockchip,link-id = <0x04>;
reg = <0x0 0x7c00000 0x0 0x20000>;
memory-region = <&rpmsg_dma_reserved>;
status = "okay";
};
};
&mailbox {

View file

@ -2266,6 +2266,7 @@
&i2s0m0_sdo2
&i2s0m0_sdo3>;
#sound-dai-cells = <0>;
sound-name-prefix = "SAI0";
status = "disabled";
};
@ -2293,6 +2294,7 @@
&i2s1m0_sdo2
&i2s1m0_sdo3>;
#sound-dai-cells = <0>;
sound-name-prefix = "SAI1";
status = "disabled";
};
@ -2314,6 +2316,7 @@
&i2s2m0_sdi
&i2s2m0_sdo>;
#sound-dai-cells = <0>;
sound-name-prefix = "SAI2";
status = "disabled";
};

View file

@ -0,0 +1,168 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include <dt-bindings/display/media-bus-format.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3567-evb2-lp4x-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
model = "Rockchip RK3567 EVB2 LP4X V10 Board";
compatible = "rockchip,rk3567-evb2-lp4x-v10", "rockchip,rk3567";
panel {
compatible = "simple-panel";
backlight = <&backlight>;
power-supply = <&vcc3v3_lcd0_n>;
enable-delay-ms = <20>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
bus-format = <MEDIA_BUS_FMT_RGB888_1X7X4_SPWG>;
width-mm = <217>;
height-mm = <136>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <96>;
hfront-porch = <120>;
vback-porch = <16>;
vfront-porch = <64>;
hsync-len = <64>;
vsync-len = <16>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dual-lvds-odd-pixels;
panel_in_lvds0: endpoint {
remote-endpoint = <&lvds0_out_panel>;
};
};
port@1 {
reg = <1>;
dual-lvds-even-pixels;
panel_in_lvds1: endpoint {
remote-endpoint = <&lvds1_out_panel>;
};
};
};
};
};
&backlight1 {
status = "okay";
};
&backlight {
status = "okay";
};
&lvds {
status = "okay";
dual-channel;
ports {
port@1 {
reg = <1>;
lvds0_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds0>;
};
};
};
};
&lvds1 {
status = "okay";
ports {
port@1 {
reg = <1>;
lvds1_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds1>;
};
};
};
};
&lvds_in_vp1 {
status = "okay";
};
&lvds1_in_vp1 {
status = "disabled";
};
&lvds1_in_vp2 {
status = "okay";
};
/* enable hdmi */
&hdmi_in_vp1 {
status = "okay";
};
/* enable video phy */
&video_phy0 {
status = "okay";
};
&video_phy1 {
status = "okay";
};
/* disable other encoder output */
&dsi0 {
status = "disabled";
};
&dsi0_in_vp0 {
status = "disabled";
};
&dsi0_in_vp1 {
status = "disabled";
};
&dsi1_in_vp1 {
status = "disabled";
};
&edp_in_vp1 {
status = "disabled";
};
&rgb_in_vp2 {
status = "disabled";
};
&vcc3v3_lcd0_n {
gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&vcc3v3_lcd1_n {
gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View file

@ -0,0 +1,172 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include <dt-bindings/display/media-bus-format.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3567-evb2-lp4x-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
model = "Rockchip RK3567 EVB2 LP4X V10 Board";
compatible = "rockchip,rk3567-evb2-lp4x-v10", "rockchip,rk3567";
panel {
compatible = "simple-panel";
backlight = <&backlight>;
power-supply = <&vcc3v3_lcd0_n>;
enable-delay-ms = <20>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
bus-format = <MEDIA_BUS_FMT_RGB666_1X7X3_SPWG>;
width-mm = <217>;
height-mm = <136>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <134000000>;
hactive = <1600>;
vactive = <1280>;
hback-porch = <60>;
hfront-porch = <60>;
vback-porch = <4>;
vfront-porch = <2>;
hsync-len = <8>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
/**
* Panel <----> LVDS0
* Panel <----> LVDS1
*/
port@0 {
reg = <0>;
dual-lvds-left-pixels;
panel_in_lvds0: endpoint {
remote-endpoint = <&lvds0_out_panel>;
};
};
port@1 {
reg = <1>;
dual-lvds-right-pixels;
panel_in_lvds1: endpoint {
remote-endpoint = <&lvds1_out_panel>;
};
};
};
};
};
&backlight1 {
status = "okay";
};
&backlight {
status = "okay";
};
&lvds {
status = "okay";
dual-channel;
ports {
port@1 {
reg = <1>;
lvds0_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds0>;
};
};
};
};
&lvds1 {
status = "okay";
ports {
port@1 {
reg = <1>;
lvds1_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds1>;
};
};
};
};
&lvds_in_vp1 {
status = "okay";
};
&lvds1_in_vp1 {
status = "disabled";
};
&lvds1_in_vp2 {
status = "okay";
};
/* enable hdmi */
&hdmi_in_vp1 {
status = "okay";
};
/* enable video phy */
&video_phy0 {
status = "okay";
};
&video_phy1 {
status = "okay";
};
/* disable other encoder output */
&dsi0 {
status = "disabled";
};
&dsi0_in_vp0 {
status = "disabled";
};
&dsi0_in_vp1 {
status = "disabled";
};
&dsi1_in_vp1 {
status = "disabled";
};
&edp_in_vp1 {
status = "disabled";
};
&rgb_in_vp2 {
status = "disabled";
};
&vcc3v3_lcd0_n {
gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&vcc3v3_lcd1_n {
gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View file

@ -24,18 +24,6 @@
};
};
rpmsg: rpmsg@7c00000 {
compatible = "rockchip,rk3568-rpmsg";
mbox-names = "rpmsg-rx", "rpmsg-tx";
mboxes = <&mailbox 0 &mailbox 3>;
rockchip,vdev-nums = <1>;
rockchip,link-id = <0x03>;
reg = <0x0 0x7c00000 0x0 0x20000>;
memory-region = <&rpmsg_dma_reserved>;
status = "okay";
};
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@ -64,6 +52,18 @@
no-map;
};
};
rpmsg: rpmsg@7c00000 {
compatible = "rockchip,rpmsg";
mbox-names = "rpmsg-rx", "rpmsg-tx";
mboxes = <&mailbox 0 &mailbox 3>;
rockchip,vdev-nums = <1>;
rockchip,link-id = <0x03>;
reg = <0x0 0x7c00000 0x0 0x20000>;
memory-region = <&rpmsg_dma_reserved>;
status = "okay";
};
};
&mailbox {

View file

@ -3,12 +3,15 @@
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include <dt-bindings/soc/rockchip-amp.h>
/ {
rockchip_amp: rockchip-amp {
compatible = "rockchip,mcu-amp";
compatible = "rockchip,amp";
clocks = <&cru HCLK_PMU_CM0_ROOT>, <&cru FCLK_PMU_CM0_CORE>,
<&cru CLK_PMU_CM0_RTC>, <&cru PCLK_PMUCM0_INTMUX>,
<&cru SCLK_UART5>, <&cru PCLK_UART5>,
<&cru PCLK_BUSTIMER0>, <&cru CLK_BUSTIMER4>, <&cru CLK_BUSTIMER5>,
<&cru PCLK_BUSTIMER1>, <&cru CLK_BUSTIMER10>, <&cru CLK_BUSTIMER11>;
pinctrl-names = "default";
@ -22,10 +25,44 @@
#size-cells = <2>;
ranges;
/* remote amp core address */
amp_shmem_reserved: amp-shmem@7800000 {
reg = <0x0 0x7800000 0x0 0x400000>;
no-map;
};
rpmsg_reserved: rpmsg@7c00000 {
reg = <0x0 0x07c00000 0x0 0x400000>;
no-map;
};
rpmsg_dma_reserved: rpmsg-dma@8000000 {
compatible = "shared-dma-pool";
reg = <0x0 0x08000000 0x0 0x100000>;
no-map;
};
/* mcu address */
mcu_reserved: mcu@8200000 {
reg = <0x0 0x8200000 0x0 0x100000>;
no-map;
};
};
rpmsg: rpmsg@7c00000 {
compatible = "rockchip,rpmsg";
mbox-names = "rpmsg-rx", "rpmsg-tx";
mboxes = <&mailbox0 0 &mailbox0 3>;
rockchip,vdev-nums = <1>;
rockchip,link-id = <0x03>;
reg = <0x0 0x7c00000 0x0 0x20000>;
memory-region = <&rpmsg_dma_reserved>;
status = "okay";
};
};
&mailbox0 {
rockchip,txpoll-period-ms = <1>;
status = "okay";
};

View file

@ -0,0 +1,71 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
/dts-v1/;
#include "rk3588-evb1-lp4.dtsi"
#include "rk3588-evb1-imx415.dtsi"
#include "rk3588-linux.dtsi"
#include "rk3588-amp.dtsi"
/ {
model = "Rockchip RK3588 EVB1 LP4 V10 Board";
compatible = "rockchip,rk3588-evb1-lp4-v10", "rockchip,rk3588";
cpus {
cpu-map {
cluster0 {
/delete-node/ core3;
};
};
};
memory {
device_type = "memory";
reg = <0x0 0x02000000 0x0 0x06400000>,
<0x0 0x09400000 0x0 0xe6c00000>,
<0x1 0x00000000 0x1 0x00000000>,
<0x2 0xf0000000 0x0 0x10000000>;
};
};
&arm_pmu {
interrupt-affinity = <&cpu_l0>, <&cpu_l1>, <&cpu_l2>,
<&cpu_b0>, <&cpu_b1>, <&cpu_b2>, <&cpu_b3>;
};
/delete-node/ &cpu_l3;
&route_hdmi0 {
status = "okay";
connect = <&vp0_out_hdmi0>;
/delete-property/ force-output;
/delete-node/ force_timing;
};
&route_hdmi1 {
status = "okay";
connect = <&vp1_out_hdmi1>;
/delete-property/ force-output;
/delete-node/ force_timing;
};
&vcc_1v8_s0 {
/delete-property/ regulator-state-mem;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
&vcc_3v3_s0 {
/delete-property/ regulator-state-mem;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};

View file

@ -0,0 +1,696 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96712_dcphy0_osc: max96712-dcphy0-oscillator {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96712-dcphy0-osc";
};
};
&mipi_dcphy0 {
status = "okay";
};
&csi2_dcphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dcphy0_in_max96712: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96712_dcphy0_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidcphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi0_csi2_input>;
};
};
};
};
&i2c8 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c8m2_xfer>;
max96712_dcphy0: max96712@29 {
compatible = "maxim4c,max96712";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96712_dcphy0_osc 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96712_dcphy0_pwdn>, <&max96712_dcphy0_errb>, <&max96712_dcphy0_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96712";
rockchip,camera-module-lens-name = "max96712";
port {
max96712_dcphy0_out: endpoint {
remote-endpoint = <&mipi_dcphy0_in_max96712>;
data-lanes = <1 2>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1280>;
sensor-height = <800>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <12>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy0_link0_in: endpoint {
remote-endpoint = <&max96712_dcphy0_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
0B 06 ef 00 00 // HIM on
0B 07 84 00 00 // Enable HVEN and DBL
0B 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy0_link1_in: endpoint {
remote-endpoint = <&max96712_dcphy0_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
0C 06 ef 00 00 // HIM on
0C 07 84 00 00 // Enable HVEN and DBL
0C 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link C: link-id = 2
gmsl-link-config-2 {
status = "okay";
link-id = <2>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy0_link2_in: endpoint {
remote-endpoint = <&max96712_dcphy0_remote2_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
16 D1 03 00 00 // VGAHiGain
16 45 00 00 00 // Disable SSC
0D 06 ef 00 00 // HIM on
0D 07 84 00 00 // Enable HVEN and DBL
0D 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link D: link-id = 3
gmsl-link-config-3 {
status = "okay";
link-id = <3>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy0_link3_in: endpoint {
remote-endpoint = <&max96712_dcphy0_remote3_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
17 D1 03 00 00 // VGAHiGain
17 45 00 00 00 // Disable SSC
0E 06 ef 00 00 // HIM on
0E 07 84 00 00 // Enable HVEN and DBL
0E 0F 01 00 00 // Disable processing DE signals
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 0
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 0
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
];
};
};
// Video Pipe 2
video-pipe-config-2 {
status = "okay";
pipe-id = <2>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <2>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 2 to Controller 0
09 8B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 AD 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 8D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 8E 9e 00 00 // DST0 VC = 2, DT = YUV422 8bit
09 8F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 90 80 00 00 // DST1 VC = 2, DT = Frame Start
09 91 01 00 00 // SRC2 VC = 0, DT = Frame End
09 92 81 00 00 // DST2 VC = 2, DT = Frame End
];
};
};
// Video Pipe 3
video-pipe-config-3 {
status = "okay";
pipe-id = <3>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <3>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 3 to Controller 0
09 CB 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 ED 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 CD 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 CE de 00 00 // DST0 VC = 3, DT = YUV422 8bit
09 CF 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 D0 c0 00 00 // DST1 VC = 3, DT = Frame Start
09 D1 01 00 00 // SRC2 VC = 0, DT = Frame End
09 D2 c1 00 00 // DST2 VC = 3, DT = Frame End
];
};
};
// Software override for parallel mode
parallel-mode-config {
status = "okay";
parallel-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Enable software override for all pipes since GMSL1 data is parallel mode, bpp=8, dt=0x1e(yuv-8)
04 1A f0 00 00 // pipe 0/1/2/3: Enable YUV8-/10-bit mux mode
04 0B 40 00 00 // pipe 0 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 0C 00 00 00 // pipe 0 and 1 VC software override: 0x00
04 0D 00 00 00 // pipe 2 and 3 VC software override: 0x00
04 0E 5e 00 00 // pipe 0 DT=0x1E: YUV422 8-bit
04 0F 7e 00 00 // pipe 1 DT=0x1E: YUV422 8-bit
04 10 7a 00 00 // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit
04 11 48 00 00 // pipe 1 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 12 20 00 00 // pipe 2 bpp=0x08, pipe 3 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 15 c0 c0 00 // pipe 0/1 enable software overide
04 18 c0 c0 00 // pipe 2/3 enable software overide
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <1>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <0>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x00>;
data-lane-num = <2>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max96715";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
port {
max96712_dcphy0_remote0_out: endpoint {
remote-endpoint = <&max96712_dcphy0_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max96715";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
port {
max96712_dcphy0_remote1_out: endpoint {
remote-endpoint = <&max96712_dcphy0_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-2 {
compatible = "maxim4c,link2,max96715";
status = "okay";
remote-id = <2>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x43>; // 0: disable remap
port {
max96712_dcphy0_remote2_out: endpoint {
remote-endpoint = <&max96712_dcphy0_link2_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-3 {
compatible = "maxim4c,link3,max96715";
status = "okay";
remote-id = <3>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x44>; // 0: disable remap
port {
max96712_dcphy0_remote3_out: endpoint {
remote-endpoint = <&max96712_dcphy0_link3_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
/* serdes remote device end */
};
};
&mipi0_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidcphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi0_in>;
};
};
};
};
&rkcif_mipi_lvds {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi0_in: endpoint {
remote-endpoint = <&mipi0_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96712-dcphy0 {
max96712_dcphy0_pwdn: max96712-dcphy0-pwdn {
rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dcphy0_errb: max96712-dcphy0-errb {
rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dcphy0_lock: max96712-dcphy0-lock {
rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -0,0 +1,466 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96712_dcphy1_osc: max96712-dcphy1-oscillator {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96712-dcphy1-osc";
};
};
&mipi_dcphy1 {
status = "okay";
};
&csi2_dcphy1 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dcphy1_in_max96712: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96712_dcphy1_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidcphy1_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi1_csi2_input>;
};
};
};
};
&i2c2 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c2m4_xfer>;
max96712_dcphy1: max96712@29 {
compatible = "maxim4c,max96712";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96712_dcphy1_osc 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96712_dcphy1_pwdn>, <&max96712_dcphy1_errb>, <&max96712_dcphy1_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio4 RK_PD3 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96712";
rockchip,camera-module-lens-name = "max96712";
port {
max96712_dcphy1_out: endpoint {
remote-endpoint = <&mipi_dcphy1_in_max96712>;
data-lanes = <1 2>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1600>;
sensor-height = <1300>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy1_link0_in: endpoint {
remote-endpoint = <&max96712_dcphy1_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dcphy1_link1_in: endpoint {
remote-endpoint = <&max96712_dcphy1_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 0
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
// pipe Cross
01 D9 59 00 00 // pipe 0: Inverts Cross VS
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 0
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 00 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 0;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
// pipe Cross
01 F9 59 00 00 // pipe 1: Inverts Cross VS
];
};
};
// Software override for parallel mode
parallel-mode-config {
status = "okay";
parallel-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Enable software override for all pipes since GMSL1 data is parallel mode, bpp=8, dt=0x1e(yuv-8)
04 1A f0 00 00 // pipe 0/1/2/3: Enable YUV8-/10-bit mux mode
04 0B 40 00 00 // pipe 0 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 0C 00 00 00 // pipe 0 and 1 VC software override: 0x00
04 0D 00 00 00 // pipe 2 and 3 VC software override: 0x00
04 0E 5e 00 00 // pipe 0 DT=0x1E: YUV422 8-bit
04 0F 7e 00 00 // pipe 1 DT=0x1E: YUV422 8-bit
04 10 7a 00 00 // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit
04 11 48 00 00 // pipe 1 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 12 20 00 00 // pipe 2 bpp=0x08, pipe 3 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 15 c0 c0 00 // pipe 0/1 enable software overide
04 18 c0 c0 00 // pipe 2/3 enable software overide
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <1>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <0>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x00>;
data-lane-num = <2>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max9295";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
port {
max96712_dcphy1_remote0_out: endpoint {
remote-endpoint = <&max96712_dcphy1_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
00 01 04 00 00 // RX_RATE: 187.5Mbps, TX_RATE: 3Gbps
00 11 03 00 00 // Coax Drive
02 D6 03 00 00 // MFP8: GPIO_OUT_DIS = 1, GPIO_TX_EN = 1
03 F0 51 00 00 // RCLK: 27MHz/24MHz (ALT),Enable reference-generation PLL, Enable pre-defined clock setting for reference-generation PLL
00 03 07 00 00 // RCLK: Enable RCLK output from altermative MFP pin, RCLKOUT clock select reference PLL
00 06 b1 00 00 // RCLK: GMSL2, Enable RCLK output, i2c selected
02 C1 10 00 00 // MFP1: GPIO_OUT pin output is driven to 1 when GPIO_RX_EN = 0
02 C2 60 00 00 // MFP1: OUT_TYPE = 1: Push-pull, PULL_UPDN_SEL[1:0] = 0b01: Pullup
00 07 07 00 00 // Enable Parallel video input, Parallel HS and VS Enable
00 10 05 00 00 // AUTO_LINK = 0, LINK_CFG = 1: LinkA is selected, REG_ENABLE = 1: Regulator enabled
00 12 14 00 00 // REG_MNL = 1: Enable LDO on/off state controlled by REG_ENABLE
01 00 62 00 00 // Video X, Line CRC enabled, ENC_MODE = 2: HS, VS, DE encoding on, color bits sent only when DE is high
01 01 50 00 00 // Video X, BPP = 0x10
00 53 10 00 00 // Video X, TX_STR_SEL = 0: Stream ID = 0 for packets from this channel
00 02 13 00 00 // Video transmit enable for Port X
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max9295";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
port {
max96712_dcphy1_remote1_out: endpoint {
remote-endpoint = <&max96712_dcphy1_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
00 01 04 00 00 // RX_RATE: 187.5Mbps, TX_RATE: 3Gbps
00 11 03 00 00 // Coax Drive
02 D6 03 00 00 // MFP8: GPIO_OUT_DIS = 1, GPIO_TX_EN = 1
03 F0 51 00 00 // RCLK: 27MHz/24MHz (ALT),Enable reference-generation PLL, Enable pre-defined clock setting for reference-generation PLL
00 03 07 00 00 // RCLK: Enable RCLK output from altermative MFP pin, RCLKOUT clock select reference PLL
00 06 b1 00 00 // RCLK: GMSL2, Enable RCLK output, i2c selected
02 C1 10 00 00 // MFP1: GPIO_OUT pin output is driven to 1 when GPIO_RX_EN = 0
02 C2 60 00 00 // MFP1: OUT_TYPE = 1: Push-pull, PULL_UPDN_SEL[1:0] = 0b01: Pullup
00 07 07 00 00 // Enable Parallel video input, Parallel HS and VS Enable
00 10 05 00 00 // AUTO_LINK = 0, LINK_CFG = 1: LinkA is selected, REG_ENABLE = 1: Regulator enabled
00 12 14 00 00 // REG_MNL = 1: Enable LDO on/off state controlled by REG_ENABLE
01 00 62 00 00 // Video X, Line CRC enabled, ENC_MODE = 2: HS, VS, DE encoding on, color bits sent only when DE is high
01 01 50 00 00 // Video X, BPP = 0x10
00 53 10 00 00 // Video X, TX_STR_SEL = 0: Stream ID = 0 for packets from this channel
00 02 13 00 00 // Video transmit enable for Port X
];
};
};
/* serdes remote device end */
};
};
&mipi1_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi1_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidcphy1_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi1_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi1_in>;
};
};
};
};
&rkcif_mipi_lvds1 {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi1_in: endpoint {
remote-endpoint = <&mipi1_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96712-dcphy1 {
max96712_dcphy1_pwdn: max96712-dcphy1-pwdn {
rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dcphy1_errb: max96712-dcphy1-errb {
rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dcphy1_lock: max96712-dcphy1-lock {
rockchip,pins = <4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -0,0 +1,708 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96712_dphy0_osc0: max96712-dphy0-oscillator@0 {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96712-dphy0-osc0";
};
};
&csi2_dphy0_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dphy0_in_max96712: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96712_dphy0_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
};
};
};
};
&i2c7 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c7m3_xfer>;
max96712_dphy0: max96712@29 {
compatible = "maxim4c,max96712";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96712_dphy0_osc0 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96712_dphy0_pwdn>, <&max96712_dphy0_errb>, <&max96712_dphy0_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96712";
rockchip,camera-module-lens-name = "max96712";
port {
max96712_dphy0_out: endpoint {
remote-endpoint = <&mipi_dphy0_in_max96712>;
data-lanes = <1 2 3 4>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1280>;
sensor-height = <800>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dphy0_link0_in: endpoint {
remote-endpoint = <&max96712_dphy0_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
0B 06 ef 00 00 // HIM on
0B 07 84 00 00 // Enable HVEN and DBL
0B 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dphy0_link1_in: endpoint {
remote-endpoint = <&max96712_dphy0_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
0C 06 ef 00 00 // HIM on
0C 07 84 00 00 // Enable HVEN and DBL
0C 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link C: link-id = 2
gmsl-link-config-2 {
status = "okay";
link-id = <2>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dphy0_link2_in: endpoint {
remote-endpoint = <&max96712_dphy0_remote2_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
16 D1 03 00 00 // VGAHiGain
16 45 00 00 00 // Disable SSC
0D 06 ef 00 00 // HIM on
0D 07 84 00 00 // Enable HVEN and DBL
0D 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link D: link-id = 3
gmsl-link-config-3 {
status = "okay";
link-id = <3>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96712_dphy0_link3_in: endpoint {
remote-endpoint = <&max96712_dphy0_remote3_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
17 D1 03 00 00 // VGAHiGain
17 45 00 00 00 // Disable SSC
0E 06 ef 00 00 // HIM on
0E 07 84 00 00 // Enable HVEN and DBL
0E 0F 01 00 00 // Disable processing DE signals
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 1
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 1
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
];
};
};
// Video Pipe 2
video-pipe-config-2 {
status = "okay";
pipe-id = <2>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <2>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 2 to Controller 1
09 8B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 AD 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 8D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 8E 9e 00 00 // DST0 VC = 2, DT = YUV422 8bit
09 8F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 90 80 00 00 // DST1 VC = 2, DT = Frame Start
09 91 01 00 00 // SRC2 VC = 0, DT = Frame End
09 92 81 00 00 // DST2 VC = 2, DT = Frame End
];
};
};
// Video Pipe 3
video-pipe-config-3 {
status = "okay";
pipe-id = <3>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <3>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 3 to Controller 1
09 CB 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 ED 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 CD 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 CE de 00 00 // DST0 VC = 3, DT = YUV422 8bit
09 CF 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 D0 c0 00 00 // DST1 VC = 3, DT = Frame Start
09 D1 01 00 00 // SRC2 VC = 0, DT = Frame End
09 D2 c1 00 00 // DST2 VC = 3, DT = Frame End
];
};
};
// Software override for parallel mode
parallel-mode-config {
status = "okay";
parallel-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Enable software override for all pipes since GMSL1 data is parallel mode, bpp=8, dt=0x1e(yuv-8)
04 1A f0 00 00 // pipe 0/1/2/3: Enable YUV8-/10-bit mux mode
04 0B 40 00 00 // pipe 0 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 0C 00 00 00 // pipe 0 and 1 VC software override: 0x00
04 0D 00 00 00 // pipe 2 and 3 VC software override: 0x00
04 0E 5e 00 00 // pipe 0 DT=0x1E: YUV422 8-bit
04 0F 7e 00 00 // pipe 1 DT=0x1E: YUV422 8-bit
04 10 7a 00 00 // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit
04 11 48 00 00 // pipe 1 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 12 20 00 00 // pipe 2 bpp=0x08, pipe 3 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 15 c0 c0 00 // pipe 0/1 enable software overide
04 18 c0 c0 00 // pipe 2/3 enable software overide
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <0>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <1>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
// MIPI TXPHY B: phy-id = 1
mipi-txphy-config-1 {
status = "okay";
phy-id = <1>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0xe>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max96715";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
port {
max96712_dphy0_remote0_out: endpoint {
remote-endpoint = <&max96712_dphy0_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max96715";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
port {
max96712_dphy0_remote1_out: endpoint {
remote-endpoint = <&max96712_dphy0_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-2 {
compatible = "maxim4c,link2,max96715";
status = "okay";
remote-id = <2>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x43>; // 0: disable remap
port {
max96712_dphy0_remote2_out: endpoint {
remote-endpoint = <&max96712_dphy0_link2_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-3 {
compatible = "maxim4c,link3,max96715";
status = "okay";
remote-id = <3>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x44>; // 0: disable remap
port {
max96712_dphy0_remote3_out: endpoint {
remote-endpoint = <&max96712_dphy0_link3_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
/* serdes remote device end */
};
};
&mipi2_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi2_in>;
};
};
};
};
&rkcif_mipi_lvds2 {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi2_in: endpoint {
remote-endpoint = <&mipi2_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96712-dphy0 {
max96712_dphy0_pwdn: max96712-dphy0-pwdn {
rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy0_errb: max96712-dphy0-errb {
rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy0_lock: max96712-dphy0-lock {
rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -0,0 +1,613 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96712_dphy3_osc0: max96712-dphy3-oscillator@0 {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96712-dphy3-osc0";
};
};
&csi2_dphy1_hw {
status = "okay";
};
&csi2_dphy3 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dphy3_in_max96712: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96712_dphy3_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy3_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi4_csi2_input>;
};
};
};
};
&i2c6 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c6m3_xfer>;
max96712_dphy3: max96712@29 {
compatible = "maxim4c,max96712";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96712_dphy3_osc0 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96712_dphy3_pwdn>, <&max96712_dphy3_errb>, <&max96712_dphy3_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96712";
rockchip,camera-module-lens-name = "max96712";
port {
max96712_dphy3_out: endpoint {
remote-endpoint = <&mipi_dphy3_in_max96712>;
data-lanes = <1 2 3 4>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1920>;
sensor-height = <1440>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <1>;
link-tx-rate = <0>;
port {
max96712_dphy3_link0_in: endpoint {
remote-endpoint = <&max96712_dphy3_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <1>;
link-tx-rate = <0>;
port {
max96712_dphy3_link1_in: endpoint {
remote-endpoint = <&max96712_dphy3_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
];
};
};
// Link C: link-id = 2
gmsl-link-config-2 {
status = "okay";
link-id = <2>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <1>;
link-tx-rate = <0>;
port {
max96712_dphy3_link2_in: endpoint {
remote-endpoint = <&max96712_dphy3_remote2_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
16 D1 03 00 00 // VGAHiGain
16 45 00 00 00 // Disable SSC
];
};
};
// Link D: link-id = 3
gmsl-link-config-3 {
status = "okay";
link-id = <3>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <1>;
link-tx-rate = <0>;
port {
max96712_dphy3_link3_in: endpoint {
remote-endpoint = <&max96712_dphy3_remote3_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
17 D1 03 00 00 // VGAHiGain
17 45 00 00 00 // Disable SSC
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <2>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 1
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <2>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 1
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
];
};
};
// Video Pipe 2
video-pipe-config-2 {
status = "okay";
pipe-id = <2>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <2>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <2>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 2 to Controller 1
09 8B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 AD 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 8D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 8E 9e 00 00 // DST0 VC = 2, DT = YUV422 8bit
09 8F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 90 80 00 00 // DST1 VC = 2, DT = Frame Start
09 91 01 00 00 // SRC2 VC = 0, DT = Frame End
09 92 81 00 00 // DST2 VC = 2, DT = Frame End
];
};
};
// Video Pipe 3
video-pipe-config-3 {
status = "okay";
pipe-id = <3>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <2>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <3>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 3 to Controller 1
09 CB 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 ED 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 CD 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 CE de 00 00 // DST0 VC = 3, DT = YUV422 8bit
09 CF 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 D0 c0 00 00 // DST1 VC = 3, DT = Frame Start
09 D1 01 00 00 // SRC2 VC = 0, DT = Frame End
09 D2 c1 00 00 // DST2 VC = 3, DT = Frame End
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <0>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <1>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
// MIPI TXPHY B: phy-id = 1
mipi-txphy-config-1 {
status = "okay";
phy-id = <1>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0xe>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max96717";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
// Camera i2c 7bit address remap
cam-i2c-addr-def = <0x30>;
cam-i2c-addr-map = <0x31>; // 0: disable remap
port {
max96712_dphy3_remote0_out: endpoint {
remote-endpoint = <&max96712_dphy3_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
03 02 10 00 00
14 17 00 00 00
14 32 7f 00 00
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max96717";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
// Camera i2c 7bit address remap
cam-i2c-addr-def = <0x30>;
cam-i2c-addr-map = <0x32>; // 0: disable remap
port {
max96712_dphy3_remote1_out: endpoint {
remote-endpoint = <&max96712_dphy3_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
03 02 10 00 00
14 17 00 00 00
14 32 7f 00 00
];
};
};
serdes-remote-device-2 {
compatible = "maxim4c,link2,max96717";
status = "okay";
remote-id = <2>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x43>; // 0: disable remap
// Camera i2c 7bit address remap
cam-i2c-addr-def = <0x30>;
cam-i2c-addr-map = <0x33>; // 0: disable remap
port {
max96712_dphy3_remote2_out: endpoint {
remote-endpoint = <&max96712_dphy3_link2_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
03 02 10 00 00
14 17 00 00 00
14 32 7f 00 00
];
};
};
serdes-remote-device-3 {
compatible = "maxim4c,link3,max96717";
status = "okay";
remote-id = <3>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x44>; // 0: disable remap
// Camera i2c 7bit address remap
cam-i2c-addr-def = <0x30>;
cam-i2c-addr-map = <0x34>; // 0: disable remap
port {
max96712_dphy3_remote3_out: endpoint {
remote-endpoint = <&max96712_dphy3_link3_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
03 02 10 00 00
14 17 00 00 00
14 32 7f 00 00
];
};
};
/* serdes remote device end */
};
};
&mipi4_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi4_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy3_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi4_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi4_in>;
};
};
};
};
&rkcif_mipi_lvds4 {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi4_in: endpoint {
remote-endpoint = <&mipi4_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96712-dphy3 {
max96712_dphy3_pwdn: max96712-dphy3-pwdn {
rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy3_errb: max96712-dphy3-errb {
rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy3_lock: max96712-dphy3-lock {
rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -0,0 +1,708 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96722_dphy0_osc0: max96722-dphy0-oscillator@0 {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96722-dphy0-osc0";
};
};
&csi2_dphy0_hw {
status = "okay";
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dphy0_in_max96722: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96722_dphy0_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
};
};
};
};
&i2c7 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c7m3_xfer>;
max96722_dphy0: max96722@29 {
compatible = "maxim4c,max96722";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96722_dphy0_osc0 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96722_dphy0_pwdn>, <&max96722_dphy0_errb>, <&max96722_dphy0_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96722";
rockchip,camera-module-lens-name = "max96722";
port {
max96722_dphy0_out: endpoint {
remote-endpoint = <&mipi_dphy0_in_max96722>;
data-lanes = <1 2 3 4>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1280>;
sensor-height = <800>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy0_link0_in: endpoint {
remote-endpoint = <&max96722_dphy0_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
0B 06 ef 00 00 // HIM on
0B 07 84 00 00 // Enable HVEN and DBL
0B 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy0_link1_in: endpoint {
remote-endpoint = <&max96722_dphy0_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
0C 06 ef 00 00 // HIM on
0C 07 84 00 00 // Enable HVEN and DBL
0C 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link C: link-id = 2
gmsl-link-config-2 {
status = "okay";
link-id = <2>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy0_link2_in: endpoint {
remote-endpoint = <&max96722_dphy0_remote2_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
16 D1 03 00 00 // VGAHiGain
16 45 00 00 00 // Disable SSC
0D 06 ef 00 00 // HIM on
0D 07 84 00 00 // Enable HVEN and DBL
0D 0F 01 00 00 // Disable processing DE signals
];
};
};
// Link D: link-id = 3
gmsl-link-config-3 {
status = "okay";
link-id = <3>; // Link ID: 0/1/2/3
link-type = <0>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy0_link3_in: endpoint {
remote-endpoint = <&max96722_dphy0_remote3_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
17 D1 03 00 00 // VGAHiGain
17 45 00 00 00 // Disable SSC
0E 06 ef 00 00 // HIM on
0E 07 84 00 00 // Enable HVEN and DBL
0E 0F 01 00 00 // Disable processing DE signals
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 1
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 1
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
];
};
};
// Video Pipe 2
video-pipe-config-2 {
status = "okay";
pipe-id = <2>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <2>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 2 to Controller 1
09 8B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 AD 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 8D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 8E 9e 00 00 // DST0 VC = 2, DT = YUV422 8bit
09 8F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 90 80 00 00 // DST1 VC = 2, DT = Frame Start
09 91 01 00 00 // SRC2 VC = 0, DT = Frame End
09 92 81 00 00 // DST2 VC = 2, DT = Frame End
];
};
};
// Video Pipe 3
video-pipe-config-3 {
status = "okay";
pipe-id = <3>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <3>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 3 to Controller 1
09 CB 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 ED 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 CD 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 CE de 00 00 // DST0 VC = 3, DT = YUV422 8bit
09 CF 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 D0 c0 00 00 // DST1 VC = 3, DT = Frame Start
09 D1 01 00 00 // SRC2 VC = 0, DT = Frame End
09 D2 c1 00 00 // DST2 VC = 3, DT = Frame End
];
};
};
// Software override for parallel mode
parallel-mode-config {
status = "okay";
parallel-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Enable software override for all pipes since GMSL1 data is parallel mode, bpp=8, dt=0x1e(yuv-8)
04 1A f0 00 00 // pipe 0/1/2/3: Enable YUV8-/10-bit mux mode
04 0B 40 00 00 // pipe 0 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 0C 00 00 00 // pipe 0 and 1 VC software override: 0x00
04 0D 00 00 00 // pipe 2 and 3 VC software override: 0x00
04 0E 5e 00 00 // pipe 0 DT=0x1E: YUV422 8-bit
04 0F 7e 00 00 // pipe 1 DT=0x1E: YUV422 8-bit
04 10 7a 00 00 // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit
04 11 48 00 00 // pipe 1 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 12 20 00 00 // pipe 2 bpp=0x08, pipe 3 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 15 c0 c0 00 // pipe 0/1 enable software overide
04 18 c0 c0 00 // pipe 2/3 enable software overide
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <0>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <1>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
// MIPI TXPHY B: phy-id = 1
mipi-txphy-config-1 {
status = "okay";
phy-id = <1>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0xe>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max96715";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
port {
max96722_dphy0_remote0_out: endpoint {
remote-endpoint = <&max96722_dphy0_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max96715";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
port {
max96722_dphy0_remote1_out: endpoint {
remote-endpoint = <&max96722_dphy0_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-2 {
compatible = "maxim4c,link2,max96715";
status = "okay";
remote-id = <2>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x43>; // 0: disable remap
port {
max96722_dphy0_remote2_out: endpoint {
remote-endpoint = <&max96722_dphy0_link2_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
serdes-remote-device-3 {
compatible = "maxim4c,link3,max96715";
status = "okay";
remote-id = <3>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x44>; // 0: disable remap
port {
max96722_dphy0_remote3_out: endpoint {
remote-endpoint = <&max96722_dphy0_link3_in>;
};
};
remote-init-sequence {
seq-item-size = <4>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <1>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
07 84 00 00
67 c4 00 00
0F bf 00 00
3F 08 00 00
40 2d 00 00
20 10 00 00
21 11 00 00
22 12 00 00
23 13 00 00
24 14 00 00
25 15 00 00
26 16 00 00
27 17 00 00
30 00 00 00
31 01 00 00
32 02 00 00
33 03 00 00
34 04 00 00
35 05 00 00
36 06 00 00
37 07 00 00
];
};
};
/* serdes remote device end */
};
};
&mipi2_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi2_in>;
};
};
};
};
&rkcif_mipi_lvds2 {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi2_in: endpoint {
remote-endpoint = <&mipi2_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96722-dphy0 {
max96722_dphy0_pwdn: max96722-dphy0-pwdn {
rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96722_dphy0_errb: max96722-dphy0-errb {
rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96722_dphy0_lock: max96722-dphy0-lock {
rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -0,0 +1,478 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
/ {
max96722_dphy3_osc0: max96722-dphy3-oscillator@0 {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
clock-output-names = "max96722-dphy3-osc0";
};
};
&csi2_dphy1_hw {
status = "okay";
};
&csi2_dphy3 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_dphy3_in_max96722: endpoint@1 {
reg = <1>;
remote-endpoint = <&max96722_dphy3_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy3_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi4_csi2_input>;
};
};
};
};
&i2c6 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c6m3_xfer>;
max96722_dphy3: max96722@29 {
compatible = "maxim4c,max96722";
status = "okay";
reg = <0x29>;
clock-names = "xvclk";
clocks = <&max96722_dphy3_osc0 0>;
pinctrl-names = "default";
pinctrl-0 = <&max96722_dphy3_pwdn>, <&max96722_dphy3_errb>, <&max96722_dphy3_lock>;
power-domains = <&power RK3588_PD_VI>;
rockchip,grf = <&sys_grf>;
pwdn-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
pocen-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_HIGH>;
lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "max96722";
rockchip,camera-module-lens-name = "max96722";
port {
max96722_dphy3_out: endpoint {
remote-endpoint = <&mipi_dphy3_in_max96722>;
data-lanes = <1 2 3 4>;
};
};
/* support mode config start */
support-mode-config {
status = "okay";
bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
sensor-width = <1600>;
sensor-height = <1300>;
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */
/* serdes local device start */
serdes-local-device {
status = "okay";
/* GMSL LINK config start */
gmsl-links {
status = "okay";
link-vdd-ldo1-en = <1>;
link-vdd-ldo2-en = <1>;
// Link A: link-id = 0
gmsl-link-config-0 {
status = "okay";
link-id = <0>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy3_link0_in: endpoint {
remote-endpoint = <&max96722_dphy3_remote0_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
14 D1 03 00 00 // VGAHiGain
14 45 00 00 00 // Disable SSC
];
};
};
// Link B: link-id = 1
gmsl-link-config-1 {
status = "okay";
link-id = <1>; // Link ID: 0/1/2/3
link-type = <1>;
link-rx-rate = <0>;
link-tx-rate = <0>;
port {
max96722_dphy3_link1_in: endpoint {
remote-endpoint = <&max96722_dphy3_remote1_out>;
};
};
link-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
15 D1 03 00 00 // VGAHiGain
15 45 00 00 00 // Disable SSC
];
};
};
};
/* GMSL LINK config end */
/* VIDEO PIPE config start */
video-pipes {
status = "okay";
// Video Pipe 0
video-pipe-config-0 {
status = "okay";
pipe-id = <0>; // Video Pipe ID: 0/1/2/3/4/5/6/7
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <0>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 0 to Controller 1
09 0B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 2D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 0D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 0E 1e 00 00 // DST0 VC = 0, DT = YUV422 8bit
09 0F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 10 00 00 00 // DST1 VC = 0, DT = Frame Start
09 11 01 00 00 // SRC2 VC = 0, DT = Frame End
09 12 01 00 00 // DST2 VC = 0, DT = Frame End
// pipe Cross
01 D9 59 00 00 // pipe 0: Inverts Cross VS
];
};
};
// Video Pipe 1
video-pipe-config-1 {
status = "okay";
pipe-id = <1>; // Video Pipe 1: pipe-id = 1
pipe-idx = <0>; // Video Pipe X/Y/Z/U: 0/1/2/3
link-idx = <1>; // Link A/B/C/D: 0/1/2/3
pipe-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Send YUV422, FS, and FE from Video Pipe 1 to Controller 1
09 4B 07 00 00 // Enable 0/1/2 SRC/DST Mappings
09 6D 15 00 00 // SRC/DST 0/1/2 -> CSI2 Controller 1;
// For the following MSB 2 bits = VC, LSB 6 bits = DT
09 4D 1e 00 00 // SRC0 VC = 0, DT = YUV422 8bit
09 4E 5e 00 00 // DST0 VC = 1, DT = YUV422 8bit
09 4F 00 00 00 // SRC1 VC = 0, DT = Frame Start
09 50 40 00 00 // DST1 VC = 1, DT = Frame Start
09 51 01 00 00 // SRC2 VC = 0, DT = Frame End
09 52 41 00 00 // DST2 VC = 1, DT = Frame End
// pipe Cross
01 F9 59 00 00 // pipe 1: Inverts Cross VS
];
};
};
// Software override for parallel mode
parallel-mode-config {
status = "okay";
parallel-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// Enable software override for all pipes since GMSL1 data is parallel mode, bpp=8, dt=0x1e(yuv-8)
04 1A f0 00 00 // pipe 0/1/2/3: Enable YUV8-/10-bit mux mode
04 0B 40 00 00 // pipe 0 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 0C 00 00 00 // pipe 0 and 1 VC software override: 0x00
04 0D 00 00 00 // pipe 2 and 3 VC software override: 0x00
04 0E 5e 00 00 // pipe 0 DT=0x1E: YUV422 8-bit
04 0F 7e 00 00 // pipe 1 DT=0x1E: YUV422 8-bit
04 10 7a 00 00 // pipe 2 DT=0x1E, pipe 3 DT=0x1E: YUV422 8-bit
04 11 48 00 00 // pipe 1 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 12 20 00 00 // pipe 2 bpp=0x08, pipe 3 bpp=0x08: Datatypes = 0x2A, 0x10-12, 0x31-37
04 15 c0 c0 00 // pipe 0/1 enable software overide
04 18 c0 c0 00 // pipe 2/3 enable software overide
];
};
};
};
/* VIDEO PIPE config end */
/* MIPI TXPHY config start */
mipi-txphys {
status = "okay";
phy-mode = <0>;
phy-force-clock-out = <1>;
phy-force-clk0-en = <1>;
phy-force-clk3-en = <0>;
// MIPI TXPHY A: phy-id = 0
mipi-txphy-config-0 {
status = "okay";
phy-id = <0>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0x4>;
vc-ext-en = <0>;
};
// MIPI TXPHY B: phy-id = 1
mipi-txphy-config-1 {
status = "okay";
phy-id = <1>; // MIPI TXPHY ID: 0/1/2/3
phy-type = <0>;
auto-deskew = <0x80>;
data-lane-num = <4>;
data-lane-map = <0xe>;
vc-ext-en = <0>;
};
};
/* MIPI TXPHY config end */
/* local device extra init sequence */
extra-init-sequence {
status = "disabled";
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
// common init sequence such as fsync / gpio and so on
];
};
};
/* serdes local device end */
/* serdes remote device start */
serdes-remote-device-0 {
compatible = "maxim4c,link0,max9295";
status = "okay";
remote-id = <0>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x41>; // 0: disable remap
port {
max96722_dphy3_remote0_out: endpoint {
remote-endpoint = <&max96722_dphy3_link0_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
00 01 04 00 00 // RX_RATE: 187.5Mbps, TX_RATE: 3Gbps
00 11 03 00 00 // Coax Drive
02 D6 03 00 00 // MFP8: GPIO_OUT_DIS = 1, GPIO_TX_EN = 1
03 F0 51 00 00 // RCLK: 27MHz/24MHz (ALT),Enable reference-generation PLL, Enable pre-defined clock setting for reference-generation PLL
00 03 07 00 00 // RCLK: Enable RCLK output from altermative MFP pin, RCLKOUT clock select reference PLL
00 06 b1 00 00 // RCLK: GMSL2, Enable RCLK output, i2c selected
02 C1 10 00 00 // MFP1: GPIO_OUT pin output is driven to 1 when GPIO_RX_EN = 0
02 C2 60 00 00 // MFP1: OUT_TYPE = 1: Push-pull, PULL_UPDN_SEL[1:0] = 0b01: Pullup
00 07 07 00 00 // Enable Parallel video input, Parallel HS and VS Enable
00 10 05 00 00 // AUTO_LINK = 0, LINK_CFG = 1: LinkA is selected, REG_ENABLE = 1: Regulator enabled
00 12 14 00 00 // REG_MNL = 1: Enable LDO on/off state controlled by REG_ENABLE
01 00 62 00 00 // Video X, Line CRC enabled, ENC_MODE = 2: HS, VS, DE encoding on, color bits sent only when DE is high
01 01 50 00 00 // Video X, BPP = 0x10
00 53 10 00 00 // Video X, TX_STR_SEL = 0: Stream ID = 0 for packets from this channel
00 02 13 00 00 // Video transmit enable for Port X
];
};
};
serdes-remote-device-1 {
compatible = "maxim4c,link1,max9295";
status = "okay";
remote-id = <1>; // Same as Link ID: 0/1/2/3
// Serializer i2c 7bit address remap
ser-i2c-addr-def = <0x40>;
ser-i2c-addr-map = <0x42>; // 0: disable remap
port {
max96722_dphy3_remote1_out: endpoint {
remote-endpoint = <&max96722_dphy3_link1_in>;
};
};
remote-init-sequence {
seq-item-size = <5>; // reg-addr-len + reg-val-len * 2 + 1
reg-addr-len = <2>; // 1: 8bits, 2: 16bits
reg-val-len = <1>; // 1: 8bits, 2: 16bits, 3: 24bits
// reg_addr reg_val val_mask delay
init-sequence = [
00 01 04 00 00 // RX_RATE: 187.5Mbps, TX_RATE: 3Gbps
00 11 03 00 00 // Coax Drive
02 D6 03 00 00 // MFP8: GPIO_OUT_DIS = 1, GPIO_TX_EN = 1
03 F0 51 00 00 // RCLK: 27MHz/24MHz (ALT),Enable reference-generation PLL, Enable pre-defined clock setting for reference-generation PLL
00 03 07 00 00 // RCLK: Enable RCLK output from altermative MFP pin, RCLKOUT clock select reference PLL
00 06 b1 00 00 // RCLK: GMSL2, Enable RCLK output, i2c selected
02 C1 10 00 00 // MFP1: GPIO_OUT pin output is driven to 1 when GPIO_RX_EN = 0
02 C2 60 00 00 // MFP1: OUT_TYPE = 1: Push-pull, PULL_UPDN_SEL[1:0] = 0b01: Pullup
00 07 07 00 00 // Enable Parallel video input, Parallel HS and VS Enable
00 10 05 00 00 // AUTO_LINK = 0, LINK_CFG = 1: LinkA is selected, REG_ENABLE = 1: Regulator enabled
00 12 14 00 00 // REG_MNL = 1: Enable LDO on/off state controlled by REG_ENABLE
01 00 62 00 00 // Video X, Line CRC enabled, ENC_MODE = 2: HS, VS, DE encoding on, color bits sent only when DE is high
01 01 50 00 00 // Video X, BPP = 0x10
00 53 10 00 00 // Video X, TX_STR_SEL = 0: Stream ID = 0 for packets from this channel
00 02 13 00 00 // Video transmit enable for Port X
];
};
};
/* serdes remote device end */
};
};
&mipi4_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi4_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy3_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi4_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi4_in>;
};
};
};
};
&rkcif_mipi_lvds4 {
status = "okay";
/* parameters for do cif reset detecting:
* index0: monitor mode,
0 for idle,
1 for continue,
2 for trigger,
3 for hotplug (for nextchip)
* index1: the frame id to start timer,
min is 2
* index2: frame num of monitoring cycle
* index3: err time for keep monitoring
after finding out err (ms)
* index4: csi2 err reference val for resetting
*/
rockchip,cif-monitor = <3 2 1 1000 5>;
port {
cif_mipi4_in: endpoint {
remote-endpoint = <&mipi4_csi2_output>;
};
};
};
&rkcif {
status = "okay";
rockchip,android-usb-camerahal-enable;
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
max96722-dphy3 {
max96722_dphy3_pwdn: max96722-dphy3-pwdn {
rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96722_dphy3_errb: max96722-dphy3-errb {
rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96722_dphy3_lock: max96722-dphy3-lock {
rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};

View file

@ -7,8 +7,8 @@
/dts-v1/;
#include "rk3588-vehicle-evb-v21.dtsi"
#include "rk3588-vehicle-evb-maxim-max96712.dtsi"
#include "rk3588-vehicle-serdes-display-v21.dtsi"
#include "rk3588-vehicle-evb-maxim-max96712-dphy3.dtsi"
#include "rk3588-vehicle-serdes-mfd-display-rohm.dtsi"
#include "rk3588-android.dtsi"
/ {
@ -55,6 +55,32 @@
};
};
&i2c2 {
himax@48 {
himax,irq-gpio = <&gpio1 RK_PB0 IRQ_TYPE_EDGE_FALLING>;
};
};
&i2c4 {
himax@48 {
himax,irq-gpio = <&gpio3 RK_PC5 IRQ_TYPE_EDGE_FALLING>;
};
};
&i2c5 {
ilitek@41 {
interrupt-parent = <&gpio0>;
interrupts = <RK_PD4 IRQ_TYPE_LEVEL_LOW>;
reset-gpio = <&gpio0 RK_PD1 GPIO_ACTIVE_LOW>;
};
};
&i2c6 {
himax@48 {
himax,irq-gpio = <&gpio1 RK_PB7 IRQ_TYPE_EDGE_FALLING>; //use rst as int
};
};
&i2s2_2ch {
pinctrl-0 = <&i2s2m1_lrck
&i2s2m1_sclk
@ -63,6 +89,78 @@
status = "okay";
};
&pinctrl {
bl {
bl0_enable_pin: bl0-enable-pin {
rockchip,pins =
<1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>,
<4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>,
<4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl1_enable_pin: bl1-enable-pin {
rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl2_enable_pin: bl2-enable-pin {
rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl3_enable_pin: bl3-enable-pin {
rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl4_enable_pin: bl4-enable-pin {
rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl5_enable_pin: bl5-enable-pin {
rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
serdes {
//dsi0
ser0_rst_pin: ser0-rst-pin {
rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
};
//dsi1
ser1_rst_pin: ser1-rst-pin {
rockchip,pins = <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
touch {
//dsi0-i2c2
touch_gpio_dsi0: touch-gpio-dsi0 {
rockchip,pins =
<1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; //rst
};
//dsi1-i2c6
touch_gpio_dsi1: touch-gpio-dsi1 {
rockchip,pins =
<1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>, //rst
<1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; //int
};
//dp0-i2c4
touch_gpio_dp0: touch-gpio-dp0 {
rockchip,pins =
<3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>, //rst
<0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>; //int
};
//edp0-i2c5
touch_gpio_edp0: touch-gpio-edp0 {
rockchip,pins =
<0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>, //rst
<0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; //int
};
};
};
&rockchip_suspend {
rockchip,sleep-mode-config = <
(0

View file

@ -0,0 +1,36 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
/ {
nca9539_vdd: nca9539-vdd3v3 {
compatible = "regulator-fixed";
regulator-name = "nca9539_vdd";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
startup-delay-us = <20>; // NCA9539 POR
vin-supply = <&vcc_3v3_s0>;
};
};
&i2c5 {
clock-frequency = <400000>;
status = "okay";
nca9539_gpio: gpio@74 {
status = "okay";
compatible = "novo,nca9539-gpio";
reg = <0x74>;
gpio-controller;
#gpio-cells = <2>;
ngpios = <16>;
interrupt-controller;
#interrupt-cells = <2>;
vdd-supply = <&nca9539_vdd>;
};
};

View file

@ -0,0 +1,594 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
/dts-v1/;
#include "rk3588-vehicle-evb-v21.dtsi"
#include "rk3588-vehicle-evb-maxim-max96712-dphy3.dtsi"
#include "rk3588-vehicle-serdes-mfd-display-rohm.dtsi"
#include "rk3588-android.dtsi"
/ {
model = "Rockchip RK3588 VEHICLE EVB V22 Board";
compatible = "rockchip,rk3588-vehicle-evb-v22", "rockchip,rk3588";
vcc5v0_buck: vcc5v0-buck {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
gpio = <&gpio4 RK_PC3 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
pinctrl-names = "default";
pinctrl-0 = <&vcc5v0_buck_en>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <5000000>;
};
};
vcc4v0_sys_mode: vcc4v0-sys-mode {
compatible = "regulator-fixed";
regulator-name = "vcc4v0_sys_mode";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <4000000>;
regulator-max-microvolt = <4000000>;
enable-active-high;
gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>;
vin-supply = <&vcc12v_dcin>;
pinctrl-names = "default";
pinctrl-0 = <&vcc4v0_sys_mode_en>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <4000000>;
};
};
lcd1_vcc12v_buck: lcd1_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd1_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 0 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
lcd2_vcc12v_buck: lcd2_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd2_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 1 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
lcd3_vcc12v_buck: lcd3_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd3_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 2 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
lcd4_vcc12v_buck: lcd4_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd4_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 3 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
lcd5_vcc12v_buck: lcd5_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd5_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 4 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
lcd6_vcc12v_buck: lcd6_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "lcd6_vcc12v_buck";
regulator-boot-on;
//regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 5 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
camera1_vcc12v_buck: camera1_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera1_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 6 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
camera2_vcc12v_buck: camera2_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera2_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 7 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
camera3_vcc12v_buck: camera3_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera3_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 8 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
camera4_vcc12v_buck: camera4_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera4_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 9 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
vcc5v0_host_usb20: vcc5v0-host-usb20 {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_host_usb20";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 10 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc5v0_usb>;
};
vcc5v0_host_usb30: vcc5v0-host-usb30 {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_host_usb30";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 11 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc5v0_usb>;
};
adsp_vcc12v_buck: adsp_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "adsp_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 12 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc12v_dcin>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
minipcie_power_buck: minipcie_power-buck {
compatible = "regulator-fixed";
regulator-name = "minipcie_power_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
gpio = <&i2c5_nca9539_gpio 13 GPIO_ACTIVE_HIGH>;
vin-supply = <&vcc5v0_usb>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <12000000>;
};
};
bt-sound {
compatible = "simple-audio-card";
simple-audio-card,format = "dsp_a";
simple-audio-card,bitclock-inversion = <1>;
simple-audio-card,mclk-fs = <256>;
simple-audio-card,name = "rockchip,bt";
simple-audio-card,cpu {
sound-dai = <&i2s2_2ch>;
};
simple-audio-card,codec {
sound-dai = <&bt_sco 1>;
};
};
bt_sco: bt-sco {
compatible = "delta,dfbmcs320";
#sound-dai-cells = <1>;
status = "okay";
};
gpio-keys {
compatible = "gpio-keys";
autorepeat;
reverse {
label = "GPIO Key Reverse";
linux,code = <KEY_CAMERA_DOWN>;
gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
debounce-interval = <100>;
};
park {
label = "GPIO Key Park";
linux,code = <KEY_CAMERA>;
gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
debounce-interval = <100>;
};
};
vcc3v3_pcie_wifi: vcc3v3-pcie-wifi {
compatible = "regulator-fixed";
regulator-name = "vcc3v3_pcie_wifi";
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-high;
gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
startup-delay-us = <5000>;
vin-supply = <&vcc_3v3_s3>;
};
wireless_bluetooth: wireless-bluetooth {
BT,reset_gpio = <&gpio0 RK_PD1 GPIO_ACTIVE_HIGH>;
status = "okay";
};
wireless_wlan: wireless-wlan {
WIFI,poweren_gpio = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
&avdd1v8_ddr_pll_s0 {
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
&i2s2_2ch {
pinctrl-0 = <&i2s2m1_lrck
&i2s2m1_sclk
&i2s2m1_sdi
&i2s2m1_sdo>;
status = "okay";
};
&i2c2 {
himax@48 {
himax,irq-gpio = <&gpio1 RK_PB0 IRQ_TYPE_EDGE_FALLING>;
};
};
&i2c2_bu18tl82 {
//route-enable;
use-delay-work;
};
&i2c2_bu18rl82 {
use-delay-work;
vpower-supply = <&lcd1_vcc12v_buck>;
};
&i2c4 {
himax@48 {
himax,irq-gpio = <&gpio3 RK_PC5 IRQ_TYPE_EDGE_FALLING>;
};
};
&i2c4_bu18tl82 {
use-delay-work;
};
&i2c4_bu18rl82 {
use-delay-work;
vpower-supply = <&lcd5_vcc12v_buck>;
};
&i2c5 {
ilitek@41 {
interrupt-parent = <&gpio1>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
};
i2c5_nca9539: i2c5-nca9539@74 {
compatible = "novo,nca9539";
reg = <0x74>;
status = "okay";
/* P00-P07 P10-P17 output HIGH level default*/
serdes-init-sequence = [
0002 00ff
0003 00ff
0004 0000
0005 0000
0006 0000
0007 0000
];
i2c5_nca9539_pinctrl: i2c5-nca9539-pinctrl {
compatible = "novo,nca9539-pinctrl";
status = "okay";
i2c5_nca9539_gpio: i2c5-nca9539-gpio {
compatible = "novo,nca9539-gpio";
status = "okay";
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&i2c5_nca9539_pinctrl 0 256 16>;
};
};
};
};
&i2c5_bu18tl82 {
use-delay-work;
};
&i2c5_bu18rl82 {
use-delay-work;
vpower-supply = <&lcd3_vcc12v_buck>;
};
&i2c6 {
himax@48 {
himax,irq-gpio = <&gpio1 RK_PB7 IRQ_TYPE_EDGE_FALLING>;
};
};
&i2c6_bu18tl82 {
//route-enable;
use-delay-work;
};
&i2c6_bu18rl82 {
use-delay-work;
vpower-supply = <&lcd2_vcc12v_buck>;
};
&pinctrl {
bl {
bl0_enable_pin: bl0-enable-pin {
rockchip,pins =
<1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>,
<4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>,
<4 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl1_enable_pin: bl1-enable-pin {
rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl2_enable_pin: bl2-enable-pin {
rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl3_enable_pin: bl3-enable-pin {
rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl4_enable_pin: bl4-enable-pin {
rockchip,pins = <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>;
};
bl5_enable_pin: bl5-enable-pin {
rockchip,pins = <1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
max96712-dphy3 {
max96712_dphy3_pwdn: max96712-dphy3-pwdn {
rockchip,pins = <4 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy3_errb: max96712-dphy3-errb {
rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
};
max96712_dphy3_lock: max96712-dphy3-lock {
rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
touch {
//dsi0-i2c2
touch_gpio_dsi0: touch-gpio-dsi0 {
rockchip,pins =
<1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; //RST->V22 INT
};
//dsi1-i2c6
touch_gpio_dsi1: touch-gpio-dsi1 {
rockchip,pins =
<1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>; //RST->V22 INT
};
//dp0-i2c4
touch_gpio_dp0: touch-gpio-dp0 {
rockchip,pins = <3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
};
//edp0-i2c5
touch_gpio_edp0: touch-gpio-edp0 {
rockchip,pins =
<1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>; //RST->V22 INT
};
};
vcc5v0-buck {
vcc5v0_buck_en: vcc5v0-buck-en {
rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
vcc4v0-mode {
vcc4v0_sys_mode_en: vcc4v0-sys-mode-en {
rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
wireless-bluetooth {
bt_reset_gpio: bt-reset-gpio {
rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&rockchip_suspend {
rockchip,sleep-mode-config = <
(0
| RKPM_SLP_ARMOFF_DDRPD
| RKPM_SLP_PMU_PMUALIVE_32K
| RKPM_SLP_PMU_DIS_OSC
| RKPM_SLP_32K_EXT
)
>;
rockchip,wakeup-config = <
(0
| RKPM_CPU0_WKUP_EN
| RKPM_GPIO_WKUP_EN
)
>;
status = "okay";
};
&route_dsi0 {
status = "disabled";
};
&route_dsi1 {
status = "disabled";
};
&u2phy1_otg {
phy-supply = <&vcc5v0_host_usb20>;
};
&u2phy2_host {
phy-supply = <&vcc5v0_host_usb20>;
};
&u2phy3_host {
phy-supply = <&vcc5v0_host_usb30>;
};
&vdd_log_s0 {
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <800000>;
};
};
&vcc_3v3_s0 {
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
&vcc_1v8_s0 {
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
&vdd_1v8_pll_s0 {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
&vcc5v0_host {
status = "disabled";
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -693,6 +693,7 @@ CONFIG_SND_SOC_ROCKCHIP=y
CONFIG_SND_SOC_ROCKCHIP_I2S=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES=y
CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y
CONFIG_SND_SOC_ROCKCHIP_PDM=y
CONFIG_SND_SOC_ROCKCHIP_SAI=y
CONFIG_SND_SOC_ROCKCHIP_SPDIF=y

View file

@ -389,6 +389,7 @@ CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_ROCKCHIP=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y
CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y
CONFIG_SND_SOC_ROCKCHIP_PDM=y
CONFIG_SND_SOC_ROCKCHIP_SAI=y
CONFIG_SND_SOC_ROCKCHIP_SPDIF=y

View file

@ -3186,6 +3186,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
struct resource *res;
int i, ret, irq;
int num_chan;
int val;
struct device_node *np = adev->dev.of_node;
ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32));
@ -3200,7 +3201,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pd = &pl330->ddma;
pd->dev = &adev->dev;
pl330->mcbufsz = 0;
if (!device_property_read_u32(&adev->dev, "arm,pl330-mcbufsz-bytes", &val)) {
if ((val > 0) && (val <= PAGE_SIZE))
pl330->mcbufsz = val;
dev_info(&adev->dev, "mcbufsz: %d bytes\n", pl330->mcbufsz);
}
/* get quirk */
for (i = 0; i < ARRAY_SIZE(of_quirks); i++)

View file

@ -1056,6 +1056,14 @@ config GPIO_MAX732X_IRQ
Say yes here to enable the max732x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
config GPIO_NCA9539
tristate "NCA9539 I2C GPIO expander"
depends on I2C || COMPILE_TEST
select REGMAP_I2C
help
Say yes here to support the NCA9539 series of I2C Expanders.
GPIO expanders used for additional digital outputs or inputs.
config GPIO_PCA953X
tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
select REGMAP_I2C

View file

@ -109,6 +109,7 @@ obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
obj-$(CONFIG_GPIO_NCA9539) += gpio-nca9539.o
obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o

332
drivers/gpio/gpio-nca9539.c Normal file
View file

@ -0,0 +1,332 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* NCA9539 I2C Port Expander I/O
*
* Copyright (C) 2023 Cody Xie <cody.xie@rock-chips.com>
*
*/
#include <linux/compiler_types.h>
#include <linux/bitfield.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <linux/types.h>
#define NCA9539_REG_INPUT_PORT_BASE 0x00
#define NCA9539_REG_INPUT_PORT0 (NCA9539_REG_INPUT_PORT_BASE + 0x0)
#define NCA9539_REG_INPUT_PORT1 (NCA9539_REG_INPUT_PORT_BASE + 0x1)
#define NCA9539_REG_OUTPUT_PORT_BASE 0x02
#define NCA9539_REG_OUTPUT_PORT0 (NCA9539_REG_OUTPUT_PORT_BASE + 0x0)
#define NCA9539_REG_OUTPUT_PORT1 (NCA9539_REG_OUTPUT_PORT_BASE + 0x1)
#define NCA9539_REG_POLARITY_BASE 0x04
#define NCA9539_REG_POLARITY_PORT0 (NCA9539_REG_POLARITY_BASE + 0x0)
#define NCA9539_REG_POLARITY_PORT1 (NCA9539_REG_POLARITY_BASE + 0x1)
#define NCA9539_REG_CONFIG_BASE 0x06
#define NCA9539_REG_CONFIG_PORT0 (NCA9539_REG_CONFIG_BASE + 0x0)
#define NCA9539_REG_CONFIG_PORT1 (NCA9539_REG_CONFIG_BASE + 0x1)
struct nca9539_chip {
struct gpio_chip gpio_chip;
struct regmap *regmap;
struct regulator *regulator;
unsigned int ngpio;
};
static int nca9539_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
struct nca9539_chip *priv = gpiochip_get_data(gc);
unsigned int port = offset / 8;
unsigned int pin = offset % 8;
unsigned int value;
int ret;
dev_dbg(gc->parent, "%s offset(%d)", __func__, offset);
ret = regmap_read(priv->regmap, NCA9539_REG_CONFIG_BASE + port, &value);
if (ret < 0) {
dev_err(gc->parent, "%s offset(%d) read config failed",
__func__, offset);
return ret;
}
if (value & BIT(pin))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
}
static int nca9539_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct nca9539_chip *priv = gpiochip_get_data(gc);
unsigned int port = offset / 8;
unsigned int pin = offset % 8;
int ret;
dev_dbg(gc->parent, "%s offset(%d)", __func__, offset);
ret = regmap_update_bits(priv->regmap, NCA9539_REG_CONFIG_BASE + port,
BIT(pin), BIT(pin));
if (ret < 0) {
dev_err(gc->parent, "%s offset(%d) read config failed",
__func__, offset);
}
return ret;
}
static int nca9539_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
int val)
{
struct nca9539_chip *priv = gpiochip_get_data(gc);
unsigned int port = offset / 8;
unsigned int pin = offset % 8;
int ret;
dev_dbg(gc->parent, "%s offset(%d) val(%d)", __func__, offset, val);
ret = regmap_update_bits(priv->regmap, NCA9539_REG_CONFIG_BASE + port,
BIT(pin), 0);
if (ret < 0) {
dev_err(gc->parent,
"%s offset(%d) val(%d) update config failed", __func__,
offset, val);
return ret;
}
ret = regmap_update_bits(priv->regmap,
NCA9539_REG_OUTPUT_PORT_BASE + port, BIT(pin),
val ? BIT(pin) : 0);
if (ret < 0) {
dev_err(gc->parent,
"%s offset(%d) val(%d) update output failed", __func__,
offset, val);
return ret;
}
return ret;
}
static int nca9539_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct nca9539_chip *priv = gpiochip_get_data(gc);
unsigned int port = offset / 8;
unsigned int pin = offset % 8;
unsigned int reg;
unsigned int value;
int ret;
dev_dbg(gc->parent, "%s offset(%d)", __func__, offset);
ret = regmap_read(priv->regmap, NCA9539_REG_CONFIG_BASE + port, &value);
if (ret < 0) {
dev_err(gc->parent, "%s offset(%d) check config failed",
__func__, offset);
return ret;
}
if (!(BIT(pin) & value))
reg = NCA9539_REG_OUTPUT_PORT_BASE + port;
else
reg = NCA9539_REG_INPUT_PORT_BASE + port;
ret = regmap_read(priv->regmap, reg, &value);
if (ret < 0) {
dev_err(gc->parent, "%s offset(%d) read value failed", __func__,
offset);
return -EIO;
}
return !!(BIT(pin) & value);
}
static void nca9539_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
struct nca9539_chip *priv = gpiochip_get_data(gc);
unsigned int port = offset / 8;
unsigned int pin = offset % 8;
unsigned int value;
int ret;
dev_dbg(gc->parent, "%s offset(%d) val(%d)", __func__, offset, val);
ret = regmap_read(priv->regmap, NCA9539_REG_CONFIG_BASE + port, &value);
if (ret < 0 || !!(BIT(pin) & value)) {
dev_err(gc->parent, "%s offset(%d) val(%d) check config failed",
__func__, offset, val);
}
ret = regmap_update_bits(priv->regmap,
NCA9539_REG_OUTPUT_PORT_BASE + port, BIT(pin),
val ? BIT(pin) : 0);
if (ret < 0) {
dev_err(gc->parent, "%s offset(%d) val(%d) read input failed",
__func__, offset, val);
}
}
static bool nca9539_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case NCA9539_REG_OUTPUT_PORT0:
case NCA9539_REG_OUTPUT_PORT1:
case NCA9539_REG_POLARITY_PORT0:
case NCA9539_REG_POLARITY_PORT1:
case NCA9539_REG_CONFIG_PORT0:
case NCA9539_REG_CONFIG_PORT1:
return true;
}
return false;
}
static bool nca9539_is_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case NCA9539_REG_INPUT_PORT0:
case NCA9539_REG_INPUT_PORT1:
case NCA9539_REG_OUTPUT_PORT0:
case NCA9539_REG_OUTPUT_PORT1:
case NCA9539_REG_POLARITY_PORT0:
case NCA9539_REG_POLARITY_PORT1:
case NCA9539_REG_CONFIG_PORT0:
case NCA9539_REG_CONFIG_PORT1:
return true;
}
return false;
}
static bool nca9539_is_volatile_reg(struct device *dev, unsigned int reg)
{
return true;
}
static const struct reg_default nca9539_regmap_default[] = {
{ NCA9539_REG_INPUT_PORT0, 0xFF },
{ NCA9539_REG_INPUT_PORT1, 0xFF },
{ NCA9539_REG_OUTPUT_PORT0, 0xFF },
{ NCA9539_REG_OUTPUT_PORT1, 0xFF },
{ NCA9539_REG_POLARITY_PORT0, 0x00 },
{ NCA9539_REG_POLARITY_PORT1, 0x00 },
{ NCA9539_REG_CONFIG_PORT0, 0xFF },
{ NCA9539_REG_CONFIG_PORT1, 0xFF },
};
static const struct regmap_config nca9539_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 7,
.writeable_reg = nca9539_is_writeable_reg,
.readable_reg = nca9539_is_readable_reg,
.volatile_reg = nca9539_is_volatile_reg,
.reg_defaults = nca9539_regmap_default,
.num_reg_defaults = ARRAY_SIZE(nca9539_regmap_default),
.cache_type = REGCACHE_FLAT,
};
static const struct gpio_chip template_chip = {
.label = "nca9539-gpio",
.owner = THIS_MODULE,
.get_direction = nca9539_gpio_get_direction,
.direction_input = nca9539_gpio_direction_input,
.direction_output = nca9539_gpio_direction_output,
.get = nca9539_gpio_get,
.set = nca9539_gpio_set,
.base = -1,
.can_sleep = true,
};
static int nca9539_probe(struct i2c_client *client)
{
struct nca9539_chip *chip;
struct regulator *reg;
int ret;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->gpio_chip = template_chip;
chip->gpio_chip.label = "nca9539-gpio";
chip->gpio_chip.parent = &client->dev;
chip->ngpio = (uintptr_t)of_device_get_match_data(&client->dev);
chip->gpio_chip.ngpio = chip->ngpio;
reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(reg))
return dev_err_probe(&client->dev, PTR_ERR(reg),
"reg get err\n");
ret = regulator_enable(reg);
if (ret) {
dev_err(&client->dev, "reg en err: %d\n", ret);
return ret;
}
chip->regulator = reg;
chip->regmap = devm_regmap_init_i2c(client, &nca9539_regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
goto err_exit;
}
regcache_mark_dirty(chip->regmap);
ret = regcache_sync(chip->regmap);
if (ret) {
dev_err(&client->dev, "Failed to sync register map: %d\n", ret);
goto err_exit;
}
// TODO(Cody): irq_chip setup
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret < 0) {
dev_err(&client->dev, "Unable to register gpiochip\n");
goto err_exit;
}
i2c_set_clientdata(client, chip);
return 0;
err_exit:
regulator_disable(chip->regulator);
return ret;
}
static int nca9539_remove(struct i2c_client *client)
{
struct nca9539_chip *chip = i2c_get_clientdata(client);
regulator_disable(chip->regulator);
return 0;
}
static const struct of_device_id nca9539_gpio_of_match_table[] = {
{
.compatible = "novo,nca9539-gpio",
.data = (void *)16,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, nca9539_gpio_of_match_table);
static const struct i2c_device_id nca9539_gpio_id_table[] = {
{ "nca9539-gpio" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(i2c, nca9539_gpio_id_table);
static struct i2c_driver nca9539_driver = {
.driver = {
.name = "nca9539-gpio",
.of_match_table = nca9539_gpio_of_match_table,
},
.probe_new = nca9539_probe,
.remove = nca9539_remove,
.id_table = nca9539_gpio_id_table,
};
module_i2c_driver(nca9539_driver);
MODULE_AUTHOR("Cody Xie <cody.xie@rock-chips.com>");
MODULE_DESCRIPTION("GPIO expander driver for Novosense nca9539");
MODULE_LICENSE("GPL");

View file

@ -2179,7 +2179,9 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
{
struct page *prop_page;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566"))
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
gfp_flags |= GFP_DMA32;
prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
if (!prop_page)
@ -2317,7 +2319,9 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
}
gfp_flags = GFP_KERNEL | __GFP_ZERO;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566"))
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
gfp_flags |= GFP_DMA32;
page = alloc_pages_node(its->numa_node, gfp_flags, order);
if (!page)
@ -2368,6 +2372,7 @@ retry_baser:
if (IS_ENABLED(CONFIG_NO_GKI) &&
(of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566") ||
of_machine_is_compatible("rockchip,rk3588"))) {
if (tmp & GITS_BASER_SHAREABILITY_MASK)
@ -2958,7 +2963,9 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
{
struct page *pend_page;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566"))
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
gfp_flags |= GFP_DMA32;
pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
get_order(LPI_PENDBASE_SZ));
@ -3117,6 +3124,7 @@ static void its_cpu_init_lpis(void)
if (IS_ENABLED(CONFIG_NO_GKI) &&
(of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566") ||
of_machine_is_compatible("rockchip,rk3588")))
tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK;
@ -3147,6 +3155,7 @@ static void its_cpu_init_lpis(void)
if (IS_ENABLED(CONFIG_NO_GKI) &&
(of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566") ||
of_machine_is_compatible("rockchip,rk3588")))
tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK;
@ -3316,7 +3325,9 @@ static bool its_alloc_table_entry(struct its_node *its,
if (!table[idx]) {
gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566"))
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
gfp_flags |= GFP_DMA32;
page = alloc_pages_node(its->numa_node, gfp_flags,
get_order(baser->psz));
@ -3424,7 +3435,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
gfp_flags = GFP_KERNEL;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566")) {
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566")) {
gfp_flags |= GFP_DMA32;
itt = (void *)__get_free_pages(gfp_flags, get_order(sz));
} else {
@ -3446,6 +3459,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
kfree(dev);
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
free_pages((unsigned long)itt, get_order(sz));
else
@ -3490,6 +3504,7 @@ static void its_free_device(struct its_device *its_dev)
kfree(its_dev->event_map.col_map);
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
free_pages((unsigned long)its_dev->itt, get_order(its_dev->itt_sz));
else
@ -5122,7 +5137,9 @@ static int __init its_probe_one(struct resource *res,
its->numa_node = numa_node;
gfp_flags = GFP_KERNEL | __GFP_ZERO;
if (of_machine_is_compatible("rockchip,rk3568") || of_machine_is_compatible("rockchip,rk3566"))
if (of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566"))
gfp_flags |= GFP_DMA32;
page = alloc_pages_node(its->numa_node, gfp_flags,
get_order(ITS_CMD_QUEUE_SZ));
@ -5157,6 +5174,7 @@ static int __init its_probe_one(struct resource *res,
if (IS_ENABLED(CONFIG_NO_GKI) &&
(of_machine_is_compatible("rockchip,rk3568") ||
of_machine_is_compatible("rockchip,rk3567") ||
of_machine_is_compatible("rockchip,rk3566") ||
of_machine_is_compatible("rockchip,rk3588")))
tmp &= ~GITS_CBASER_SHAREABILITY_MASK;

View file

@ -98,6 +98,12 @@ config ROCKCHIP_MBOX
Please check it that the Soc you use have Mailbox hardware.
Say Y here if you want to use the Rockchip Mailbox support.
config ROCKCHIP_MBOX_DEMO
tristate "Rockchip MBOX Demo"
depends on ROCKCHIP_MBOX
help
Say y here to enable Rockchip MBOX Demo.
config PCC
bool "Platform Communication Channel Driver"
depends on ACPI

View file

@ -21,6 +21,8 @@ obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
obj-$(CONFIG_ROCKCHIP_MBOX) += rockchip-mailbox.o
obj-$(CONFIG_ROCKCHIP_MBOX_DEMO) += rockchip-mbox-demo.o
obj-$(CONFIG_PCC) += pcc.o
obj-$(CONFIG_ALTERA_MBOX) += mailbox-altera.o

View file

@ -0,0 +1,138 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Rockchip MBOX Demo.
*
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
* Author: Jiahang Zheng <jiahang.zheng@rock-chips.com>
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <soc/rockchip/rockchip-mailbox.h>
#include <linux/delay.h>
/*
* The Linux kernel uses the mailbox framework TXDONE_BY_POLL mechanism.
* The minimum unit of the txpoll period interface is ms.
* Configure rockchip,txpoll-period-ms = <1> in dts.
* If data that is longer than MBOX_TX_QUEUE_LEN may be lost,
* each send should be at least interval txpoll-period-ms
*/
#define MSG_LIMIT (100)
#define LINUX_TEST_COMPENSATION (1)
struct rk_mbox_dev {
struct platform_device *pdev;
struct mbox_client mbox_cl;
struct mbox_chan *mbox_rx_chan;
struct mbox_chan *mbox_tx_chan;
struct rockchip_mbox_msg tx_msg;
int rx_count;
};
static void rk_mbox_rx_callback(struct mbox_client *client, void *message)
{
struct rk_mbox_dev *test_dev = container_of(client, struct rk_mbox_dev, mbox_cl);
struct platform_device *pdev = test_dev->pdev;
struct device *dev = &pdev->dev;
struct rockchip_mbox_msg *tx_msg;
struct rockchip_mbox_msg *rx_msg;
rx_msg = message;
dev_info(dev, "mbox master: rx_count:%d cmd=0x%x data=0x%x\n",
++test_dev->rx_count, rx_msg->cmd, rx_msg->data);
/* test should not live forever */
if (test_dev->rx_count >= MSG_LIMIT) {
dev_info(dev, "Rockchip mbox test exit!\n");
return;
}
mdelay(LINUX_TEST_COMPENSATION);
tx_msg = &test_dev->tx_msg;
mbox_send_message(test_dev->mbox_tx_chan, tx_msg);
}
static int mbox_demo_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rk_mbox_dev *test_dev = NULL;
struct mbox_client *cl;
struct rockchip_mbox_msg *tx_msg;
int ret = 0;
test_dev = devm_kzalloc(dev, sizeof(*test_dev), GFP_KERNEL);
if (!test_dev)
return -ENOMEM;
/* link_id: master core 0 and remote core 3 */
tx_msg = &test_dev->tx_msg;
tx_msg->cmd = 0x03U;
tx_msg->data = 0x524D5347U;
dev_info(dev, "rockchip mbox demo probe.\n");
test_dev->pdev = pdev;
test_dev->rx_count = 0;
cl = &test_dev->mbox_cl;
cl->dev = dev;
cl->rx_callback = rk_mbox_rx_callback;
platform_set_drvdata(pdev, test_dev);
test_dev->mbox_rx_chan = mbox_request_channel_byname(cl, "test-rx");
if (IS_ERR(test_dev->mbox_rx_chan)) {
ret = PTR_ERR(test_dev->mbox_rx_chan);
dev_err(dev, "failed to request mbox rx chan, ret %d\n", ret);
return ret;
}
test_dev->mbox_tx_chan = mbox_request_channel_byname(cl, "test-tx");
if (IS_ERR(test_dev->mbox_tx_chan)) {
ret = PTR_ERR(test_dev->mbox_tx_chan);
dev_err(dev, "failed to request mbox tx chan, ret %d\n", ret);
return ret;
}
dev_info(dev, "mbox master: send cmd=0x%x data=0x%x\n", tx_msg->cmd, tx_msg->data);
mbox_send_message(test_dev->mbox_tx_chan, tx_msg);
return ret;
}
static int mbox_demo_remove(struct platform_device *pdev)
{
struct rk_mbox_dev *test_dev = platform_get_drvdata(pdev);
mbox_free_channel(test_dev->mbox_rx_chan);
mbox_free_channel(test_dev->mbox_tx_chan);
return 0;
}
static const struct of_device_id mbox_demo_match[] = {
{ .compatible = "rockchip,mbox-demo", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mbox_demo_match);
static struct platform_driver mbox_demo_driver = {
.probe = mbox_demo_probe,
.remove = mbox_demo_remove,
.driver = {
.name = "mbox-demo",
.of_match_table = mbox_demo_match,
},
};
module_platform_driver(mbox_demo_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Rockchip MBOX Demo");
MODULE_AUTHOR("Jiahang Zheng <jiahang.zheng@rock-chips.com>");

View file

@ -3,44 +3,46 @@
# Maxim Quad GMSL deserializer and serializer devices
#
config VIDEO_DES_MAXIM4C
tristate "Maxim Qual GMSL deserializer support"
tristate "Maxim Quad GMSL deserializer support"
depends on I2C && VIDEO_DEV
depends on MEDIA_CAMERA_SUPPORT
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select V4L2_FWNODE
help
This driver supports the Maxim Qual GMSL2/GMSL1 deserializer.
This driver supports the Maxim Quad GMSL2/GMSL1 deserializer.
To compile this driver as a module, choose M here: the
module will be called maxim4c.
menu "Maxim Quad GMSL serializer devices support"
visible if VIDEO_DES_MAXIM4C
config MAXIM4C_SER_MAX9295
tristate "Maxim GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL2 serializer max9295 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 serializer.
This driver supports the Maxim GMSL2 max9295 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max9295.
config MAXIM4C_SER_MAX96715
tristate "Maxim GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL1 Serializer max96715 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL1 serializer.
This driver supports the Maxim GMSL1 max96715 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max96715.
config MAXIM4C_SER_MAX96717
tristate "Maxim GMSL serializer support"
depends on I2C
select VIDEO_DES_MAXIM4C
tristate "Maxim GMSL2 Serializer max96717 support"
depends on VIDEO_DES_MAXIM4C
help
This driver supports the Maxim GMSL2 serializer.
This driver supports the Maxim GMSL2 max96717 serializer.
To compile this driver as a module, choose M here: the
module will be called remote_max96717.
endmenu

View file

@ -23,6 +23,9 @@
/* Maxim Deserializer Test Pattern */
#define MAXIM4C_TEST_PATTERN 0
/* Maxim Deserializer pwdn on/off enable */
#define MAXIM4C_LOCAL_DES_ON_OFF_EN 0
/* maxim4c i2c api */
int maxim4c_i2c_write_reg(struct i2c_client *client,
u16 reg_addr, u16 reg_len, u16 val_len, u32 reg_val);
@ -77,15 +80,22 @@ int maxim4c_remote_mfd_add_devices(maxim4c_t *maxim4c);
int maxim4c_remote_devices_init(maxim4c_t *maxim4c, u8 link_init_mask);
int maxim4c_remote_devices_deinit(maxim4c_t *maxim4c, u8 link_init_mask);
int maxim4c_remote_load_init_seq(maxim4c_remote_t *remote_device);
int maxim4c_remote_i2c_addr_select(maxim4c_remote_t *remote_device, u32 i2c_id);
int maxim4c_remote_i2c_client_init(maxim4c_remote_t *remote_device,
struct i2c_client *des_client);
int maxim4c_remote_device_register(maxim4c_t *maxim4c,
maxim4c_remote_t *remote_device);
maxim4c_remote_t *remote_device);
/* maxim4c v4l2 subdev api */
int maxim4c_v4l2_subdev_init(maxim4c_t *maxim4c);
void maxim4c_v4l2_subdev_deinit(maxim4c_t *maxim4c);
int maxim4c_module_hw_init(maxim4c_t *maxim4c);
/* maxim4c pattern api */
int maxim4c_pattern_init(maxim4c_t *maxim4c);
int maxim4c_pattern_hw_init(maxim4c_t *maxim4c);
int maxim4c_pattern_support_mode_init(maxim4c_t *maxim4c);
int maxim4c_pattern_data_init(maxim4c_t *maxim4c);
int maxim4c_pattern_enable(maxim4c_t *maxim4c, bool enable);
#endif /* __MAXIM4C_API_H__ */

View file

@ -6,7 +6,7 @@
*
* Author: Cai Wenzhong <cwz@rock-chips.com>
*
* V2.0.00 maxim serdes qual GMSL2/GMSL1 driver framework.
* V2.00.00 maxim serdes quad GMSL2/GMSL1 driver framework.
* 1. local deserializer support: max96712/max96722
* 2. remote serializer support: max9295/max96715/max96717
* 3. support deserializer and serializer auto adaptive
@ -14,6 +14,14 @@
* 5. support remote serializer I2c address mapping
* 6. support remote serializer hot plug detection and recovery
*
* V2.01.00
* 1. remote device and local link are bound through link id
* 2. support local and remote port chain check
* 3. drivers/media/i2c/maxim4c/Kconfig support menu select
* 4. optimize delay time and error messages
* 5. power control: local by pwdn gpio, remote by pocen gpio
* 6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN
*
*/
#include <linux/clk.h>
#include <linux/i2c.h>
@ -43,14 +51,10 @@
#include "maxim4c_api.h"
#define DRIVER_VERSION KERNEL_VERSION(2, 0x00, 0x00)
#define DRIVER_VERSION KERNEL_VERSION(2, 0x01, 0x00)
#define MAXIM4C_XVCLK_FREQ 25000000
/* device compatible */
#define MAXIM4C_MAX96712_COMPAT "maxim4c,max96712"
#define MAXIM4C_MAX96722_COMPAT "maxim4c,max96722"
static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
{
struct i2c_client *client = maxim4c->client;
@ -59,6 +63,11 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
u8 chipid = 0;
for (loop = 0; loop < 5; loop++) {
if (loop != 0) {
dev_info(dev, "check local chipid retry (%d)", loop);
msleep(10);
}
ret = maxim4c_i2c_read_byte(client,
MAXIM4C_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chipid);
@ -74,13 +83,10 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
return 0;
}
} else {
dev_err(dev, "Unexpected maxim chipid(%02x)\n", chipid);
dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid);
return -ENODEV;
}
}
dev_info(dev, "retry (%d) to check local chipid", loop + 1);
msleep(10);
}
dev_err(dev, "maxim check chipid error, ret(%d)\n", ret);
@ -181,13 +187,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_A;
if (curr_lock_state & MAXIM4C_LINK_MASK_A) {
dev_info(dev, "link A plug in\n");
dev_info(dev, "Link A plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link A plug out\n");
dev_info(dev, "Link A plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@ -197,13 +203,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_B;
if (curr_lock_state & MAXIM4C_LINK_MASK_B) {
dev_info(dev, "link B plug in\n");
dev_info(dev, "Link B plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link B plug out\n");
dev_info(dev, "Link B plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@ -213,13 +219,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_C;
if (curr_lock_state & MAXIM4C_LINK_MASK_C) {
dev_info(dev, "link C plug in\n");
dev_info(dev, "Link C plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link C plug out\n");
dev_info(dev, "Link C plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@ -229,13 +235,13 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
link_id = MAXIM4C_LINK_ID_D;
if (curr_lock_state & MAXIM4C_LINK_MASK_D) {
dev_info(dev, "link D plug in\n");
dev_info(dev, "Link D plug in\n");
maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D);
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
} else {
dev_info(dev, "link D plug out\n");
dev_info(dev, "Link D plug out\n");
maxim4c_video_pipe_linkid_enable(maxim4c, link_id, false);
}
@ -290,10 +296,10 @@ static int maxim4c_local_device_power_on(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
if (!IS_ERR(maxim4c->power_gpio)) {
dev_info(dev, "local device power gpio on\n");
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio on\n");
gpiod_set_value_cansleep(maxim4c->power_gpio, 1);
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1);
usleep_range(5000, 10000);
}
@ -305,10 +311,10 @@ static void maxim4c_local_device_power_off(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
if (!IS_ERR(maxim4c->power_gpio)) {
dev_info(dev, "local device power gpio off\n");
if (!IS_ERR(maxim4c->pwdn_gpio)) {
dev_info(dev, "local device pwdn gpio off\n");
gpiod_set_value_cansleep(maxim4c->power_gpio, 0);
gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0);
}
}
@ -318,7 +324,7 @@ static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c)
// remote PoC enable
if (!IS_ERR(maxim4c->pocen_gpio)) {
dev_info(dev, "remote device poc gpio on\n");
dev_info(dev, "remote device pocen gpio on\n");
gpiod_set_value_cansleep(maxim4c->pocen_gpio, 1);
usleep_range(5000, 10000);
@ -333,7 +339,7 @@ static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c)
// remote PoC enable
if (!IS_ERR(maxim4c->pocen_gpio)) {
dev_info(dev, "remote device poc gpio off\n");
dev_info(dev, "remote device pocen gpio off\n");
gpiod_set_value_cansleep(maxim4c->pocen_gpio, 0);
}
@ -346,8 +352,15 @@ static int maxim4c_runtime_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
return maxim4c_remote_device_power_on(maxim4c);
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
ret |= maxim4c_local_device_power_on(maxim4c);
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
ret |= maxim4c_remote_device_power_on(maxim4c);
return ret;
}
static int maxim4c_runtime_suspend(struct device *dev)
@ -355,8 +368,15 @@ static int maxim4c_runtime_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
int ret = 0;
return maxim4c_remote_device_power_off(maxim4c);
ret |= maxim4c_remote_device_power_off(maxim4c);
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
maxim4c_local_device_power_off(maxim4c);
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
return ret;
}
static const struct dev_pm_ops maxim4c_pm_ops = {
@ -378,22 +398,26 @@ static int maxim4c_extra_init_seq_parse(maxim4c_t *maxim4c, struct device_node *
struct maxim4c_i2c_init_seq *init_seq = NULL;
init_seq_node = of_get_child_by_name(node, "extra-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
if (!of_device_is_available(init_seq_node)) {
dev_info(dev, "%pOF is disabled\n", init_seq_node);
if (IS_ERR_OR_NULL(init_seq_node)) {
dev_dbg(dev, "%pOF no child node extra-init-sequence\n", node);
return 0;
}
return 0;
}
dev_info(dev, "load extra-init-sequence\n");
init_seq = &maxim4c->extra_init_seq;
maxim4c_i2c_load_init_seq(dev,
init_seq_node, init_seq);
if (!of_device_is_available(init_seq_node)) {
dev_dbg(dev, "%pOF is disabled\n", init_seq_node);
of_node_put(init_seq_node);
return 0;
}
dev_info(dev, "load extra-init-sequence\n");
init_seq = &maxim4c->extra_init_seq;
maxim4c_i2c_load_init_seq(dev,
init_seq_node, init_seq);
of_node_put(init_seq_node);
return 0;
}
@ -404,8 +428,12 @@ static int maxim4c_module_parse_dt(maxim4c_t *maxim4c)
// maxim serdes local
node = of_get_child_by_name(dev->of_node, "serdes-local-device");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: serdes-local-device\n",
dev->of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@ -492,36 +520,51 @@ static int maxim4c_module_hw_postinit(maxim4c_t *maxim4c)
return ret;
}
static int maxim4c_module_hw_init(maxim4c_t *maxim4c)
int maxim4c_module_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
ret = maxim4c_module_hw_previnit(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw prev init error\n", __func__);
return ret;
}
ret = maxim4c_link_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw link init error\n", __func__);
return ret;
}
ret = maxim4c_video_pipe_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw pipe init error\n", __func__);
return ret;
}
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw txphy init error\n", __func__);
return ret;
}
ret = maxim4c_run_extra_init_seq(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: run extra init seq error\n", __func__);
return ret;
}
ret = maxim4c_module_hw_postinit(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: hw post init error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_module_hw_init);
static int maxim4c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@ -529,32 +572,30 @@ static int maxim4c_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
maxim4c_t *maxim4c = NULL;
const u32 *chip_id = NULL;
u32 chip_id;
int ret = 0;
dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff);
chip_id = of_device_get_match_data(dev);
if (chip_id == NULL) {
dev_err(dev, "maxim4c driver get match data error\n");
return -EINVAL;
}
if (*chip_id == MAX96712_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96712");
} else if (*chip_id == MAX96722_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96722");
chip_id = (uintptr_t)of_device_get_match_data(dev);
if (chip_id == MAX96712_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96712\n");
} else if (chip_id == MAX96722_CHIP_ID) {
dev_info(dev, "maxim4c driver for max96722\n");
} else {
dev_err(dev, "maxim4c driver unknown chip");
dev_err(dev, "maxim4c driver unknown chip\n");
return -EINVAL;
}
maxim4c = devm_kzalloc(dev, sizeof(*maxim4c), GFP_KERNEL);
if (!maxim4c)
if (!maxim4c) {
dev_err(dev, "maxim4c probe no memory error\n");
return -ENOMEM;
}
maxim4c->client = client;
maxim4c->chipid = *chip_id;
maxim4c->chipid = chip_id;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&maxim4c->module_index);
@ -569,9 +610,9 @@ static int maxim4c_probe(struct i2c_client *client,
return -EINVAL;
}
maxim4c->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->power_gpio))
dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
maxim4c->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->pwdn_gpio))
dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n");
maxim4c->pocen_gpio = devm_gpiod_get(dev, "pocen", GPIOD_OUT_LOW);
if (IS_ERR(maxim4c->pocen_gpio))
@ -594,13 +635,21 @@ static int maxim4c_probe(struct i2c_client *client,
// client->dev->driver_data = subdev
// subdev->dev->driver_data = maxim4c
ret = maxim4c_v4l2_subdev_init(maxim4c);
if (ret) {
dev_err(dev, "maxim4c probe v4l2 subdev init error\n");
goto err_power_off;
}
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_data_init(maxim4c);
if (ret)
goto err_power_off;
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_init(maxim4c);
#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0)
ret = maxim4c_pattern_hw_init(maxim4c);
if (ret)
goto err_power_off;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@ -612,9 +661,11 @@ static int maxim4c_probe(struct i2c_client *client,
maxim4c_module_data_init(maxim4c);
maxim4c_module_parse_dt(maxim4c);
#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0)
ret = maxim4c_module_hw_init(maxim4c);
if (ret)
goto err_subdev_deinit;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
ret = maxim4c_remote_mfd_add_devices(maxim4c);
if (ret)
@ -657,28 +708,17 @@ static int maxim4c_remove(struct i2c_client *client)
return 0;
}
#if IS_ENABLED(CONFIG_OF)
static const u32 max96712_chip_id = MAX96712_CHIP_ID;
static const u32 max96722_chip_id = MAX96722_CHIP_ID;
static const struct of_device_id maxim4c_of_match[] = {
{
.compatible = MAXIM4C_MAX96712_COMPAT,
.data = &max96712_chip_id,
.compatible = "maxim4c,max96712",
.data = (const void *)MAX96712_CHIP_ID
}, {
.compatible = MAXIM4C_MAX96722_COMPAT,
.data = &max96722_chip_id,
.compatible = "maxim4c,max96722",
.data = (const void *)MAX96722_CHIP_ID
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, maxim4c_of_match);
#endif
static const struct i2c_device_id maxim4c_match_id[] = {
{ MAXIM4C_MAX96712_COMPAT, 0 },
{ MAXIM4C_MAX96722_COMPAT, 0 },
{},
};
static struct i2c_driver maxim4c_i2c_driver = {
.driver = {
@ -688,11 +728,10 @@ static struct i2c_driver maxim4c_i2c_driver = {
},
.probe = &maxim4c_probe,
.remove = &maxim4c_remove,
.id_table = maxim4c_match_id,
};
module_i2c_driver(maxim4c_i2c_driver);
MODULE_AUTHOR("Cai wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim qual gmsl deserializer driver");
MODULE_AUTHOR("Cai Wenzhong <cwz@rock-chips.com>");
MODULE_DESCRIPTION("Maxim quad gmsl deserializer driver");
MODULE_LICENSE("GPL");

View file

@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include <linux/rk-camera-module.h>
#include <linux/mfd/core.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
@ -55,7 +56,7 @@ struct maxim4c_mode {
typedef struct maxim4c {
struct i2c_client *client;
struct clk *xvclk;
struct gpio_desc *power_gpio;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *pocen_gpio;
struct gpio_desc *lock_gpio;
@ -101,6 +102,7 @@ typedef struct maxim4c {
struct maxim4c_i2c_init_seq extra_init_seq;
struct mfd_cell remote_mfd_devs[MAXIM4C_LINK_ID_MAX];
maxim4c_remote_t *remote_device[MAXIM4C_LINK_ID_MAX];
} maxim4c_t;

View file

@ -88,7 +88,7 @@ int maxim4c_i2c_read_reg(struct i2c_client *client,
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
dev_err(&client->dev,
"%s: reading register 0x%x from 0x%x failed\n",
"%s: reading register 0x%04x from 0x%02x failed\n",
__func__, reg_addr, client->addr);
return -EIO;
}

View file

@ -107,16 +107,16 @@ static int maxim4c_link_run_init_seq(maxim4c_t *maxim4c)
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct maxim4c_link_cfg *link_cfg = NULL;
struct maxim4c_i2c_init_seq *init_seq = NULL;
int i = 0;
int link_idx = 0;
int ret = 0;
// link init sequence
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_cfg = &gmsl_link->link_cfg[i];
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_cfg = &gmsl_link->link_cfg[link_idx];
init_seq = &link_cfg->link_init_seq;
ret = maxim4c_i2c_run_init_seq(client, init_seq);
if (ret) {
dev_err(dev, "link id = %d init sequence error\n", i);
dev_err(dev, "link id = %d init sequence error\n", link_idx);
return ret;
}
}
@ -386,6 +386,11 @@ int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
msleep(time_ms);
for (loop_idx = 0; loop_idx < 20; loop_idx++) {
if (loop_idx != 0) {
msleep(10);
time_ms += 10;
}
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_bit_mask = BIT(link_idx);
@ -405,9 +410,6 @@ int maxim4c_link_wait_linklock(struct maxim4c *maxim4c, u8 link_mask)
maxim4c->link_lock_state = lock_state;
return 0;
}
msleep(10);
time_ms += 10;
}
if ((lock_state & link_mask) != 0) {
@ -554,9 +556,7 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
struct device_node *init_seq_node = NULL;
struct maxim4c_i2c_init_seq *init_seq = NULL;
struct maxim4c_link_cfg *link_cfg = NULL;
struct maxim4c_remote_info *remote_info;
const char *link_cfg_name = "gmsl-link-config";
const char *prop_str = NULL;
u32 value = 0;
u32 sub_idx = 0, link_id = 0;
int ret = 0;
@ -568,7 +568,8 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
link_cfg_name,
strlen(link_cfg_name))) {
if (sub_idx >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "Too many matching %s node\n", link_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, link_cfg_name);
of_node_put(node);
break;
@ -622,20 +623,6 @@ static int maxim4c_gmsl_link_config_parse_dt(struct device *dev,
link_cfg->link_rx_rate = value;
}
/* remote info */
remote_info = &link_cfg->remote_info;
ret = of_property_read_string(node, "remote-name", &prop_str);
if (ret == 0) {
dev_info(dev, "remote-name property: %s", prop_str);
remote_info->remote_name = prop_str;
}
ret = of_property_read_string(node, "remote-compatible", &prop_str);
if (ret == 0) {
dev_info(dev, "remote-compatible property: %s", prop_str);
remote_info->remote_compatible = prop_str;
}
/* link init sequence */
init_seq_node = of_get_child_by_name(node, "link-init-sequence");
if (!IS_ERR_OR_NULL(init_seq_node)) {
@ -666,8 +653,11 @@ int maxim4c_link_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c link parse dt ===\n");
node = of_get_child_by_name(of_node, "gmsl-links");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: gmsl-links\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@ -699,29 +689,42 @@ EXPORT_SYMBOL(maxim4c_link_parse_dt);
int maxim4c_link_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
int ret = 0;
// All links disable at beginning.
ret = maxim4c_link_status_init(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: link status error\n", __func__);
return ret;
}
if (gmsl_link->link_vdd_ldo1_en)
ret |= maxim4c_link_enable_vdd_ldo1(maxim4c);
if (gmsl_link->link_vdd_ldo2_en)
ret |= maxim4c_link_enable_vdd_ldo2(maxim4c);
if (ret) {
dev_err(dev, "%s: link vdd ldo enable error\n", __func__);
return ret;
}
// Link Rate Setting
ret |= maxim4c_link_set_rate(maxim4c);
if (ret)
ret = maxim4c_link_set_rate(maxim4c);
if (ret) {
dev_err(dev, "%s: link set rate error\n", __func__);
return ret;
}
// link init sequence
ret = maxim4c_link_run_init_seq(maxim4c);
if (ret) {
dev_err(dev, "%s: link run init seq error\n", __func__);
return ret;
}
return ret;
return 0;
}
EXPORT_SYMBOL(maxim4c_link_hw_init);
@ -745,8 +748,6 @@ void maxim4c_link_data_init(maxim4c_t *maxim4c)
else
link_cfg->link_rx_rate = MAXIM4C_LINK_RX_RATE_6GBPS;
link_cfg->link_tx_rate = MAXIM4C_LINK_TX_RATE_187_5MPS;
link_cfg->remote_info.remote_name = NULL;
link_cfg->remote_info.remote_compatible = NULL;
link_cfg->link_init_seq.reg_init_seq = NULL;
}
}

View file

@ -63,18 +63,12 @@ enum maxim4c_link_tx_rate {
MAXIM4C_LINK_TX_RATE_187_5MPS = 0,
};
struct maxim4c_remote_info {
const char *remote_name;
const char *remote_compatible;
};
struct maxim4c_link_cfg {
u8 link_enable;
u8 link_type;
u8 link_rx_rate;
u8 link_tx_rate;
struct maxim4c_remote_info remote_info;
struct maxim4c_i2c_init_seq link_init_seq;
};

View file

@ -220,11 +220,22 @@ int maxim4c_mipi_csi_output(maxim4c_t *maxim4c, bool enable)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
maxim4c_mipi_txphy_t *mipi_txphy = &maxim4c->mipi_txphy;
u8 reg_mask = 0, reg_value = 0;
int ret = 0;
dev_dbg(dev, "%s: enable = %d\n", __func__, enable);
if (mipi_txphy->force_clock_out_en != 0) {
reg_mask = BIT(7);
reg_value = enable ? BIT(7) : 0;
// Force all MIPI clocks running Config
ret |= maxim4c_i2c_update_byte(client,
0x08A0, MAXIM4C_I2C_REG_ADDR_16BITS,
reg_mask, reg_value);
}
/* Bit1 of the register 0x040B: CSI_OUT_EN
* 1 = CSI output enabled
* 0 = CSI output disabled
@ -259,7 +270,8 @@ static int maxim4c_mipi_txphy_config_parse_dt(struct device *dev,
txphy_cfg_name,
strlen(txphy_cfg_name))) {
if (sub_idx >= MAXIM4C_TXPHY_ID_MAX) {
dev_err(dev, "Too many matching %s node\n", txphy_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, txphy_cfg_name);
of_node_put(node);
break;
@ -355,8 +367,11 @@ int maxim4c_mipi_txphy_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c mipi txphy parse dt ===\n");
node = of_get_child_by_name(of_node, "mipi-txphys");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: mipi-txphys\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@ -404,6 +419,7 @@ EXPORT_SYMBOL(maxim4c_mipi_txphy_parse_dt);
int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
{
struct i2c_client *client = maxim4c->client;
struct device *dev = &client->dev;
maxim4c_mipi_txphy_t *mipi_txphy = &maxim4c->mipi_txphy;
struct maxim4c_txphy_cfg *phy_cfg = NULL;
u8 mode = 0;
@ -479,9 +495,6 @@ int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
phy_cfg->clock_master = 1;
break;
}
// MIPI clocks running mode
if (mipi_txphy->force_clock_out_en != 0)
mode |= BIT(7);
// MIPI TXPHY Mode setting
ret |= maxim4c_i2c_write_byte(client,
@ -497,7 +510,12 @@ int maxim4c_mipi_txphy_hw_init(maxim4c_t *maxim4c)
// mipi txphy auto init deskew
ret |= maxim4c_txphy_auto_init_deskew(maxim4c);
return ret;
if (ret) {
dev_err(dev, "%s: txphy hw init error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_mipi_txphy_hw_init);

View file

@ -91,6 +91,13 @@ static int maxim4c_pattern_previnit(maxim4c_t *maxim4c)
if (ret)
return ret;
// video pipe disable.
ret = maxim4c_i2c_write_byte(client,
0x00F4, MAXIM4C_I2C_REG_ADDR_16BITS,
0x00);
if (ret)
return ret;
// MIPI CSI output disable.
ret = maxim4c_i2c_write_byte(client,
0x040B, MAXIM4C_I2C_REG_ADDR_16BITS,
@ -108,7 +115,7 @@ static int maxim4c_pattern_previnit(maxim4c_t *maxim4c)
return 0;
}
static int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
static int maxim4c_pattern_config(maxim4c_t *maxim4c)
{
const u32 h_active = PATTERN_WIDTH;
const u32 h_fp = 88;
@ -249,18 +256,40 @@ static int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
return ret;
}
int maxim4c_pattern_init(maxim4c_t *maxim4c)
int maxim4c_pattern_support_mode_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
struct maxim4c_mode *supported_mode = NULL;
dev_info(dev, "=== maxim4c pattern support mode init ===\n");
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
supported_mode = &maxim4c->supported_mode;
// init using def mode
memcpy(supported_mode, &maxim4c_pattern_mode, sizeof(struct maxim4c_mode));
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_support_mode_init);
int maxim4c_pattern_data_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
struct device_node *node = NULL;
struct maxim4c_mode *supported_mode = NULL;
struct maxim4c_pattern *pattern = NULL;
maxim4c_mipi_txphy_t *mipi_txphy = &maxim4c->mipi_txphy;
int ret = 0;
// maxim serdes local
node = of_get_child_by_name(dev->of_node, "serdes-local-device");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: serdes-local-device\n",
dev->of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@ -273,23 +302,14 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
/* mipi txphy parse dt */
ret = maxim4c_mipi_txphy_parse_dt(maxim4c, node);
if (ret)
if (ret) {
dev_err(dev, "%s: txphy parse dt error\n", __func__);
return ret;
}
ret = maxim4c_pattern_previnit(maxim4c);
if (ret)
return ret;
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret)
return ret;
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
supported_mode = &maxim4c->supported_mode;
// init using def mode
memcpy(supported_mode, &maxim4c_pattern_mode, sizeof(struct maxim4c_mode));
// pattern need enable force_clock_out_en
dev_info(dev, "Pattern mode force_clock_out_en default enable\n");
mipi_txphy->force_clock_out_en = 1;
// pattern generator and mode init
pattern = &maxim4c->pattern;
@ -297,6 +317,7 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
pattern->pattern_mode = PATTERN_CHECKERBOARD;
pattern->pattern_pclk = PATTERN_PCLK_75M;
supported_mode = &maxim4c->supported_mode;
switch (pattern->pattern_pclk) {
case PATTERN_PCLK_25M:
supported_mode->max_fps.denominator = 100000;
@ -307,13 +328,13 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
case PATTERN_PCLK_150M:
supported_mode->max_fps.denominator = 600000;
if (supported_mode->link_freq_idx < 12)
dev_info(dev, "link_freq_idx = %d is too low\n",
dev_warn(dev, "link_freq_idx = %d is too low\n",
supported_mode->link_freq_idx);
break;
case PATTERN_PCLK_375M:
supported_mode->max_fps.denominator = 1500000;
if (supported_mode->link_freq_idx < 22)
dev_info(dev, "link_freq_idx = %d is too low\n",
dev_warn(dev, "link_freq_idx = %d is too low\n",
supported_mode->link_freq_idx);
break;
}
@ -321,8 +342,33 @@ int maxim4c_pattern_init(maxim4c_t *maxim4c)
dev_info(dev, "video pattern: generator = %d, mode = %d, pclk = %d\n",
pattern->pattern_generator, pattern->pattern_mode, pattern->pattern_pclk);
ret = maxim4c_pattern_hw_init(maxim4c);
return ret;
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_init);
EXPORT_SYMBOL(maxim4c_pattern_data_init);
int maxim4c_pattern_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
int ret = 0;
ret = maxim4c_pattern_previnit(maxim4c);
if (ret) {
dev_err(dev, "%s: pattern previnit error\n", __func__);
return ret;
}
ret = maxim4c_mipi_txphy_hw_init(maxim4c);
if (ret) {
dev_err(dev, "%s: txphy hw init error\n", __func__);
return ret;
}
ret = maxim4c_pattern_config(maxim4c);
if (ret) {
dev_err(dev, "%s: pattern config error\n", __func__);
return ret;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_pattern_hw_init);

View file

@ -8,48 +8,129 @@
*
*/
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/mfd/core.h>
#include "maxim4c_api.h"
static struct mfd_cell maxim4c_remote_devs[MAXIM4C_LINK_ID_MAX];
static const char *maxim4c_remote_devs_name[MAXIM4C_LINK_ID_MAX] = {
"remote0", "remote1", "remote2", "remote3"
};
static const char *maxim4c_remote_link_compat[MAXIM4C_LINK_ID_MAX] = {
"maxim4c,link0", "maxim4c,link1", "maxim4c,link2", "maxim4c,link3"
};
static int maxim4c_remote_dev_info_parse(struct device *dev,
struct mfd_cell *remote_mfd_dev, u8 link_id)
{
struct device_node *node = NULL;
const char *remote_device_name = "serdes-remote-device";
const char *prop_str = NULL, *link_compat = NULL;
u32 sub_idx = 0, remote_id = 0;
int ret = 0;
node = NULL;
sub_idx = 0;
while ((node = of_get_next_child(dev->of_node, node))) {
if (!strncasecmp(node->name,
remote_device_name,
strlen(remote_device_name))) {
if (sub_idx >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "%pOF: Too many matching %s node\n",
dev->of_node, remote_device_name);
of_node_put(node);
break;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
sub_idx++;
continue;
}
/* remote id */
ret = of_property_read_u32(node, "remote-id", &remote_id);
if (ret) {
sub_idx++;
continue;
}
if (remote_id >= MAXIM4C_LINK_ID_MAX) {
sub_idx++;
continue;
}
if (remote_id != link_id) {
sub_idx++;
continue;
}
dev_info(dev, "remote device id = %d\n", remote_id);
ret = of_property_read_string(node, "compatible", &prop_str);
if (ret) {
dev_err(dev, "%pOF no compatible error\n", node);
of_node_put(node);
return -EINVAL;
}
link_compat = maxim4c_remote_link_compat[remote_id];
if (!strncasecmp(prop_str,
link_compat, strlen(link_compat))) {
dev_info(dev, "compatible property: %s\n", prop_str);
remote_mfd_dev->name = maxim4c_remote_devs_name[remote_id];
remote_mfd_dev->of_compatible = prop_str;
of_node_put(node);
return 0;
}
dev_err(dev, "%pOF compatible and remote_id mismatch\n", node);
of_node_put(node);
return -EINVAL;
}
}
return -EINVAL;
}
static int maxim4c_remote_mfd_devs_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link;
struct maxim4c_link_cfg *link_cfg = NULL;
struct mfd_cell *remote_mfd_dev = NULL;
const char *remote_name = NULL, *remote_compatible = NULL;
int link_idx = 0, nr_mfd_cell = 0;
int ret = 0;
remote_mfd_dev = maxim4c_remote_devs;
remote_mfd_dev = maxim4c->remote_mfd_devs;
nr_mfd_cell = 0;
for (link_idx = 0; link_idx < MAXIM4C_LINK_ID_MAX; link_idx++) {
link_cfg = &gmsl_link->link_cfg[link_idx];
if (link_cfg->link_enable == 0)
continue;
remote_mfd_dev->name = NULL;
remote_mfd_dev->of_compatible = NULL;
remote_name = link_cfg->remote_info.remote_name;
remote_compatible = link_cfg->remote_info.remote_compatible;
if (remote_compatible == NULL) {
dev_err(dev, "%s: link id = %d, remote compatible = NULL",
__func__, link_idx);
if (gmsl_link->link_cfg[link_idx].link_enable == 0) {
dev_dbg(dev, "%s: link id = %d is disabled\n",
__func__, link_idx);
continue;
}
if (remote_name == NULL) {
dev_err(dev, "%s: link id = %d, remote name = NULL",
__func__, link_idx);
continue;
ret = maxim4c_remote_dev_info_parse(dev, remote_mfd_dev, link_idx);
if (ret == 0) {
remote_mfd_dev++;
nr_mfd_cell++;
}
remote_mfd_dev->name = remote_name;
remote_mfd_dev->of_compatible = remote_compatible;
remote_mfd_dev++;
nr_mfd_cell++;
}
dev_info(dev, "Total number of remote devices is %d", nr_mfd_cell);
return nr_mfd_cell;
}
@ -58,19 +139,21 @@ int maxim4c_remote_mfd_add_devices(maxim4c_t *maxim4c)
struct device *dev = &maxim4c->client->dev;
int nr_mfd_cell = 0, ret = 0;
dev_info(dev, "=== maxim4c add remote devices ===");
nr_mfd_cell = maxim4c_remote_mfd_devs_init(maxim4c);
if (nr_mfd_cell == 0) {
dev_err(dev, "%s: remote mfd devices init error\n",
__func__);
__func__);
return -EINVAL;
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
maxim4c_remote_devs, nr_mfd_cell,
maxim4c->remote_mfd_devs, nr_mfd_cell,
NULL, 0, NULL);
if (ret)
dev_err(dev, "%s: add remote mfd devices error: %d\n",
__func__, ret);
__func__, ret);
return ret;
}
@ -87,14 +170,14 @@ int maxim4c_remote_devices_init(maxim4c_t *maxim4c, u8 link_init_mask)
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
if ((link_init_mask & BIT(i)) == 0) {
dev_info(dev, "link id = %d init mask is disabled\n", i);
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
@ -143,14 +226,14 @@ int maxim4c_remote_devices_deinit(maxim4c_t *maxim4c, u8 link_init_mask)
dev_dbg(dev, "%s: link init mask = 0x%02x\n", __func__, link_init_mask);
for (i = 0; i < MAXIM4C_LINK_ID_MAX; i++) {
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
if ((link_init_mask & BIT(i)) == 0) {
dev_dbg(dev, "link id = %d init mask is disabled\n", i);
continue;
}
if ((link_init_mask & BIT(i)) == 0) {
dev_info(dev, "link id = %d init mask is disabled\n", i);
link_enable = maxim4c->gmsl_link.link_cfg[i].link_enable;
if (link_enable == 0) {
dev_info(dev, "link id = %d is disabled\n", i);
continue;
}
@ -196,54 +279,156 @@ int maxim4c_remote_load_init_seq(maxim4c_remote_t *remote_device)
node = of_get_child_by_name(dev->of_node, "remote-init-sequence");
if (!IS_ERR_OR_NULL(node)) {
dev_info(dev, "load remote-init-sequence\n");
ret = maxim4c_i2c_load_init_seq(dev, node,
&remote_device->remote_init_seq);
of_node_put(node);
} else {
ret = 0;
dev_info(dev, "no node remote-init-sequence\n");
return ret;
}
return ret;
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_load_init_seq);
int maxim4c_remote_i2c_addr_select(maxim4c_remote_t *remote_device, u32 i2c_id)
{
struct device *dev = remote_device->dev;
struct i2c_client *client = remote_device->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = remote_device->ser_i2c_addr_def;
dev_info(dev, "ser select default i2c addr = 0x%02x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = remote_device->ser_i2c_addr_map;
dev_info(dev, "ser select mapping i2c addr = 0x%02x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_i2c_addr_select);
int maxim4c_remote_i2c_client_init(maxim4c_remote_t *remote_device,
struct i2c_client *des_client)
{
struct device *dev = remote_device->dev;
struct i2c_client *ser_client = NULL;
u16 ser_client_addr = 0;
if (remote_device->ser_i2c_addr_map)
ser_client_addr = remote_device->ser_i2c_addr_map;
else
ser_client_addr = remote_device->ser_i2c_addr_def;
ser_client = devm_i2c_new_dummy_device(&des_client->dev,
des_client->adapter, ser_client_addr);
if (IS_ERR(ser_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(ser_client);
}
ser_client->addr = remote_device->ser_i2c_addr_def;
remote_device->client = ser_client;
i2c_set_clientdata(ser_client, remote_device);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%02x\n",
ser_client_addr);
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_i2c_client_init);
static int maxim4c_remote_device_chain_check(maxim4c_remote_t *remote_device)
{
struct device *dev = NULL;
struct device_node *endpoint = NULL;
struct device_node *link_node = NULL;
u8 remote_id, link_id;
u32 value;
int ret = 0;
if (remote_device == NULL) {
dev_err(dev, "%s: input parameter is error\n", __func__);
return -EINVAL;
}
dev = remote_device->dev;
remote_id = remote_device->remote_id;
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
if (!endpoint) {
dev_err(dev, "%s: no endpoint error\n", __func__);
return -EINVAL;
}
link_node = of_graph_get_remote_port_parent(endpoint);
if (!link_node) {
dev_err(dev, "%pOF: endpoint has no remote port parent error\n",
endpoint);
return -EINVAL;
}
ret = of_property_read_u32(link_node, "link-id", &value);
if (ret) {
dev_err(dev, "%pOF: no property link_id error\n", link_node);
of_node_put(link_node);
return -EINVAL;
}
of_node_put(link_node);
link_id = value;
if (remote_id != link_id) {
dev_err(dev, "remote_id (%d) != link_id (%d) of %pOF\n",
remote_id, link_id, link_node);
return -EINVAL;
}
return 0;
}
int maxim4c_remote_device_register(maxim4c_t *maxim4c,
maxim4c_remote_t *remote_device)
{
struct device *dev = NULL;
u8 remote_id;
int ret = 0;
if ((maxim4c == NULL) || (remote_device == NULL)) {
dev_err(dev, "%s: input parameter is error!\n",
__func__);
dev_err(dev, "%s: input parameter is error!\n", __func__);
return -EINVAL;
}
dev = remote_device->dev;
remote_id = remote_device->remote_id;
if (remote_id < MAXIM4C_LINK_ID_MAX) {
if (maxim4c->remote_device[remote_id] == NULL) {
remote_device->remote_enable = 1;
maxim4c->remote_device[remote_id] = remote_device;
dev_dbg(dev, "%s: remote_id = %d is success\n",
__func__, remote_id);
return 0;
} else {
dev_err(dev, "%s: remote_id = %d is conflict\n",
__func__, remote_id);
return -EINVAL;
}
} else {
if (remote_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(dev, "%s: remote_id = %d is error\n",
__func__, remote_id);
__func__, remote_id);
return -EINVAL;
}
if (maxim4c->remote_device[remote_id] != NULL) {
dev_err(dev, "%s: remote_id = %d is conflict\n",
__func__, remote_id);
return -EINVAL;
}
ret = maxim4c_remote_device_chain_check(remote_device);
if (ret) {
dev_err(dev, "%s: remote device id = %d chain error\n",
__func__, remote_id);
return -EINVAL;
}
remote_device->remote_enable = 1;
maxim4c->remote_device[remote_id] = remote_device;
return 0;
}
EXPORT_SYMBOL(maxim4c_remote_device_register);

View file

@ -95,6 +95,11 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
dev_info(dev, "=== maxim4c support mode init ===\n");
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_support_mode_init(maxim4c);
return ret;
#endif
maxim4c->cfg_modes_num = 1;
maxim4c->cur_mode = &maxim4c->supported_mode;
mode = &maxim4c->supported_mode;
@ -311,14 +316,12 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
break;
case RKMODULE_SET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
rk3588_dcphy_param = *dphy_param;
rk3588_dcphy_param = *dphy_param;
dev_dbg(&maxim4c->client->dev, "set dcphy param\n");
break;
case RKMODULE_GET_CSI_DPHY_PARAM:
dphy_param = (struct rkmodule_csi_dphy_param *)arg;
if (dphy_param->vendor == rk3588_dcphy_param.vendor)
*dphy_param = rk3588_dcphy_param;
*dphy_param = rk3588_dcphy_param;
dev_dbg(&maxim4c->client->dev, "get dcphy param\n");
break;
default:
@ -430,6 +433,22 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c)
u8 link_mask = 0, link_freq_idx = 0;
u8 video_pipe_mask = 0;
#if MAXIM4C_LOCAL_DES_ON_OFF_EN
#if MAXIM4C_TEST_PATTERN
ret = maxim4c_pattern_hw_init(maxim4c);
if (ret) {
dev_err(dev, "test pattern hw init error\n");
return ret;
}
#else
ret = maxim4c_module_hw_init(maxim4c);
if (ret) {
dev_err(dev, "maxim4c module hw init error\n");
return ret;
}
#endif /* MAXIM4C_TEST_PATTERN */
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
link_mask = maxim4c->gmsl_link.link_enable_mask;
video_pipe_mask = maxim4c->video_pipe.pipe_enable_mask;

View file

@ -100,8 +100,8 @@ static int maxim4c_video_pipe_config_parse_dt(struct device *dev,
pipe_cfg_name,
strlen(pipe_cfg_name))) {
if (sub_idx >= MAXIM4C_PIPE_O_ID_MAX) {
dev_err(dev, "Too many matching %s node\n",
pipe_cfg_name);
dev_err(dev, "%pOF: Too many matching %s node\n",
parent_node, pipe_cfg_name);
of_node_put(node);
break;
@ -205,8 +205,11 @@ int maxim4c_video_pipe_parse_dt(maxim4c_t *maxim4c, struct device_node *of_node)
dev_info(dev, "=== maxim4c video pipe parse dt ===\n");
node = of_get_child_by_name(of_node, "video-pipes");
if (IS_ERR_OR_NULL(node))
if (IS_ERR_OR_NULL(node)) {
dev_err(dev, "%pOF has no child node: video-pipes\n",
of_node);
return -ENODEV;
}
if (!of_device_is_available(node)) {
dev_info(dev, "%pOF is disabled\n", node);
@ -325,21 +328,28 @@ EXPORT_SYMBOL(maxim4c_video_pipe_data_init);
int maxim4c_video_pipe_hw_init(maxim4c_t *maxim4c)
{
struct device *dev = &maxim4c->client->dev;
u8 pipe_enable_mask = 0;
int ret = 0;
ret = maxim4c_video_pipe_select(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe select error\n", __func__);
return ret;
}
pipe_enable_mask = maxim4c->video_pipe.pipe_enable_mask;
ret = maxim4c_video_pipe_mask_enable(maxim4c, pipe_enable_mask, true);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe mask enable error\n", __func__);
return ret;
}
ret = maxim4c_video_pipe_run_init_seq(maxim4c);
if (ret)
if (ret) {
dev_err(dev, "%s: video pipe run init seq error\n", __func__);
return ret;
}
return 0;
}

View file

@ -20,25 +20,6 @@
#define MAX9295_CHIP_ID 0x91
#define MAX9295_REG_CHIP_ID 0x0D
static int max9295_i2c_addr_select(maxim4c_remote_t *max9295, u32 i2c_id)
{
struct device *dev = max9295->dev;
struct i2c_client *client = max9295->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max9295->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max9295->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
{
struct device *dev = max9295->dev;
@ -49,7 +30,7 @@ static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max9295->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
@ -60,7 +41,7 @@ static int max9295_i2c_addr_remap(maxim4c_remote_t *max9295)
return ret;
}
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
}
if (max9295->cam_i2c_addr_map) {
@ -98,7 +79,7 @@ static int max9295_i2c_addr_def(maxim4c_remote_t *max9295)
if (max9295->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max9295->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
@ -109,7 +90,7 @@ static int max9295_i2c_addr_def(maxim4c_remote_t *max9295)
return ret;
}
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
}
return 0;
@ -128,13 +109,13 @@ static int max9295_check_chipid(maxim4c_remote_t *max9295)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX9295_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX9295 detect error, ret(%d)\n", ret);
max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@ -143,13 +124,13 @@ static int max9295_check_chipid(maxim4c_remote_t *max9295)
}
if (chip_id != MAX9295_CHIP_ID) {
dev_err(dev, "Unexpected MAX9295 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX9295 chipid: 0x%02x\n", chip_id);
dev_info(dev, "Detected MAX9295 chip id: 0x%02x\n", chip_id);
return ret;
return 0;
}
static int max9295_soft_power_down(maxim4c_remote_t *max9295)
@ -175,7 +156,7 @@ static int max9295_module_init(maxim4c_remote_t *max9295)
struct i2c_client *client = max9295->client;
int ret = 0;
ret = max9295_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max9295, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@ -263,47 +244,30 @@ static int max9295_parse_dt(maxim4c_remote_t *max9295)
return 0;
}
static int max9295_i2c_client_init(maxim4c_remote_t *max9295,
struct i2c_client *local_client)
{
struct device *dev = max9295->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max9295->ser_i2c_addr_map)
remote_client_addr = max9295->ser_i2c_addr_map;
else
remote_client_addr = max9295->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max9295->ser_i2c_addr_def;
max9295->client = remote_client;
i2c_set_clientdata(remote_client, max9295);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
return 0;
}
static int max9295_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max9295 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max9295 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max9295 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max9295 probe link id = %d\n", link_id);
max9295 = devm_kzalloc(&pdev->dev, sizeof(*max9295), GFP_KERNEL);
if (!max9295)
if (!max9295) {
dev_err(&pdev->dev, "max9295 probe no memory error\n");
return -ENOMEM;
}
max9295->dev = &pdev->dev;
max9295->remote_ops = &max9295_ops;
@ -312,11 +276,22 @@ static int max9295_probe(struct platform_device *pdev)
max9295_parse_dt(max9295);
max9295_i2c_client_init(max9295, client);
if (max9295->remote_id != link_id) {
dev_err(&pdev->dev, "max9295 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max9295, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max9295);
if (ret)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max9295);
@ -329,10 +304,21 @@ static int max9295_remove(struct platform_device *pdev)
}
static const struct of_device_id max9295_of_table[] = {
{ .compatible = "maxim4c,max9295", },
{
.compatible = "maxim4c,link0,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max9295",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max9295_of_table);
static struct platform_driver max9295_driver = {

View file

@ -34,43 +34,28 @@ static int __maybe_unused max96715_link_mode_select(maxim4c_remote_t *max96715,
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
u8 reg_mask = 0, reg_value = 0;
u32 delay_ms = 0;
int ret = 0;
dev_dbg(dev, "%s: mode = %d\n", __func__, mode);
reg_mask = BIT(7) | BIT(6);
if (mode == LINK_MODE_CONFIG)
if (mode == LINK_MODE_CONFIG) {
reg_value = BIT(6);
else
delay_ms = 5;
} else {
reg_value = BIT(7);
delay_ms = 50;
}
ret |= maxim4c_i2c_update_byte(client,
0x04, MAXIM4C_I2C_REG_ADDR_08BITS,
reg_mask, reg_value);
mdelay(5);
msleep(delay_ms);
return ret;
}
static int max96715_i2c_addr_select(maxim4c_remote_t *max96715, u32 i2c_id)
{
struct device *dev = max96715->dev;
struct i2c_client *client = max96715->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max96715->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max96715->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
{
struct device *dev = max96715->dev;
@ -81,7 +66,7 @@ static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max96715->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
@ -92,7 +77,7 @@ static int max96715_i2c_addr_remap(maxim4c_remote_t *max96715)
return ret;
}
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
}
if (max96715->cam_i2c_addr_map) {
@ -130,7 +115,7 @@ static int max96715_i2c_addr_def(maxim4c_remote_t *max96715)
if (max96715->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max96715->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
@ -141,7 +126,7 @@ static int max96715_i2c_addr_def(maxim4c_remote_t *max96715)
return ret;
}
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
}
return 0;
@ -160,13 +145,13 @@ static int max96715_check_chipid(maxim4c_remote_t *max96715)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX96715_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_08BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX96715 detect error, ret(%d)\n", ret);
max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@ -175,13 +160,13 @@ static int max96715_check_chipid(maxim4c_remote_t *max96715)
}
if (chip_id != MAX96715_CHIP_ID) {
dev_err(dev, "Unexpected MAX96715 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96715 chipid: 0x%02x\n", chip_id);
dev_info(dev, "Detected MAX96715 chip id: 0x%02x\n", chip_id);
return ret;
return 0;
}
static int max96715_soft_power_down(maxim4c_remote_t *max96715)
@ -208,7 +193,7 @@ static int max96715_module_init(maxim4c_remote_t *max96715)
struct maxim4c *maxim4c = max96715->local;
int ret = 0;
ret = max96715_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@ -322,47 +307,30 @@ static int max96715_parse_dt(maxim4c_remote_t *max96715)
return 0;
}
static int max96715_i2c_client_init(maxim4c_remote_t *max96715,
struct i2c_client *local_client)
{
struct device *dev = max96715->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max96715->ser_i2c_addr_map)
remote_client_addr = max96715->ser_i2c_addr_map;
else
remote_client_addr = max96715->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max96715->ser_i2c_addr_def;
max96715->client = remote_client;
i2c_set_clientdata(remote_client, max96715);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
return 0;
}
static int max96715_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max96715 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max96715 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max96715 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max96715 probe link id = %d\n", link_id);
max96715 = devm_kzalloc(&pdev->dev, sizeof(*max96715), GFP_KERNEL);
if (!max96715)
if (!max96715) {
dev_err(&pdev->dev, "max96715 probe no memory error\n");
return -ENOMEM;
}
max96715->dev = &pdev->dev;
max96715->remote_ops = &max96715_ops;
@ -371,11 +339,22 @@ static int max96715_probe(struct platform_device *pdev)
max96715_parse_dt(max96715);
max96715_i2c_client_init(max96715, client);
if (max96715->remote_id != link_id) {
dev_err(&pdev->dev, "max96715 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max96715, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max96715);
if (ret)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96715);
@ -388,10 +367,21 @@ static int max96715_remove(struct platform_device *pdev)
}
static const struct of_device_id max96715_of_table[] = {
{ .compatible = "maxim4c,max96715", },
{
.compatible = "maxim4c,link0,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max96715",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max96715_of_table);
static struct platform_driver max96715_driver = {

View file

@ -20,25 +20,6 @@
#define MAX96717_CHIP_ID 0xBF
#define MAX96717_REG_CHIP_ID 0x0D
static int max96717_i2c_addr_select(maxim4c_remote_t *max96717, u32 i2c_id)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
if (i2c_id == MAXIM4C_I2C_SER_DEF) {
client->addr = max96717->ser_i2c_addr_def;
dev_info(dev, "select default i2c addr = 0x%x\n", client->addr);
} else if (i2c_id == MAXIM4C_I2C_SER_MAP) {
client->addr = max96717->ser_i2c_addr_map;
dev_info(dev, "select mapping i2c addr = 0x%x\n", client->addr);
} else {
dev_err(dev, "i2c select id = %d error\n", i2c_id);
return -EINVAL;
}
return 0;
}
static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
@ -49,7 +30,7 @@ static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address remap\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
i2c_8bit_addr = (max96717->ser_i2c_addr_map << 1);
ret = maxim4c_i2c_write_byte(client,
@ -60,7 +41,7 @@ static int max96717_i2c_addr_remap(maxim4c_remote_t *max96717)
return ret;
}
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
}
if (max96717->cam_i2c_addr_map) {
@ -98,7 +79,7 @@ static int max96717_i2c_addr_def(maxim4c_remote_t *max96717)
if (max96717->ser_i2c_addr_map) {
dev_info(dev, "Serializer i2c address def\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
i2c_8bit_addr = (max96717->ser_i2c_addr_def << 1);
ret = maxim4c_i2c_write_byte(client,
@ -109,7 +90,7 @@ static int max96717_i2c_addr_def(maxim4c_remote_t *max96717)
return ret;
}
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
}
return 0;
@ -128,13 +109,13 @@ static int max96717_check_chipid(maxim4c_remote_t *max96717)
&chip_id);
if (ret != 0) {
dev_info(dev, "Retry check chipid using map address\n");
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_MAP);
ret = maxim4c_i2c_read_byte(client,
MAX96717_REG_CHIP_ID, MAXIM4C_I2C_REG_ADDR_16BITS,
&chip_id);
if (ret != 0) {
dev_err(dev, "MAX96717 detect error, ret(%d)\n", ret);
max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
return -ENODEV;
}
@ -143,27 +124,10 @@ static int max96717_check_chipid(maxim4c_remote_t *max96717)
}
if (chip_id != MAX96717_CHIP_ID) {
dev_err(dev, "Unexpected MAX96717 chip id(%02x)\n", chip_id);
dev_err(dev, "Unexpected chip id = %02x\n", chip_id);
return -ENODEV;
}
dev_info(dev, "Detected MAX96717 chipid: 0x%02x\n", chip_id);
return ret;
}
static int max96717_soft_power_down(maxim4c_remote_t *max96717)
{
struct device *dev = max96717->dev;
struct i2c_client *client = max96717->client;
int ret = 0;
ret = maxim4c_i2c_write_byte(client,
0x10, MAXIM4C_I2C_REG_ADDR_16BITS,
BIT(7));
if (ret) {
dev_err(dev, "soft power down setting error!\n");
return ret;
}
dev_info(dev, "Detected MAX96717 chip id: 0x%02x\n", chip_id);
return 0;
}
@ -174,7 +138,7 @@ static int max96717_module_init(maxim4c_remote_t *max96717)
struct i2c_client *client = max96717->client;
int ret = 0;
ret = max96717_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
ret = maxim4c_remote_i2c_addr_select(max96717, MAXIM4C_I2C_SER_DEF);
if (ret)
return ret;
@ -201,10 +165,7 @@ static int max96717_module_deinit(maxim4c_remote_t *max96717)
{
int ret = 0;
#if 0
ret |= max96717_i2c_addr_def(max96717);
#endif
ret |= max96717_soft_power_down(max96717);
return ret;
}
@ -262,47 +223,30 @@ static int max96717_parse_dt(maxim4c_remote_t *max96717)
return 0;
}
static int max96717_i2c_client_init(maxim4c_remote_t *max96717,
struct i2c_client *local_client)
{
struct device *dev = max96717->dev;
struct i2c_client *remote_client = NULL;
u16 remote_client_addr = 0;
if (max96717->ser_i2c_addr_map)
remote_client_addr = max96717->ser_i2c_addr_map;
else
remote_client_addr = max96717->ser_i2c_addr_def;
remote_client = devm_i2c_new_dummy_device(&local_client->dev,
local_client->adapter, remote_client_addr);
if (IS_ERR(remote_client)) {
dev_err(dev, "failed to alloc i2c client.\n");
return -PTR_ERR(remote_client);
}
remote_client->addr = max96717->ser_i2c_addr_def;
max96717->client = remote_client;
i2c_set_clientdata(remote_client, max96717);
dev_info(dev, "remote i2c client init, i2c_addr = 0x%x\n",
remote_client_addr);
return 0;
}
static int max96717_probe(struct platform_device *pdev)
{
struct i2c_client *client = to_i2c_client(pdev->dev.parent);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct maxim4c *maxim4c = v4l2_get_subdevdata(sd);
struct maxim4c_remote *max96717 = NULL;
u32 link_id = MAXIM4C_LINK_ID_MAX;
int ret = 0;
dev_info(&pdev->dev, "max96717 serializer probe\n");
link_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
link_id = link_id - MAXIM4C_LINK_ID_MAX;
if (link_id >= MAXIM4C_LINK_ID_MAX) {
dev_err(&pdev->dev, "max96717 probe match data error\n");
return -EINVAL;
}
dev_info(&pdev->dev, "max96717 probe link id = %d\n", link_id);
max96717 = devm_kzalloc(&pdev->dev, sizeof(*max96717), GFP_KERNEL);
if (!max96717)
if (!max96717) {
dev_err(&pdev->dev, "max96717 probe no memory error\n");
return -ENOMEM;
}
max96717->dev = &pdev->dev;
max96717->remote_ops = &max96717_ops;
@ -311,11 +255,22 @@ static int max96717_probe(struct platform_device *pdev)
max96717_parse_dt(max96717);
max96717_i2c_client_init(max96717, client);
if (max96717->remote_id != link_id) {
dev_err(&pdev->dev, "max96717 probe remote_id error\n");
return -EINVAL;
}
ret = maxim4c_remote_i2c_client_init(max96717, client);
if (ret) {
dev_err(&pdev->dev, "remote i2c client init error\n");
return ret;
}
ret = maxim4c_remote_device_register(maxim4c, max96717);
if (ret)
if (ret) {
dev_err(&pdev->dev, "remote serializer register error\n");
return ret;
}
maxim4c_remote_load_init_seq(max96717);
@ -328,10 +283,21 @@ static int max96717_remove(struct platform_device *pdev)
}
static const struct of_device_id max96717_of_table[] = {
{ .compatible = "maxim4c,max96717", },
{
.compatible = "maxim4c,link0,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_A)
}, {
.compatible = "maxim4c,link1,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_B)
}, {
.compatible = "maxim4c,link2,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_C)
}, {
.compatible = "maxim4c,link3,max96717",
.data = (const void *)(MAXIM4C_LINK_ID_MAX + MAXIM4C_LINK_ID_D)
},
{ /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, max96717_of_table);
static struct platform_driver max96717_driver = {

View file

@ -530,6 +530,16 @@ static int hdmirx_g_dv_timings(struct file *file, void *_fh,
struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev;
u32 dma_cfg1;
if (port_no_link(hdmirx_dev)) {
v4l2_err(v4l2_dev, "%s port has no link!\n", __func__);
return -ENOLINK;
}
if (signal_not_lock(hdmirx_dev)) {
v4l2_err(v4l2_dev, "%s signal is not locked!\n", __func__);
return -ENOLCK;
}
*timings = hdmirx_dev->timings;
dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1);
v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n",
@ -1558,7 +1568,7 @@ static int hdmirx_wait_lock_and_get_timing(struct rk_hdmirx_dev *hdmirx_dev)
}
hdmirx_reset_dma(hdmirx_dev);
usleep_range(200*1000, 200*1010);
usleep_range(500*1000, 500*1010);
hdmirx_format_change(hdmirx_dev);
return 0;
@ -2473,13 +2483,28 @@ static void mainunit_2_int_handler(struct rk_hdmirx_dev *hdmirx_dev,
hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_FORCE, 0x0);
}
/*
* In the normal preview, some scenarios will trigger the change interrupt
* by mistake, and the trigger source of the interrupt needs to be detected
* to avoid the problem.
*/
static void pkt_0_int_handler(struct rk_hdmirx_dev *hdmirx_dev,
int status, bool *handled)
{
struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev;
u32 pre_fmt_fourcc = hdmirx_dev->cur_fmt_fourcc;
u32 pre_color_range = hdmirx_dev->cur_color_range;
u32 pre_color_space = hdmirx_dev->cur_color_space;
if ((status & PKTDEC_AVIIF_CHG_IRQ)) {
process_signal_change(hdmirx_dev);
hdmirx_get_color_range(hdmirx_dev);
hdmirx_get_color_space(hdmirx_dev);
hdmirx_get_pix_fmt(hdmirx_dev);
if (hdmirx_dev->cur_fmt_fourcc != pre_fmt_fourcc ||
hdmirx_dev->cur_color_range != pre_color_range ||
hdmirx_dev->cur_color_space != pre_color_space) {
process_signal_change(hdmirx_dev);
}
v4l2_dbg(2, debug, v4l2_dev, "%s: ptk0_st:%#x\n",
__func__, status);
*handled = true;

View file

@ -1537,7 +1537,7 @@ static struct irq_chip rk_pcie_legacy_irq_chip = {
static int rk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &rk_pcie_legacy_irq_chip, handle_simple_irq);
irq_set_chip_and_handler(irq, &rk_pcie_legacy_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
return 0;

View file

@ -26,11 +26,6 @@
#include "rpmsg_internal.h"
enum rk_rpmsg_chip {
RK3562,
RK3568,
};
struct rk_virtio_dev {
struct virtio_device vdev;
unsigned int vring[2];
@ -44,7 +39,6 @@ struct rk_virtio_dev {
struct rk_rpmsg_dev {
struct platform_device *pdev;
enum rk_rpmsg_chip chip;
int vdev_nums;
unsigned int link_id;
int first_notify;
@ -307,7 +301,6 @@ static int rockchip_rpmsg_probe(struct platform_device *pdev)
dev_info(dev, "rockchip rpmsg platform probe.\n");
rpdev->pdev = pdev;
rpdev->chip = (enum rk_rpmsg_chip)device_get_match_data(dev);
rpdev->first_notify = 0;
cl = &rpdev->mbox_cl;
@ -399,8 +392,7 @@ static int rockchip_rpmsg_remove(struct platform_device *pdev)
}
static const struct of_device_id rockchip_rpmsg_match[] = {
{ .compatible = "rockchip,rk3562-rpmsg", .data = (void *)RK3562, },
{ .compatible = "rockchip,rk3568-rpmsg", .data = (void *)RK3568, },
{ .compatible = "rockchip,rpmsg", },
{ /* sentinel */ },
};

View file

@ -2104,7 +2104,7 @@ task_done_ret:
if (ret < 0)
return ret;
} while (ret > 0);
} while (!ret);
rkvenc2_task_timeout_process(session, task);

View file

@ -97,6 +97,9 @@ struct rv1106_codec_priv {
unsigned int mic_mute_l;
unsigned int mic_mute_r;
/* DAC Control Manually */
unsigned int dac_ctrl_manual;
/* For the high pass filter */
unsigned int hpf_cutoff;
@ -182,12 +185,22 @@ static int rv1106_codec_main_micbias_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int rv1106_codec_main_micbias_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static const char *offon_text[2] = {
[0] = "Off",
[1] = "On",
};
static const char *noneoffon_text[3] = {
[0] = "None",
[1] = "Off",
[2] = "On",
};
static const char *mute_text[2] = {
[0] = "Work",
[1] = "Mute",
@ -254,6 +267,11 @@ static const struct soc_enum rv1106_mic_mute_enum_array[] = {
SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(mute_text), mute_text),
};
/* DAC Control Manually */
static const struct soc_enum rv1106_dac_pa_ctrl_maunal_enum_array[] = {
SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(noneoffon_text), noneoffon_text),
};
/* ALC AGC Approximate Sample Rate */
#define AGC_ASR_NUM 8
@ -422,6 +440,10 @@ static const struct snd_kcontrol_new rv1106_codec_dapm_controls[] = {
rv1106_codec_hpmix_gain_get,
rv1106_codec_hpmix_gain_put,
rv1106_codec_dac_hpmix_gain_tlv),
/* DAC Control Manually */
SOC_ENUM_EXT("DAC Control Manually", rv1106_dac_pa_ctrl_maunal_enum_array[0],
rv1106_codec_dac_ctrl_manual_get, rv1106_codec_dac_ctrl_manual_put),
};
static unsigned int using_adc_lr(enum adc_mode_e adc_mode)
@ -1015,35 +1037,47 @@ static int rv1106_codec_adc_dig_config(struct rv1106_codec_priv *rv1106,
return 0;
}
static int rv1106_codec_dac_mute(struct rv1106_codec_priv *rv1106, int mute)
{
if (mute) {
/* Mute DAC HPMIX/LINEOUT */
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_ANA_CTL1,
ACODEC_DAC_L_LINEOUT_MUTE_MSK,
ACODEC_DAC_L_LINEOUT_MUTE);
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_HPMIX_CTL,
ACODEC_DAC_HPMIX_MUTE_MSK,
ACODEC_DAC_HPMIX_MUTE);
rv1106_codec_pa_ctrl(rv1106, false);
} else {
/* Unmute DAC HPMIX/LINEOUT */
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_HPMIX_CTL,
ACODEC_DAC_HPMIX_MUTE_MSK,
ACODEC_DAC_HPMIX_WORK);
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_ANA_CTL1,
ACODEC_DAC_L_LINEOUT_MUTE_MSK,
ACODEC_DAC_L_LINEOUT_WORK);
rv1106_codec_pa_ctrl(rv1106, true);
}
return 0;
}
static int rv1106_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (mute) {
/* Mute DAC HPMIX/LINEOUT */
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_ANA_CTL1,
ACODEC_DAC_L_LINEOUT_MUTE_MSK,
ACODEC_DAC_L_LINEOUT_MUTE);
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_HPMIX_CTL,
ACODEC_DAC_HPMIX_MUTE_MSK,
ACODEC_DAC_HPMIX_MUTE);
rv1106_codec_pa_ctrl(rv1106, false);
} else {
/* Unmute DAC HPMIX/LINEOUT */
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_HPMIX_CTL,
ACODEC_DAC_HPMIX_MUTE_MSK,
ACODEC_DAC_HPMIX_WORK);
regmap_update_bits(rv1106->regmap,
ACODEC_DAC_L_LINEOUT_MUTE_MSK,
ACODEC_DAC_MUTE_MSK,
ACODEC_DAC_L_LINEOUT_WORK);
rv1106_codec_pa_ctrl(rv1106, true);
}
if (rv1106->dac_ctrl_manual == 1)
mute = 1; /* Force DAC control off manually */
else if (rv1106->dac_ctrl_manual == 2)
mute = 0; /* Force DAC control on manually */
rv1106_codec_dac_mute(rv1106, mute);
}
return 0;
@ -1343,6 +1377,36 @@ static int rv1106_codec_hpmix_gain_put(struct snd_kcontrol *kcontrol,
return snd_soc_put_volsw_range(kcontrol, ucontrol);
}
static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = rv1106->dac_ctrl_manual;
return 0;
}
static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component);
rv1106->dac_ctrl_manual = ucontrol->value.integer.value[0];
if (rv1106->dac_ctrl_manual == 0)
return 0;
if (rv1106->dac_ctrl_manual == 1)
rv1106_codec_dac_mute(rv1106, 1); /* Force DAC control off manually */
else if (rv1106->dac_ctrl_manual == 2)
rv1106_codec_dac_mute(rv1106, 0); /* Force DAC control on manually */
return 0;
}
static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106)
{
unsigned int lr = using_adc_lr(rv1106->adc_mode);
@ -1774,6 +1838,7 @@ static int rv1106_codec_check_micbias(struct rv1106_codec_priv *rv1106,
static int rv1106_codec_dapm_controls_prepare(struct rv1106_codec_priv *rv1106)
{
rv1106->adc_mode = DIFF_ADCL;
rv1106->dac_ctrl_manual = 0;
rv1106->hpf_cutoff = 0;
rv1106->agc_l = 0;
rv1106->agc_r = 0;

View file

@ -66,6 +66,12 @@ config SND_SOC_ROCKCHIP_SAI
Rockchip SAI Controller. The Controller supports up to maximum of
128 channels each for play and record.
config SND_SOC_ROCKCHIP_SAI_VERBOSE
bool "Rockchip SAI Verbose Controls"
depends on SND_SOC_ROCKCHIP_SAI
help
Say Y if you want to export much more controls and info for SAI.
config SND_SOC_ROCKCHIP_SPDIF
tristate "Rockchip SPDIF Device Driver"
depends on HAVE_CLK && SND_SOC_ROCKCHIP

View file

@ -653,7 +653,9 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
i2s->has_capture ? &i2s->capture_dma_data : NULL);
if (i2s->mclk_calibrate)
snd_soc_add_dai_controls(dai, &rockchip_i2s_compensation_control, 1);
snd_soc_add_component_controls(dai->component,
&rockchip_i2s_compensation_control,
1);
return 0;
}

View file

@ -66,6 +66,7 @@
#define CLK_PPM_MIN (-1000)
#define CLK_PPM_MAX (1000)
#define MAXBURST_PER_FIFO 8
#define WAIT_TIME_MS_MAX 10000
#define TRCM_TXRX 0
#define TRCM_TX 1
@ -114,6 +115,7 @@ struct rk_i2s_tdm_dev {
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1];
struct reset_control *tx_reset;
struct reset_control *rx_reset;
struct pinctrl *pinctrl;
@ -2030,7 +2032,101 @@ static int rockchip_i2s_tdm_loopback_put(struct snd_kcontrol *kcontrol,
return 0;
}
static const char * const rpaths_text[] = {
"From SDI0", "From SDI1", "From SDI2", "From SDI3" };
static const char * const tpaths_text[] = {
"From PATH0", "From PATH1", "From PATH2", "From PATH3" };
/* TXCR */
static SOC_ENUM_SINGLE_DECL(tpath3_enum, I2S_TXCR, 29, tpaths_text);
static SOC_ENUM_SINGLE_DECL(tpath2_enum, I2S_TXCR, 27, tpaths_text);
static SOC_ENUM_SINGLE_DECL(tpath1_enum, I2S_TXCR, 25, tpaths_text);
static SOC_ENUM_SINGLE_DECL(tpath0_enum, I2S_TXCR, 23, tpaths_text);
/* RXCR */
static SOC_ENUM_SINGLE_DECL(rpath3_enum, I2S_RXCR, 23, rpaths_text);
static SOC_ENUM_SINGLE_DECL(rpath2_enum, I2S_RXCR, 21, rpaths_text);
static SOC_ENUM_SINGLE_DECL(rpath1_enum, I2S_RXCR, 19, rpaths_text);
static SOC_ENUM_SINGLE_DECL(rpath0_enum, I2S_RXCR, 17, rpaths_text);
static int rockchip_i2s_tdm_wait_time_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = WAIT_TIME_MS_MAX;
uinfo->value.integer.step = 1;
return 0;
}
static int rockchip_i2s_tdm_rd_wait_time_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = i2s_tdm->wait_time[SNDRV_PCM_STREAM_CAPTURE];
return 0;
}
static int rockchip_i2s_tdm_rd_wait_time_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
return -EINVAL;
i2s_tdm->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0];
return 1;
}
static int rockchip_i2s_tdm_wr_wait_time_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = i2s_tdm->wait_time[SNDRV_PCM_STREAM_PLAYBACK];
return 0;
}
static int rockchip_i2s_tdm_wr_wait_time_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
return -EINVAL;
i2s_tdm->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0];
return 1;
}
#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \
.info = rockchip_i2s_tdm_wait_time_info, \
.get = xhandler_get, .put = xhandler_put }
static const struct snd_kcontrol_new rockchip_i2s_tdm_snd_controls[] = {
SOC_ENUM("Receive PATH3 Source Select", rpath3_enum),
SOC_ENUM("Receive PATH2 Source Select", rpath2_enum),
SOC_ENUM("Receive PATH1 Source Select", rpath1_enum),
SOC_ENUM("Receive PATH0 Source Select", rpath0_enum),
SOC_ENUM("Transmit SDO3 Source Select", tpath3_enum),
SOC_ENUM("Transmit SDO2 Source Select", tpath2_enum),
SOC_ENUM("Transmit SDO1 Source Select", tpath1_enum),
SOC_ENUM("Transmit SDO0 Source Select", tpath0_enum),
SOC_ENUM_EXT("I2STDM Digital Loopback Mode", loopback_mode,
rockchip_i2s_tdm_loopback_get,
rockchip_i2s_tdm_loopback_put),
@ -2040,6 +2136,12 @@ static const struct snd_kcontrol_new rockchip_i2s_tdm_snd_controls[] = {
SOC_ENUM_EXT("Receive SDIx Select", rx_lanes_enum,
rockchip_i2s_tdm_rx_lanes_get, rockchip_i2s_tdm_rx_lanes_put),
#endif
SAI_PCM_WAIT_TIME("PCM Read Wait Time MS",
rockchip_i2s_tdm_rd_wait_time_get,
rockchip_i2s_tdm_rd_wait_time_put),
SAI_PCM_WAIT_TIME("PCM Write Wait Time MS",
rockchip_i2s_tdm_wr_wait_time_get,
rockchip_i2s_tdm_wr_wait_time_put),
};
static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
@ -2052,7 +2154,9 @@ static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
dai->playback_dma_data = &i2s_tdm->playback_dma_data;
if (i2s_tdm->mclk_calibrate)
snd_soc_add_dai_controls(dai, &rockchip_i2s_tdm_compensation_control, 1);
snd_soc_add_component_controls(dai->component,
&rockchip_i2s_tdm_compensation_control,
1);
return 0;
}
@ -2101,11 +2205,15 @@ static int rockchip_i2s_tdm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
if (i2s_tdm->substreams[substream->stream])
if (i2s_tdm->substreams[stream])
return -EBUSY;
i2s_tdm->substreams[substream->stream] = substream;
if (i2s_tdm->wait_time[stream])
substream->wait_time = msecs_to_jiffies(i2s_tdm->wait_time[stream]);
i2s_tdm->substreams[stream] = substream;
return 0;
}

View file

@ -23,6 +23,8 @@
#define DAIS_DRV_NAME "rockchip-mdais"
#define RK3308_GRF_SOC_CON2 0x308
#define SOUND_NAME_PREFIX "sound-name-prefix"
static inline struct rk_mdais_dev *to_info(struct snd_soc_dai *dai)
{
return snd_soc_dai_get_drvdata(dai);
@ -220,13 +222,23 @@ static int rockchip_mdais_tdm_slot(struct snd_soc_dai *dai,
static int rockchip_mdais_dai_probe(struct snd_soc_dai *dai)
{
struct rk_mdais_dev *mdais = to_info(dai);
struct snd_soc_component *comp;
struct snd_soc_dai *child;
const char *str;
int ret, i = 0;
for (i = 0; i < mdais->num_dais; i++) {
child = mdais->dais[i].dai;
comp = child->component;
if (!child->probed && child->driver->probe) {
child->component->card = dai->component->card;
if (!comp->name_prefix) {
ret = device_property_read_string(child->dev,
SOUND_NAME_PREFIX, &str);
if (!ret)
comp->name_prefix = str;
}
comp->card = dai->component->card;
ret = child->driver->probe(child);
if (ret < 0) {
dev_err(child->dev,
@ -234,6 +246,14 @@ static int rockchip_mdais_dai_probe(struct snd_soc_dai *dai)
child->name, ret);
return ret;
}
ret = snd_soc_add_component_controls(comp,
comp->driver->controls,
comp->driver->num_controls);
if (ret)
dev_err(dai->dev, "%s: Failed to add controls, should add '%s' in DT\n",
dev_name(child->dev), SOUND_NAME_PREFIX);
dai->probed = 1;
}
}
@ -383,9 +403,9 @@ static int rockchip_mdais_dai_prepare(struct platform_device *pdev,
.probe = rockchip_mdais_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 32,
.rates = SNDRV_PCM_RATE_8000_192000,
.channels_min = 1,
.channels_max = 512,
.rates = SNDRV_PCM_RATE_8000_384000,
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
@ -394,9 +414,9 @@ static int rockchip_mdais_dai_prepare(struct platform_device *pdev,
},
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 32,
.rates = SNDRV_PCM_RATE_8000_192000,
.channels_min = 1,
.channels_max = 512,
.rates = SNDRV_PCM_RATE_8000_384000,
.formats = (SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |

View file

@ -20,6 +20,10 @@
#define MAX_FIFO_SIZE 32 /* max fifo size in frames */
#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm"
static unsigned int prealloc_buffer_size_kbytes = 512;
module_param(prealloc_buffer_size_kbytes, uint, 0444);
MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB).");
struct dmaengine_mpcm {
struct rk_mdais_dev *mdais;
struct dma_chan *tx_chans[MAX_DAIS];
@ -561,7 +565,7 @@ static int dmaengine_mpcm_new(struct snd_soc_component *component, struct snd_so
size_t max_buffer_size;
unsigned int i;
prealloc_buffer_size = 512 * 1024;
prealloc_buffer_size = prealloc_buffer_size_kbytes * 1024;
max_buffer_size = SIZE_MAX;
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
@ -683,6 +687,9 @@ int snd_dmaengine_mpcm_register(struct rk_mdais_dev *mdais)
if (!pcm)
return -ENOMEM;
#ifdef CONFIG_DEBUG_FS
pcm->component.debugfs_prefix = "dma";
#endif
pcm->mdais = mdais;
for (i = 0; i < num; i++) {
child = mdais->dais[i].dev;

View file

@ -22,6 +22,7 @@
#define DRV_NAME "rockchip-sai"
#define CLK_SHIFT_RATE_HZ_MAX 1 /* 1 Hz */
#define FW_RATIO_MAX 8
#define FW_RATIO_MIN 1
#define MAXBURST_PER_FIFO 8
@ -496,9 +497,10 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
if (sai->is_clk_auto)
clk_set_rate(sai->mclk, bclk_rate);
mclk_rate = clk_get_rate(sai->mclk);
if (mclk_rate < bclk_rate) {
dev_err(sai->dev, "Mismatch mclk: %u, expected %u at least\n",
mclk_rate, bclk_rate);
if (mclk_rate < bclk_rate - CLK_SHIFT_RATE_HZ_MAX ||
mclk_rate > bclk_rate + CLK_SHIFT_RATE_HZ_MAX) {
dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
mclk_rate, bclk_rate, CLK_SHIFT_RATE_HZ_MAX);
return -EINVAL;
}
@ -795,8 +797,8 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
if (sai->has_playback) {
dai->playback.stream_name = "Playback";
dai->playback.channels_min = 1;
dai->playback.channels_max = 128;
dai->playback.rates = SNDRV_PCM_RATE_8000_192000;
dai->playback.channels_max = 512;
dai->playback.rates = SNDRV_PCM_RATE_8000_384000;
dai->playback.formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
@ -811,8 +813,8 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
if (sai->has_capture) {
dai->capture.stream_name = "Capture";
dai->capture.channels_min = 1;
dai->capture.channels_max = 128;
dai->capture.rates = SNDRV_PCM_RATE_8000_192000;
dai->capture.channels_max = 512;
dai->capture.rates = SNDRV_PCM_RATE_8000_384000;
dai->capture.formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
@ -867,14 +869,14 @@ static const char * const lpx_text[] = {
"From SDO0", "From SDO1", "From SDO2", "From SDO3" };
static const char * const lps_text[] = { "Disable", "Enable" };
static const char * const sync_out_text[] = { "External", "Internal" };
static const char * const sync_in_text[] = { "External", "Internal" };
static const char * const sync_out_text[] = { "From CRU", "From IO" };
static const char * const sync_in_text[] = { "From IO", "From Sync Port" };
static const char * const rpaths_text[] = {
"From SDI0", "From SDI1", "From SDI2", "From SDI3" };
static const char * const tpaths_text[] = {
"To SDO0", "To SDO1", "To SDO2", "To SDO3" };
"From PATH0", "From PATH1", "From PATH2", "From PATH3" };
/* TXCR */
static SOC_ENUM_SINGLE_DECL(tsft_enum, SAI_TXCR, 22, edge_shift_text);
@ -931,8 +933,8 @@ static SOC_ENUM_SINGLE_DECL(tpath2_enum, SAI_PATH_SEL, 4, tpaths_text);
static SOC_ENUM_SINGLE_DECL(tpath1_enum, SAI_PATH_SEL, 2, tpaths_text);
static SOC_ENUM_SINGLE_DECL(tpath0_enum, SAI_PATH_SEL, 0, tpaths_text);
static int rockchip_sai_fpw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_fpw_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -942,8 +944,8 @@ static int rockchip_sai_fpw_get(struct snd_kcontrol *kcontrol,
return 0;
}
static int rockchip_sai_fpw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_fpw_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -958,8 +960,8 @@ static int rockchip_sai_fpw_put(struct snd_kcontrol *kcontrol,
return 1;
}
static int rockchip_sai_fw_ratio_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_fw_ratio_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -969,8 +971,8 @@ static int rockchip_sai_fw_ratio_get(struct snd_kcontrol *kcontrol,
return 0;
}
static int rockchip_sai_fw_ratio_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_fw_ratio_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -1038,8 +1040,8 @@ static int rockchip_sai_rx_lanes_put(struct snd_kcontrol *kcontrol,
return 1;
}
static int rockchip_sai_mss_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_mss_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -1049,8 +1051,8 @@ static int rockchip_sai_mss_get(struct snd_kcontrol *kcontrol,
return 0;
}
static int rockchip_sai_mss_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int __maybe_unused rockchip_sai_mss_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_sai_dev *sai = snd_soc_component_get_drvdata(component);
@ -1186,21 +1188,17 @@ static int rockchip_sai_wr_wait_time_put(struct snd_kcontrol *kcontrol,
.info = rockchip_sai_wait_time_info, \
.get = xhandler_get, .put = xhandler_put }
static DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0);
static __maybe_unused DECLARE_TLV_DB_SCALE(fs_shift_tlv, 0, 8192, 0);
static const struct snd_kcontrol_new rockchip_sai_controls[] = {
#ifdef CONFIG_SND_SOC_ROCKCHIP_SAI_VERBOSE
SOC_ENUM("Transmit Edge Shift", tsft_enum),
SOC_ENUM_EXT("Transmit SDOx Select", tx_lanes_enum,
rockchip_sai_tx_lanes_get, rockchip_sai_tx_lanes_put),
SOC_ENUM("Transmit Store Justified Mode", tsjm_enum),
SOC_ENUM("Transmit First Bit Mode", tfbm_enum),
SOC_ENUM("Transmit Valid Data Justified", tvdj_enum),
SOC_ENUM("Transmit Slot Bit Width", tsbw_enum),
SOC_ENUM("Receive Edge Shift", rsft_enum),
SOC_ENUM_EXT("Receive SDIx Select", rx_lanes_enum,
rockchip_sai_rx_lanes_get, rockchip_sai_rx_lanes_put),
SOC_ENUM("Receive Store Justified Mode", rsjm_enum),
SOC_ENUM("Receive First Bit Mode", rfbm_enum),
SOC_ENUM("Receive Valid Data Justified", rvdj_enum),
@ -1212,16 +1210,25 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = {
SOC_ENUM_EXT("Frame Width Ratio", fw_ratio_enum,
rockchip_sai_fw_ratio_get, rockchip_sai_fw_ratio_put),
SOC_ENUM_EXT("Master Slave Mode Select", mss_switch,
rockchip_sai_mss_get, rockchip_sai_mss_put),
SOC_ENUM("Sclk Polarity", sp_switch),
SOC_ENUM("Frame Sync Polarity", fp_switch),
SOC_SINGLE_TLV("Transmit Frame Shift Select", SAI_TX_SHIFT,
0, 8192, 0, fs_shift_tlv),
SOC_SINGLE_TLV("Receive Frame Shift Select", SAI_RX_SHIFT,
0, 8192, 0, fs_shift_tlv),
#endif
SOC_ENUM_EXT("Transmit SDOx Select", tx_lanes_enum,
rockchip_sai_tx_lanes_get, rockchip_sai_tx_lanes_put),
SOC_ENUM_EXT("Receive SDIx Select", rx_lanes_enum,
rockchip_sai_rx_lanes_get, rockchip_sai_rx_lanes_put),
SOC_SINGLE_TLV("Receive Mono Slot Select", SAI_MONO_CR,
2, 128, 0, rmss_tlv),
SOC_ENUM("Receive Mono Switch", rmono_switch),
SOC_ENUM("Transmit Mono Switch", tmono_switch),
SOC_ENUM_EXT("Master / Slave Mode Select", mss_switch,
rockchip_sai_mss_get, rockchip_sai_mss_put),
SOC_ENUM("Sclk Polarity", sp_switch),
SOC_ENUM("Frame Sync Polarity", fp_switch),
SOC_ENUM("SDI3 Loopback Src Select", lp3_enum),
SOC_ENUM("SDI2 Loopback Src Select", lp2_enum),
SOC_ENUM("SDI1 Loopback Src Select", lp1_enum),
@ -1236,15 +1243,10 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = {
SOC_ENUM("Receive PATH2 Source Select", rpath2_enum),
SOC_ENUM("Receive PATH1 Source Select", rpath1_enum),
SOC_ENUM("Receive PATH0 Source Select", rpath0_enum),
SOC_ENUM("Transmit PATH3 Sink Select", tpath3_enum),
SOC_ENUM("Transmit PATH2 Sink Select", tpath2_enum),
SOC_ENUM("Transmit PATH1 Sink Select", tpath1_enum),
SOC_ENUM("Transmit PATH0 Sink Select", tpath0_enum),
SOC_SINGLE_TLV("Transmit Frame Shift Select", SAI_TX_SHIFT,
0, 8192, 0, fs_shift_tlv),
SOC_SINGLE_TLV("Receive Frame Shift Select", SAI_RX_SHIFT,
0, 8192, 0, fs_shift_tlv),
SOC_ENUM("Transmit SDO3 Source Select", tpath3_enum),
SOC_ENUM("Transmit SDO2 Source Select", tpath2_enum),
SOC_ENUM("Transmit SDO1 Source Select", tpath1_enum),
SOC_ENUM("Transmit SDO0 Source Select", tpath0_enum),
SOC_SINGLE_BOOL_EXT("Clk Auto Switch", 0,
rockchip_sai_clk_auto_get,
@ -1276,6 +1278,9 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid)
dev_warn_ratelimited(sai->dev, "TX FIFO Underrun\n");
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXUIC, SAI_INTCR_TXUIC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_TXUIE_MASK,
SAI_INTCR_TXUIE(0));
substream = sai->substreams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream)
snd_pcm_stop_xrun(substream);
@ -1285,6 +1290,9 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid)
dev_warn_ratelimited(sai->dev, "RX FIFO Overrun\n");
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXOIC, SAI_INTCR_RXOIC);
regmap_update_bits(sai->regmap, SAI_INTCR,
SAI_INTCR_RXOIE_MASK,
SAI_INTCR_RXOIE(0));
substream = sai->substreams[SNDRV_PCM_STREAM_CAPTURE];
if (substream)
snd_pcm_stop_xrun(substream);