summaryrefslogtreecommitdiffstats
path: root/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch')
-rw-r--r--bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch4855
1 files changed, 4855 insertions, 0 deletions
diff --git a/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch
new file mode 100644
index 00000000..a9535a92
--- /dev/null
+++ b/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0493-media-i2c-add-max96712-and-max9296.patch
@@ -0,0 +1,4855 @@
+From 845697c2d8a9620131759d72483923ed5612063d Mon Sep 17 00:00:00 2001
+From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+Date: Mon, 27 Apr 2020 10:52:23 +0300
+Subject: [PATCH] media: i2c: add max96712 and max9296
+
+This adds GMSL2 drivers for MAX96712 and MAX9296
+
+Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
+Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
+---
+ drivers/media/i2c/soc_camera/gmsl/Kconfig | 14 +
+ drivers/media/i2c/soc_camera/gmsl/Makefile | 2 +
+ drivers/media/i2c/soc_camera/gmsl/common.h | 499 +++++++
+ drivers/media/i2c/soc_camera/gmsl/max9295.h | 29 +
+ drivers/media/i2c/soc_camera/gmsl/max9296.c | 1423 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/gmsl/max9296.h | 281 ++++
+ drivers/media/i2c/soc_camera/gmsl/max9296_debug.h | 462 +++++++
+ drivers/media/i2c/soc_camera/gmsl/max96712.c | 1423 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/gmsl/max96712.h | 263 ++++
+ drivers/media/i2c/soc_camera/gmsl/max96712_debug.h | 362 +++++
+ 10 files changed, 4758 insertions(+)
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/common.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9295.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.c
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.c
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712.h
+ create mode 100644 drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Kconfig b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+index c7a33bf..4a7dd6c 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/Kconfig
++++ b/drivers/media/i2c/soc_camera/gmsl/Kconfig
+@@ -9,3 +9,17 @@ config SOC_CAMERA_MAX9288
+ depends on I2C
+ help
+ This is a MAXIM max9288 GMSL driver
++
++config SOC_CAMERA_MAX9296
++ tristate "max9296 GMSL2 support"
++ depends on I2C
++ select REGMAP_I2C
++ help
++ This is a MAXIM max9296 GMSL2 driver
++
++config SOC_CAMERA_MAX96712
++ tristate "max96712 GMSL2 support"
++ depends on I2C
++ select REGMAP_I2C
++ help
++ This is a MAXIM max96712 GMSL2 driver
+diff --git a/drivers/media/i2c/soc_camera/gmsl/Makefile b/drivers/media/i2c/soc_camera/gmsl/Makefile
+index 9925314..bda7a58 100644
+--- a/drivers/media/i2c/soc_camera/gmsl/Makefile
++++ b/drivers/media/i2c/soc_camera/gmsl/Makefile
+@@ -1,3 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o
+ obj-$(CONFIG_SOC_CAMERA_MAX9288) += max9288.o
++obj-$(CONFIG_SOC_CAMERA_MAX9296) += max9296.o
++obj-$(CONFIG_SOC_CAMERA_MAX96712) += max96712.o
+diff --git a/drivers/media/i2c/soc_camera/gmsl/common.h b/drivers/media/i2c/soc_camera/gmsl/common.h
+new file mode 100644
+index 0000000..98bb1c0
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/common.h
+@@ -0,0 +1,499 @@
++/*
++ * MAXIM GMSL common header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/i2c-mux.h>
++#include "max9295.h"
++
++#define MAX9271_ID 0x09
++#define MAX9286_ID 0x40
++#define MAX9288_ID 0x2A
++#define MAX9290_ID 0x2C
++#define MAX9295A_ID 0x91
++#define MAX9295B_ID 0x93
++#define MAX9296A_ID 0x94
++#define MAX96705_ID 0x41
++#define MAX96706_ID 0x4A
++#define MAX96707_ID 0x45 /* MAX96715: same but lack of HS pin */
++#define MAX96708_ID 0x4C
++#define MAX96712_ID 0x20
++
++#define UB960_ID 0x00 /* strapped */
++
++#define BROADCAST 0x6f
++
++#define REG8_NUM_RETRIES 1 /* number of read/write retries */
++#define REG16_NUM_RETRIES 10 /* number of read/write retries */
++
++static inline char* chip_name(int id)
++{
++ switch (id) {
++ case MAX9271_ID:
++ return "MAX9271";
++ case MAX9286_ID:
++ return "MAX9286";
++ case MAX9288_ID:
++ return "MAX9288";
++ case MAX9290_ID:
++ return "MAX9290";
++ case MAX9295A_ID:
++ return "MAX9295A";
++ case MAX9295B_ID:
++ return "MAX9295B";
++ case MAX9296A_ID:
++ return "MAX9296A";
++ case MAX96705_ID:
++ return "MAX96705";
++ case MAX96706_ID:
++ return "MAX96706";
++ case MAX96707_ID:
++ return "MAX96707";
++ case MAX96712_ID:
++ return "MAX96712";
++ default:
++ return "serializer";
++ }
++}
++
++enum gmsl_mode {
++ MODE_GMSL1 = 1,
++ MODE_GMSL2,
++};
++
++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */
++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */
++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */
++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */
++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */
++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */
++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */
++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ
++
++#define MIPI_DT_GENERIC 0x10
++#define MIPI_DT_GENERIC_1 0x11
++#define MIPI_DT_EMB 0x12
++#define MIPI_DT_YUV8 0x1e
++#define MIPI_DT_YUV10 0x1f
++#define MIPI_DT_RGB565 0x22
++#define MIPI_DT_RGB666 0x23
++#define MIPI_DT_RGB888 0x24
++#define MIPI_DT_RAW8 0x2a
++#define MIPI_DT_RAW10 0x2b
++#define MIPI_DT_RAW12 0x2c
++#define MIPI_DT_RAW14 0x2d
++#define MIPI_DT_RAW16 0x2e
++#define MIPI_DT_RAW20 0x2f
++#define MIPI_DT_YUV12 0x30
++
++static inline int mipi_dt_to_bpp(unsigned int dt)
++{
++ switch (dt) {
++ case 0x2a:
++ case 0x10 ... 0x12:
++ case 0x31 ... 0x37:
++ return 0x08;
++ case 0x2b:
++ return 0x0a;
++ case 0x2c:
++ return 0x0c;
++ case 0x0d:
++ return 0x0e;
++ case 0x22:
++ case 0x1e:
++ case 0x2e:
++ return 0x10;
++ case 0x23:
++ return 0x12;
++ case 0x1f:
++ case 0x2f:
++ return 0x14;
++ case 0x24:
++ case 0x30:
++ return 0x18;
++ default:
++ return 0x08;
++ }
++}
++
++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val)
++{
++ int ret, retries;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_read_byte_data(client, reg);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ret;
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val)
++{
++ int ret, retries;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_write_byte_data(client, reg, val);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2;
++ reg8_read(client, reg, &val2);
++ if (val != val2)
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x "
++ "0x%x->0x%x\n", client->addr, reg, val, val2);
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 1);
++ if (ret == 1)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = buf[0];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val)
++{
++ int ret, retries;
++ u8 buf[3] = {reg >> 8, reg & 0xff, val};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 3);
++ if (ret == 3)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2;
++ reg16_read(client, reg, &val2);
++ if (val != val2)
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x "
++ "0x%x->0x%x\n", client->addr, reg, val, val2);
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, buf, 2);
++ if (ret == 2)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ } else {
++ *val = ((u16)buf[0] << 8) | buf[1];
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val)
++{
++ int ret, retries;
++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff};
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 4);
++ if (ret == 4)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x: %d\n",
++ client->addr, reg, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_read_n(struct i2c_client *client, u16 reg, u8 *val, int n)
++{
++ int ret, retries;
++ u8 buf[2] = {reg >> 8, reg & 0xff};
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2);
++ if (ret == 2) {
++ ret = i2c_master_recv(client, val, n);
++ if (ret == n)
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x registers 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg16_write_n(struct i2c_client *client, u16 reg, const u8* val, int n)
++{
++ int ret, retries;
++ u8 buf[2 + n];
++
++ buf[0] = reg >> 8;
++ buf[1] = reg & 0xff;
++ memcpy(&buf[2], val, n);
++
++ for (retries = REG16_NUM_RETRIES; retries; retries--) {
++ ret = i2c_master_send(client, buf, 2 + n);
++ if (ret == 2 + n)
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x-0x%x: %d\n",
++ client->addr, reg, reg + n, ret);
++ } else {
++#ifdef WRITE_VERIFY
++ u8 val2[n];
++ ret = reg16_read_n(client, reg, val2, n);
++ if (ret < 0)
++ return ret;
++
++ if (memcmp(val, val2, n)) {
++ dev_err(&client->dev,
++ "write verify mismatch: chip 0x%x reg=0x%x-0x%x "
++ "'%*phN'->'%*phN'\n", client->addr, reg, reg + n,
++ n, val, n, val2);
++ ret = -EBADE;
++ }
++#endif
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_read_addr(struct i2c_client *client, int addr, u8 reg, u8 *val)
++{
++ int ret, retries;
++ union i2c_smbus_data data;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags,
++ I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "read fail: chip 0x%x register 0x%x: %d\n",
++ addr, reg, ret);
++ } else {
++ *val = data.byte;
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++static inline int reg8_write_addr(struct i2c_client *client, u8 addr, u8 reg, u8 val)
++{
++ int ret, retries;
++ union i2c_smbus_data data;
++
++ data.byte = val;
++
++ for (retries = REG8_NUM_RETRIES; retries; retries--) {
++ ret = i2c_smbus_xfer(client->adapter, addr, client->flags,
++ I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data);
++ if (!(ret < 0))
++ break;
++ }
++
++ if (ret < 0) {
++ dev_dbg(&client->dev,
++ "write fail: chip 0x%x register 0x%x value 0x%0x: %d\n",
++ addr, reg, val, ret);
++ }
++
++ return ret < 0 ? ret : 0;
++}
++
++
++static inline int reg16_write_addr(struct i2c_client *client, int chip, u16 reg, u8 val)
++{
++ struct i2c_msg msg[1];
++ u8 wbuf[3];
++ int ret;
++
++ msg->addr = chip;
++ msg->flags = 0;
++ msg->len = 3;
++ msg->buf = wbuf;
++ wbuf[0] = reg >> 8;
++ wbuf[1] = reg & 0xff;
++ wbuf[2] = val;
++
++ ret = i2c_transfer(client->adapter, msg, 1);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x wr 0x%04x (0x%02x): %d\n",
++ chip, reg, val, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static inline int reg16_read_addr(struct i2c_client *client, int chip, u16 reg, int *val)
++{
++ struct i2c_msg msg[2];
++ u8 wbuf[2];
++ u8 rbuf[1];
++ int ret;
++
++ msg[0].addr = chip;
++ msg[0].flags = 0;
++ msg[0].len = 2;
++ msg[0].buf = wbuf;
++ wbuf[0] = reg >> 8;
++ wbuf[1] = reg & 0xff;
++
++ msg[1].addr = chip;
++ msg[1].flags = I2C_M_RD;
++ msg[1].len = 1;
++ msg[1].buf = rbuf;
++
++ ret = i2c_transfer(client->adapter, msg, 2);
++ if (ret < 0) {
++ dev_dbg(&client->dev, "i2c fail: chip 0x%02x rd 0x%04x: %d\n", chip, reg, ret);
++ return ret;
++ }
++
++ *val = rbuf[0];
++
++ return 0;
++}
++
++#define __reg8_read(addr, reg, val) reg8_read_addr(priv->client, addr, reg, val)
++#define __reg8_write(addr, reg, val) reg8_write_addr(priv->client, addr, reg, val)
++#define __reg16_read(addr, reg, val) reg16_read_addr(priv->client, addr, reg, val)
++#define __reg16_write(addr, reg, val) reg16_write_addr(priv->client, addr, reg, val)
++
++/* copy this struct from drivers/i2c/i2c-mux.c for getting muxc from adapter private data */
++struct i2c_mux_priv {
++ struct i2c_adapter adap;
++ struct i2c_algorithm algo;
++ struct i2c_mux_core *muxc;
++ u32 chan_id;
++};
++
++static inline int get_des_id(struct i2c_client *client)
++{
++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data;
++
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9286"))
++ return MAX9286_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9288"))
++ return MAX9288_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max9296"))
++ return MAX9296A_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96706"))
++ return MAX96706_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "max96712"))
++ return MAX96712_ID;
++ if (!strcmp(mux_priv->muxc->dev->driver->name, "ti9x4"))
++ return UB960_ID;
++
++ return -EINVAL;
++}
++
++static inline int get_des_addr(struct i2c_client *client)
++{
++ struct i2c_mux_priv *mux_priv = client->adapter->algo_data;
++
++ return to_i2c_client(mux_priv->muxc->dev)->addr;
++}
++
++static inline void setup_i2c_translator(struct i2c_client *client, int ser_addr, int sensor_addr, int gmsl_mode)
++{
++ switch (get_des_id(client)) {
++ case MAX9286_ID:
++ case MAX9288_ID:
++ case MAX9296A_ID:
++ case MAX96706_ID:
++ case MAX96712_ID:
++ if (gmsl_mode == MODE_GMSL1) {
++ reg8_write_addr(client, ser_addr, 0x09, client->addr << 1); /* Sensor translated I2C address */
++ reg8_write_addr(client, ser_addr, 0x0A, sensor_addr << 1); /* Sensor native I2C address */
++ }
++ if (gmsl_mode == MODE_GMSL2) {
++ reg16_write_addr(client, ser_addr, MAX9295_I2C2, client->addr << 1); /* Sensor translated I2C address */
++ reg16_write_addr(client, ser_addr, MAX9295_I2C3, sensor_addr << 1); /* Sensor native I2C address */
++ }
++ break;
++ case UB960_ID:
++ reg8_write_addr(client, get_des_addr(client), 0x65, client->addr << 1); /* Sensor translated I2C address */
++ reg8_write_addr(client, get_des_addr(client), 0x5d, sensor_addr << 1); /* Sensor native I2C address */
++ break;
++ }
++ usleep_range(2000, 2500);
++}
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9295.h b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+new file mode 100644
+index 0000000..cf12d3c
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9295.h
+@@ -0,0 +1,29 @@
++/*
++ * MAXIM max9295 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#define MAX9295_REG2 0x02
++#define MAX9295_REG7 0x07
++#define MAX9295_CTRL0 0x10
++#define MAX9295_I2C2 0x42
++#define MAX9295_I2C3 0x43
++#define MAX9295_I2C4 0x44
++#define MAX9295_I2C5 0x45
++#define MAX9295_I2C6 0x46
++
++#define MAX9295_CROSS(n) (0x1b0 + n)
++
++#define MAX9295_GPIO_A(n) (0x2be + (3 * n))
++#define MAX9295_GPIO_B(n) (0x2bf + (3 * n))
++#define MAX9295_GPIO_C(n) (0x2c0 + (3 * n))
++
++#define MAX9295_VIDEO_TX_BASE(n) (0x100 + (0x8 * n))
++#define MAX9295_VIDEO_TX0(n) (MAX9295_VIDEO_TX_BASE(n) + 0)
++#define MAX9295_VIDEO_TX1(n) (MAX9295_VIDEO_TX_BASE(n) + 1)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.c b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+new file mode 100644
+index 0000000..a6d286f
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.c
+@@ -0,0 +1,1423 @@
++/*
++ * MAXIM max9296 GMSL2 driver
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/i2c-mux.h>
++#include <linux/module.h>
++#include <linux/regulator/consumer.h>
++#include <linux/notifier.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/regmap.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-clk.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "common.h"
++#include "max9296.h"
++#include "max9296_debug.h"
++
++static char mbus_default[10] = "dvp"; /* mipi, dvp */
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int fsync_period;
++module_param(fsync_period, int, 0644);
++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = MIPI_DT_YUV8;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)");
++
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)");
++
++static int gmsl = MODE_GMSL2;
++module_param(gmsl, int, 0644);
++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
++
++static char *mbus = "dvp";
++module_param(mbus, charp, 0644);
++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
++
++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1;
++module_param(gpio0, int, 0644);
++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)");
++module_param(gpio1, int, 0644);
++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)");
++module_param(gpio7, int, 0644);
++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)");
++module_param(gpio8, int, 0644);
++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)");
++
++static const struct regmap_config max9296_regmap[] = {
++ {
++ /* max9296 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1f03,
++ }, {
++ /* max9271/max96705 */
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 0xff,
++ }, {
++ /* max9695 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1b03,
++ }
++};
++
++static void max9296_write_remote_verify(struct max9296_priv *priv, int link_n, u8 reg, int val)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ int sts = 0;
++ u8 val2 = 0;
++
++ ser_write(reg, val);
++ des_read(MAX9296_COMMON1, &sts);
++ /* check ACKed */
++ if (sts & BIT(link_n)) {
++ ser_read(reg, &val2);
++ if (val2 == val)
++ break;
++ }
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&priv->client->dev, "timeout remote write acked\n");
++}
++
++static void max9296_reset_oneshot(struct max9296_priv *priv)
++{
++ int timeout;
++ int reg = 0;
++
++ des_update_bits(MAX9296_CTRL0, BIT(5), BIT(5)); /* set reset one-shot */
++
++ /* wait for one-shot bit self-cleared */
++ for (timeout = 0; timeout < 100; timeout++) {
++ des_read(MAX9296_CTRL0, &reg);
++ if (!(reg & BIT(5)))
++ break;
++
++ msleep(1);
++ }
++
++ if (reg & BIT(5))
++ dev_err(&priv->client->dev, "Failed reset oneshot\n");
++}
++
++/* -----------------------------------------------------------------------------
++ * MIPI, mapping, routing
++ */
++
++static void max9296_pipe_override(struct max9296_priv *priv, unsigned int pipe,
++ unsigned int dt, unsigned int vc)
++{
++ int bpp, bank;
++
++ bpp = mipi_dt_to_bpp(dt);
++ bank = pipe / 4;
++ pipe %= 4;
++
++ if (priv->dbl == 1) {
++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */
++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */
++ bpp = bpp / 2; /* divide because of MUX=1 */
++ }
++
++ switch (pipe) {
++ case 0:
++ /* Pipe X: 0 or 4 */
++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */
++ break;
++ case 1:
++ /* Pipe Y: 1 or 5 */
++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f);
++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ case 2:
++ /* Pipe Z: 2 or 6 */
++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03);
++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */
++ break;
++ case 3:
++ /* Pipe U: 3 or 7 */
++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ }
++}
++
++static void max9296_set_pipe_to_mipi_mapping(struct max9296_priv *priv,
++ unsigned int pipe, unsigned int map_n,
++ unsigned int in_dt, unsigned int in_vc,
++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi)
++{
++ int offset = 2 * (map_n % 4);
++
++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt);
++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt);
++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset);
++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */
++}
++
++static void max9296_mipi_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_REG2, 0); /* disable all pipes */
++
++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */
++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */
++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */
++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */
++ //des_write(MAX_MIPI_PHY6, 0x00);
++
++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */
++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */
++
++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */
++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++
++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL1
++ */
++
++static int max9296_gmsl1_sensor_reset(struct max9296_priv *priv, int link_n, int reset_on)
++{
++ struct max9296_link *link = priv->link[link_n];
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return -EINVAL;
++
++ /* sensor reset/unreset */
++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++
++ return 0;
++}
++
++static void max9296_gmsl1_cc_enable(struct max9296_priv *priv, int link, int on)
++{
++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00);
++ usleep_range(2000, 2500);
++}
++
++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX_GMSL1_CB(link_n), &val);
++
++ return !!(val & BIT(0));
++}
++
++static void max9296_gmsl1_link_crossbar_setup(struct max9296_priv *priv, int link, int dt)
++{
++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */
++ switch (dt) {
++ case MIPI_DT_YUV8:
++ des_write(MAX_CROSS(link, 0), 7);
++ des_write(MAX_CROSS(link, 1), 6);
++ des_write(MAX_CROSS(link, 2), 5);
++ des_write(MAX_CROSS(link, 3), 4);
++ des_write(MAX_CROSS(link, 4), 3);
++ des_write(MAX_CROSS(link, 5), 2);
++ des_write(MAX_CROSS(link, 6), 1);
++ des_write(MAX_CROSS(link, 7), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 8), 15);
++ des_write(MAX_CROSS(link, 9), 14);
++ des_write(MAX_CROSS(link, 10), 13);
++ des_write(MAX_CROSS(link, 11), 12);
++ des_write(MAX_CROSS(link, 12), 11);
++ des_write(MAX_CROSS(link, 13), 10);
++ des_write(MAX_CROSS(link, 14), 9);
++ des_write(MAX_CROSS(link, 15), 8);
++ }
++ break;
++ case MIPI_DT_RAW12:
++ des_write(MAX_CROSS(link, 0), 11);
++ des_write(MAX_CROSS(link, 1), 10);
++ des_write(MAX_CROSS(link, 2), 9);
++ des_write(MAX_CROSS(link, 3), 8);
++ des_write(MAX_CROSS(link, 4), 7);
++ des_write(MAX_CROSS(link, 5), 6);
++ des_write(MAX_CROSS(link, 6), 5);
++ des_write(MAX_CROSS(link, 7), 4);
++ des_write(MAX_CROSS(link, 8), 3);
++ des_write(MAX_CROSS(link, 9), 2);
++ des_write(MAX_CROSS(link, 10), 1);
++ des_write(MAX_CROSS(link, 11), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 12), 23);
++ des_write(MAX_CROSS(link, 13), 22);
++ des_write(MAX_CROSS(link, 14), 21);
++ des_write(MAX_CROSS(link, 15), 20);
++ des_write(MAX_CROSS(link, 16), 19);
++ des_write(MAX_CROSS(link, 17), 18);
++ des_write(MAX_CROSS(link, 18), 17);
++ des_write(MAX_CROSS(link, 19), 16);
++ des_write(MAX_CROSS(link, 20), 15);
++ des_write(MAX_CROSS(link, 21), 14);
++ des_write(MAX_CROSS(link, 22), 13);
++ des_write(MAX_CROSS(link, 23), 12);
++ }
++ break;
++ default:
++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt);
++ break;
++ }
++
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max9296_gmsl1_initial_setup(struct max9296_priv *priv)
++{
++ int i;
++
++ des_write(MAX9296_REG6, 0x10); /* set GMSL1 mode */
++ des_write(MAX9296_REG1, 0x01); /* 187.5M/3G */
++
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */
++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */
++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */
++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */
++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */
++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */
++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */
++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */
++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */
++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */
++ }
++}
++
++static int max9296_gmsl1_reverse_channel_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */
++ int lock_sts;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ u8 val = 0;
++ int ret = 0;
++
++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */
++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */
++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */
++ usleep_range(2000, 2500);
++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */
++ des_write(MAX9296_GMSL1_EN, BIT(link_n)); /* enable GMSL link# */
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++ usleep_range(2000, 2500);
++
++ for (; timeout > 0; timeout--) {
++ if (priv->him) {
++ /* HIM mode setup */
++ __reg8_write(ser_addrs[0], 0x4d, 0xc0);
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++ } else {
++ /* Legacy mode setup */
++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */
++ usleep_range(2000, 2500);
++
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */
++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500);
++
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++
++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */
++ usleep_range(2000, 2500);
++ }
++
++ __reg8_read(ser_addrs[0], 0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ ser_read(0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) {
++ regulator_disable(link->poc_reg); /* POC power off */
++ mdelay(200);
++ ret = regulator_enable(link->poc_reg); /* POC power on */
++ if (ret)
++ dev_err(&link->client->dev, "failed to enable poc regulator\n");
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max9296_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */
++
++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */
++ usleep_range(2000, 2500);
++ des_read(MAX_GMSL1_CB(link_n), &lock_sts);
++ lock_sts = !!(lock_sts & 0x01);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts);
++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr,
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++ return ret;
++}
++
++static int max9296_gmsl1_link_serializer_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++
++ /* GMSL setup */
++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500);
++
++ if (link->ser_id != MAX9271_ID) {
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ if (priv->dbl == 1) {
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ ser_write(0x20, priv->cb[7]);
++ ser_write(0x21, priv->cb[6]);
++ ser_write(0x22, priv->cb[5]);
++ ser_write(0x23, priv->cb[4]);
++ ser_write(0x24, priv->cb[3]);
++ ser_write(0x25, priv->cb[2]);
++ ser_write(0x26, priv->cb[1]);
++ ser_write(0x27, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer always) */
++ ser_write(0x30, priv->cb[7] + 16);
++ ser_write(0x31, priv->cb[6] + 16);
++ ser_write(0x32, priv->cb[5] + 16);
++ ser_write(0x33, priv->cb[4] + 16);
++ ser_write(0x34, priv->cb[3] + 16);
++ ser_write(0x35, priv->cb[2] + 16);
++ ser_write(0x36, priv->cb[1] + 16);
++ ser_write(0x37, priv->cb[0] + 16);
++ } else {
++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */
++ ser_write(0x20, priv->cb[4]);
++ ser_write(0x21, priv->cb[3]);
++ ser_write(0x22, priv->cb[2]);
++ ser_write(0x23, priv->cb[1]);
++ ser_write(0x24, priv->cb[0]);
++ ser_write(0x25, 0x40);
++ ser_write(0x26, 0x40);
++ if (link->ser_id == MAX96705_ID) {
++ ser_write(0x27, 14); /* HS: D14->D18 */
++ ser_write(0x28, 15); /* VS: D15->D19 */
++ ser_write(0x29, 14); /* DE: D14->D20 */
++ }
++ if (link->ser_id == MAX96707_ID) {
++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */
++ ser_write(0x28, 13); /* VS: D13->D19 */
++ ser_write(0x29, 12); /* DE: D12->D20 */
++ }
++ ser_write(0x2A, 0x40);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, 0x10 + priv->cb[7]);
++ ser_write(0x31, 0x10 + priv->cb[6]);
++ ser_write(0x32, 0x10 + priv->cb[5]);
++ ser_write(0x33, 0x10 + priv->cb[4]);
++ ser_write(0x34, 0x10 + priv->cb[3]);
++ ser_write(0x35, 0x10 + priv->cb[2]);
++ ser_write(0x36, 0x10 + priv->cb[1]);
++ ser_write(0x37, 0x10 + priv->cb[0]);
++ ser_write(0x38, priv->cb[7]);
++ ser_write(0x39, priv->cb[6]);
++ ser_write(0x3A, priv->cb[5]);
++
++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
++ }
++ break;
++ case MIPI_DT_RAW12:
++ /* setup crossbar for RAW12: reverse DVP bus */
++ ser_write(0x20, priv->cb[11]);
++ ser_write(0x21, priv->cb[10]);
++ ser_write(0x22, priv->cb[9]);
++ ser_write(0x23, priv->cb[8]);
++ ser_write(0x24, priv->cb[7]);
++ ser_write(0x25, priv->cb[6]);
++ ser_write(0x26, priv->cb[5]);
++ ser_write(0x27, priv->cb[4]);
++ ser_write(0x28, priv->cb[3]);
++ ser_write(0x29, priv->cb[2]);
++ ser_write(0x2a, priv->cb[1]);
++ ser_write(0x2b, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, priv->cb[11] + 16);
++ ser_write(0x31, priv->cb[10] + 16);
++ ser_write(0x32, priv->cb[9] + 16);
++ ser_write(0x33, priv->cb[8] + 16);
++ ser_write(0x34, priv->cb[7] + 16);
++ ser_write(0x35, priv->cb[6] + 16);
++ ser_write(0x36, priv->cb[5] + 16);
++ ser_write(0x37, priv->cb[4] + 16);
++ ser_write(0x38, priv->cb[3] + 16);
++ ser_write(0x39, priv->cb[2] + 16);
++ ser_write(0x3a, priv->cb[1] + 16);
++ ser_write(0x3b, priv->cb[0] + 16);
++
++ if (!(priv->bws || priv->hibw) && priv->dbl)
++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++ break;
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */
++ /* put serializer in configuration link state */
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static void max9296_gmsl1_link_pipe_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight map */
++ int dt = priv->dt; /* should come from imager */
++ int in_vc = 0;
++
++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ /* use map #0 for payload data */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */
++ dt, in_vc, /* src DT, VC */
++ dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #1 for FS */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */
++ 0x00, in_vc, /* src DT, VC */
++ 0x00, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #2 for FE */
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */
++ 0x01, in_vc, /* src DT, VC */
++ 0x01, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ usleep_range(5000, 5500);
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max9296_gmsl1_postinit(struct max9296_priv *priv)
++{
++ int i;
++ u8 val = 0;
++
++ for (i = 0; i < priv->n_links; i++) {
++ struct max9296_link *link = priv->link[i];
++
++ if (!(priv->links_mask & BIT(i)))
++ continue;
++
++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */
++ des_write(MAX9296_GMSL1_EN, BIT(i)); /* enable GMSL link# */
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(i)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++ usleep_range(2000, 2500);
++
++ ser_read(0x15, &val);
++ if (!(val & BIT(1)))
++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i);
++
++ /* switch to GMSL serial_link for streaming video */
++ max9296_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83);
++ usleep_range(2000, 2500);
++
++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */
++
++ switch (priv->link[i]->ser_id) {
++ case MAX9271_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */
++ break;
++ case MAX96705_ID:
++ case MAX96707_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */
++ break;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */
++
++ des_write(MAX9296_GMSL1_EN, priv->links_mask); /* enable detected links */
++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */
++ max9296_reset_oneshot(priv); /* one-shot reset links */
++}
++
++static void max9296_gmsl1_fsync_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX9296_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX9296_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ //des_write(MAX9296_FSYNC_8, 0x00); /* Disable Err Thresh */
++ //des_write(MAX9296_FSYNC_9, 0x00); /* Disable Err Thresh */
++ des_write(MAX9296_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX9296_FSYNC_11, 0x00);
++
++ des_write(MAX9296_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */
++
++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */
++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */
++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */
++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */
++
++ des_write(MAX9296_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL2
++ */
++
++static void max9296_gmsl2_cc_enable(struct max9296_priv *priv, int link, int on)
++{
++ /* nothing */
++}
++
++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX9296_CTRL3, &val);
++
++ return !!(val & BIT(3)) && (val & BIT(link_n + 4));
++}
++
++static void max9296_gmsl2_initial_setup(struct max9296_priv *priv)
++{
++ des_write(MAX9296_REG6, 0xC0 | 0x10); /* set GMSL2 mode */
++ des_write(MAX9296_REG1, 0x02); /* 187.5M/6G */
++}
++
++static int max9296_gmsl2_reverse_channel_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */
++ int timeout = priv->timeout;
++ int ret = 0;
++ int i = 0;
++
++ des_update_bits(MAX9296_CTRL0, 0x13, BIT(link_n)); /* enable GMSL link# */
++ max9296_reset_oneshot(priv);
++
++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
++ while ((!max9296_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
++ msleep(1);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) {
++ int val = 0;
++
++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */
++ if (val == MAX9295A_ID || val == MAX9295B_ID) {
++ link->ser_id = val;
++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++ }
++
++ if (i == ARRAY_SIZE(ser_addrs)) {
++ dev_err(&priv->client->dev, "serializer not found\n");
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i],
++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : "");
++ return ret;
++}
++
++static int max9296_gmsl2_link_serializer_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int i;
++
++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
++ //msleep(100);
++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
++ }
++
++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
++
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++
++ for (i = 0; i < 11; i++) {
++ if (priv->gpio[i] == 0) {
++ /* GPIO set 0 */
++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */
++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */
++ }
++ if (priv->gpio[i] == 1) {
++ /* GPIO set 1 */
++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */
++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */
++ }
++ if (priv->gpio[i] == 2) {
++ /* GPIO FSIN */
++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ }
++ if (priv->gpio[i] == 3) {
++ /* GPIO Interrupt */
++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */
++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static struct {
++ int in_dt;
++ int out_dt;
++} gmsl2_pipe_maps[] = {
++ {0x00, 0x00}, /* FS */
++ {0x01, 0x01}, /* FE */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++};
++
++static void max9296_gmsl2_pipe_set_source(struct max9296_priv *priv, int pipe, int phy, int in_pipe)
++{
++ // TODO
++}
++
++static void max9296_gmsl2_link_pipe_setup(struct max9296_priv *priv, int link_n)
++{
++ struct max9296_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight mapping */
++ int dt = priv->dt; /* must come from imager */
++ int in_vc = 0;
++ int i;
++
++ max9296_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ des_write(MAX9296_RX0(pipe), 0); /* stream_id = 0 */
++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */
++ max9296_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++ }
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) {
++ max9296_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */
++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */
++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ }
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max9296_gmsl2_postinit(struct max9296_priv *priv)
++{
++ des_update_bits(MAX9296_CTRL0, 0x13, priv->links_mask == 3 ? 0x13 : priv->links_mask); /* enable detected links */
++ max9296_reset_oneshot(priv); /* one-shot reset links */
++}
++
++static void max9296_gmsl2_link_crossbar_setup(struct max9296_priv *priv, int link, int dt)
++{
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max9296_gmsl2_fsync_setup(struct max9296_priv *priv)
++{
++ /* TODO */
++}
++
++/* -----------------------------------------------------------------------------
++ * I2C Multiplexer
++ */
++
++static int max9296_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
++{
++ /* Do nothing! */
++ return 0;
++}
++
++static int max9296_i2c_mux_init(struct max9296_priv *priv)
++{
++ struct i2c_client *client = priv->client;
++
++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
++ return -ENODEV;
++
++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev,
++ priv->n_links, 0, I2C_MUX_LOCKED,
++ max9296_i2c_mux_select, NULL);
++ if (!priv->mux)
++ return -ENOMEM;
++
++ priv->mux->priv = priv;
++
++ return 0;
++}
++
++#define max9296_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_cc_enable(priv, i, en) : \
++ max9296_gmsl1_cc_enable(priv, i, en))
++#define max9296_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_initial_setup(priv) : \
++ max9296_gmsl1_initial_setup(priv))
++#define max9296_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_reverse_channel_setup(priv, i) : \
++ max9296_gmsl1_reverse_channel_setup(priv, i))
++#define max9296_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_serializer_setup(priv, i) : \
++ max9296_gmsl1_link_serializer_setup(priv, i))
++#define max9296_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_pipe_setup(priv, i) : \
++ max9296_gmsl1_link_pipe_setup(priv, i))
++#define max9296_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_link_crossbar_setup(priv, i, dt) : \
++ max9296_gmsl1_link_crossbar_setup(priv, i, dt))
++#define max9296_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_postinit(priv) : \
++ max9296_gmsl1_postinit(priv))
++#define max9296_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max9296_gmsl2_fsync_setup(priv) : \
++ max9296_gmsl1_fsync_setup(priv))
++
++static int max9296_preinit(struct max9296_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX9296_CTRL0, BIT(7), BIT(7)); /* reset chip */
++ mdelay(5);
++
++ /* enable internal regulator for 1.2V VDD supply */
++ des_update_bits(MAX9296_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */
++ des_update_bits(MAX9296_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */
++
++ /* this is needed for engineering samples */
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_RLMS4(i), 0x29);
++ des_write(MAX_RLMSA4(i), 0xc8);
++ des_write(MAX_RLMSA(i), 0x00);
++ des_write(MAX_RLMSB(i), 0x00);
++ }
++
++ /* I2C-I2C timings */
++ des_write(MAX9296_I2C_PT_0, 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX9296_I2C_PT_1, 0x51); /* i2c speed: 397Kbps, 32mS timeout */
++ des_write(MAX9296_I2C_0, 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX9296_I2C_1, 0x51); /* i2c speed: 397Kbps, 1mS timeout */
++
++ des_write(MAX9296_CTRL1, priv->is_coax ? 0x5 : 0); /* cable mode */
++ des_write(MAX9296_GMSL1_EN, 0); /* disable all links */
++ des_update_bits(MAX9296_CTRL0, 0x13, 0); /* disable all links */
++
++ return 0;
++}
++
++static int max9296_initialize(struct max9296_priv *priv)
++{
++ int ret, i;
++
++ max9296_preinit(priv);
++ max9296_initial_setup(priv);
++ max9296_mipi_setup(priv);
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg)) {
++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */
++ if (ret) {
++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n");
++ continue;
++ }
++ mdelay(priv->poc_delay);
++ }
++
++ ret = max9296_reverse_channel_setup(priv, i);
++ if (ret == -ETIMEDOUT)
++ continue;
++ if (!ret)
++ max9296_link_serializer_setup(priv, i);
++
++ max9296_link_pipe_setup(priv, i);
++ max9296_link_crossbar_setup(priv, i, priv->dt);
++
++ i2c_mux_add_adapter(priv->mux, 0, i, 0);
++ max9296_cc_enable(priv, i, 0);
++ }
++
++ max9296_postinit(priv);
++ max9296_fsync_setup(priv);
++
++ return 0;
++}
++
++static int max9296_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data)
++{
++ struct max9296_priv *priv = container_of(nb, struct max9296_priv, reboot_nb);
++ int i;
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return NOTIFY_DONE;
++}
++
++static int max9296_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++
++ if (on) {
++ if (atomic_inc_return(&priv->use_count) == 1)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max9296_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++ int ret;
++ int val = 0;
++
++ ret = des_read(reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int max9296_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
++{
++ struct max9296_priv *priv = v4l2_get_subdevdata(sd);
++
++ return des_write(reg->reg, (u8)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops max9296_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max9296_g_register,
++ .s_register = max9296_s_register,
++#endif
++ .s_power = max9296_s_power,
++};
++
++static struct v4l2_subdev_ops max9296_subdev_ops = {
++ .core = &max9296_subdev_core_ops,
++};
++
++static const struct of_device_id max9296_dt_ids[] = {
++ { .compatible = "maxim,max9296" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max9296_dt_ids);
++
++static int max9296_parse_dt(struct i2c_client *client)
++{
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ struct property *prop;
++ char name[16];
++ int i, csi_rate;
++
++ if (of_property_read_u32(np, "maxim,links", &priv->n_links))
++ priv->n_links = MAX9296_MAX_LINKS;
++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode))
++ priv->gmsl_mode = MODE_GMSL2;
++ if (of_property_read_bool(np, "maxim,stp"))
++ priv->is_coax = 0;
++ else
++ priv->is_coax = 1;
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
++ priv->fsync_period = 3210000;/* 96MHz/30fps */
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,hven", &priv->hven))
++ priv->hven = 1;
++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw))
++ priv->hibw = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = MIPI_DT_YUV8;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus))
++ priv->mbus = mbus_default;
++ for (i = 0; i < 11; i++) {
++ sprintf(name, "maxim,gpio%d", i);
++ if (of_property_read_u32(np, name, &priv->gpio[i]))
++ priv->gpio[i] = -1;
++ }
++
++ /* module params override dts */
++ if (gmsl != MODE_GMSL2)
++ priv->gmsl_mode = gmsl;
++ if (him)
++ priv->him = him;
++ if (fsync_period) {
++ priv->fsync_period = fsync_period;
++// priv->fsync_mode = fsync_mode_default;
++ }
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != MIPI_DT_YUV8)
++ priv->dt = dt;
++// if (hsgen)
++// priv->hsgen = hsgen;
++ if (gpio0 >= 0)
++ priv->gpio[0] = gpio0;
++ if (gpio1 >= 0)
++ priv->gpio[1] = gpio1;
++ if (gpio7 >= 0)
++ priv->gpio[7] = gpio7;
++ if (gpio8 >= 0)
++ priv->gpio[8] = gpio8;
++
++ /* parse serializer crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
++ }
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (i < priv->n_links) {
++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "ser-addr not set\n");
++ return -EINVAL;
++ }
++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint);
++ }
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (prop) {
++ of_property_read_u32(endpoint, "csi-rate", &csi_rate);
++ of_update_property(rendpoint, prop);
++ }
++
++ prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (prop)
++ of_update_property(rendpoint, prop);
++ }
++
++ of_node_put(endpoint);
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */
++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */
++ }
++
++ prop = of_find_property(np, "maxim,links-mipi-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= MAX9296_MAX_MIPI)
++ return -EINVAL;
++ priv->link[i]->out_mipi = val;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate;
++
++ prop = of_find_property(np, "maxim,links-vc-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= 4)
++ return -EINVAL;
++ priv->link[i]->out_vc = val;
++ }
++ }
++
++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n");
++ for (i = 0; i < priv->n_links; i++)
++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc);
++
++ return 0;
++}
++
++static int max9296_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max9296_priv *priv;
++ struct gpio_desc *pwdn_gpio;
++ int ret, i;
++ int val = 0;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->regmap = devm_regmap_init_i2c(client, &max9296_regmap[0]);
++ if (IS_ERR(priv->regmap))
++ return PTR_ERR(priv->regmap);
++
++ i2c_set_clientdata(client, priv);
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++
++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
++ if (!IS_ERR(priv->ref_clk)) {
++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
++ v4l2_clk_enable(priv->ref_clk);
++ }
++
++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH);
++ if (!IS_ERR(pwdn_gpio)) {
++ udelay(5);
++ gpiod_set_value_cansleep(pwdn_gpio, 0);
++ usleep_range(3000, 5000);
++ }
++
++ des_read(MAX9296_REG13, &val);
++ if (val != MAX9296A_ID)
++ return -ENODEV;
++
++ for (i = 0; i < MAX9296_MAX_LINKS; i++) {
++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL);
++ if (!priv->link[i])
++ return -ENOMEM;
++ }
++
++ ret = max9296_parse_dt(client);
++ if (ret)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ char poc_name[10];
++
++ sprintf(poc_name, "poc%d", i);
++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name);
++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ }
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr);
++ if (!priv->link[i]->client)
++ return -ENOMEM;
++
++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max9296_regmap[priv->gmsl_mode]);
++ if (IS_ERR(priv->link[i]->regmap))
++ return PTR_ERR(priv->link[i]->regmap);
++ }
++
++ ret = max9296_i2c_mux_init(priv);
++ if (ret) {
++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
++ goto out;
++ }
++
++ ret = max9296_initialize(priv);
++ if (ret < 0)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_subdev_init(&priv->link[i]->sd, &max9296_subdev_ops);
++ priv->link[i]->sd.owner = client->dev.driver->owner;
++ priv->link[i]->sd.dev = &client->dev;
++ priv->link[i]->sd.grp_id = i;
++ v4l2_set_subdevdata(&priv->link[i]->sd, priv);
++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode;
++
++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
++ client->dev.driver->name, i, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ ret = v4l2_async_register_subdev(&priv->link[i]->sd);
++ if (ret < 0)
++ goto out;
++ }
++
++ priv->reboot_nb.notifier_call = max9296_reboot_notifier;
++ ret = register_reboot_notifier(&priv->reboot_nb);
++ if (ret) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
++ //max9296_debug_add(priv);
++out:
++ return ret;
++}
++
++static int max9296_remove(struct i2c_client *client)
++{
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ //max9296_debug_remove(priv);
++ i2c_mux_del_adapters(priv->mux);
++ unregister_reboot_notifier(&priv->reboot_nb);
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_async_unregister_subdev(&priv->link[i]->sd);
++ v4l2_device_unregister_subdev(&priv->link[i]->sd);
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return 0;
++}
++
++static const struct i2c_device_id max9296_id[] = {
++ { "max9296", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max9296_id);
++
++static struct i2c_driver max9296_i2c_driver = {
++ .driver = {
++ .name = "max9296",
++ .of_match_table = of_match_ptr(max9296_dt_ids),
++ },
++ .probe = max9296_probe,
++ .remove = max9296_remove,
++ .id_table = max9296_id,
++};
++
++module_i2c_driver(max9296_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL2 driver for MAX9296");
++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296.h b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+new file mode 100644
+index 0000000..800df43
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296.h
+@@ -0,0 +1,281 @@
++/*
++ * MAXIM max9296 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#define MAX9296_MAX_LINKS 2
++#define MAX9296_MAX_PIPES 4
++#define MAX9296_MAX_PIPE_MAPS 16
++#define MAX9296_MAX_MIPI 4
++
++struct max9296_link {
++ struct v4l2_subdev sd;
++ struct fwnode_handle *sd_fwnode;
++ struct i2c_client *client;
++ struct regmap *regmap;
++ int ser_id;
++ int ser_addr;
++ int pipes_mask; /* mask of pipes used by this link */
++ int out_mipi; /* MIPI# */
++ int out_vc; /* VC# */
++ struct regulator *poc_reg; /* PoC power supply */
++};
++
++struct max9296_priv {
++ struct i2c_client *client;
++ struct regmap *regmap;
++ struct i2c_mux_core *mux;
++ int n_links;
++ int links_mask;
++ enum gmsl_mode gmsl_mode;
++ struct max9296_link *link[MAX9296_MAX_LINKS];
++ int gpio_resetb;
++ int active_low_resetb;
++ bool pclk_rising_edge;
++ bool is_coax;
++ int him;
++ int bws;
++ int dbl;
++ int hibw;
++ int hven;
++ int hsync;
++ int vsync;
++ int dt;
++ u64 crossbar;
++ char cb[16];
++ const char *mbus;
++ int gpio[11];
++ int timeout;
++ int poc_delay;
++ struct v4l2_clk *ref_clk;
++ int csi_rate[MAX9296_MAX_MIPI];
++ int fsync_period;
++ atomic_t use_count;
++ struct notifier_block reboot_nb;
++};
++
++#define MAX9296_REG1 0x01
++#define MAX9296_REG2 0x02
++#define MAX9296_REG3 0x03
++#define MAX9296_REG4 0x04
++#define MAX9296_REG5 0x05
++#define MAX9296_REG6 0x06
++#define MAX9296_REG13 0x0d
++#define MAX9296_REG14 0x0e
++#define MAX9296_REG26 0x26
++
++#define MAX9296_INTR3 0x1b
++#define MAX9296_INTR5 0x1d
++#define MAX9296_INTR7 0x1f
++#define MAX9296_DEC_ERR_A 0x22
++#define MAX9296_DEC_ERR_B 0x23
++#define MAX9296_IDLE_ERR 0x24
++#define MAX9296_PKT_CNT 0x25
++#define MAX9296_RX_0 0x2c
++#define MAX9296_RX_3 0x2f
++
++#define MAX9296_CTRL0 0x17
++#define MAX9296_CTRL1 0x18
++#define MAX9296_CTRL2 0x19
++#define MAX9296_CTRL3 0x1a
++#define MAX9296_CTRL11 0x22
++#define MAX9296_CTRL12 0x0a
++#define MAX9296_CTRL13 0x0b
++#define MAX9296_CTRL14 0x0c
++
++#define MAX9296_CNT(n) (0x22 + n)
++
++#define MAX9296_I2C_PT_0 0x4c
++#define MAX9296_I2C_PT_1 0x4d
++
++#define MAX9296_CNT4 0x55c
++
++#define MAX9296_GMSL1_EN 0xf00
++#define MAX9296_COMMON1 0xf02
++#define MAX9296_I2C_0 0xf05
++#define MAX9296_I2C_1 0xf06
++#define MAX9296_I2C_2 0xf07
++#define MAX9296_I2C_3 0xf08
++#define MAX9296_I2C_4 0xf09
++#define MAX9296_I2C_5 0xf0a
++
++#define MAX9296_RX0(n) (0x50 + n)
++
++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \
++ (0x160 + (0x12 * (n - 5))))
++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00)
++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03)
++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08)
++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a)
++
++#define MAX_VPRBS(n) (0x1dc + (0x20 * n))
++
++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n))
++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m)
++
++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank))
++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00)
++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a)
++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b)
++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c)
++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d)
++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e)
++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f)
++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10)
++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11)
++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12)
++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13)
++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14)
++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15)
++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16)
++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17)
++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18)
++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19)
++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a)
++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b)
++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c)
++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d)
++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e)
++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f)
++
++#define MAX9296_FSYNC_0 0x3a0
++#define MAX9296_FSYNC_5 0x3a5
++#define MAX9296_FSYNC_6 0x3a6
++#define MAX9296_FSYNC_7 0x3a7
++#define MAX9296_FSYNC_8 0x3a8
++#define MAX9296_FSYNC_9 0x3a9
++#define MAX9296_FSYNC_10 0x3aa
++#define MAX9296_FSYNC_11 0x3ab
++#define MAX9296_FSYNC_15 0x3af
++
++#define MAX_MIPI_PHY_BASE 0x8a0
++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02)
++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03)
++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04)
++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05)
++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06)
++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08)
++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09)
++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a)
++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b)
++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d)
++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e)
++
++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n)
++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02)
++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a)
++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b)
++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c)
++
++/* 16 pairs of source-dest registers */
++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n))
++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n))
++/* Phy dst. Each reg contains 4 dest */
++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n)
++
++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch))
++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch))
++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch))
++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch))
++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch))
++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch))
++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch))
++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch))
++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch))
++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch))
++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch))
++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch))
++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch))
++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch))
++
++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch))
++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch))
++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch))
++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch))
++
++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch))
++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch))
++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch))
++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch))
++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch))
++
++static inline int max9296_write(struct max9296_priv *priv, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_read(struct max9296_priv *priv, int reg, int *val)
++{
++ int ret;
++
++ ret = regmap_read(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_update_bits(struct max9296_priv *priv, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(priv->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define des_read(reg, val) max9296_read(priv, reg, val)
++#define des_write(reg, val) max9296_write(priv, reg, val)
++#define des_update_bits(reg, mask, bits) max9296_update_bits(priv, reg, mask, bits)
++
++static inline int max9296_ser_write(struct max9296_link *link, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(link->regmap, reg, val);
++ if (ret < 0)
++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_ser_read(struct max9296_link *link, int reg, u8 *val)
++{
++ int ret;
++
++ ret = regmap_read(link->regmap, reg, (int *)val);
++ if (ret)
++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max9296_ser_update_bits(struct max9296_link *link, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(link->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define ser_read(reg, val) max9296_ser_read(link, reg, val)
++#define ser_write(reg, val) max9296_ser_write(link, reg, val)
++#define ser_update_bits(reg, mask, bits) max9296_ser_update_bits(link, reg, mask, bits)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+new file mode 100644
+index 0000000..6bf03a2
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max9296_debug.h
+@@ -0,0 +1,462 @@
++/*
++ * MAXIM max9296 GMSL2 driver debug stuff
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++static char *max9296_link_mode[4] = {
++ "Splitter mode",
++ "Link A",
++ "Link B",
++ "Dual link",
++};
++
++static char *line_status[8] = {
++ "Short to battery",
++ "Short to GND",
++ "Normal operation",
++ "Line open",
++ "Line-to-line short",
++ "Line-to-line short",
++ "Line-to-line short",
++ "Line-to-line short"
++};
++
++static char *paxket_cnt_types[] = {
++ "None",
++ "VIDEO",
++ "AUDIO",
++ "INFO Frame",
++ "SPI",
++ "I2C",
++ "UART",
++ "GPIO",
++ "AHDCP",
++ "RGMII",
++ "Reserved",
++ "Reserved",
++ "Reserved",
++ "Reserved",
++ "All",
++ "Unknown and packets with error",
++};
++
++static int max9296_gmsl1_get_link_lock(struct max9296_priv *priv, int link_n);
++static int max9296_gmsl2_get_link_lock(struct max9296_priv *priv, int link_n);
++
++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1))
++
++static ssize_t max_link_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i = -1;
++ int j;
++ int gmsl2;
++ u32 crc = 0 ;
++ char *_buf = buf;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "link_%d", &i))
++ return -EINVAL;
++
++ if (i < 0)
++ return -EINVAL;
++
++ if (i >= priv->n_links) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ buf += sprintf(buf, "Link %c status\n", 'A' + i);
++
++ des_read(MAX9296_REG6, &reg);
++ gmsl2 = !!(reg & BIT(6 + i));
++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1");
++
++ if (gmsl2) {
++ buf += sprintf(buf, "GMSL2 Link lock: %d\n",
++ max9296_gmsl2_get_link_lock(priv, i));
++ } else {
++ reg = max9296_gmsl1_get_link_lock(priv, i);
++ buf += sprintf(buf,
++ "GMSL1_CB: 0x%02x:\t"
++ "LOCKED_G1: %d\n",
++ reg, reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_CA(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_CA: 0x%02x:\t"
++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n",
++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_1B(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1B: 0x%02x:\t"
++ "LINE_CRC_ERR: %d ",
++ reg, reg_bits(2, 1));
++ for (j = 0; j < 4; j++) {
++ des_read(MAX_GMSL1_20(i) + j, &reg);
++ crc = crc | ((reg & 0xff) << (j * 8));
++ }
++ buf += sprintf(buf, "last crc 0x%08x\n", crc);
++
++ des_read(MAX_GMSL1_19(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_19: CC_CRC_ERRCNT %d\n",
++ reg);
++
++ des_read(MAX_GMSL1_1D(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1D: 0x%02x:\t"
++ "UNDERBOOST: %d, AEQ-BST: %d\n",
++ reg, reg_bits(4, 1), reg_bits(0, 4));
++
++ {
++ des_read(MAX9296_CTRL1, &reg);
++ buf += sprintf(buf,
++ "CTRL1: 0x%02x:\t"
++ "Cable: %s\n",
++ reg,
++ reg_bits(i * 2, 1) ? "coax" : "stp");
++
++ des_read(MAX9296_REG26, &reg);
++ buf += sprintf(buf,
++ "REG26: 0x%02x:\t"
++ "Line status: %s\n",
++ reg,
++ line_status[reg_bits(i * 4, 3)]);
++
++ des_read(MAX9296_CNT(i), &reg);
++ buf += sprintf(buf,
++ "CNT%d: DEC_ERR_x: %d\n",
++ i, reg);
++ }
++ /* TODO: add same for 96712 */
++ }
++
++ return (buf - _buf);
++}
++
++static ssize_t max_pipe_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ char *_buf = buf;
++ int pipe = 0;
++ int map;
++ int maps_en = 0;
++ int pipes_en;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe))
++ return -EINVAL;
++
++ if (pipe < 0)
++ return -EINVAL;
++
++ if (pipe >= MAX9296_MAX_PIPES) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ des_read(MAX9296_REG2, &pipes_en);
++ pipes_en = pipes_en >> 4;
++
++ buf += sprintf(buf, "Video Pipe %d %s\n",
++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled");
++ if (!(pipes_en & BIT(pipe)))
++ goto out;
++
++ des_read(MAX_VPRBS(pipe), &reg);
++ /* bit 5 is not valid for MAX96712 */
++ buf += sprintf(buf,
++ "\tVPRBS: 0x%02x\t"
++ "VPRBS_FAIL: %d,"
++ "VIDEO_LOCK: %d\n",
++ reg,
++ reg_bits(5, 1), reg_bits(0, 1));
++
++ /* show source */
++ /* TODO */
++
++ /* show maps */
++ des_read(MAX_MIPI_TX11(pipe), &maps_en);
++ des_read(MAX_MIPI_TX12(pipe), &reg);
++ maps_en |= reg << 8;
++
++ for (map = 0; map < MAX9296_MAX_PIPE_MAPS; map++) {
++ int src, dst, mipi;
++ if (!(maps_en & BIT(map)))
++ continue;
++
++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src);
++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst);
++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi);
++
++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n",
++ map,
++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03,
++ (mipi >> ((map % 4) * 2)) & 0x03);
++ }
++
++ des_read(MAX9296_CNT4 + pipe, &reg);
++ buf += sprintf(buf, "VID_PXL_CRC_ERR: 0x%02x\n", reg);
++
++ des_read(MAX_VIDEO_RX0(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX0: 0x%02x\t"
++ "LCRC_ERR: %d, "
++ "LINE_CRC_SEL: %d, "
++ "LINE_CRC_EN: %d, "
++ "DIS_PKT_DET: %d\n",
++ reg,
++ reg_bits(7, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX3(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX3: 0x%02x\t"
++ "HD_TR_MODE: %d, "
++ "DLOCKED: %d, "
++ "VLOCKED: %d, "
++ "HLOCKED: %d, "
++ "DTRACKEN: %d, "
++ "VTRACKEN: %d, "
++ "HTRACKEN: %d\n",
++ reg,
++ reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX8(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX8: 0x%02x\t"
++ "VID_BLK_LEN_ERR: %d, "
++ "VID_LOCK: %d, "
++ "VID_PKT_DET: %d, "
++ "VID_SEQ_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1));
++ des_read(MAX_VIDEO_RX10(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX10: 0x%02x\t"
++ "MASK_VIDEO_DE: %d\n",
++ reg,
++ reg_bits(6, 1));
++
++out:
++ return (buf - _buf);
++}
++
++static ssize_t max_stat_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max9296_priv *priv = i2c_get_clientdata(client);
++ int i;
++ char *_buf = buf;
++ int reg = 0, reg2 = 0;
++
++ des_read(MAX9296_REG3, &reg);
++ buf += sprintf(buf,
++ "REG_REG3: 0x%02x\t"
++ "LOCK_CFG: %d\n",
++ reg, reg_bits(7, 1));
++
++ des_read(MAX9296_CTRL0, &reg);
++ buf += sprintf(buf,
++ "CTRL0: 0x%02x\n",
++ reg);
++
++ des_read(MAX9296_CTRL3, &reg);
++ buf += sprintf(buf,
++ "CTRL3: 0x%02x:\t"
++ "LINK_MODE: %s, "
++ "GMSL2 LOCKED: %d, ERROR: %d, "
++ "CMU_LOCKED: %d\n",
++ reg,
++ max9296_link_mode[reg_bits(4, 2)],
++ reg_bits(3, 1), reg_bits(2 ,1),
++ reg_bits(1, 1));
++ /* get errors */
++ if (reg_bits(2, 1)) {
++ des_read(MAX9296_INTR3, &reg);
++ buf += sprintf(buf,
++ "INTR3: 0x%02x:\t"
++ "PHY_INT_OEN_B: %d "
++ "PHY_INT_OEN_A: %d "
++ "REM_ERR_FLAG: %d "
++ "MEM_INT_ERR_FLAG: %d "
++ "LFLT_INT: %d "
++ "IDLE_ERR_FLAG: %d "
++ "DEC_ERR_FLAG_B: %d "
++ "DEC_ERR_FLAG_A: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX9296_INTR5, &reg);
++ buf += sprintf(buf,
++ "INTR5: 0x%02x:\t"
++ "EOM_ERR_FLAG_B: %d "
++ "EOM_ERR_FLAG_A: %d "
++ "MAX_RT_FLAG: %d "
++ "RT_CNT_FLAG: %d "
++ "PKT_CNT_FLAG: %d "
++ "WM_ERR_FLAG: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX9296_INTR7, &reg);
++ buf += sprintf(buf,
++ "INTR7: 0x%02x:\t"
++ "VDDCMP_INT_FLAG: %d "
++ "PORZ_INT_FLAG: %d "
++ "VDDBAD_INT_FLAG: %d "
++ "LCRC_ERR_FLAG: %d "
++ "VPRBS_ERR_FLAG: %d "
++ "VID_PXL_CRC_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(0, 1));
++
++ des_read(MAX9296_DEC_ERR_A, &reg);
++ buf += sprintf(buf,
++ "ERR_A: 0x%02x\n", reg);
++ des_read(MAX9296_DEC_ERR_B, &reg);
++ buf += sprintf(buf,
++ "ERR_B: 0x%02x\n", reg);
++ des_read(MAX9296_IDLE_ERR, &reg);
++ buf += sprintf(buf,
++ "IDLE_ERR: 0x%02x\n", reg);
++ des_read(MAX9296_PKT_CNT, &reg);
++ buf += sprintf(buf,
++ "PKT_CNT: 0x%02x\n", reg);
++
++ }
++
++ des_read(MAX9296_CNT(2), &reg);
++ buf += sprintf(buf,
++ "CNT2: IDLE_ERR: %d\n",
++ reg);
++
++ des_read(MAX9296_CNT(3), &reg);
++ des_read(MAX9296_RX_0, &reg2);
++ buf += sprintf(buf,
++ "CNT3: PKT_CNT: 0x%02x (type %x: %s)\n",
++ reg, reg2 & 0x0f,
++ paxket_cnt_types[reg2 & 0x0f]);
++
++ des_read(MAX9296_RX_3, &reg);
++ buf += sprintf(buf,
++ "RX3: 0x%02x:\t"
++ "PRBS_SYNCED_B: %d, "
++ "SYNC_LOCKED_B: %d, "
++ "WBLOCK_B: %d, "
++ "FAILLOCK_B: %d, "
++ "PRBS_SYNCED_A: %d, "
++ "SYNC_LOCKED_A: %d, "
++ "WBLOCK_A: %d, "
++ "FAILLOCK_A: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_BACKTOP1(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP1: 0x%02x:\t"
++ "CSIPLLU_LOCK: %d, "
++ "CSIPLLZ_LOCK: %d, "
++ "CSIPLLY_LOCK: %d, "
++ "CSIPLLX_LOCK: %d, "
++ "LINE_SPL2: %d, "
++ "LINE_SPL1: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1));
++
++ des_read(MAX_BACKTOP11(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP11: 0x%02x:\t"
++ "CMD_OWERFLOW4: %d, "
++ "CMD_OWERFLOW3: %d, "
++ "CMD_OWERFLOW2: %d, "
++ "CMD_OWERFLOW1: %d, "
++ "LMO_Z: %d, "
++ "LMO_Y: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(2, 1), reg_bits(1, 1));
++
++ for (i = 0; i < MAX9296_MAX_MIPI; i++) {
++ buf += sprintf(buf, "MIPI %d\n", i);
++ des_read(MAX_MIPI_TX2(i), &reg);
++ buf += sprintf(buf,
++ "\tMIPI_TX2: 0x%02x\n",
++ reg);
++ }
++
++ return (buf - _buf);
++}
++
++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL);
++
++static struct attribute *max9296_attributes[] = {
++ &dev_attr_link_0.attr,
++ &dev_attr_link_1.attr,
++ &dev_attr_link_2.attr,
++ &dev_attr_link_3.attr,
++ &dev_attr_pipe_0.attr,
++ &dev_attr_pipe_1.attr,
++ &dev_attr_pipe_2.attr,
++ &dev_attr_pipe_3.attr,
++ &dev_attr_pipe_4.attr,
++ &dev_attr_pipe_5.attr,
++ &dev_attr_pipe_6.attr,
++ &dev_attr_pipe_7.attr,
++ &dev_attr_stat.attr,
++ NULL
++};
++
++static const struct attribute_group max9296_group = {
++ .attrs = max9296_attributes,
++};
++
++int max9296_debug_add(struct max9296_priv *priv)
++{
++ int ret;
++
++ ret = sysfs_create_group(&priv->client->dev.kobj, &max9296_group);
++ if (ret < 0) {
++ dev_err(&priv->client->dev, "Sysfs registration failed\n");
++ return ret;
++ }
++
++ /* count video packets */
++ des_update_bits(MAX9296_RX_0, 0x0f, 0x01);
++
++ return ret;
++}
++
++void max9296_debug_remove(struct max9296_priv *priv)
++{
++ sysfs_remove_group(&priv->client->dev.kobj, &max9296_group);
++}
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.c b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+new file mode 100644
+index 0000000..af5e1d7
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.c
+@@ -0,0 +1,1423 @@
++/*
++ * MAXIM max96712 GMSL2 driver
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/i2c-mux.h>
++#include <linux/module.h>
++#include <linux/regulator/consumer.h>
++#include <linux/notifier.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
++#include <linux/of_graph.h>
++#include <linux/reboot.h>
++#include <linux/regmap.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-clk.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-subdev.h>
++
++#include "common.h"
++#include "max96712.h"
++#include "max96712_debug.h"
++
++static char mbus_default[10] = "dvp"; /* mipi, dvp */
++
++static int conf_link;
++module_param(conf_link, int, 0644);
++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)");
++
++static int poc_trig;
++module_param(poc_trig, int, 0644);
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during RC setup. Useful on systems with dedicated PoC and unstable ser-des lock");
++
++static int him;
++module_param(him, int, 0644);
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
++
++static int fsync_period;
++module_param(fsync_period, int, 0644);
++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)");
++
++static int hsync;
++module_param(hsync, int, 0644);
++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)");
++
++static int vsync = 1;
++module_param(vsync, int, 0644);
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
++
++static int gpio_resetb;
++module_param(gpio_resetb, int, 0644);
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
++
++static int active_low_resetb;
++module_param(active_low_resetb, int, 0644);
++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)");
++
++static int timeout_n = 100;
++module_param(timeout_n, int, 0644);
++MODULE_PARM_DESC(timeout_n, " Timeout of link detection (default: 100 retries)");
++
++static int poc_delay = 50;
++module_param(poc_delay, int, 0644);
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 50 ms)");
++
++static int bws;
++module_param(bws, int, 0644);
++MODULE_PARM_DESC(bws, " BWS mode (default: 0 - 24-bit gmsl packets)");
++
++static int dbl = 1;
++module_param(dbl, int, 0644);
++MODULE_PARM_DESC(dbl, " DBL mode (default: 1 - DBL mode enabled)");
++
++static int dt = MIPI_DT_YUV8;
++module_param(dt, int, 0644);
++MODULE_PARM_DESC(dt, " DataType (default: 0x1e - YUV8)");
++
++static unsigned long crossbar = 0xba9876543210;
++module_param(crossbar, ulong, 0644);
++MODULE_PARM_DESC(crossbar, " Serializer crossbar setup (default: ba9876543210 - reversed)");
++
++static int gmsl = MODE_GMSL2;
++module_param(gmsl, int, 0644);
++MODULE_PARM_DESC(gmsl, " GMSL mode (default: 2 - GMSL2)");
++
++static char *mbus = "dvp";
++module_param(mbus, charp, 0644);
++MODULE_PARM_DESC(mbus, " Interfaces mipi,dvp (default: dvp)");
++
++static int gpio0 = -1, gpio1 = -1, gpio7 = -1, gpio8 = -1;
++module_param(gpio0, int, 0644);
++MODULE_PARM_DESC(gpio0, " GPIO0 function select (default: GPIO0 tri-state)");
++module_param(gpio1, int, 0644);
++MODULE_PARM_DESC(gpio1, " GPIO1 function select (default: GPIO1 tri-state)");
++module_param(gpio7, int, 0644);
++MODULE_PARM_DESC(gpio7, " GPIO7 function select (default: GPIO7 tri-state)");
++module_param(gpio8, int, 0644);
++MODULE_PARM_DESC(gpio8, " GPIO8 function select (default: GPIO8 tri-state)");
++
++static const struct regmap_config max96712_regmap[] = {
++ {
++ /* max96712 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1f03,
++ }, {
++ /* max9271/max96705 */
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = 0xff,
++ }, {
++ /* max9695 */
++ .reg_bits = 16,
++ .val_bits = 8,
++ .max_register = 0x1b03,
++ }
++};
++
++static void max96712_write_remote_verify(struct max96712_priv *priv, int link_n, u8 reg, int val)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int timeout;
++
++ for (timeout = 0; timeout < 10; timeout++) {
++ u8 val2 = 0;
++
++ ser_write(reg, val);
++ ser_read(reg, &val2);
++ if (val2 == val)
++ break;
++
++ usleep_range(1000, 1500);
++ }
++
++ if (timeout >= 10)
++ dev_err(&priv->client->dev, "timeout remote write acked\n");
++}
++
++static void max96712_reset_oneshot(struct max96712_priv *priv, int mask)
++{
++ int timeout;
++ int reg = 0;
++
++ mask &= 0x0f;
++ des_update_bits(MAX96712_CTRL1, mask, mask); /* set reset one-shot */
++
++ /* wait for one-shot bit self-cleared */
++ for (timeout = 0; timeout < 100; timeout++) {
++ des_read(MAX96712_CTRL1, &reg);
++ if (!(reg & mask))
++ break;
++
++ msleep(1);
++ }
++
++ if (reg & mask)
++ dev_err(&priv->client->dev, "Failed reset oneshot 0x%x\n", mask);
++}
++
++/* -----------------------------------------------------------------------------
++ * MIPI, mapping, routing
++ */
++
++static void max96712_pipe_override(struct max96712_priv *priv, unsigned int pipe,
++ unsigned int dt, unsigned int vc)
++{
++ int bpp, bank;
++
++ bpp = mipi_dt_to_bpp(dt);
++ bank = pipe / 4;
++ pipe %= 4;
++
++ if (priv->dbl == 1) {
++ /* DBL=1 is MUX mode, DBL=0 is Normal mode */
++ des_update_bits(MAX_BACKTOP27(bank), BIT(pipe + 4), BIT(pipe + 4)); /* enable MUX mode */
++ bpp = bpp / 2; /* divide because of MUX=1 */
++ }
++
++ switch (pipe) {
++ case 0:
++ /* Pipe X: 0 or 4 */
++ des_update_bits(MAX_BACKTOP12(bank), 0x1f << 3, bpp << 3);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP15(bank), 0x3f, dt);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(6), BIT(6)); /* enalbe s/w override */
++ break;
++ case 1:
++ /* Pipe Y: 1 or 5 */
++ des_update_bits(MAX_BACKTOP18(bank), 0x1f, bpp);
++ des_update_bits(MAX_BACKTOP13(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f, dt & 0x0f);
++ des_update_bits(MAX_BACKTOP15(bank), 0x03 << 6, (dt & 0x30) << 2);
++ des_update_bits(bank ? MAX_BACKTOP28(0) : MAX_BACKTOP22(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ case 2:
++ /* Pipe Z: 2 or 6 */
++ des_update_bits(MAX_BACKTOP19(bank), 0x03, bpp & 0x03);
++ des_update_bits(MAX_BACKTOP18(bank), 0xe0, (bpp & 0x1c) << 3);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f, vc);
++ des_update_bits(MAX_BACKTOP17(bank), 0x03, dt & 0x03);
++ des_update_bits(MAX_BACKTOP16(bank), 0x0f << 4, (dt & 0x3c) << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(6), BIT(6)); /* enable s/w override */
++ break;
++ case 3:
++ /* Pipe U: 3 or 7 */
++ des_update_bits(MAX_BACKTOP19(bank), 0xfc, bpp << 2);
++ des_update_bits(MAX_BACKTOP14(bank), 0x0f << 4, vc << 4);
++ des_update_bits(MAX_BACKTOP17(bank), 0x3f << 2, dt << 2);
++ des_update_bits(bank ? MAX_BACKTOP30(0) : MAX_BACKTOP25(0), BIT(7), BIT(7)); /* enable s/w override */
++ break;
++ }
++}
++
++static void max96712_set_pipe_to_mipi_mapping(struct max96712_priv *priv,
++ unsigned int pipe, unsigned int map_n,
++ unsigned int in_dt, unsigned int in_vc,
++ unsigned int out_dt, unsigned int out_vc, unsigned int out_mipi)
++{
++ int offset = 2 * (map_n % 4);
++
++ des_write(MAX_MIPI_MAP_SRC(pipe, map_n), (in_vc << 6) | in_dt);
++ des_write(MAX_MIPI_MAP_DST(pipe, map_n), (out_vc << 6) | out_dt);
++ des_update_bits(MAX_MIPI_MAP_DST_PHY(pipe, map_n / 4), 0x03 << offset, out_mipi << offset);
++ des_update_bits(MAX_MIPI_TX11(pipe), BIT(map_n), BIT(map_n)); /* enable SRC_n to DST_n mapping */
++}
++
++static void max96712_mipi_setup(struct max96712_priv *priv)
++{
++ des_write(MAX96712_VIDEO_PIPE_EN, 0); /* disable all pipes */
++
++ des_write(MAX_MIPI_PHY0, 0x04); /* MIPI Phy 2x4 mode */
++ des_write(MAX_MIPI_PHY3, 0xe4); /* Lane map: straight */
++ des_write(MAX_MIPI_PHY4, 0xe4); /* Lane map: straight */
++ //des_write(MAX_MIPI_PHY5, 0x00); /* HS_prepare time, non-inverted polarity */
++ //des_write(MAX_MIPI_PHY6, 0x00);
++
++ des_write(MAX_MIPI_TX10(1), 0xc0); /* MIPI1: 4 lanes */
++ des_write(MAX_MIPI_TX10(2), 0xc0); /* MIPI2: 4 lanes */
++
++ des_update_bits(MAX_BACKTOP22(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5)); /* MIPI rate */
++ des_update_bits(MAX_BACKTOP25(0), 0x3f, ((priv->csi_rate[1] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP28(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++ des_update_bits(MAX_BACKTOP31(0), 0x3f, ((priv->csi_rate[2] / 100) & 0x1f) | BIT(5));
++
++ des_update_bits(MAX_MIPI_PHY2, 0xf0, 0xf0); /* enable all MIPI PHYs */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL1
++ */
++
++static int max96712_gmsl1_sensor_reset(struct max96712_priv *priv, int link_n, int reset_on)
++{
++ struct max96712_link *link = priv->link[link_n];
++
++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
++ return -EINVAL;
++
++ /* sensor reset/unreset */
++ ser_write(0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */
++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on));
++ ser_write(0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */
++
++ return 0;
++}
++
++static void max96712_gmsl1_cc_enable(struct max96712_priv *priv, int link, int on)
++{
++ des_update_bits(MAX_GMSL1_4(link), 0x03, on ? 0x03 : 0x00);
++ usleep_range(2000, 2500);
++}
++
++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n)
++{
++ int val = 0;
++
++ des_read(MAX_GMSL1_CB(link_n), &val);
++
++ return !!(val & BIT(0));
++}
++
++static void max96712_gmsl1_link_crossbar_setup(struct max96712_priv *priv, int link, int dt)
++{
++ /* Always decode reversed bus, since we always reverse on serializer (old imagers need this) */
++ switch (dt) {
++ case MIPI_DT_YUV8:
++ des_write(MAX_CROSS(link, 0), 7);
++ des_write(MAX_CROSS(link, 1), 6);
++ des_write(MAX_CROSS(link, 2), 5);
++ des_write(MAX_CROSS(link, 3), 4);
++ des_write(MAX_CROSS(link, 4), 3);
++ des_write(MAX_CROSS(link, 5), 2);
++ des_write(MAX_CROSS(link, 6), 1);
++ des_write(MAX_CROSS(link, 7), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 8), 15);
++ des_write(MAX_CROSS(link, 9), 14);
++ des_write(MAX_CROSS(link, 10), 13);
++ des_write(MAX_CROSS(link, 11), 12);
++ des_write(MAX_CROSS(link, 12), 11);
++ des_write(MAX_CROSS(link, 13), 10);
++ des_write(MAX_CROSS(link, 14), 9);
++ des_write(MAX_CROSS(link, 15), 8);
++ }
++ break;
++ case MIPI_DT_RAW12:
++ des_write(MAX_CROSS(link, 0), 11);
++ des_write(MAX_CROSS(link, 1), 10);
++ des_write(MAX_CROSS(link, 2), 9);
++ des_write(MAX_CROSS(link, 3), 8);
++ des_write(MAX_CROSS(link, 4), 7);
++ des_write(MAX_CROSS(link, 5), 6);
++ des_write(MAX_CROSS(link, 6), 5);
++ des_write(MAX_CROSS(link, 7), 4);
++ des_write(MAX_CROSS(link, 8), 3);
++ des_write(MAX_CROSS(link, 9), 2);
++ des_write(MAX_CROSS(link, 10), 1);
++ des_write(MAX_CROSS(link, 11), 0);
++
++ if (priv->dbl == 0) {
++ /* deserializer DBL=1 is MUX, DBL=0 is Normal */
++ des_write(MAX_CROSS(link, 12), 23);
++ des_write(MAX_CROSS(link, 13), 22);
++ des_write(MAX_CROSS(link, 14), 21);
++ des_write(MAX_CROSS(link, 15), 20);
++ des_write(MAX_CROSS(link, 16), 19);
++ des_write(MAX_CROSS(link, 17), 18);
++ des_write(MAX_CROSS(link, 18), 17);
++ des_write(MAX_CROSS(link, 19), 16);
++ des_write(MAX_CROSS(link, 20), 15);
++ des_write(MAX_CROSS(link, 21), 14);
++ des_write(MAX_CROSS(link, 22), 13);
++ des_write(MAX_CROSS(link, 23), 12);
++ }
++ break;
++ default:
++ dev_err(&priv->client->dev, "crossbar for dt %d is not supported\n", dt);
++ break;
++ }
++
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max96712_gmsl1_initial_setup(struct max96712_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX96712_REG6, 0xf0, 0); /* set GMSL1 mode */
++ des_write(MAX96712_REG26, 0x11); /* 187.5M/3G */
++ des_write(MAX96712_REG27, 0x11); /* 187.5M/3G */
++
++ for (i = 0; i < priv->n_links; i++) {
++ des_write(MAX_GMSL1_2(i), 0x03); /* Autodetect serial data rate range */
++ des_write(MAX_GMSL1_4(i), 0); /* disable REV/FWD CC */
++ des_update_bits(MAX_GMSL1_6(i), BIT(7), priv->him ? BIT(7) : 0); /* HIM/Legacy mode */
++ des_write(MAX_GMSL1_7(i), (priv->dbl ? BIT(7) : 0) | /* DBL mode */
++ (priv->bws ? BIT(5) : 0) | /* BWS 32/24-bit */
++ (priv->hibw ? BIT(3) : 0) | /* High-bandwidth mode */
++ (priv->hven ? BIT(2) : 0)); /* HS/VS encoding enable */
++ des_write(MAX_GMSL1_D(i), 0); /* disable artificial ACKs, RC conf disable */
++ des_write(MAX_GMSL1_F(i), 0); /* disable DE processing */
++ des_write(MAX_GMSL1_96(i), (0x13 << 3) | 0x3); /* color map: RAW12 double - i.e. bypass packet as is */
++ }
++}
++
++static int max96712_gmsl1_reverse_channel_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int ser_addrs[] = { 0x40 }; /* possible MAX9271/MAX96705 addresses on i2c bus */
++ int lock_sts;
++ int timeout = priv->timeout;
++ char timeout_str[40];
++ u8 val = 0;
++ int ret = 0;
++
++ des_write(MAX_GMSL1_D(link_n), 0x81); /* enable artificial ACKs, RC conf mode */
++ des_write(MAX_RLMSC5(link_n), 0xa0); /* override RC pulse length */
++ des_write(MAX_RLMSC4(link_n), 0x80); /* override RC rise/fall time */
++ usleep_range(2000, 2500);
++ des_write(MAX_GMSL1_4(link_n), 0x3); /* enable REV/FWD CC */
++ des_write(MAX96712_REG6, BIT(link_n)); /* GMSL1 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(link_n));
++ usleep_range(2000, 2500);
++
++ for (; timeout > 0; timeout--) {
++ if (priv->him) {
++ /* HIM mode setup */
++ __reg8_write(ser_addrs[0], 0x4d, 0xc0);
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++ } else {
++ /* Legacy mode setup */
++ des_write(MAX_RLMS95(link_n), 0x88); /* override RC Tx amplitude */
++ usleep_range(2000, 2500);
++
++ __reg8_write(ser_addrs[0], 0x04, 0x43); /* wake-up, enable RC, conf_link */
++ usleep_range(2000, 2500);
++ __reg8_write(ser_addrs[0], 0x08, 0x01); /* RC receiver high threshold enable */
++ __reg8_write(ser_addrs[0], 0x97, 0x5f); /* enable RC programming (MAX96705-MAX96711 only) */
++ usleep_range(2000, 2500);
++
++ if (priv->bws) {
++ __reg8_write(ser_addrs[0], 0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ }
++
++ des_write(MAX_RLMS95(link_n), 0xd3); /* increase RC Tx amplitude */
++ usleep_range(2000, 2500);
++ }
++
++ __reg8_read(ser_addrs[0], 0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ __reg8_write(ser_addrs[0], 0x00, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++
++ /* Check if already initialized (after reboot/reset ?) */
++ ser_read(0x1e, &val);
++ if (val == MAX9271_ID || val == MAX96705_ID || val == MAX96707_ID) {
++ link->ser_id = val;
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++ ret = -EADDRINUSE;
++ break;
++ }
++
++ if (poc_trig) {
++ if (!IS_ERR(link->poc_reg) && (timeout % poc_trig == 0)) {
++ regulator_disable(link->poc_reg); /* POC power off */
++ mdelay(200);
++ ret = regulator_enable(link->poc_reg); /* POC power on */
++ if (ret)
++ dev_err(&link->client->dev, "failed to enable poc regulator\n");
++ mdelay(priv->poc_delay);
++ }
++ }
++ }
++
++ max96712_gmsl1_sensor_reset(priv, link_n, 0); /* sensor un-reset */
++
++ des_write(MAX_GMSL1_D(link_n), 0); /* disable artificial ACKs, RC conf disable */
++ usleep_range(2000, 2500);
++ des_read(MAX_GMSL1_CB(link_n), &lock_sts);
++ lock_sts = !!(lock_sts & 0x01);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ sprintf(timeout_str, " retries=%d lock_sts=%d", priv->timeout - timeout, lock_sts);
++ dev_info(&priv->client->dev, "GMSL1 link%d %s %sat 0x%x %s %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr,
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout ? timeout_str : "");
++ return ret;
++}
++
++static int max96712_gmsl1_link_serializer_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++
++ /* GMSL setup */
++ ser_write(0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */
++ ser_write(0x07, (priv->hven ? 0x04 : 0) | /* HS/VS encoding enable */
++ (priv->pclk_rising_edge ? 0 : 0x10) | /* PCLK edge */
++ (0x80) | /* DBL=1 in serializer */
++ (priv->bws ? 0x20 : 0)); /* BWS 32/24-bit */
++ usleep_range(2000, 2500);
++ ser_write(0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */
++ usleep_range(2000, 2500);
++
++ if (link->ser_id != MAX9271_ID) {
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ if (priv->dbl == 1) {
++ /* setup crossbar for YUV8/RAW8: reverse DVP bus */
++ ser_write(0x20, priv->cb[7]);
++ ser_write(0x21, priv->cb[6]);
++ ser_write(0x22, priv->cb[5]);
++ ser_write(0x23, priv->cb[4]);
++ ser_write(0x24, priv->cb[3]);
++ ser_write(0x25, priv->cb[2]);
++ ser_write(0x26, priv->cb[1]);
++ ser_write(0x27, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer always) */
++ ser_write(0x30, priv->cb[7] + 16);
++ ser_write(0x31, priv->cb[6] + 16);
++ ser_write(0x32, priv->cb[5] + 16);
++ ser_write(0x33, priv->cb[4] + 16);
++ ser_write(0x34, priv->cb[3] + 16);
++ ser_write(0x35, priv->cb[2] + 16);
++ ser_write(0x36, priv->cb[1] + 16);
++ ser_write(0x37, priv->cb[0] + 16);
++ } else {
++ /* setup crossbar for YUV8/RAW8: reversed DVP bus */
++ ser_write(0x20, priv->cb[4]);
++ ser_write(0x21, priv->cb[3]);
++ ser_write(0x22, priv->cb[2]);
++ ser_write(0x23, priv->cb[1]);
++ ser_write(0x24, priv->cb[0]);
++ ser_write(0x25, 0x40);
++ ser_write(0x26, 0x40);
++ if (link->ser_id == MAX96705_ID) {
++ ser_write(0x27, 14); /* HS: D14->D18 */
++ ser_write(0x28, 15); /* VS: D15->D19 */
++ ser_write(0x29, 14); /* DE: D14->D20 */
++ }
++ if (link->ser_id == MAX96707_ID) {
++ ser_write(0x27, 12); /* HS: D12->D18, this is a virtual NC pin, hence it is D14 at HS */
++ ser_write(0x28, 13); /* VS: D13->D19 */
++ ser_write(0x29, 12); /* DE: D12->D20 */
++ }
++ ser_write(0x2A, 0x40);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, 0x10 + priv->cb[7]);
++ ser_write(0x31, 0x10 + priv->cb[6]);
++ ser_write(0x32, 0x10 + priv->cb[5]);
++ ser_write(0x33, 0x10 + priv->cb[4]);
++ ser_write(0x34, 0x10 + priv->cb[3]);
++ ser_write(0x35, 0x10 + priv->cb[2]);
++ ser_write(0x36, 0x10 + priv->cb[1]);
++ ser_write(0x37, 0x10 + priv->cb[0]);
++ ser_write(0x38, priv->cb[7]);
++ ser_write(0x39, priv->cb[6]);
++ ser_write(0x3A, priv->cb[5]);
++
++ ser_write(0x67, 0xC4); /* DBL_ALIGN_TO = 100b */
++ }
++ break;
++ case MIPI_DT_RAW12:
++ /* setup crossbar for RAW12: reverse DVP bus */
++ ser_write(0x20, priv->cb[11]);
++ ser_write(0x21, priv->cb[10]);
++ ser_write(0x22, priv->cb[9]);
++ ser_write(0x23, priv->cb[8]);
++ ser_write(0x24, priv->cb[7]);
++ ser_write(0x25, priv->cb[6]);
++ ser_write(0x26, priv->cb[5]);
++ ser_write(0x27, priv->cb[4]);
++ ser_write(0x28, priv->cb[3]);
++ ser_write(0x29, priv->cb[2]);
++ ser_write(0x2a, priv->cb[1]);
++ ser_write(0x2b, priv->cb[0]);
++
++ /* this is second byte in the packet (DBL=1 in serializer) */
++ ser_write(0x30, priv->cb[11] + 16);
++ ser_write(0x31, priv->cb[10] + 16);
++ ser_write(0x32, priv->cb[9] + 16);
++ ser_write(0x33, priv->cb[8] + 16);
++ ser_write(0x34, priv->cb[7] + 16);
++ ser_write(0x35, priv->cb[6] + 16);
++ ser_write(0x36, priv->cb[5] + 16);
++ ser_write(0x37, priv->cb[4] + 16);
++ ser_write(0x38, priv->cb[3] + 16);
++ ser_write(0x39, priv->cb[2] + 16);
++ ser_write(0x3a, priv->cb[1] + 16);
++ ser_write(0x3b, priv->cb[0] + 16);
++
++ if (!(priv->bws || priv->hibw) && priv->dbl)
++ dev_err(&priv->client->dev, " BWS must be 27/32-bit for RAW12 in DBL mode\n");
++ break;
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(0x09, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(0x0A, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(0x0B, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(0x0C, link->ser_addr << 1); /* serializer broadcast I2C native */
++ /* put serializer in configuration link state */
++ ser_write(0x04, 0x43); /* enable RC, conf_link */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static void max96712_gmsl1_link_pipe_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight map */
++ int dt = priv->dt; /* should come from imager */
++ int in_vc = 0;
++
++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ /* use map #0 for payload data */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 0, /* pipe, map# */
++ dt, in_vc, /* src DT, VC */
++ dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #1 for FS */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 1, /* pipe, map# */
++ 0x00, in_vc, /* src DT, VC */
++ 0x00, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ /* use map #2 for FE */
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, 2, /* pipe, map# */
++ 0x01, in_vc, /* src DT, VC */
++ 0x01, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ usleep_range(5000, 5500);
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max96712_gmsl1_postinit(struct max96712_priv *priv)
++{
++ int i;
++ u8 val = 0;
++
++ for (i = 0; i < priv->n_links; i++) {
++ struct max96712_link *link = priv->link[i];
++
++ if (!(priv->links_mask & BIT(i)))
++ continue;
++
++ des_write(MAX_GMSL1_4(i), 0x3); /* enable REV/FWD CC */
++ des_write(MAX96712_REG6, BIT(i)); /* GMSL1 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(i));
++ usleep_range(2000, 2500);
++
++ ser_read(0x15, &val);
++ if (!(val & BIT(1)))
++ dev_warn(&priv->client->dev, "link%d valid PCLK is not detected\n", i);
++
++ /* switch to GMSL serial_link for streaming video */
++ max96712_write_remote_verify(priv, i, 0x04, conf_link ? 0x43 : 0x83);
++ usleep_range(2000, 2500);
++
++ des_write(MAX_GMSL1_4(i), 0x00); /* disable REV/FWD CC */
++
++ switch (priv->link[i]->ser_id) {
++ case MAX9271_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x01); /* use D14/15 for HS/VS */
++ break;
++ case MAX96705_ID:
++ case MAX96707_ID:
++ des_update_bits(MAX_GMSL1_6(i), 0x07, 0x00); /* use D18/D19 for HS/VS */
++ break;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ des_write(MAX_GMSL1_4(i), priv->links_mask & BIT(i) ? 0x03 : 0); /* enable REV/FWD CC */
++
++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */
++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */
++}
++
++static void max96712_gmsl1_fsync_setup(struct max96712_priv *priv)
++{
++ des_write(MAX96712_FSYNC_5, priv->fsync_period & 0xff); /* Fsync Period L */
++ des_write(MAX96712_FSYNC_6, (priv->fsync_period >> 8) & 0xff);/* Fsync Period M */
++ des_write(MAX96712_FSYNC_7, priv->fsync_period >> 16); /* Fsync Period H */
++ //des_write(MAX96712_FSYNC_8, 0x00); /* Disable Err Thresh */
++ //des_write(MAX96712_FSYNC_9, 0x00); /* Disable Err Thresh */
++ des_write(MAX96712_FSYNC_10, 0x00); /* Disable Overlap */
++ des_write(MAX96712_FSYNC_11, 0x00);
++
++ des_write(MAX96712_FSYNC_0, 0x00); /* Manual method, Internal GMSL1 generator mode */
++
++ des_write(MAX_GMSL1_8(0), 0x11); /* Fsync Tx Enable on Link A */
++ des_write(MAX_GMSL1_8(1), 0x11); /* Fsync Tx Enable on Link B */
++ des_write(MAX_GMSL1_8(2), 0x11); /* Fsync Tx Enable on Link C */
++ des_write(MAX_GMSL1_8(3), 0x11); /* Fsync Tx Enable on Link D */
++
++ des_write(MAX96712_FSYNC_15, 0x1f); /* GMSL1 Type Fsync, Enable all pipes */
++}
++
++/* -----------------------------------------------------------------------------
++ * GMSL2
++ */
++
++static void max96712_gmsl2_cc_enable(struct max96712_priv *priv, int link, int on)
++{
++ /* nothing */
++}
++
++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n)
++{
++ int lock_reg[] = {MAX96712_CTRL3, MAX96712_CTRL12, MAX96712_CTRL13, MAX96712_CTRL14};
++ int val = 0;
++
++ des_read(lock_reg[link_n], &val);
++
++ return !!(val & BIT(3));
++}
++
++static void max96712_gmsl2_initial_setup(struct max96712_priv *priv)
++{
++ des_update_bits(MAX96712_REG6, 0xf0, 0xf0); /* set GMSL2 mode */
++ des_write(MAX96712_REG26, 0x22); /* 187.5M/6G */
++ des_write(MAX96712_REG27, 0x22); /* 187.5M/6G */
++}
++
++static int max96712_gmsl2_reverse_channel_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int ser_addrs[] = {0x40, 0x42, 0x60, 0x62}; /* possible MAX9295 addresses on i2c bus */
++ int timeout = priv->timeout;
++ int ret = 0;
++ int i = 0;
++
++ des_write(MAX96712_REG6, 0xf0 | BIT(link_n)); /* GMSL2 mode, enable GMSL link# */
++ max96712_reset_oneshot(priv, BIT(link_n));
++
++ /* wait 100ms for link to be established, indicated when status bit LOCKED goes high */
++ while ((!max96712_gmsl2_get_link_lock(priv, link_n)) && (--timeout))
++ msleep(1);
++
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(ser_addrs); i++) {
++ int val = 0;
++
++ __reg16_read(ser_addrs[i], 0x000d, &val); /* read serializer ID */
++ if (val == MAX9295A_ID || val == MAX9295B_ID) {
++ link->ser_id = val;
++ __reg16_write(ser_addrs[i], 0x0000, link->ser_addr << 1); /* relocate serizlizer on I2C bus */
++ usleep_range(2000, 2500);
++ break;
++ }
++ }
++
++ if (i == ARRAY_SIZE(ser_addrs)) {
++ dev_err(&priv->client->dev, "serializer not found\n");
++ goto out;
++ }
++
++ priv->links_mask |= BIT(link_n);
++
++out:
++ dev_info(&priv->client->dev, "link%d %s %sat 0x%x (0x%x) %s\n", link_n, chip_name(link->ser_id),
++ ret == -EADDRINUSE ? "already " : "", link->ser_addr, ser_addrs[i],
++ ret == -ETIMEDOUT ? "not found: timeout GMSL2 link establish" : "");
++ return ret;
++}
++
++static int max96712_gmsl2_link_serializer_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int i;
++
++ //ser_write(MAX9295_CTRL0, 0x31); /* link reset */
++ //msleep(100);
++ ser_write(MAX9295_REG2, 0x03); /* disable all pipes */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ ser_write(MAX9295_VIDEO_TX0(0), BIT(6) | /* line CRC enable */
++ (priv->hven ? BIT(5) : 0)); /* HS/VS encoding */
++ ser_write(MAX9295_VIDEO_TX1(0), 0x0a); /* BPP = 10 */
++ ser_write(MAX9295_REG7, 0x07); /* DVP stream, enable HS/VS, rising edge */
++ }
++
++ ser_write(MAX9295_REG2, 0x13); /* enable Pipe X */
++
++ switch (priv->dt) {
++ case MIPI_DT_YUV8:
++ case MIPI_DT_RAW12:
++ /* setup crossbar: strait DVP mapping */
++ ser_write(MAX9295_CROSS(0), priv->cb[0]);
++ ser_write(MAX9295_CROSS(1), priv->cb[1]);
++ ser_write(MAX9295_CROSS(2), priv->cb[2]);
++ ser_write(MAX9295_CROSS(3), priv->cb[3]);
++ ser_write(MAX9295_CROSS(4), priv->cb[4]);
++ ser_write(MAX9295_CROSS(5), priv->cb[5]);
++ ser_write(MAX9295_CROSS(6), priv->cb[6]);
++ ser_write(MAX9295_CROSS(7), priv->cb[7]);
++ ser_write(MAX9295_CROSS(8), priv->cb[8]);
++ ser_write(MAX9295_CROSS(9), priv->cb[9]);
++ ser_write(MAX9295_CROSS(10), priv->cb[10]);
++ ser_write(MAX9295_CROSS(11), priv->cb[11]);
++ break;
++ }
++
++ for (i = 0; i < 11; i++) {
++ if (priv->gpio[i] == 0) {
++ /* GPIO set 0 */
++ ser_write(MAX9295_GPIO_A(i), 0x80); /* 1MOm, GPIO output low */
++ ser_write(MAX9295_GPIO_B(i), 0xa0); /* push-pull, pull-down */
++ }
++ if (priv->gpio[i] == 1) {
++ /* GPIO set 1 */
++ ser_write(MAX9295_GPIO_A(i), 0x90); /* 1MOm, GPIO output high */
++ ser_write(MAX9295_GPIO_B(i), 0x60); /* push-pull, pull-up */
++ }
++ if (priv->gpio[i] == 2) {
++ /* GPIO FSIN */
++ ser_write(MAX9295_GPIO_A(i), 0x84); /* 1MOm, GMSL2 RX from deserializer */
++ ser_write(MAX9295_GPIO_C(i), 0x01); /* pull-none, GPIO stream ID=1 */
++ }
++ if (priv->gpio[i] == 3) {
++ /* GPIO Interrupt */
++ ser_write(MAX9295_GPIO_A(i), 0x63); /* 40kOm, GMSL2 TX to deserializer */
++ ser_write(MAX9295_GPIO_B(i), 0x25); /* push-pull, pull-none, GPIO stream ID=5 */
++ }
++ }
++
++ /* I2C translator setup */
++// ser_write(MAX9295_I2C2, OV490_I2C_ADDR_NEW << 1); /* sensor I2C translated - must be set by sensor driver */
++// ser_write(MAX9295_I2C3, OV490_I2C_ADDR << 1); /* sensor I2C native - must be set by sensor driver */
++ ser_write(MAX9295_I2C4, BROADCAST << 1); /* serializer broadcast I2C translated */
++ ser_write(MAX9295_I2C5, link->ser_addr << 1); /* serializer broadcast I2C native */
++ usleep_range(2000, 2500);
++
++ return 0;
++}
++
++static struct {
++ int in_dt;
++ int out_dt;
++} gmsl2_pipe_maps[] = {
++ {0x00, 0x00}, /* FS */
++ {0x01, 0x01}, /* FE */
++ {MIPI_DT_YUV8, MIPI_DT_YUV8} /* payload data */
++};
++
++static void max96712_gmsl2_pipe_set_source(struct max96712_priv *priv, int pipe, int phy, int in_pipe)
++{
++ int offset = (pipe % 2) * 4;
++
++ des_update_bits(MAX96712_VIDEO_PIPE_SEL(pipe / 2), 0x0f << offset, (phy << (offset + 2)) |
++ (in_pipe << offset));
++}
++
++static void max96712_gmsl2_link_pipe_setup(struct max96712_priv *priv, int link_n)
++{
++ struct max96712_link *link = priv->link[link_n];
++ int pipe = link_n; /* straight mapping */
++ int dt = priv->dt; /* must come from imager */
++ int in_vc = 0;
++ int i;
++
++ max96712_gmsl2_pipe_set_source(priv, pipe, link_n, 0); /* route Pipe X only */
++
++ if (strcmp(priv->mbus, "dvp") == 0) {
++ des_write(MAX96712_RX0(pipe), 0); /* stream_id = 0 */
++ //des_update_bits(MAX_VIDEO_RX0(pipe), BIT(0), BIT(0)); /* disable Packet detector */
++ max96712_pipe_override(priv, pipe, dt, in_vc); /* override dt, vc */
++ }
++
++ des_write(MAX_MIPI_TX11(pipe), 0x00); /* disable all mappings */
++ des_write(MAX_MIPI_TX12(pipe), 0x00);
++
++ for (i = 0; i < ARRAY_SIZE(gmsl2_pipe_maps); i++) {
++ max96712_set_pipe_to_mipi_mapping(priv, pipe, i, /* pipe, map# */
++ gmsl2_pipe_maps[i].in_dt, in_vc, /* src DT, VC */
++ gmsl2_pipe_maps[i].out_dt, link->out_vc, /* dst DT, VC */
++ link->out_mipi); /* dst MIPI PHY */
++ }
++
++ link->pipes_mask |= BIT(pipe);
++}
++
++static void max96712_gmsl2_postinit(struct max96712_priv *priv)
++{
++ des_update_bits(MAX96712_REG6, 0x0f, priv->links_mask); /* enable detected links */
++ max96712_reset_oneshot(priv, priv->links_mask); /* one-shot reset valid links */
++}
++
++static void max96712_gmsl2_link_crossbar_setup(struct max96712_priv *priv, int link, int dt)
++{
++ des_write(MAX_CROSS(link, 24), (priv->hsync ? 0x40 : 0) + 24); /* invert HS polarity */
++ des_write(MAX_CROSS(link, 25), (priv->vsync ? 0 : 0x40) + 25); /* invert VS polarity */
++ des_write(MAX_CROSS(link, 26), (priv->hsync ? 0x40 : 0) + 26); /* invert DE polarity */
++}
++
++static void max96712_gmsl2_fsync_setup(struct max96712_priv *priv)
++{
++ /* TODO */
++}
++
++/* -----------------------------------------------------------------------------
++ * I2C Multiplexer
++ */
++
++static int max96712_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
++{
++ /* Do nothing! */
++ return 0;
++}
++
++static int max96712_i2c_mux_init(struct max96712_priv *priv)
++{
++ struct i2c_client *client = priv->client;
++
++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
++ return -ENODEV;
++
++ priv->mux = i2c_mux_alloc(client->adapter, &client->dev,
++ priv->n_links, 0, I2C_MUX_LOCKED,
++ max96712_i2c_mux_select, NULL);
++ if (!priv->mux)
++ return -ENOMEM;
++
++ priv->mux->priv = priv;
++
++ return 0;
++}
++
++#define max96712_cc_enable(priv,i,en) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_cc_enable(priv, i, en) : \
++ max96712_gmsl1_cc_enable(priv, i, en))
++#define max96712_initial_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_initial_setup(priv) : \
++ max96712_gmsl1_initial_setup(priv))
++#define max96712_reverse_channel_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_reverse_channel_setup(priv, i) : \
++ max96712_gmsl1_reverse_channel_setup(priv, i))
++#define max96712_link_serializer_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_serializer_setup(priv, i) : \
++ max96712_gmsl1_link_serializer_setup(priv, i))
++#define max96712_link_pipe_setup(priv,i) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_pipe_setup(priv, i) : \
++ max96712_gmsl1_link_pipe_setup(priv, i))
++#define max96712_link_crossbar_setup(priv,i,dt) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_link_crossbar_setup(priv, i, dt) : \
++ max96712_gmsl1_link_crossbar_setup(priv, i, dt))
++#define max96712_postinit(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_postinit(priv) : \
++ max96712_gmsl1_postinit(priv))
++#define max96712_fsync_setup(priv) (priv->gmsl_mode == MODE_GMSL2 ? max96712_gmsl2_fsync_setup(priv) : \
++ max96712_gmsl1_fsync_setup(priv))
++
++static int max96712_preinit(struct max96712_priv *priv)
++{
++ int i;
++
++ des_update_bits(MAX96712_PWR1, BIT(6), BIT(6)); /* reset chip */
++ mdelay(5);
++
++ /* enable internal regulator for 1.2V VDD supply */
++ des_update_bits(MAX96712_CTRL0, BIT(2), BIT(2)); /* REG_ENABLE = 1 */
++ des_update_bits(MAX96712_CTRL2, BIT(4), BIT(4)); /* REG_MNL = 1 */
++
++ //for (i = 0; i < priv->n_links; i++) {
++ // des_write(MAX_RLMS58(i), 0x28);
++ // des_write(MAX_RLMS59(i), 0x68);
++ // max96712_reset_oneshot(priv, BIT(i));
++ //}
++
++ /* I2C-I2C timings */
++ for (i = 0; i < 8; i++) {
++ des_write(MAX96712_I2C_0(i), 0x01); /* Fast mode Plus, 1mS timeout */
++ des_write(MAX96712_I2C_1(i), 0x51); /* i2c speed: 397Kbps, 1mS timeout */
++ }
++
++ des_update_bits(MAX96712_CTRL11, 0x55, priv->is_coax ? 0x55 : 0); /* cable mode */
++ des_update_bits(MAX96712_REG6, 0x0f, 0); /* disable all links */
++
++ return 0;
++}
++
++static int max96712_initialize(struct max96712_priv *priv)
++{
++ int ret, i;
++
++ max96712_preinit(priv);
++ max96712_initial_setup(priv);
++ max96712_mipi_setup(priv);
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg)) {
++ ret = regulator_enable(priv->link[i]->poc_reg); /* POC power on */
++ if (ret) {
++ dev_err(&priv->link[i]->client->dev, "failed to enable poc regulator\n");
++ continue;
++ }
++ mdelay(priv->poc_delay);
++ }
++
++ ret = max96712_reverse_channel_setup(priv, i);
++ if (ret == -ETIMEDOUT)
++ continue;
++ if (!ret)
++ max96712_link_serializer_setup(priv, i);
++
++ max96712_link_pipe_setup(priv, i);
++ max96712_link_crossbar_setup(priv, i, priv->dt);
++
++ i2c_mux_add_adapter(priv->mux, 0, i, 0);
++ max96712_cc_enable(priv, i, 0);
++ }
++
++ max96712_postinit(priv);
++ max96712_fsync_setup(priv);
++
++ return 0;
++}
++
++static int max96712_reboot_notifier(struct notifier_block *nb, unsigned long code, void *data)
++{
++ struct max96712_priv *priv = container_of(nb, struct max96712_priv, reboot_nb);
++ int i;
++
++ for (i = 0; i < priv->n_links; i++) {
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return NOTIFY_DONE;
++}
++
++static int max96712_s_power(struct v4l2_subdev *sd, int on)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++ int i = sd->grp_id;
++ int pipes_mask = priv->link[i]->pipes_mask;
++
++ if (on) {
++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, pipes_mask); /* enable link pipes */
++ if (atomic_inc_return(&priv->use_count) == 1)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0x02); /* CSI output enable */
++ } else {
++ if (atomic_dec_return(&priv->use_count) == 0)
++ des_update_bits(MAX_BACKTOP12(0), 0x02, 0); /* CSI output disable */
++ des_update_bits(MAX96712_VIDEO_PIPE_EN, pipes_mask, 0); /* disable link pipes */
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++static int max96712_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++ int ret;
++ int val = 0;
++
++ ret = des_read(reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int max96712_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
++{
++ struct max96712_priv *priv = v4l2_get_subdevdata(sd);
++
++ return des_write(reg->reg, (u8)reg->val);
++}
++#endif
++
++static struct v4l2_subdev_core_ops max96712_subdev_core_ops = {
++#ifdef CONFIG_VIDEO_ADV_DEBUG
++ .g_register = max96712_g_register,
++ .s_register = max96712_s_register,
++#endif
++ .s_power = max96712_s_power,
++};
++
++static struct v4l2_subdev_ops max96712_subdev_ops = {
++ .core = &max96712_subdev_core_ops,
++};
++
++static const struct of_device_id max96712_dt_ids[] = {
++ { .compatible = "maxim,max96712" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, max96712_dt_ids);
++
++static int max96712_parse_dt(struct i2c_client *client)
++{
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ struct device_node *np = client->dev.of_node;
++ struct device_node *endpoint = NULL, *rendpoint = NULL;
++ struct property *prop;
++ char name[16];
++ int i, csi_rate;
++
++ if (of_property_read_u32(np, "maxim,links", &priv->n_links))
++ priv->n_links = MAX96712_MAX_LINKS;
++ if (of_property_read_u32(np, "maxim,gmsl", &priv->gmsl_mode))
++ priv->gmsl_mode = MODE_GMSL2;
++ if (of_property_read_bool(np, "maxim,stp"))
++ priv->is_coax = 0;
++ else
++ priv->is_coax = 1;
++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) {
++ priv->gpio_resetb = -1;
++ } else {
++ if (of_property_read_bool(np, "maxim,resetb-active-high"))
++ priv->active_low_resetb = 0;
++ else
++ priv->active_low_resetb = 1;
++ }
++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period))
++ priv->fsync_period = 3210000;/* 96MHz/30fps */
++ priv->pclk_rising_edge = true;
++ if (of_property_read_bool(np, "maxim,pclk-falling-edge"))
++ priv->pclk_rising_edge = false;
++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout))
++ priv->timeout = 100;
++ if (of_property_read_u32(np, "maxim,him", &priv->him))
++ priv->him = 0;
++ if (of_property_read_u32(np, "maxim,bws", &priv->bws))
++ priv->bws = 0;
++ if (of_property_read_u32(np, "maxim,dbl", &priv->dbl))
++ priv->dbl = 1;
++ if (of_property_read_u32(np, "maxim,hven", &priv->hven))
++ priv->hven = 1;
++ if (of_property_read_u32(np, "maxim,hibw", &priv->hibw))
++ priv->hibw = 0;
++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync))
++ priv->hsync = 0;
++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync))
++ priv->vsync = 1;
++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay))
++ priv->poc_delay = 50;
++ if (of_property_read_u32(np, "maxim,dt", &priv->dt))
++ priv->dt = MIPI_DT_YUV8;
++ if (of_property_read_u64(np, "maxim,crossbar", &priv->crossbar))
++ priv->crossbar = crossbar;
++ if (of_property_read_string(np, "maxim,mbus", &priv->mbus))
++ priv->mbus = mbus_default;
++ for (i = 0; i < 11; i++) {
++ sprintf(name, "maxim,gpio%d", i);
++ if (of_property_read_u32(np, name, &priv->gpio[i]))
++ priv->gpio[i] = -1;
++ }
++
++ /* module params override dts */
++ if (gmsl != MODE_GMSL2)
++ priv->gmsl_mode = gmsl;
++ if (him)
++ priv->him = him;
++ if (fsync_period) {
++ priv->fsync_period = fsync_period;
++// priv->fsync_mode = fsync_mode_default;
++ }
++ if (hsync)
++ priv->hsync = hsync;
++ if (!vsync)
++ priv->vsync = vsync;
++ if (gpio_resetb)
++ priv->gpio_resetb = gpio_resetb;
++ if (active_low_resetb)
++ priv->active_low_resetb = active_low_resetb;
++ if (timeout_n)
++ priv->timeout = timeout_n;
++ if (poc_delay)
++ priv->poc_delay = poc_delay;
++ if (bws)
++ priv->bws = bws;
++ if (!dbl)
++ priv->dbl = dbl;
++ if (dt != MIPI_DT_YUV8)
++ priv->dt = dt;
++// if (hsgen)
++// priv->hsgen = hsgen;
++ if (gpio0 >= 0)
++ priv->gpio[0] = gpio0;
++ if (gpio1 >= 0)
++ priv->gpio[1] = gpio1;
++ if (gpio7 >= 0)
++ priv->gpio[7] = gpio7;
++ if (gpio8 >= 0)
++ priv->gpio[8] = gpio8;
++
++ /* parse serializer crossbar setup */
++ for (i = 0; i < 16; i++) {
++ priv->cb[i] = priv->crossbar % 16;
++ priv->crossbar /= 16;
++ }
++
++ for (i = 0; ; i++) {
++ endpoint = of_graph_get_next_endpoint(np, endpoint);
++ if (!endpoint)
++ break;
++
++ if (i < priv->n_links) {
++ if (of_property_read_u32(endpoint, "ser-addr", &priv->link[i]->ser_addr)) {
++ of_node_put(endpoint);
++ dev_err(&client->dev, "ser-addr not set\n");
++ return -EINVAL;
++ }
++ priv->link[i]->sd_fwnode = of_fwnode_handle(endpoint);
++ }
++
++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0);
++ if (!rendpoint)
++ continue;
++
++ prop = of_find_property(endpoint, "csi-rate", NULL);
++ if (prop) {
++ of_property_read_u32(endpoint, "csi-rate", &csi_rate);
++ of_update_property(rendpoint, prop);
++ }
++
++ prop = of_find_property(endpoint, "dvp-order", NULL);
++ if (prop)
++ of_update_property(rendpoint, prop);
++ }
++
++ of_node_put(endpoint);
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->out_mipi = 1; /* CSI default forwarding is to MIPI1 */
++ priv->link[i]->out_vc = i; /* Default VC map: 0 1 2 3 */
++ }
++
++ prop = of_find_property(np, "maxim,links-mipi-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= MAX96712_MAX_MIPI)
++ return -EINVAL;
++ priv->link[i]->out_mipi = val;
++ }
++ }
++
++ for (i = 0; i < priv->n_links; i++)
++ priv->csi_rate[priv->link[i]->out_mipi] = csi_rate;
++
++ prop = of_find_property(np, "maxim,links-vc-map", NULL);
++ if (prop) {
++ const __be32 *map = NULL;
++ u32 val;
++
++ for (i = 0; i < priv->n_links; i++) {
++ map = of_prop_next_u32(prop, map, &val);
++ if (!map)
++ break;
++ if (val >= 4)
++ return -EINVAL;
++ priv->link[i]->out_vc = val;
++ }
++ }
++
++ dev_dbg(&client->dev, "Link# | MIPI rate | Map | VC\n");
++ for (i = 0; i < priv->n_links; i++)
++ dev_dbg(&client->dev, "%5d | %9d | %3d | %2d\n", i, priv->csi_rate[i], priv->link[i]->out_mipi, priv->link[i]->out_vc);
++
++ return 0;
++}
++
++static int max96712_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct max96712_priv *priv;
++ struct gpio_desc *pwdn_gpio;
++ int ret, i;
++ int val = 0;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->regmap = devm_regmap_init_i2c(client, &max96712_regmap[0]);
++ if (IS_ERR(priv->regmap))
++ return PTR_ERR(priv->regmap);
++
++ i2c_set_clientdata(client, priv);
++ priv->client = client;
++ atomic_set(&priv->use_count, 0);
++
++ priv->ref_clk = v4l2_clk_get(&client->dev, "ref_clk");
++ if (!IS_ERR(priv->ref_clk)) {
++ dev_info(&client->dev, "ref_clk = %luKHz", v4l2_clk_get_rate(priv->ref_clk) / 1000);
++ v4l2_clk_enable(priv->ref_clk);
++ }
++
++ pwdn_gpio = devm_gpiod_get_optional(&client->dev, "shutdown", GPIOD_OUT_HIGH);
++ if (!IS_ERR(pwdn_gpio)) {
++ udelay(5);
++ gpiod_set_value_cansleep(pwdn_gpio, 0);
++ usleep_range(3000, 5000);
++ }
++
++ des_read(MAX96712_DEV_ID, &val);
++ if (val != MAX96712_ID)
++ return -ENODEV;
++
++ for (i = 0; i < MAX96712_MAX_LINKS; i++) {
++ priv->link[i] = devm_kzalloc(&client->dev, sizeof(*priv->link[i]), GFP_KERNEL);
++ if (!priv->link[i])
++ return -ENOMEM;
++ }
++
++ ret = max96712_parse_dt(client);
++ if (ret)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ char poc_name[10];
++
++ sprintf(poc_name, "poc%d", i);
++ priv->link[i]->poc_reg = devm_regulator_get(&client->dev, poc_name);
++ if (PTR_ERR(priv->link[i]->poc_reg) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ }
++
++ for (i = 0; i < priv->n_links; i++) {
++ priv->link[i]->client = i2c_new_dummy(client->adapter, priv->link[i]->ser_addr);
++ if (!priv->link[i]->client)
++ return -ENOMEM;
++
++ priv->link[i]->regmap = regmap_init_i2c(priv->link[i]->client, &max96712_regmap[priv->gmsl_mode]);
++ if (IS_ERR(priv->link[i]->regmap))
++ return PTR_ERR(priv->link[i]->regmap);
++ }
++
++ ret = max96712_i2c_mux_init(priv);
++ if (ret) {
++ dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
++ goto out;
++ }
++
++ ret = max96712_initialize(priv);
++ if (ret < 0)
++ goto out;
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_subdev_init(&priv->link[i]->sd, &max96712_subdev_ops);
++ priv->link[i]->sd.owner = client->dev.driver->owner;
++ priv->link[i]->sd.dev = &client->dev;
++ priv->link[i]->sd.grp_id = i;
++ v4l2_set_subdevdata(&priv->link[i]->sd, priv);
++ priv->link[i]->sd.fwnode = priv->link[i]->sd_fwnode;
++
++ snprintf(priv->link[i]->sd.name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x",
++ client->dev.driver->name, i, i2c_adapter_id(client->adapter),
++ client->addr);
++
++ ret = v4l2_async_register_subdev(&priv->link[i]->sd);
++ if (ret < 0)
++ goto out;
++ }
++
++ priv->reboot_nb.notifier_call = max96712_reboot_notifier;
++ ret = register_reboot_notifier(&priv->reboot_nb);
++ if (ret) {
++ dev_err(&client->dev, "failed to register reboot notifier\n");
++ goto out;
++ }
++
++ //max96712_debug_add(priv);
++out:
++ return ret;
++}
++
++static int max96712_remove(struct i2c_client *client)
++{
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i;
++
++ //max96712_debug_remove(priv);
++ i2c_mux_del_adapters(priv->mux);
++ unregister_reboot_notifier(&priv->reboot_nb);
++
++ for (i = 0; i < priv->n_links; i++) {
++ v4l2_async_unregister_subdev(&priv->link[i]->sd);
++ v4l2_device_unregister_subdev(&priv->link[i]->sd);
++ if (!IS_ERR(priv->link[i]->poc_reg))
++ regulator_disable(priv->link[i]->poc_reg); /* POC power off */
++ }
++
++ return 0;
++}
++
++static const struct i2c_device_id max96712_id[] = {
++ { "max96712", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, max96712_id);
++
++static struct i2c_driver max96712_i2c_driver = {
++ .driver = {
++ .name = "max96712",
++ .of_match_table = of_match_ptr(max96712_dt_ids),
++ },
++ .probe = max96712_probe,
++ .remove = max96712_remove,
++ .id_table = max96712_id,
++};
++
++module_i2c_driver(max96712_i2c_driver);
++
++MODULE_DESCRIPTION("GMSL2 driver for MAX96712");
++MODULE_AUTHOR("Andrey Gusakov, Vladimir Barinov");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712.h b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+new file mode 100644
+index 0000000..2976027
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712.h
+@@ -0,0 +1,263 @@
++/*
++ * MAXIM max96712 GMSL2 driver header
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#define MAX96712_MAX_LINKS 4
++#define MAX96712_MAX_PIPES 8
++#define MAX96712_MAX_PIPE_MAPS 16
++#define MAX96712_MAX_MIPI 4
++
++struct max96712_link {
++ struct v4l2_subdev sd;
++ struct fwnode_handle *sd_fwnode;
++ struct i2c_client *client;
++ struct regmap *regmap;
++ int ser_id;
++ int ser_addr;
++ int pipes_mask; /* mask of pipes used by this link */
++ int out_mipi; /* MIPI# */
++ int out_vc; /* VC# */
++ struct regulator *poc_reg; /* PoC power supply */
++};
++
++struct max96712_priv {
++ struct i2c_client *client;
++ struct regmap *regmap;
++ struct i2c_mux_core *mux;
++ int n_links;
++ int links_mask;
++ enum gmsl_mode gmsl_mode;
++ struct max96712_link *link[MAX96712_MAX_LINKS];
++ int gpio_resetb;
++ int active_low_resetb;
++ bool pclk_rising_edge;
++ bool is_coax;
++ int him;
++ int bws;
++ int dbl;
++ int hibw;
++ int hven;
++ int hsync;
++ int vsync;
++ int dt;
++ u64 crossbar;
++ char cb[16];
++ const char *mbus;
++ int gpio[11];
++ int timeout;
++ int poc_delay;
++ struct v4l2_clk *ref_clk;
++ int csi_rate[MAX96712_MAX_MIPI];
++ int fsync_period;
++ atomic_t use_count;
++ struct notifier_block reboot_nb;
++};
++
++#define MAX96712_REG4 0x04
++#define MAX96712_REG5 0x05
++#define MAX96712_REG6 0x06
++#define MAX96712_REG14 0x0e
++#define MAX96712_REG26 0x10
++#define MAX96712_REG27 0x11
++
++#define MAX96712_CTRL0 0x17
++#define MAX96712_CTRL1 0x18
++#define MAX96712_CTRL2 0x19
++#define MAX96712_CTRL3 0x1a
++#define MAX96712_CTRL11 0x22
++#define MAX96712_CTRL12 0x0a
++#define MAX96712_CTRL13 0x0b
++#define MAX96712_CTRL14 0x0c
++
++#define MAX96712_PWR1 0x13
++
++#define MAX96712_DEV_ID 0x4a
++#define MAX96712_REV 0x4c
++
++#define MAX96712_VIDEO_PIPE_SEL(n) (0xf0 + n)
++#define MAX96712_VIDEO_PIPE_EN 0xf4
++
++#define MAX96712_I2C_0(n) (0x640 + (0x10 * n))
++#define MAX96712_I2C_1(n) (0x641 + (0x10 * n))
++
++#define MAX96712_RX0(n) (0x50 + n)
++
++#define MAX_VIDEO_RX_BASE(n) (n < 5 ? (0x100 + (0x12 * n)) : \
++ (0x160 + (0x12 * (n - 5))))
++#define MAX_VIDEO_RX0(n) (MAX_VIDEO_RX_BASE(n) + 0x00)
++#define MAX_VIDEO_RX3(n) (MAX_VIDEO_RX_BASE(n) + 0x03)
++#define MAX_VIDEO_RX8(n) (MAX_VIDEO_RX_BASE(n) + 0x08)
++#define MAX_VIDEO_RX10(n) (MAX_VIDEO_RX_BASE(n) + 0x0a)
++
++#define MAX_VPRBS(n) (0x1dc + (0x20 * n))
++
++#define MAX_CROSS_BASE(n) (0x1c0 + (0x20 * n))
++#define MAX_CROSS(n, m) (MAX_CROSS_BASE(n) + m)
++
++#define MAX_BACKTOP_BASE(bank) (0x400 + (0x20 * bank))
++#define MAX_BACKTOP1(bank) (MAX_BACKTOP_BASE(bank) + 0x00)
++#define MAX_BACKTOP11(bank) (MAX_BACKTOP_BASE(bank) + 0x0a)
++#define MAX_BACKTOP12(bank) (MAX_BACKTOP_BASE(bank) + 0x0b)
++#define MAX_BACKTOP13(bank) (MAX_BACKTOP_BASE(bank) + 0x0c)
++#define MAX_BACKTOP14(bank) (MAX_BACKTOP_BASE(bank) + 0x0d)
++#define MAX_BACKTOP15(bank) (MAX_BACKTOP_BASE(bank) + 0x0e)
++#define MAX_BACKTOP16(bank) (MAX_BACKTOP_BASE(bank) + 0x0f)
++#define MAX_BACKTOP17(bank) (MAX_BACKTOP_BASE(bank) + 0x10)
++#define MAX_BACKTOP18(bank) (MAX_BACKTOP_BASE(bank) + 0x11)
++#define MAX_BACKTOP19(bank) (MAX_BACKTOP_BASE(bank) + 0x12)
++#define MAX_BACKTOP20(bank) (MAX_BACKTOP_BASE(bank) + 0x13)
++#define MAX_BACKTOP21(bank) (MAX_BACKTOP_BASE(bank) + 0x14)
++#define MAX_BACKTOP22(bank) (MAX_BACKTOP_BASE(bank) + 0x15)
++#define MAX_BACKTOP23(bank) (MAX_BACKTOP_BASE(bank) + 0x16)
++#define MAX_BACKTOP24(bank) (MAX_BACKTOP_BASE(bank) + 0x17)
++#define MAX_BACKTOP25(bank) (MAX_BACKTOP_BASE(bank) + 0x18)
++#define MAX_BACKTOP26(bank) (MAX_BACKTOP_BASE(bank) + 0x19)
++#define MAX_BACKTOP27(bank) (MAX_BACKTOP_BASE(bank) + 0x1a)
++#define MAX_BACKTOP28(bank) (MAX_BACKTOP_BASE(bank) + 0x1b)
++#define MAX_BACKTOP29(bank) (MAX_BACKTOP_BASE(bank) + 0x1c)
++#define MAX_BACKTOP30(bank) (MAX_BACKTOP_BASE(bank) + 0x1d)
++#define MAX_BACKTOP31(bank) (MAX_BACKTOP_BASE(bank) + 0x1e)
++#define MAX_BACKTOP32(bank) (MAX_BACKTOP_BASE(bank) + 0x1f)
++
++#define MAX96712_FSYNC_0 0x4a0
++#define MAX96712_FSYNC_5 0x4a5
++#define MAX96712_FSYNC_6 0x4a6
++#define MAX96712_FSYNC_7 0x4a7
++#define MAX96712_FSYNC_8 0x4a8
++#define MAX96712_FSYNC_9 0x4a9
++#define MAX96712_FSYNC_10 0x4aa
++#define MAX96712_FSYNC_11 0x4ab
++#define MAX96712_FSYNC_15 0x4af
++
++#define MAX_MIPI_PHY_BASE 0x8a0
++#define MAX_MIPI_PHY0 (MAX_MIPI_PHY_BASE + 0x00)
++#define MAX_MIPI_PHY2 (MAX_MIPI_PHY_BASE + 0x02)
++#define MAX_MIPI_PHY3 (MAX_MIPI_PHY_BASE + 0x03)
++#define MAX_MIPI_PHY4 (MAX_MIPI_PHY_BASE + 0x04)
++#define MAX_MIPI_PHY5 (MAX_MIPI_PHY_BASE + 0x05)
++#define MAX_MIPI_PHY6 (MAX_MIPI_PHY_BASE + 0x06)
++#define MAX_MIPI_PHY8 (MAX_MIPI_PHY_BASE + 0x08)
++#define MAX_MIPI_PHY9 (MAX_MIPI_PHY_BASE + 0x09)
++#define MAX_MIPI_PHY10 (MAX_MIPI_PHY_BASE + 0x0a)
++#define MAX_MIPI_PHY11 (MAX_MIPI_PHY_BASE + 0x0b)
++#define MAX_MIPI_PHY13 (MAX_MIPI_PHY_BASE + 0x0d)
++#define MAX_MIPI_PHY14 (MAX_MIPI_PHY_BASE + 0x0e)
++
++#define MAX_MIPI_TX_BASE(n) (0x900 + 0x40 * n)
++#define MAX_MIPI_TX2(n) (MAX_MIPI_TX_BASE(n) + 0x02)
++#define MAX_MIPI_TX10(n) (MAX_MIPI_TX_BASE(n) + 0x0a)
++#define MAX_MIPI_TX11(n) (MAX_MIPI_TX_BASE(n) + 0x0b)
++#define MAX_MIPI_TX12(n) (MAX_MIPI_TX_BASE(n) + 0x0c)
++
++/* 16 pairs of source-dest registers */
++#define MAX_MIPI_MAP_SRC(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0d + (2 * n))
++#define MAX_MIPI_MAP_DST(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x0e + (2 * n))
++/* Phy dst. Each reg contains 4 dest */
++#define MAX_MIPI_MAP_DST_PHY(pipe, n) (MAX_MIPI_TX_BASE(pipe) + 0x2d + n)
++
++#define MAX_GMSL1_2(ch) (0xb02 + (0x100 * ch))
++#define MAX_GMSL1_4(ch) (0xb04 + (0x100 * ch))
++#define MAX_GMSL1_6(ch) (0xb06 + (0x100 * ch))
++#define MAX_GMSL1_7(ch) (0xb07 + (0x100 * ch))
++#define MAX_GMSL1_8(ch) (0xb08 + (0x100 * ch))
++#define MAX_GMSL1_D(ch) (0xb0d + (0x100 * ch))
++#define MAX_GMSL1_F(ch) (0xb0f + (0x100 * ch))
++#define MAX_GMSL1_19(ch) (0xb19 + (0x100 * ch))
++#define MAX_GMSL1_1B(ch) (0xb1b + (0x100 * ch))
++#define MAX_GMSL1_1D(ch) (0xb1d + (0x100 * ch))
++#define MAX_GMSL1_20(ch) (0xb20 + (0x100 * ch))
++#define MAX_GMSL1_96(ch) (0xb96 + (0x100 * ch))
++#define MAX_GMSL1_CA(ch) (0xbca + (0x100 * ch))
++#define MAX_GMSL1_CB(ch) (0xbcb + (0x100 * ch))
++
++#define MAX_RLMS4(ch) (0x1404 + (0x100 * ch))
++#define MAX_RLMSA(ch) (0x140A + (0x100 * ch))
++#define MAX_RLMSB(ch) (0x140B + (0x100 * ch))
++#define MAX_RLMSA4(ch) (0x14a4 + (0x100 * ch))
++
++#define MAX_RLMS58(ch) (0x1458 + (0x100 * ch))
++#define MAX_RLMS59(ch) (0x1459 + (0x100 * ch))
++#define MAX_RLMS95(ch) (0x1495 + (0x100 * ch))
++#define MAX_RLMSC4(ch) (0x14c4 + (0x100 * ch))
++#define MAX_RLMSC5(ch) (0x14c5 + (0x100 * ch))
++
++static inline int max96712_write(struct max96712_priv *priv, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_read(struct max96712_priv *priv, int reg, int *val)
++{
++ int ret;
++
++ ret = regmap_read(priv->regmap, reg, val);
++ if (ret)
++ dev_dbg(&priv->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_update_bits(struct max96712_priv *priv, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(priv->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&priv->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define des_read(reg, val) max96712_read(priv, reg, val)
++#define des_write(reg, val) max96712_write(priv, reg, val)
++#define des_update_bits(reg, mask, bits) max96712_update_bits(priv, reg, mask, bits)
++
++static inline int max96712_ser_write(struct max96712_link *link, int reg, int val)
++{
++ int ret;
++
++ ret = regmap_write(link->regmap, reg, val);
++ if (ret < 0)
++ dev_dbg(&link->client->dev, "write register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_ser_read(struct max96712_link *link, int reg, u8 *val)
++{
++ int ret;
++
++ ret = regmap_read(link->regmap, reg, (int *)val);
++ if (ret)
++ dev_dbg(&link->client->dev, "read register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++static inline int max96712_ser_update_bits(struct max96712_link *link, int reg, int mask, int bits)
++{
++ int ret;
++
++ ret = regmap_update_bits(link->regmap, reg, mask, bits);
++ if (ret)
++ dev_dbg(&link->client->dev, "update register 0x%04x failed (%d)\n", reg, ret);
++
++ return ret;
++}
++
++#define ser_read(reg, val) max96712_ser_read(link, reg, val)
++#define ser_write(reg, val) max96712_ser_write(link, reg, val)
++#define ser_update_bits(reg, mask, bits) max96712_ser_update_bits(link, reg, mask, bits)
+diff --git a/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+new file mode 100644
+index 0000000..ee47c04
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/gmsl/max96712_debug.h
+@@ -0,0 +1,362 @@
++/*
++ * MAXIM max96712 GMSL2 driver debug stuff
++ *
++ * Copyright (C) 2019-2020 Cogent Embedded, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++static char *pipe_names[4] = {
++ "X", "Y", "Z", "U"
++};
++
++static int max96712_gmsl1_get_link_lock(struct max96712_priv *priv, int link_n);
++static int max96712_gmsl2_get_link_lock(struct max96712_priv *priv, int link_n);
++
++#define reg_bits(x, y) ((reg >> (x)) & ((1 << (y)) - 1))
++
++static ssize_t max_link_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i = -1;
++ int j;
++ int gmsl2;
++ u32 crc = 0 ;
++ char *_buf = buf;
++ int reg = 0;
++
++ if (!sscanf(attr->attr.name, "link_%d", &i))
++ return -EINVAL;
++
++ if (i < 0)
++ return -EINVAL;
++
++ if (i >= priv->n_links) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ buf += sprintf(buf, "Link %c status\n", 'A' + i);
++
++ des_read(MAX96712_REG6, &reg);
++ gmsl2 = !!(reg & BIT(4 + i));
++ buf += sprintf(buf, "Link mode: %s\n", gmsl2 ? "GMSL2" : "GMSL1");
++
++ if (gmsl2) {
++ buf += sprintf(buf, "GMSL2 Link lock: %d\n", max96712_gmsl2_get_link_lock(priv, i));
++ } else {
++ reg = max96712_gmsl1_get_link_lock(priv, i);
++ buf += sprintf(buf,
++ "GMSL1_CB: 0x%02x:\t"
++ "LOCKED_G1: %d\n",
++ reg, reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_CA(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_CA: 0x%02x:\t"
++ "PHASELOCK: %d, WBLOCK_G1: %d, DATAOK: %d\n",
++ reg, reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ des_read(MAX_GMSL1_1B(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1B: 0x%02x:\t"
++ "LINE_CRC_ERR: %d ",
++ reg, reg_bits(2, 1));
++ for (j = 0; j < 4; j++) {
++ des_read(MAX_GMSL1_20(i) + j, &reg);
++ crc = crc | ((reg & 0xff) << (j * 8));
++ }
++ buf += sprintf(buf, "last crc 0x%08x\n", crc);
++
++ des_read(MAX_GMSL1_19(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_19: CC_CRC_ERRCNT %d\n",
++ reg);
++
++ des_read(MAX_GMSL1_1D(i), &reg);
++ buf += sprintf(buf,
++ "GMSL1_1D: 0x%02x:\t"
++ "UNDERBOOST: %d, AEQ-BST: %d\n",
++ reg, reg_bits(4, 1), reg_bits(0, 4));
++ }
++
++ return (buf - _buf);
++}
++
++static ssize_t max_pipe_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ char *_buf = buf;
++ int pipe = 0;
++ int map;
++ int maps_en = 0;
++ int pipes_en;
++ int reg = 0;
++ int shift;
++
++ if (!sscanf(attr->attr.name, "pipe_%d", &pipe))
++ return -EINVAL;
++
++ if (pipe < 0)
++ return -EINVAL;
++
++ if (pipe >= MAX96712_MAX_PIPES) {
++ buf += sprintf(buf, "\n");
++ return (buf - _buf);
++ }
++
++ des_read(MAX96712_VIDEO_PIPE_EN, &pipes_en);
++
++ buf += sprintf(buf, "Video Pipe %d %s\n",
++ pipe, (pipes_en & BIT(pipe)) ? "ENABLED" : "disabled");
++ if (!(pipes_en & BIT(pipe)))
++ goto out;
++
++ des_read(MAX_VPRBS(pipe), &reg);
++ /* bit 5 is not valid for MAX96712 */
++ buf += sprintf(buf,
++ "\tVPRBS: 0x%02x\t"
++ "VPRBS_FAIL: %d,"
++ "VIDEO_LOCK: %d\n",
++ reg,
++ reg_bits(5, 1), reg_bits(0, 1));
++
++ /* show source */
++ shift = (pipe % 2) * 4;
++ des_read(MAX96712_VIDEO_PIPE_SEL(pipe / 2), &reg);
++ buf += sprintf(buf, "SRC: PHY %c, PIPE %s\n",
++ 'A' + (char)((reg >> (shift + 2)) & 0x03),
++ pipe_names[(reg >> shift) & 0x03]);
++
++ /* show maps */
++ des_read(MAX_MIPI_TX11(pipe), &maps_en);
++ des_read(MAX_MIPI_TX12(pipe), &reg);
++ maps_en |= reg << 8;
++
++ for (map = 0; map < MAX96712_MAX_PIPE_MAPS; map++) {
++ int src, dst, mipi;
++ if (!(maps_en & BIT(map)))
++ continue;
++
++ des_read(MAX_MIPI_MAP_SRC(pipe, map), &src);
++ des_read(MAX_MIPI_MAP_DST(pipe, map), &dst);
++ des_read(MAX_MIPI_MAP_DST_PHY(pipe, map / 4), &mipi);
++
++ buf += sprintf(buf, " MAP%d: DT %02x, VC %d -> DT %02x, VC %d MIPI %d\n",
++ map,
++ src & 0x3f, (src >> 6) & 0x03, dst & 0x3f, (dst >> 6) & 0x03,
++ (mipi >> ((map % 4) * 2)) & 0x03);
++ }
++
++ des_read(MAX_VIDEO_RX0(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX0: 0x%02x\t"
++ "LCRC_ERR: %d, "
++ "LINE_CRC_SEL: %d, "
++ "LINE_CRC_EN: %d, "
++ "DIS_PKT_DET: %d\n",
++ reg,
++ reg_bits(7, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX3(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX3: 0x%02x\t"
++ "HD_TR_MODE: %d, "
++ "DLOCKED: %d, "
++ "VLOCKED: %d, "
++ "HLOCKED: %d, "
++ "DTRACKEN: %d, "
++ "VTRACKEN: %d, "
++ "HTRACKEN: %d\n",
++ reg,
++ reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1), reg_bits(3, 1),
++ reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++ des_read(MAX_VIDEO_RX8(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX8: 0x%02x\t"
++ "VID_BLK_LEN_ERR: %d, "
++ "VID_LOCK: %d, "
++ "VID_PKT_DET: %d, "
++ "VID_SEQ_ERR: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1),
++ reg_bits(5, 1), reg_bits(4, 1));
++ des_read(MAX_VIDEO_RX10(pipe), &reg);
++ buf += sprintf(buf,
++ "VIDEO_RX10: 0x%02x\t"
++ "MASK_VIDEO_DE: %d\n",
++ reg,
++ reg_bits(6, 1));
++
++out:
++ return (buf - _buf);
++}
++
++static ssize_t max_stat_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct max96712_priv *priv = i2c_get_clientdata(client);
++ int i;
++ char *_buf = buf;
++ int reg = 0;
++
++ /* TODO: add same for 96712 */
++ des_read(MAX96712_REG4, &reg);
++ buf += sprintf(buf,
++ "REG_REG4: 0x%02x\t"
++ "LOCK_CFG: %d\n",
++ reg, reg_bits(5, 1));
++
++ des_read(MAX_BACKTOP1(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP1: 0x%02x:\t"
++ "CSIPLL3_LOCK: %d, "
++ "CSIPLL2_LOCK: %d, "
++ "CSIPLL1_LOCK: %d, "
++ "CSIPLL0_LOCK: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1));
++
++ des_read(MAX_BACKTOP11(0), &reg);
++ buf += sprintf(buf,
++ "BACKTOP11: 0x%02x:\t"
++ "CMD_OWERFLOW4: %d, "
++ "CMD_OWERFLOW3: %d, "
++ "CMD_OWERFLOW2: %d, "
++ "CMD_OWERFLOW1: %d, "
++ "LMO_3: %d, "
++ "LMO_2: %d, "
++ "LMO_1: %d, "
++ "LMO_0: %d\n",
++ reg,
++ reg_bits(7, 1), reg_bits(6, 1), reg_bits(5, 1), reg_bits(4, 1),
++ reg_bits(3, 1), reg_bits(2, 1), reg_bits(1, 1), reg_bits(0, 1));
++
++ for (i = 0; i < MAX96712_MAX_MIPI; i++) {
++ buf += sprintf(buf, "MIPI %d\n", i);
++ des_read(MAX_MIPI_TX2(i), &reg);
++ buf += sprintf(buf,
++ "\tMIPI_TX2: 0x%02x\n",
++ reg);
++ }
++
++ return (buf - _buf);
++}
++
++static DEVICE_ATTR(link_0, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_1, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_2, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(link_3, S_IRUGO, max_link_show, NULL);
++static DEVICE_ATTR(pipe_0, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_1, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_2, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_3, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_4, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_5, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_6, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(pipe_7, S_IRUGO, max_pipe_show, NULL);
++static DEVICE_ATTR(stat, S_IRUGO, max_stat_show, NULL);
++
++static struct attribute *max96712_attributes[] = {
++ &dev_attr_link_0.attr,
++ &dev_attr_link_1.attr,
++ &dev_attr_link_2.attr,
++ &dev_attr_link_3.attr,
++ &dev_attr_pipe_0.attr,
++ &dev_attr_pipe_1.attr,
++ &dev_attr_pipe_2.attr,
++ &dev_attr_pipe_3.attr,
++ &dev_attr_pipe_4.attr,
++ &dev_attr_pipe_5.attr,
++ &dev_attr_pipe_6.attr,
++ &dev_attr_pipe_7.attr,
++ &dev_attr_stat.attr,
++ NULL
++};
++
++static const struct attribute_group max96712_group = {
++ .attrs = max96712_attributes,
++};
++
++int max96712_debug_add(struct max96712_priv *priv)
++{
++ int ret;
++
++ ret = sysfs_create_group(&priv->client->dev.kobj, &max96712_group);
++ if (ret < 0) {
++ dev_err(&priv->client->dev, "Sysfs registration failed\n");
++ return ret;
++ }
++
++ return ret;
++}
++
++void max96712_debug_remove(struct max96712_priv *priv)
++{
++ sysfs_remove_group(&priv->client->dev.kobj, &max96712_group);
++}
++
++#if 0
++int max96712_patgen(struct max96712_priv *priv)
++{
++ int ret = 0;
++
++ const u32 xres = 1280;
++ const u32 yres = 800;
++ const u32 hbp = 128;
++ const u32 hfp = 80;
++ const u32 hsa = 32;
++ const u32 vbp = 17;
++ const u32 vfp = 4;
++ const u32 vsa = 3;
++
++ u32 vtotal = vfp + vsa + vbp + yres;
++ u32 htotal = xres + hfp + hbp + hsa;
++ u32 vs_high = vsa * htotal;
++ u32 vs_low = (vfp + yres + vbp) * htotal;
++ u32 v2h = (vsa + vbp) * htotal + hfp;
++ u32 hs_high = hsa;
++ u32 hs_low = xres + hfp + hbp;
++ u32 v2d = v2h + hsa + hbp;
++ u32 de_high = xres;
++ u32 de_low = hfp + hsa + hbp;
++ u32 de_cnt = yres;
++
++ /* DEBUG_EXTRA & PATGEN_CLK_SRC = 75Mhz pclk */
++ des_write(0x0009, 0x01); /* if DEBUG_EXTRA[1:0] = 2b01, PCLK Frequency is 75MHz (don't care PATGEN_CLK_SRC) */
++ des_write(0x01dc, 0x00);
++
++ des_write_n(0x1052, 3, 0); /* vs delay */
++ des_write_n(0x1055, 3, vs_high);
++ des_write_n(0x1058, 3, vs_low);
++ des_write_n(0x105B, 3, v2h);
++ des_write_n(0x105E, 2, hs_high);
++ des_write_n(0x1060, 2, hs_low);
++ des_write_n(0x1062, 2, vtotal); /* hs cnt */
++ des_write_n(0x1064, 3, v2d);
++ des_write_n(0x1067, 2, de_high);
++ des_write_n(0x1069, 2, de_low);
++ des_write_n(0x106B, 2, de_cnt);
++
++ des_write_n(0x106E, 3, 0xff0000); /* color A */
++ des_write_n(0x1071, 3, 0x0000ff); /* color B */
++
++ des_write(0x1074, 0x50); /* chkr_rpt_a = 80 */
++ des_write(0x1075, 0x50); /* chkr_rpt_b = 80 */
++ des_write(0x1076, 0x50); /* chkr_alt = 80 */
++
++ des_write(0x1050, 0xfb); /* gen_vs,gen_hs,gen_de, vtg[0:1] */
++ des_write(0x1051, 0x10); /* patgen_mode[5:4] = 0b1,checkerboard */
++
++out:
++ return ret;
++}
++#endif
+--
+2.7.4
+