{"id":2220300,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2220300/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260406-gmsl2-3_serdes-v10-16-645560fedca5@analog.com/","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.1/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260406-gmsl2-3_serdes-v10-16-645560fedca5@analog.com>","date":"2026-04-06T20:14:55","name":"[v10,16/22] media: i2c: maxim-serdes: add MAX96717 driver","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"053fc8d6dafcecae49d7c0e4e09e0771edf8e21b","submitter":{"id":88270,"url":"http://patchwork.ozlabs.org/api/1.1/people/88270/?format=json","name":"Dumitru Ceclan via B4 Relay","email":"devnull+dumitru.ceclan.analog.com@kernel.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260406-gmsl2-3_serdes-v10-16-645560fedca5@analog.com/mbox/","series":[{"id":498894,"url":"http://patchwork.ozlabs.org/api/1.1/series/498894/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/list/?series=498894","date":"2026-04-06T20:14:42","name":"media: i2c: add Maxim GMSL2/3 serializer and deserializer drivers","version":10,"mbox":"http://patchwork.ozlabs.org/series/498894/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2220300/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2220300/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-34738-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=Yg7rXydV;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-gpio+bounces-34738-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"Yg7rXydV\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fqLLB0bHxz1yFt\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 07 Apr 2026 06:20:34 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 1100730532E5\n\tfor <incoming@patchwork.ozlabs.org>; Mon,  6 Apr 2026 20:16:17 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id BFBFE3A3E63;\n\tMon,  6 Apr 2026 20:15:23 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B87C39FCD0;\n\tMon,  6 Apr 2026 20:15:22 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPS id 70A65C2BCB2;\n\tMon,  6 Apr 2026 20:15:22 +0000 (UTC)","from aws-us-west-2-korg-lkml-1.web.codeaurora.org\n (localhost.localdomain [127.0.0.1])\n\tby smtp.lore.kernel.org (Postfix) with ESMTP id 68ED1FB5160;\n\tMon,  6 Apr 2026 20:15:22 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775506522; cv=none;\n b=FltiSrJVmommoeCc7XoOXPJsCYUxO8vWd1sNAWYuQnHmXM2sRrjulPjlqZMkAOhOi3wFrDaAXTJILj5Y2jIk07n8l2Ei3jZN7NTX0qKPMlrkS8Y8k+GIrnZUBLcDwI1U1FVDWRz5Cw3i5QKNk176TRSxbWsA5tPqM/WNNBgG0lg=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775506522; c=relaxed/simple;\n\tbh=g89EghnraR9cK8RQ6hmyUaQJ9xQxZVePYGJ8xO+sBhY=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=k1ZbbifGsXhdYULNHbbtxP2jh7p6VaiBoDCEQQbJYq85PNu7cKPVk4FHsCR0F7v5CA5/ktM+R4SJe/F+PRIVTF6rsh49A2o06UfA/puqlNoNM0IzRQTY2kpboH1g/iz+1ndYH/8aNr99ToEW6ScajigNhXq2n407w3b1F1GoSr0=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=Yg7rXydV; arc=none smtp.client-ip=10.30.226.201","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1775506522;\n\tbh=g89EghnraR9cK8RQ6hmyUaQJ9xQxZVePYGJ8xO+sBhY=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From;\n\tb=Yg7rXydVc/o8Bp6eItzV01zdT7i9QOw6SFn5Ia2sESQrv+5S0rbT080KYFpcb1TLF\n\t 4LucqzsbKS21jCxWIxNTSKsbFsvoqh5f1DGunwcMSVAuwIYxicR86ehuvcd3RqQZlP\n\t UpB6JxWgrPxgACRgFDd8TSuMDAV9mVMXKLAEmJrtEIh646C9xlcwKKTz0mDHJANOCd\n\t H1w0VISycLILmwfaINKViAkpLDXXe/Mi5CMsVoGMIEel5n78t6zPsaXyW6DgdnpV9o\n\t zWyGHNUANv97SDkepMP8kTk4FMeX+A/LCbCUBStGX7YjMnWuOS7k9c04F/h2TdMlx5\n\t 2U/1mPCd97UVw==","From":"Dumitru Ceclan via B4 Relay\n <devnull+dumitru.ceclan.analog.com@kernel.org>","Date":"Mon, 06 Apr 2026 23:14:55 +0300","Subject":"[PATCH v10 16/22] media: i2c: maxim-serdes: add MAX96717 driver","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"7bit","Message-Id":"<20260406-gmsl2-3_serdes-v10-16-645560fedca5@analog.com>","References":"<20260406-gmsl2-3_serdes-v10-0-645560fedca5@analog.com>","In-Reply-To":"<20260406-gmsl2-3_serdes-v10-0-645560fedca5@analog.com>","To":"Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>,\n  Mauro Carvalho Chehab <mchehab@kernel.org>,\n  Sakari Ailus <sakari.ailus@linux.intel.com>,\n  Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n  Julien Massot <julien.massot@collabora.com>, Rob Herring <robh@kernel.org>,\n\t=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>,\n  Greg Kroah-Hartman <gregkh@linuxfoundation.org>,\n  Cosmin Tanislav <cosmin.tanislav@analog.com>","Cc":"mitrutzceclan@gmail.com, linux-media@vger.kernel.org,\n  linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,\n  linux-staging@lists.linux.dev, linux-gpio@vger.kernel.org, =?utf-8?q?Nikla?=\n\t=?utf-8?q?s_S=C3=B6derlund?= <niklas.soderlund+renesas@ragnatech.se>,\n  Martin Hecht <Martin.Hecht@avnet.eu>,\n  Cosmin Tanislav <demonsingur@gmail.com>","X-Mailer":"b4 0.14.3","X-Developer-Signature":"v=1; a=ed25519-sha256; t=1775506518; l=52214;\n i=dumitru.ceclan@analog.com; s=20240313; h=from:subject:message-id;\n bh=3UJ/gP3/e3FWVrbROcScjDTZ9qKVMnnSLW7mFugpvvQ=;\n b=cBgD41ndW3WzMZm1YGk95Ldu0B4VEHh5EL3z1HU1ULJqM6nZ4HW0krcmaMMr64BBqz1KNCwoa\n +2UHXQ/IVGBBz4+lTwQYGy0EbcGDO9kbokgUBM/VRfl4NMUyo63vIWt","X-Developer-Key":"i=dumitru.ceclan@analog.com; a=ed25519;\n pk=HdqMlVyrcazwoiai7oN6ghU+Bj1pusGUFRl30jhS7Bo=","X-Endpoint-Received":"by B4 Relay for dumitru.ceclan@analog.com/20240313\n with auth_id=140","X-Original-From":"Dumitru Ceclan <dumitru.ceclan@analog.com>","Reply-To":"dumitru.ceclan@analog.com"},"content":"From: Cosmin Tanislav <demonsingur@gmail.com>\n\nAdd a new MAX96717 driver that also supports MAX9295A, MAX96717F and\nMAX96793.\n\nIntegrate it with the common serializer framework, while keeping\ncompatibility with existing usecases, avoiding code duplication, and\nalso enabling more features across all chips.\n\nSigned-off-by: Cosmin Tanislav <demonsingur@gmail.com>\n---\n drivers/media/i2c/maxim-serdes/Kconfig    |   18 +\n drivers/media/i2c/maxim-serdes/Makefile   |    1 +\n drivers/media/i2c/maxim-serdes/max96717.c | 1686 +++++++++++++++++++++++++++++\n 3 files changed, 1705 insertions(+)","diff":"diff --git a/drivers/media/i2c/maxim-serdes/Kconfig b/drivers/media/i2c/maxim-serdes/Kconfig\nindex f5a4ca80a263..ddbb5791e934 100644\n--- a/drivers/media/i2c/maxim-serdes/Kconfig\n+++ b/drivers/media/i2c/maxim-serdes/Kconfig\n@@ -15,3 +15,21 @@ config VIDEO_MAXIM_SERDES\n \n \t  To compile this driver as a module, choose M here: the module\n \t  will be called max_serdes.\n+\n+config VIDEO_MAX96717\n+\ttristate \"Maxim MAX96717 Serializer support\"\n+\tdepends on COMMON_CLK\n+\tdepends on I2C\n+\tdepends on PINCTRL\n+\tselect VIDEO_MAXIM_SERDES\n+\tselect GENERIC_PINCONF\n+\tselect GENERIC_PINCTRL_GROUPS\n+\tselect GENERIC_PINMUX_FUNCTIONS\n+\tselect GPIOLIB\n+\thelp\n+\t  This driver supports the Maxim MAX9295A, MAX96717, MAX96717F,\n+\t  MAX96793 Serializers, which receive video on a MIPI CSI-2\n+\t  interface and output it on a GMSL2/3 link.\n+\n+\t  To compile this driver as a module, choose M here: the module\n+\t  will be called max96717.\ndiff --git a/drivers/media/i2c/maxim-serdes/Makefile b/drivers/media/i2c/maxim-serdes/Makefile\nindex b54326a5c81b..04abda6a5437 100644\n--- a/drivers/media/i2c/maxim-serdes/Makefile\n+++ b/drivers/media/i2c/maxim-serdes/Makefile\n@@ -1,3 +1,4 @@\n # SPDX-License-Identifier: GPL-2.0\n max-serdes-objs := max_serdes.o max_ser.o max_des.o\n obj-$(CONFIG_VIDEO_MAXIM_SERDES) += max-serdes.o\n+obj-$(CONFIG_VIDEO_MAX96717) += max96717.o\ndiff --git a/drivers/media/i2c/maxim-serdes/max96717.c b/drivers/media/i2c/maxim-serdes/max96717.c\nnew file mode 100644\nindex 000000000000..a23aa2784713\n--- /dev/null\n+++ b/drivers/media/i2c/maxim-serdes/max96717.c\n@@ -0,0 +1,1686 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Maxim MAX96717 GMSL2 Serializer Driver\n+ *\n+ * Copyright (C) 2025 Analog Devices Inc.\n+ */\n+\n+#include <linux/bitfield.h>\n+#include <linux/clk.h>\n+#include <linux/clk-provider.h>\n+#include <linux/gpio/driver.h>\n+#include <linux/iopoll.h>\n+#include <linux/pinctrl/pinctrl.h>\n+#include <linux/pinctrl/pinmux.h>\n+#include <linux/pinctrl/pinconf.h>\n+#include <linux/pinctrl/pinconf-generic.h>\n+#include <linux/regmap.h>\n+\n+#include \"max_ser.h\"\n+\n+#define MAX96717_REG0\t\t\t\t0x0\n+\n+#define MAX96717_REG2\t\t\t\t0x2\n+#define MAX96717_REG2_VID_TX_EN_P(p)\t\tBIT(4 + (p))\n+\n+#define MAX96717_REG3\t\t\t\t0x3\n+#define MAX96717_REG3_RCLKSEL\t\t\tGENMASK(1, 0)\n+#define MAX96717_REG3_RCLK_ALT\t\t\tBIT(2)\n+\n+#define MAX96717_REG6\t\t\t\t0x6\n+#define MAX96717_REG6_RCLKEN\t\t\tBIT(5)\n+\n+#define MAX96717_I2C_2(x)\t\t\t(0x42 + (x) * 0x2)\n+#define MAX96717_I2C_2_SRC\t\t\tGENMASK(7, 1)\n+\n+#define MAX96717_I2C_3(x)\t\t\t(0x43 + (x) * 0x2)\n+#define MAX96717_I2C_3_DST\t\t\tGENMASK(7, 1)\n+\n+#define MAX96717_TX3(p)\t\t\t\t(0x53 + (p) * 0x4)\n+#define MAX96717_TX3_TX_STR_SEL\t\t\tGENMASK(1, 0)\n+\n+#define MAX96717_VIDEO_TX0(p)\t\t\t(0x100 + (p) * 0x8)\n+#define MAX96717_VIDEO_TX0_AUTO_BPP\t\tBIT(3)\n+\n+#define MAX96717_VIDEO_TX1(p)\t\t\t(0x101 + (p) * 0x8)\n+#define MAX96717_VIDEO_TX1_BPP\t\t\tGENMASK(5, 0)\n+\n+#define MAX96717_VIDEO_TX2(p)\t\t\t(0x102 + (p) * 0x8)\n+#define MAX96717_VIDEO_TX2_PCLKDET\t\tBIT(7)\n+#define MAX96717_VIDEO_TX2_DRIFT_DET_EN\t\tBIT(1)\n+\n+#define MAX96717_VTX0(p)\t\t\t(0x1c8 + (p) * 0x43)\n+#define MAX96717_VTX0_VTG_MODE\t\t\tGENMASK(1, 0)\n+#define MAX96717_VTX0_VTG_MODE_FREE_RUNNING\t0b11\n+#define MAX96717_VTX0_DE_INV\t\t\tBIT(2)\n+#define MAX96717_VTX0_HS_INV\t\t\tBIT(3)\n+#define MAX96717_VTX0_VS_INV\t\t\tBIT(4)\n+#define MAX96717_VTX0_GEN_DE\t\t\tBIT(5)\n+#define MAX96717_VTX0_GEN_HS\t\t\tBIT(6)\n+#define MAX96717_VTX0_GEN_VS\t\t\tBIT(7)\n+\n+#define MAX96717_VTX1(p)\t\t\t(0x1c9 + (p) * 0x43)\n+#define MAX96717_VTX1_PATGEN_CLK_SRC\t\tGENMASK(3, 1)\n+#define MAX96717_VTX1_PATGEN_CLK_SRC_25MHZ\t0b100\n+#define MAX96717_VTX1_PATGEN_CLK_SRC_75MHZ\t0b101\n+#define MAX96717_VTX1_PATGEN_CLK_SRC_150MHZ\t0b110\n+#define MAX96717_VTX1_PATGEN_CLK_SRC_375MHZ\t0b111\n+\n+#define MAX96717_VTX2_VS_DLY_2(p)\t\t(0x1ca + (p) * 0x43)\n+#define MAX96717_VTX5_VS_HIGH_2(p)\t\t(0x1cd + (p) * 0x43)\n+#define MAX96717_VTX8_VS_LOW_2(p)\t\t(0x1d0 + (p) * 0x43)\n+#define MAX96717_VTX11_V2H_2(p)\t\t\t(0x1d3 + (p) * 0x43)\n+#define MAX96717_VTX14_HS_HIGH_1(p)\t\t(0x1d6 + (p) * 0x43)\n+#define MAX96717_VTX16_HS_LOW_1(p)\t\t(0x1d8 + (p) * 0x43)\n+#define MAX96717_VTX18_HS_CNT_1(p)\t\t(0x1da + (p) * 0x43)\n+#define MAX96717_VTX20_V2D_2(p)\t\t\t(0x1dc + (p) * 0x43)\n+#define MAX96717_VTX23_DE_HIGH_1(p)\t\t(0x1df + (p) * 0x43)\n+#define MAX96717_VTX25_DE_LOW_1(p)\t\t(0x1e1 + (p) * 0x43)\n+#define MAX96717_VTX27_DE_CNT_1(p)\t\t(0x1e3 + (p) * 0x43)\n+#define MAX96717_VTX29(p)\t\t\t(0x1e5 + (p) * 0x43)\n+\n+#define MAX96717_VTX29_PATGEN_MODE\t\tGENMASK(1, 0)\n+#define MAX96717_VTX29_PATGEN_MODE_DISABLED\t0b00\n+#define MAX96717_VTX29_PATGEN_MODE_CHECKER\t0b01\n+#define MAX96717_VTX29_PATGEN_MODE_GRADIENT\t0b10\n+\n+#define MAX96717_VTX30_GRAD_INCR(p)\t\t(0x1e6 + (p) * 0x43)\n+#define MAX96717_VTX31_CHKR_A_L(p)\t\t(0x1e7 + (p) * 0x43)\n+#define MAX96717_VTX34_CHKR_B_L(p)\t\t(0x1ea + (p) * 0x43)\n+#define MAX96717_VTX37_CHKR_RPT_A(p)\t\t(0x1ed + (p) * 0x43)\n+#define MAX96717_VTX38_CHKR_RPT_B(p)\t\t(0x1ee + (p) * 0x43)\n+#define MAX96717_VTX39_CHKR_ALT(p)\t\t(0x1ef + (p) * 0x43)\n+\n+#define MAX96717_GPIO_A(x)\t\t\t(0x2be + (x) * 0x3)\n+#define MAX96717_GPIO_A_GPIO_OUT_DIS\t\tBIT(0)\n+#define MAX96717_GPIO_A_GPIO_TX_EN\t\tBIT(1)\n+#define MAX96717_GPIO_A_GPIO_RX_EN\t\tBIT(2)\n+#define MAX96717_GPIO_A_GPIO_IN\t\t\tBIT(3)\n+#define MAX96717_GPIO_A_GPIO_OUT\t\tBIT(4)\n+#define MAX96717_GPIO_A_TX_COMP_EN\t\tBIT(5)\n+#define MAX96717_GPIO_A_RES_CFG\t\t\tBIT(7)\n+\n+#define MAX96717_GPIO_B(x)\t\t\t(0x2bf + (x) * 0x3)\n+#define MAX96717_GPIO_B_GPIO_TX_ID\t\tGENMASK(4, 0)\n+#define MAX96717_GPIO_B_OUT_TYPE\t\tBIT(5)\n+#define MAX96717_GPIO_B_PULL_UPDN_SEL\t\tGENMASK(7, 6)\n+#define MAX96717_GPIO_B_PULL_UPDN_SEL_NONE\t0b00\n+#define MAX96717_GPIO_B_PULL_UPDN_SEL_PU\t0b01\n+#define MAX96717_GPIO_B_PULL_UPDN_SEL_PD\t0b10\n+\n+#define MAX96717_GPIO_C(x)\t\t\t(0x2c0 + (x) * 0x3)\n+#define MAX96717_GPIO_C_GPIO_RX_ID\t\tGENMASK(4, 0)\n+\n+#define MAX96717_CMU2\t\t\t\t0x302\n+#define MAX96717_CMU2_PFDDIV_RSHORT\t\tGENMASK(6, 4)\n+#define MAX96717_CMU2_PFDDIV_RSHORT_1_1V\t0b001\n+\n+#define MAX96717_FRONTTOP_0\t\t\t0x308\n+#define MAX96717_FRONTTOP_0_CLK_SEL_P(x)\tBIT(x)\n+#define MAX96717_FRONTTOP_0_START_PORT(x)\tBIT((x) + 4)\n+\n+#define MAX96717_FRONTTOP_1(p)\t\t\t(0x309 + (p) * 0x2)\n+#define MAX96717_FRONTTOP_2(p)\t\t\t(0x30a + (p) * 0x2)\n+\n+#define MAX96717_FRONTTOP_9\t\t\t0x311\n+#define MAX96717_FRONTTOP_9_START_PORT(p, x)\tBIT((p) + (x) * 4)\n+\n+#define MAX96717_FRONTTOP_10\t\t\t0x312\n+#define MAX96717_FRONTTOP_10_BPP8DBL(p)\t\tBIT(p)\n+\n+#define MAX96717_FRONTTOP_11\t\t\t0x313\n+#define MAX96717_FRONTTOP_11_BPP10DBL(p)\tBIT(p)\n+#define MAX96717_FRONTTOP_11_BPP12DBL(p)\tBIT((p) + 4)\n+\n+#define MAX96717_FRONTTOP_12(p, x)\t\t(0x314 + (p) * 0x2 + (x))\n+#define MAX96717_MEM_DT_SEL\t\t\tGENMASK(5, 0)\n+#define MAX96717_MEM_DT_EN\t\t\tBIT(6)\n+\n+#define MAX96717_FRONTTOP_20(p)\t\t\t(0x31c + (p) * 0x1)\n+#define MAX96717_FRONTTOP_20_SOFT_BPP_EN\tBIT(5)\n+#define MAX96717_FRONTTOP_20_SOFT_BPP\t\tGENMASK(4, 0)\n+\n+#define MAX96717_MIPI_RX0\t\t\t0x330\n+#define MAX96717_MIPI_RX0_NONCONTCLK_EN\t\tBIT(6)\n+\n+#define MAX96717_MIPI_RX1\t\t\t0x331\n+#define MAX96717_MIPI_RX1_CTRL_NUM_LANES\tGENMASK(5, 4)\n+\n+#define MAX96717_MIPI_RX2\t\t\t0x332\n+#define MAX96717_MIPI_RX2_PHY1_LANE_MAP\t\tGENMASK(7, 4)\n+\n+#define MAX96717_MIPI_RX3\t\t\t0x333\n+#define MAX96717_MIPI_RX3_PHY2_LANE_MAP\t\tGENMASK(3, 0)\n+\n+#define MAX96717_MIPI_RX4\t\t\t0x334\n+#define MAX96717_MIPI_RX4_PHY1_POL_MAP\t\tGENMASK(5, 4)\n+\n+#define MAX96717_MIPI_RX5\t\t\t0x335\n+#define MAX96717_MIPI_RX5_PHY2_POL_MAP\t\tGENMASK(1, 0)\n+#define MAX96717_MIPI_RX5_PHY2_POL_MAP_CLK\tBIT(2)\n+\n+#define MAX96717_EXTA(x)\t\t\t(0x3dc + (x))\n+\n+#define MAX96717_EXT11\t\t\t\t0x383\n+#define MAX96717_EXT11_TUN_MODE\t\t\tBIT(7)\n+\n+#define MAX96717_EXT21\t\t\t\t0x38d\n+#define MAX96717_EXT22\t\t\t\t0x38e\n+#define MAX96717_EXT23\t\t\t\t0x38f\n+#define MAX96717_EXT24\t\t\t\t0x390\n+\n+#define MAX96717_REF_VTG0\t\t\t0x3f0\n+#define MAX96717_REF_VTG0_REFGEN_EN\t\tBIT(0)\n+#define MAX96717_REF_VTG0_REFGEN_RST\t\tBIT(1)\n+#define MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ_ALT\\\n+\t\t\t\t\t\tBIT(3)\n+#define MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ\tGENMASK(5, 4)\n+\n+#define MAX96717_PIO_SLEW_0\t\t\t0x56f\n+#define MAX96717_PIO_SLEW_0_PIO00_SLEW\t\tGENMASK(1, 0)\n+#define MAX96717_PIO_SLEW_0_PIO01_SLEW\t\tGENMASK(3, 2)\n+#define MAX96717_PIO_SLEW_0_PIO02_SLEW\t\tGENMASK(5, 4)\n+\n+#define MAX96717_PIO_SLEW_1\t\t\t0x570\n+#define MAX96717_PIO_SLEW_1_PIO05_SLEW\t\tGENMASK(3, 2)\n+#define MAX96717_PIO_SLEW_1_PIO06_SLEW\t\tGENMASK(5, 4)\n+\n+#define MAX96717_PIO_SLEW_2\t\t\t0x571\n+#define MAX96717_PIO_SLEW_2_PIO010_SLEW\t\tGENMASK(5, 4)\n+#define MAX96717_PIO_SLEW_2_PIO011_SLEW\t\tGENMASK(7, 6)\n+\n+#define MAX96717_PIO_SLEW_FASTEST\t\t0b00\n+\n+#define MAX96717_BIAS_PULL_STRENGTH_1000000_OHM\t1000000U\n+#define MAX96717_BIAS_PULL_STRENGTH_40000_OHM\t40000U\n+\n+#define MAX96717_DEFAULT_CLKOUT_RATE\t\t24000000UL\n+\n+#define MAX96717_NAME\t\t\t\t\"max96717\"\n+#define MAX96717_PINCTRL_NAME\t\t\tMAX96717_NAME \"-pinctrl\"\n+#define MAX96717_GPIOCHIP_NAME\t\t\tMAX96717_NAME \"-gpiochip\"\n+#define MAX96717_GPIO_NUM\t\t\t11\n+#define MAX96717_RCLK_ALT_MFP\t\t\t2\n+#define MAX96717_RCLK_MFP\t\t\t4\n+#define MAX96717_PIPES_NUM\t\t\t4\n+#define MAX96717_PHYS_NUM\t\t\t2\n+\n+struct max96717_priv {\n+\tstruct max_ser ser;\n+\tstruct pinctrl_desc pctldesc;\n+\tstruct gpio_chip gc;\n+\tconst struct max96717_chip_info *info;\n+\n+\tstruct device *dev;\n+\tstruct i2c_client *client;\n+\tstruct regmap *regmap;\n+\tstruct pinctrl_dev *pctldev;\n+\n+\tstruct clk_hw clk_hw;\n+\tu8 pll_predef_index;\n+};\n+\n+struct max96717_chip_info {\n+\tbool supports_3_data_lanes;\n+\tbool supports_noncontinuous_clock;\n+\tbool supports_pkt_cnt;\n+\tunsigned int modes;\n+\tunsigned int num_pipes;\n+\tunsigned int num_dts_per_pipe;\n+\tunsigned int pipe_hw_ids[MAX96717_PIPES_NUM];\n+\tunsigned int num_phys;\n+\tunsigned int phy_hw_ids[MAX96717_PHYS_NUM];\n+};\n+\n+#define ser_to_priv(_ser) \\\n+\tcontainer_of(_ser, struct max96717_priv, ser)\n+\n+static inline struct max96717_priv *clk_hw_to_priv(struct clk_hw *hw)\n+{\n+\treturn container_of(hw, struct max96717_priv, clk_hw);\n+}\n+\n+static const struct regmap_config max96717_i2c_regmap = {\n+\t.reg_bits = 16,\n+\t.val_bits = 8,\n+\t.max_register = 0x1f00,\n+};\n+\n+static int max96717_wait_for_device(struct max96717_priv *priv)\n+{\n+\tunsigned int val;\n+\tint ret, err;\n+\n+\terr = read_poll_timeout(regmap_read, ret,\n+\t\t\t\t!ret && val,\n+\t\t\t\t100 * USEC_PER_MSEC,\n+\t\t\t\t1 * USEC_PER_SEC, false,\n+\t\t\t\tpriv->regmap, MAX96717_REG0, &val);\n+\tif (err)\n+\t\tdev_err(priv->dev, \"Timeout waiting for serializer: %d\\n\", ret);\n+\n+\treturn err;\n+}\n+\n+#define MAX96717_PIN(n) \\\n+\tPINCTRL_PIN(n, \"mfp\" __stringify(n))\n+\n+static const struct pinctrl_pin_desc max96717_pins[] = {\n+\tMAX96717_PIN(0),\n+\tMAX96717_PIN(1),\n+\tMAX96717_PIN(2),\n+\tMAX96717_PIN(3),\n+\tMAX96717_PIN(4),\n+\tMAX96717_PIN(5),\n+\tMAX96717_PIN(6),\n+\tMAX96717_PIN(7),\n+\tMAX96717_PIN(8),\n+\tMAX96717_PIN(9),\n+\tMAX96717_PIN(10),\n+};\n+\n+#define MAX96717_GROUP_PINS(name, ...) \\\n+\tstatic const unsigned int name ## _pins[] = { __VA_ARGS__ }\n+\n+MAX96717_GROUP_PINS(mfp0, 0);\n+MAX96717_GROUP_PINS(mfp1, 1);\n+MAX96717_GROUP_PINS(mfp2, 2);\n+MAX96717_GROUP_PINS(mfp3, 3);\n+MAX96717_GROUP_PINS(mfp4, 4);\n+MAX96717_GROUP_PINS(mfp5, 5);\n+MAX96717_GROUP_PINS(mfp6, 6);\n+MAX96717_GROUP_PINS(mfp7, 7);\n+MAX96717_GROUP_PINS(mfp8, 8);\n+MAX96717_GROUP_PINS(mfp9, 9);\n+MAX96717_GROUP_PINS(mfp10, 10);\n+\n+#define MAX96717_GROUP(name) \\\n+\tPINCTRL_PINGROUP(__stringify(name), name ## _pins, ARRAY_SIZE(name ## _pins))\n+\n+static const struct pingroup max96717_ctrl_groups[] = {\n+\tMAX96717_GROUP(mfp0),\n+\tMAX96717_GROUP(mfp1),\n+\tMAX96717_GROUP(mfp2),\n+\tMAX96717_GROUP(mfp3),\n+\tMAX96717_GROUP(mfp4),\n+\tMAX96717_GROUP(mfp5),\n+\tMAX96717_GROUP(mfp6),\n+\tMAX96717_GROUP(mfp7),\n+\tMAX96717_GROUP(mfp8),\n+\tMAX96717_GROUP(mfp9),\n+\tMAX96717_GROUP(mfp10),\n+};\n+\n+#define MAX96717_FUNC_GROUPS(name, ...) \\\n+\tstatic const char * const name ## _groups[] = { __VA_ARGS__ }\n+\n+MAX96717_FUNC_GROUPS(gpio, \"mfp0\", \"mfp1\", \"mfp2\", \"mfp3\", \"mfp4\", \"mfp5\",\n+\t\t     \"mfp6\", \"mfp7\", \"mfp8\", \"mfp9\", \"mfp10\");\n+MAX96717_FUNC_GROUPS(rclkout, \"mfp2\", \"mfp4\");\n+\n+enum max96717_func {\n+\tmax96717_func_gpio,\n+\tmax96717_func_rclkout,\n+};\n+\n+#define MAX96717_FUNC(name)\t\t\t\t\t\t\\\n+\t[max96717_func_ ## name] =\t\t\t\t\t\\\n+\t\tPINCTRL_PINFUNCTION(__stringify(name), name ## _groups,\t\\\n+\t\t\t\t    ARRAY_SIZE(name ## _groups))\n+\n+static const struct pinfunction max96717_functions[] = {\n+\tMAX96717_FUNC(gpio),\n+\tMAX96717_FUNC(rclkout),\n+};\n+\n+#define MAX96717_PINCTRL_X(x)\t\t\t(PIN_CONFIG_END + (x))\n+#define MAX96717_PINCTRL_JITTER_COMPENSATION_EN\tMAX96717_PINCTRL_X(1)\n+#define MAX96717_PINCTRL_TX_ID\t\t\tMAX96717_PINCTRL_X(2)\n+#define MAX96717_PINCTRL_RX_ID\t\t\tMAX96717_PINCTRL_X(3)\n+#define MAX96717_PINCTRL_PULL_STRENGTH_HIGH\tMAX96717_PINCTRL_X(4)\n+#define MAX96717_PINCTRL_INPUT_VALUE\t\tMAX96717_PINCTRL_X(5)\n+#define MAX96717_PINCTRL_TX_EN\t\t\tMAX96717_PINCTRL_X(6)\n+#define MAX96717_PINCTRL_RX_EN\t\t\tMAX96717_PINCTRL_X(7)\n+\n+static const struct pinconf_generic_params max96717_cfg_params[] = {\n+\t{ \"maxim,jitter-compensation\", MAX96717_PINCTRL_JITTER_COMPENSATION_EN, 0 },\n+\t{ \"maxim,tx-id\", MAX96717_PINCTRL_TX_ID, 0 },\n+\t{ \"maxim,rx-id\", MAX96717_PINCTRL_RX_ID, 0 },\n+};\n+\n+static int max96717_ctrl_get_groups_count(struct pinctrl_dev *pctldev)\n+{\n+\treturn ARRAY_SIZE(max96717_ctrl_groups);\n+}\n+\n+static const char *max96717_ctrl_get_group_name(struct pinctrl_dev *pctldev,\n+\t\t\t\t\t\tunsigned int selector)\n+{\n+\treturn max96717_ctrl_groups[selector].name;\n+}\n+\n+static int max96717_ctrl_get_group_pins(struct pinctrl_dev *pctldev,\n+\t\t\t\t\tunsigned int selector,\n+\t\t\t\t\tconst unsigned int **pins,\n+\t\t\t\t\tunsigned int *num_pins)\n+{\n+\t*pins = (unsigned int *)max96717_ctrl_groups[selector].pins;\n+\t*num_pins = max96717_ctrl_groups[selector].npins;\n+\n+\treturn 0;\n+}\n+\n+static int max96717_get_pin_config_reg(unsigned int offset, u32 param,\n+\t\t\t\t       unsigned int *reg, unsigned int *mask,\n+\t\t\t\t       unsigned int *val)\n+{\n+\t*reg = MAX96717_GPIO_A(offset);\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_OUTPUT_ENABLE:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_OUT_DIS;\n+\t\t*val = 0b0;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_OUT_DIS;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_TX_EN:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_TX_EN;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_RX_EN:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_RX_EN;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_INPUT_VALUE:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_IN;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_LEVEL:\n+\t\t*mask = MAX96717_GPIO_A_GPIO_OUT;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_JITTER_COMPENSATION_EN:\n+\t\t*mask = MAX96717_GPIO_A_TX_COMP_EN;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_PULL_STRENGTH_HIGH:\n+\t\t*mask = MAX96717_GPIO_A_RES_CFG;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\t}\n+\n+\t*reg = MAX96717_GPIO_B(offset);\n+\n+\tswitch (param) {\n+\tcase MAX96717_PINCTRL_TX_ID:\n+\t\t*mask = MAX96717_GPIO_B_GPIO_TX_ID;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\t\t*mask = MAX96717_GPIO_B_OUT_TYPE;\n+\t\t*val = 0b0;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\t\t*mask = MAX96717_GPIO_B_OUT_TYPE;\n+\t\t*val = 0b1;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\t*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;\n+\t\t*val = MAX96717_GPIO_B_PULL_UPDN_SEL_NONE;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\t*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;\n+\t\t*val = MAX96717_GPIO_B_PULL_UPDN_SEL_PD;\n+\t\treturn 0;\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\t*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;\n+\t\t*val = MAX96717_GPIO_B_PULL_UPDN_SEL_PU;\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_SLEW_RATE:\n+\t\tif (offset < 3) {\n+\t\t\t*reg = MAX96717_PIO_SLEW_0;\n+\t\t\tif (offset == 0)\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_0_PIO00_SLEW;\n+\t\t\telse if (offset == 1)\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_0_PIO01_SLEW;\n+\t\t\telse\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_0_PIO02_SLEW;\n+\t\t} else if (offset < 5) {\n+\t\t\t*reg = MAX96717_PIO_SLEW_1;\n+\t\t\tif (offset == 3)\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_1_PIO05_SLEW;\n+\t\t\telse\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_1_PIO06_SLEW;\n+\t\t} else if (offset < 7) {\n+\t\t\treturn -EINVAL;\n+\t\t} else if (offset < 9) {\n+\t\t\t*reg  = MAX96717_PIO_SLEW_2;\n+\t\t\tif (offset == 7)\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_2_PIO010_SLEW;\n+\t\t\telse\n+\t\t\t\t*mask = MAX96717_PIO_SLEW_2_PIO011_SLEW;\n+\t\t} else {\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\treturn 0;\n+\tcase MAX96717_PINCTRL_RX_ID:\n+\t\t*reg = MAX96717_GPIO_C(offset);\n+\t\t*mask = MAX96717_GPIO_C_GPIO_RX_ID;\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -ENOTSUPP;\n+\t}\n+}\n+\n+static int max96717_conf_pin_config_get(struct pinctrl_dev *pctldev,\n+\t\t\t\t\tunsigned int offset,\n+\t\t\t\t\tunsigned long *config)\n+{\n+\tstruct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tu32 param = pinconf_to_config_param(*config);\n+\tunsigned int reg, mask, val, en_val;\n+\tint ret;\n+\n+\tret = max96717_get_pin_config_reg(offset, param, &reg, &mask, &en_val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\tcase PIN_CONFIG_BIAS_DISABLE:\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\tcase MAX96717_PINCTRL_JITTER_COMPENSATION_EN:\n+\tcase MAX96717_PINCTRL_TX_EN:\n+\tcase MAX96717_PINCTRL_RX_EN:\n+\tcase PIN_CONFIG_OUTPUT_ENABLE:\n+\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\tret = regmap_read(priv->regmap, reg, &val);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tval = field_get(mask, val) == en_val;\n+\t\tif (!val)\n+\t\t\treturn -EINVAL;\n+\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_PULL_STRENGTH_HIGH:\n+\tcase MAX96717_PINCTRL_INPUT_VALUE:\n+\tcase PIN_CONFIG_LEVEL:\n+\t\tret = regmap_read(priv->regmap, reg, &val);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tval = field_get(mask, val) == en_val;\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_TX_ID:\n+\tcase MAX96717_PINCTRL_RX_ID:\n+\tcase PIN_CONFIG_SLEW_RATE:\n+\t\tret = regmap_read(priv->regmap, reg, &val);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tval = field_get(mask, val);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENOTSUPP;\n+\t}\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\t*config = pinconf_to_config_packed(MAX96717_PINCTRL_PULL_STRENGTH_HIGH, 0);\n+\n+\t\tret = max96717_conf_pin_config_get(pctldev, offset, config);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tval = pinconf_to_config_argument(*config);\n+\t\tif (val)\n+\t\t\tval = MAX96717_BIAS_PULL_STRENGTH_1000000_OHM;\n+\t\telse\n+\t\t\tval = MAX96717_BIAS_PULL_STRENGTH_40000_OHM;\n+\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_TX_ID:\n+\t\t*config = pinconf_to_config_packed(MAX96717_PINCTRL_TX_EN, 0);\n+\n+\t\tret = max96717_conf_pin_config_get(pctldev, offset, config);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_RX_ID:\n+\t\t*config = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 0);\n+\n+\t\tret = max96717_conf_pin_config_get(pctldev, offset, config);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t*config = pinconf_to_config_packed(param, val);\n+\n+\treturn 0;\n+}\n+\n+static int max96717_conf_pin_config_set_one(struct max96717_priv *priv,\n+\t\t\t\t\t    unsigned int offset,\n+\t\t\t\t\t    unsigned long config)\n+{\n+\tu32 param = pinconf_to_config_param(config);\n+\tu32 arg = pinconf_to_config_argument(config);\n+\tunsigned int reg, mask, val, en_val;\n+\tint ret;\n+\n+\tret = max96717_get_pin_config_reg(offset, param, &reg, &mask, &en_val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\tcase PIN_CONFIG_BIAS_DISABLE:\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\tval = field_prep(mask, en_val);\n+\n+\t\tret = regmap_update_bits(priv->regmap, reg, mask, val);\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_JITTER_COMPENSATION_EN:\n+\tcase MAX96717_PINCTRL_PULL_STRENGTH_HIGH:\n+\tcase MAX96717_PINCTRL_TX_EN:\n+\tcase MAX96717_PINCTRL_RX_EN:\n+\tcase PIN_CONFIG_OUTPUT_ENABLE:\n+\tcase PIN_CONFIG_INPUT_ENABLE:\n+\tcase PIN_CONFIG_LEVEL:\n+\t\tval = field_prep(mask, arg ? en_val : ~en_val);\n+\n+\t\tret = regmap_update_bits(priv->regmap, reg, mask, val);\n+\t\tbreak;\n+\tcase MAX96717_PINCTRL_TX_ID:\n+\tcase MAX96717_PINCTRL_RX_ID:\n+\tcase PIN_CONFIG_SLEW_RATE:\n+\t\tval = field_prep(mask, arg);\n+\n+\t\tret = regmap_update_bits(priv->regmap, reg, mask, val);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENOTSUPP;\n+\t}\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\targ = arg >= MAX96717_BIAS_PULL_STRENGTH_1000000_OHM;\n+\t\tconfig = pinconf_to_config_packed(MAX96717_PINCTRL_PULL_STRENGTH_HIGH, arg);\n+\t\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+\tcase PIN_CONFIG_LEVEL:\n+\t\tconfig = pinconf_to_config_packed(PIN_CONFIG_OUTPUT_ENABLE, 1);\n+\t\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+\tcase PIN_CONFIG_OUTPUT_ENABLE:\n+\t\tconfig = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 0);\n+\t\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+\tcase MAX96717_PINCTRL_TX_ID:\n+\t\tconfig = pinconf_to_config_packed(MAX96717_PINCTRL_TX_EN, 1);\n+\t\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+\tcase MAX96717_PINCTRL_RX_ID:\n+\t\tconfig = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 1);\n+\t\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int max96717_conf_pin_config_set(struct pinctrl_dev *pctldev,\n+\t\t\t\t\tunsigned int offset,\n+\t\t\t\t\tunsigned long *configs,\n+\t\t\t\t\tunsigned int num_configs)\n+{\n+\tstruct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);\n+\tint ret;\n+\n+\twhile (num_configs--) {\n+\t\tunsigned long config = *configs;\n+\n+\t\tret = max96717_conf_pin_config_set_one(priv, offset, config);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tconfigs++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int max96717_mux_get_functions_count(struct pinctrl_dev *pctldev)\n+{\n+\treturn ARRAY_SIZE(max96717_functions);\n+}\n+\n+static const char *max96717_mux_get_function_name(struct pinctrl_dev *pctldev,\n+\t\t\t\t\t\t  unsigned int selector)\n+{\n+\treturn max96717_functions[selector].name;\n+}\n+\n+static int max96717_mux_get_groups(struct pinctrl_dev *pctldev,\n+\t\t\t\t   unsigned int selector,\n+\t\t\t\t   const char * const **groups,\n+\t\t\t\t   unsigned int * const num_groups)\n+{\n+\t*groups = max96717_functions[selector].groups;\n+\t*num_groups = max96717_functions[selector].ngroups;\n+\n+\treturn 0;\n+}\n+\n+static int max96717_mux_set_rclkout(struct max96717_priv *priv, unsigned int group)\n+{\n+\tunsigned long config;\n+\tint ret;\n+\n+\tconfig = pinconf_to_config_packed(PIN_CONFIG_SLEW_RATE,\n+\t\t\t\t\t  MAX96717_PIO_SLEW_FASTEST);\n+\tret = max96717_conf_pin_config_set_one(priv, group, config);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_assign_bits(priv->regmap, MAX96717_REG3,\n+\t\t\t\t  MAX96717_REG3_RCLK_ALT,\n+\t\t\t\t  group == MAX96717_RCLK_ALT_MFP);\n+}\n+\n+static int max96717_mux_set(struct pinctrl_dev *pctldev, unsigned int selector,\n+\t\t\t    unsigned int group)\n+{\n+\tstruct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);\n+\n+\tswitch (selector) {\n+\tcase max96717_func_rclkout:\n+\t\treturn max96717_mux_set_rclkout(priv, group);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int max96717_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)\n+{\n+\tunsigned long config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT_ENABLE, 0);\n+\tstruct max96717_priv *priv = gpiochip_get_data(gc);\n+\tint ret;\n+\n+\tret = max96717_conf_pin_config_get(priv->pctldev, offset, &config);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn pinconf_to_config_argument(config) ? GPIO_LINE_DIRECTION_OUT\n+\t\t\t\t\t\t  : GPIO_LINE_DIRECTION_IN;\n+}\n+\n+static int max96717_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)\n+{\n+\tunsigned long config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);\n+\tstruct max96717_priv *priv = gpiochip_get_data(gc);\n+\n+\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+}\n+\n+static int max96717_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,\n+\t\t\t\t\t  int value)\n+{\n+\tunsigned long config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, value);\n+\tstruct max96717_priv *priv = gpiochip_get_data(gc);\n+\n+\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+}\n+\n+static int max96717_gpio_get(struct gpio_chip *gc, unsigned int offset)\n+{\n+\tunsigned long config = pinconf_to_config_packed(MAX96717_PINCTRL_INPUT_VALUE, 0);\n+\tstruct max96717_priv *priv = gpiochip_get_data(gc);\n+\tint ret;\n+\n+\tret = max96717_conf_pin_config_get(priv->pctldev, offset, &config);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn pinconf_to_config_argument(config);\n+}\n+\n+static int max96717_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)\n+{\n+\tunsigned long config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, value);\n+\tstruct max96717_priv *priv = gpiochip_get_data(gc);\n+\n+\treturn max96717_conf_pin_config_set_one(priv, offset, config);\n+}\n+\n+static unsigned int max96717_pipe_id(struct max96717_priv *priv,\n+\t\t\t\t     struct max_ser_pipe *pipe)\n+{\n+\treturn priv->info->pipe_hw_ids[pipe->index];\n+}\n+\n+static unsigned int max96717_phy_id(struct max96717_priv *priv,\n+\t\t\t\t    struct max_ser_phy *phy)\n+{\n+\treturn priv->info->phy_hw_ids[phy->index];\n+}\n+\n+static int max96717_set_pipe_enable(struct max_ser *ser,\n+\t\t\t\t    struct max_ser_pipe *pipe, bool enable)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tunsigned int mask = MAX96717_REG2_VID_TX_EN_P(index);\n+\n+\treturn regmap_assign_bits(priv->regmap, MAX96717_REG2, mask, enable);\n+}\n+\n+static int __maybe_unused max96717_reg_read(struct max_ser *ser, unsigned int reg,\n+\t\t\t\t\t    unsigned int *val)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\n+\treturn regmap_read(priv->regmap, reg, val);\n+}\n+\n+static int __maybe_unused max96717_reg_write(struct max_ser *ser, unsigned int reg,\n+\t\t\t\t\t     unsigned int val)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\n+\treturn regmap_write(priv->regmap, reg, val);\n+}\n+\n+static int max96717_set_pipe_dt_en(struct max_ser *ser, struct max_ser_pipe *pipe,\n+\t\t\t\t   unsigned int i, bool enable)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tunsigned int reg;\n+\n+\tif (i < 2)\n+\t\treg = MAX96717_FRONTTOP_12(index, i);\n+\telse\n+\t\t/*\n+\t\t * DT 7 and 8 are only supported on MAX96717, no need for pipe\n+\t\t * index to be taken into account.\n+\t\t */\n+\t\treg = MAX96717_EXTA(i - 2);\n+\n+\treturn regmap_assign_bits(priv->regmap, reg, MAX96717_MEM_DT_EN, enable);\n+}\n+\n+static int max96717_set_pipe_dt(struct max_ser *ser, struct max_ser_pipe *pipe,\n+\t\t\t\tunsigned int i, unsigned int dt)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tunsigned int reg;\n+\n+\tif (i < 2)\n+\t\treg = MAX96717_FRONTTOP_12(index,  i);\n+\telse\n+\t\treg = MAX96717_EXTA(i - 2);\n+\n+\treturn regmap_update_bits(priv->regmap, reg, MAX96717_MEM_DT_SEL,\n+\t\t\t\t  FIELD_PREP(MAX96717_MEM_DT_SEL, dt));\n+}\n+\n+static int max96717_set_pipe_vcs(struct max_ser *ser,\n+\t\t\t\t struct max_ser_pipe *pipe,\n+\t\t\t\t unsigned int vcs)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tint ret;\n+\n+\tret = regmap_write(priv->regmap, MAX96717_FRONTTOP_1(index),\n+\t\t\t   (vcs >> 0) & 0xff);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_write(priv->regmap, MAX96717_FRONTTOP_2(index),\n+\t\t\t      (vcs >> 8) & 0xff);\n+}\n+\n+static int max96717_log_status(struct max_ser *ser)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int val;\n+\tint ret;\n+\n+\tif (!(priv->info->modes & BIT(MAX_SERDES_GMSL_TUNNEL_MODE)))\n+\t\treturn 0;\n+\n+\tret = regmap_read(priv->regmap, MAX96717_EXT23, &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdev_info(priv->dev, \"tun_pkt_cnt: %u\\n\", val);\n+\n+\treturn 0;\n+}\n+\n+static int max96717_log_pipe_status(struct max_ser *ser,\n+\t\t\t\t    struct max_ser_pipe *pipe)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tunsigned int val;\n+\tint ret;\n+\n+\tret = regmap_read(priv->regmap, MAX96717_VIDEO_TX2(index), &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdev_info(priv->dev, \"\\tpclkdet: %u\\n\",\n+\t\t !!(val & MAX96717_VIDEO_TX2_PCLKDET));\n+\n+\treturn 0;\n+}\n+\n+static int max96717_log_phy_status(struct max_ser *ser,\n+\t\t\t\t   struct max_ser_phy *phy)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int val;\n+\tint ret;\n+\n+\tif (!priv->info->supports_pkt_cnt)\n+\t\treturn 0;\n+\n+\tret = regmap_read(priv->regmap, MAX96717_EXT21, &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdev_info(priv->dev, \"\\tphy_pkt_cnt: %u\\n\", val);\n+\n+\tret = regmap_read(priv->regmap, MAX96717_EXT22, &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdev_info(priv->dev, \"\\tcsi_pkt_cnt: %u\\n\", val);\n+\n+\tret = regmap_read(priv->regmap, MAX96717_EXT24, &val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdev_info(priv->dev, \"\\tphy_clk_cnt: %u\\n\", val);\n+\n+\treturn 0;\n+}\n+\n+static int max96717_init_phy(struct max_ser *ser,\n+\t\t\t     struct max_ser_phy *phy)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int num_data_lanes = phy->mipi.num_data_lanes;\n+\tunsigned int used_data_lanes = 0;\n+\tunsigned int val;\n+\tunsigned int i;\n+\tint ret;\n+\n+\tif (num_data_lanes == 3 && !priv->info->supports_3_data_lanes) {\n+\t\tdev_err(priv->dev, \"Unsupported 3 data lane mode\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (phy->mipi.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK &&\n+\t    !priv->info->supports_noncontinuous_clock) {\n+\t\tdev_err(priv->dev, \"Unsupported non-continuous mode\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Configure a lane count. */\n+\tret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX1,\n+\t\t\t\t MAX96717_MIPI_RX1_CTRL_NUM_LANES,\n+\t\t\t\t FIELD_PREP(MAX96717_MIPI_RX1_CTRL_NUM_LANES,\n+\t\t\t\t\t    num_data_lanes - 1));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Configure lane mapping. */\n+\tval = 0;\n+\tfor (i = 0; i < 4; i++) {\n+\t\tunsigned int map;\n+\n+\t\tif (i < num_data_lanes)\n+\t\t\tmap = phy->mipi.data_lanes[i] - 1;\n+\t\telse\n+\t\t\tmap = ffz(used_data_lanes);\n+\n+\t\tval |= map << (i * 2);\n+\t\tused_data_lanes |= BIT(map);\n+\t}\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX3,\n+\t\t\t\t MAX96717_MIPI_RX3_PHY2_LANE_MAP,\n+\t\t\t\t FIELD_PREP(MAX96717_MIPI_RX3_PHY2_LANE_MAP, val));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX2,\n+\t\t\t\t MAX96717_MIPI_RX2_PHY1_LANE_MAP,\n+\t\t\t\t FIELD_PREP(MAX96717_MIPI_RX2_PHY1_LANE_MAP, val >> 4));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Configure lane polarity. */\n+\tfor (i = 0, val = 0; i < num_data_lanes; i++)\n+\t\tif (phy->mipi.lane_polarities[i + 1])\n+\t\t\tval |= BIT(i);\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX5,\n+\t\t\t\t MAX96717_MIPI_RX5_PHY2_POL_MAP,\n+\t\t\t\t FIELD_PREP(MAX96717_MIPI_RX5_PHY2_POL_MAP, val));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX4,\n+\t\t\t\t MAX96717_MIPI_RX4_PHY1_POL_MAP,\n+\t\t\t\t FIELD_PREP(MAX96717_MIPI_RX4_PHY1_POL_MAP, val >> 2));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_MIPI_RX5,\n+\t\t\t\t MAX96717_MIPI_RX5_PHY2_POL_MAP_CLK,\n+\t\t\t\t phy->mipi.lane_polarities[0]);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (priv->info->supports_noncontinuous_clock) {\n+\t\tret = regmap_assign_bits(priv->regmap, MAX96717_MIPI_RX0,\n+\t\t\t\t\t MAX96717_MIPI_RX0_NONCONTCLK_EN,\n+\t\t\t\t\t phy->mipi.flags &\n+\t\t\t\t\t V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int max96717_set_phy_active(struct max_ser *ser, struct max_ser_phy *phy,\n+\t\t\t\t   bool enable)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_phy_id(priv, phy);\n+\n+\treturn regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_0,\n+\t\t\t\t  MAX96717_FRONTTOP_0_START_PORT(index), enable);\n+}\n+\n+static int max96717_set_pipe_stream_id(struct max_ser *ser,\n+\t\t\t\t       struct max_ser_pipe *pipe,\n+\t\t\t\t       unsigned int stream_id)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\n+\treturn regmap_update_bits(priv->regmap, MAX96717_TX3(index),\n+\t\t\t\t  MAX96717_TX3_TX_STR_SEL,\n+\t\t\t\t  FIELD_PREP(MAX96717_TX3_TX_STR_SEL, stream_id));\n+}\n+\n+static int max96717_set_pipe_phy(struct max_ser *ser, struct max_ser_pipe *pipe,\n+\t\t\t\t struct max_ser_phy *phy)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tunsigned int phy_id = max96717_phy_id(priv, phy);\n+\tint ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_0,\n+\t\t\t\t MAX96717_FRONTTOP_0_CLK_SEL_P(index),\n+\t\t\t\t phy_id == 1);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_9,\n+\t\t\t\t MAX96717_FRONTTOP_9_START_PORT(index, 0),\n+\t\t\t\t phy_id == 0);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_9,\n+\t\t\t\t  MAX96717_FRONTTOP_9_START_PORT(index, 1),\n+\t\t\t\t  phy_id == 1);\n+}\n+\n+static int max96717_set_pipe_mode(struct max_ser *ser,\n+\t\t\t\t  struct max_ser_pipe *pipe,\n+\t\t\t\t  struct max_ser_pipe_mode *mode)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tunsigned int index = max96717_pipe_id(priv, pipe);\n+\tint ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_VIDEO_TX0(index),\n+\t\t\t\t MAX96717_VIDEO_TX0_AUTO_BPP, !mode->bpp);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_VIDEO_TX1(index),\n+\t\t\t\t MAX96717_VIDEO_TX1_BPP,\n+\t\t\t\t FIELD_PREP(MAX96717_VIDEO_TX1_BPP, mode->bpp));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_VIDEO_TX2(index),\n+\t\t\t\t MAX96717_VIDEO_TX2_DRIFT_DET_EN, !mode->bpp);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_10,\n+\t\t\t\t MAX96717_FRONTTOP_10_BPP8DBL(index),\n+\t\t\t\t mode->dbl8);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_11,\n+\t\t\t\t MAX96717_FRONTTOP_11_BPP10DBL(index),\n+\t\t\t\t mode->dbl10);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_11,\n+\t\t\t\t MAX96717_FRONTTOP_11_BPP12DBL(index),\n+\t\t\t\t mode->dbl12);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_update_bits(priv->regmap, MAX96717_FRONTTOP_20(index),\n+\t\t\t\t  MAX96717_FRONTTOP_20_SOFT_BPP |\n+\t\t\t\t  MAX96717_FRONTTOP_20_SOFT_BPP_EN,\n+\t\t\t\t  FIELD_PREP(MAX96717_FRONTTOP_20_SOFT_BPP,\n+\t\t\t\t\t     mode->soft_bpp) |\n+\t\t\t\t  FIELD_PREP(MAX96717_FRONTTOP_20_SOFT_BPP_EN,\n+\t\t\t\t\t     !!mode->soft_bpp));\n+}\n+\n+static int max96717_set_i2c_xlate(struct max_ser *ser, unsigned int i,\n+\t\t\t\t  struct max_serdes_i2c_xlate *xlate)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tint ret;\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_I2C_2(i),\n+\t\t\t\t MAX96717_I2C_2_SRC,\n+\t\t\t\t FIELD_PREP(MAX96717_I2C_2_SRC, xlate->src));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_update_bits(priv->regmap, MAX96717_I2C_3(i),\n+\t\t\t\t  MAX96717_I2C_3_DST,\n+\t\t\t\t  FIELD_PREP(MAX96717_I2C_3_DST, xlate->dst));\n+}\n+\n+static int max96717_set_tunnel_enable(struct max_ser *ser, bool enable)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\n+\treturn regmap_assign_bits(priv->regmap, MAX96717_EXT11,\n+\t\t\t\t  MAX96717_EXT11_TUN_MODE, enable);\n+}\n+\n+static int max96717_set_tpg_timings(struct max96717_priv *priv,\n+\t\t\t\t    const struct max_serdes_tpg_timings *tm,\n+\t\t\t\t    unsigned int index)\n+{\n+\tconst struct reg_sequence regs[] = {\n+\t\tREG_SEQUENCE_3(MAX96717_VTX2_VS_DLY_2(index), tm->vs_dly),\n+\t\tREG_SEQUENCE_3(MAX96717_VTX5_VS_HIGH_2(index), tm->vs_high),\n+\t\tREG_SEQUENCE_3(MAX96717_VTX8_VS_LOW_2(index), tm->vs_low),\n+\t\tREG_SEQUENCE_3(MAX96717_VTX11_V2H_2(index), tm->v2h),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX14_HS_HIGH_1(index), tm->hs_high),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX16_HS_LOW_1(index), tm->hs_low),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX18_HS_CNT_1(index), tm->hs_cnt),\n+\t\tREG_SEQUENCE_3(MAX96717_VTX20_V2D_2(index), tm->v2d),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX23_DE_HIGH_1(index), tm->de_high),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX25_DE_LOW_1(index), tm->de_low),\n+\t\tREG_SEQUENCE_2(MAX96717_VTX27_DE_CNT_1(index), tm->de_cnt),\n+\t};\n+\tint ret;\n+\n+\tret = regmap_multi_reg_write(priv->regmap, regs, ARRAY_SIZE(regs));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn regmap_write(priv->regmap, MAX96717_VTX0(index),\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_VTG_MODE,\n+\t\t\t\t       MAX96717_VTX0_VTG_MODE_FREE_RUNNING) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_DE_INV, tm->de_inv) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_HS_INV, tm->hs_inv) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_VS_INV, tm->vs_inv) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_GEN_DE, tm->gen_de) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_GEN_HS, tm->gen_hs) |\n+\t\t\t    FIELD_PREP(MAX96717_VTX0_GEN_VS, tm->gen_vs));\n+}\n+\n+static int max96717_set_tpg_clk(struct max96717_priv *priv, u32 clock,\n+\t\t\t\tunsigned int index)\n+{\n+\tu8 pclk_src;\n+\n+\tswitch (clock) {\n+\tcase 25000000:\n+\t\tpclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_25MHZ;\n+\t\tbreak;\n+\tcase 75000000:\n+\t\tpclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_75MHZ;\n+\t\tbreak;\n+\tcase 150000000:\n+\t\tpclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_150MHZ;\n+\t\tbreak;\n+\tcase 375000000:\n+\t\tpclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_375MHZ;\n+\t\tbreak;\n+\tcase 0:\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn regmap_update_bits(priv->regmap, MAX96717_VTX1(index),\n+\t\t\t\t  MAX96717_VTX1_PATGEN_CLK_SRC,\n+\t\t\t\t  FIELD_PREP(MAX96717_VTX1_PATGEN_CLK_SRC,\n+\t\t\t\t\t     pclk_src));\n+}\n+\n+static int max96717_set_tpg_mode(struct max96717_priv *priv, bool enable,\n+\t\t\t\t unsigned int index)\n+{\n+\tunsigned int patgen_mode;\n+\n+\tswitch (priv->ser.tpg_pattern) {\n+\tcase MAX_SERDES_TPG_PATTERN_GRADIENT:\n+\t\tpatgen_mode = MAX96717_VTX29_PATGEN_MODE_GRADIENT;\n+\t\tbreak;\n+\tcase MAX_SERDES_TPG_PATTERN_CHECKERBOARD:\n+\t\tpatgen_mode = MAX96717_VTX29_PATGEN_MODE_CHECKER;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn regmap_update_bits(priv->regmap, MAX96717_VTX29(index),\n+\t\t\t\t  MAX96717_VTX29_PATGEN_MODE,\n+\t\t\t\t  FIELD_PREP(MAX96717_VTX29_PATGEN_MODE,\n+\t\t\t\t\t     enable ? patgen_mode\n+\t\t\t\t\t\t    : MAX96717_VTX29_PATGEN_MODE_DISABLED));\n+}\n+\n+static int max96717_set_tpg(struct max_ser *ser,\n+\t\t\t    const struct max_serdes_tpg_entry *entry)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\t/*\n+\t * MAX9295A supports multiple pipes, each with a pattern generator,\n+\t * use only the first pipe for simplicity.\n+\t */\n+\tunsigned int index = max96717_pipe_id(priv, &ser->pipes[0]);\n+\tstruct max_serdes_tpg_timings timings = { 0 };\n+\tint ret;\n+\n+\tret = max_serdes_get_tpg_timings(entry, &timings);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = max96717_set_tpg_timings(priv, &timings, index);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = max96717_set_tpg_clk(priv, timings.clock, index);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn max96717_set_tpg_mode(priv, entry, index);\n+}\n+\n+static const struct max_serdes_phys_config max96717_phys_configs[] = {\n+\t{ { 4 } },\n+};\n+\n+static int max96717_init_tpg(struct max_ser *ser)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\t/*\n+\t * MAX9295A supports multiple pipes, each with a pattern generator,\n+\t * use only the first pipe for simplicity.\n+\t */\n+\tunsigned int index = max96717_pipe_id(priv, &ser->pipes[0]);\n+\n+\tconst struct reg_sequence regs[] = {\n+\t\t{ MAX96717_VTX30_GRAD_INCR(index), MAX_SERDES_GRAD_INCR },\n+\t\tREG_SEQUENCE_3_LE(MAX96717_VTX31_CHKR_A_L(index),\n+\t\t\t\t  MAX_SERDES_CHECKER_COLOR_A),\n+\t\tREG_SEQUENCE_3_LE(MAX96717_VTX34_CHKR_B_L(index),\n+\t\t\t\t  MAX_SERDES_CHECKER_COLOR_B),\n+\t\t{ MAX96717_VTX37_CHKR_RPT_A(index), MAX_SERDES_CHECKER_SIZE },\n+\t\t{ MAX96717_VTX38_CHKR_RPT_B(index), MAX_SERDES_CHECKER_SIZE },\n+\t\t{ MAX96717_VTX39_CHKR_ALT(index), MAX_SERDES_CHECKER_SIZE },\n+\t};\n+\n+\treturn regmap_multi_reg_write(priv->regmap, regs, ARRAY_SIZE(regs));\n+}\n+\n+static int max96717_init(struct max_ser *ser)\n+{\n+\tstruct max96717_priv *priv = ser_to_priv(ser);\n+\tint ret;\n+\n+\t/*\n+\t * Set CMU2 PFDDIV to 1.1V for correct functionality of the device,\n+\t * as mentioned in the datasheet, under section MANDATORY REGISTER PROGRAMMING.\n+\t */\n+\tret = regmap_update_bits(priv->regmap, MAX96717_CMU2,\n+\t\t\t\t MAX96717_CMU2_PFDDIV_RSHORT,\n+\t\t\t\t FIELD_PREP(MAX96717_CMU2_PFDDIV_RSHORT,\n+\t\t\t\t\t    MAX96717_CMU2_PFDDIV_RSHORT_1_1V));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (ser->ops->set_tunnel_enable) {\n+\t\tret = ser->ops->set_tunnel_enable(ser, false);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\treturn max96717_init_tpg(ser);\n+}\n+\n+static const struct pinctrl_ops max96717_ctrl_ops = {\n+\t.get_groups_count = max96717_ctrl_get_groups_count,\n+\t.get_group_name = max96717_ctrl_get_group_name,\n+\t.get_group_pins = max96717_ctrl_get_group_pins,\n+\t.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,\n+\t.dt_free_map = pinconf_generic_dt_free_map,\n+};\n+\n+static const struct pinconf_ops max96717_conf_ops = {\n+\t.pin_config_get = max96717_conf_pin_config_get,\n+\t.pin_config_set = max96717_conf_pin_config_set,\n+\t.is_generic = true,\n+};\n+\n+static const struct pinmux_ops max96717_mux_ops = {\n+\t.get_functions_count = max96717_mux_get_functions_count,\n+\t.get_function_name = max96717_mux_get_function_name,\n+\t.get_function_groups = max96717_mux_get_groups,\n+\t.set_mux = max96717_mux_set,\n+};\n+\n+static const struct max_serdes_tpg_entry max96717_tpg_entries[] = {\n+\tMAX_TPG_ENTRY_640X480P60_RGB888,\n+\tMAX_TPG_ENTRY_1920X1080P30_RGB888,\n+\tMAX_TPG_ENTRY_1920X1080P60_RGB888,\n+};\n+\n+static const struct max_ser_ops max96717_ops = {\n+\t.num_i2c_xlates = 2,\n+\t.phys_configs = {\n+\t\t.num_configs = ARRAY_SIZE(max96717_phys_configs),\n+\t\t.configs = max96717_phys_configs,\n+\t},\n+\t.tpg_entries = {\n+\t\t.num_entries = ARRAY_SIZE(max96717_tpg_entries),\n+\t\t.entries = max96717_tpg_entries,\n+\t},\n+\t.tpg_mode = MAX_SERDES_GMSL_PIXEL_MODE,\n+\t.tpg_patterns = BIT(MAX_SERDES_TPG_PATTERN_CHECKERBOARD) |\n+\t\t\tBIT(MAX_SERDES_TPG_PATTERN_GRADIENT),\n+#ifdef CONFIG_VIDEO_ADV_DEBUG\n+\t.reg_read = max96717_reg_read,\n+\t.reg_write = max96717_reg_write,\n+#endif\n+\t.log_status = max96717_log_status,\n+\t.log_pipe_status = max96717_log_pipe_status,\n+\t.log_phy_status = max96717_log_phy_status,\n+\t.init = max96717_init,\n+\t.set_i2c_xlate = max96717_set_i2c_xlate,\n+\t.set_tpg = max96717_set_tpg,\n+\t.init_phy = max96717_init_phy,\n+\t.set_phy_active = max96717_set_phy_active,\n+\t.set_pipe_enable = max96717_set_pipe_enable,\n+\t.set_pipe_dt = max96717_set_pipe_dt,\n+\t.set_pipe_dt_en = max96717_set_pipe_dt_en,\n+\t.set_pipe_vcs = max96717_set_pipe_vcs,\n+\t.set_pipe_mode = max96717_set_pipe_mode,\n+\t.set_pipe_stream_id = max96717_set_pipe_stream_id,\n+\t.set_pipe_phy = max96717_set_pipe_phy,\n+};\n+\n+struct max96717_pll_predef_freq {\n+\tunsigned long freq;\n+\tbool is_rclk;\n+\tbool is_alt;\n+\tu8 val;\n+\tu8 rclksel;\n+};\n+\n+static const struct max96717_pll_predef_freq max96717_predef_freqs[] = {\n+\t{  6250000, true,  false, 0, 2 },\n+\t{ 12500000, true,  false, 0, 1 },\n+\t{ 13500000, false, true,  0, 3 },\n+\t{ 19200000, false, false, 0, 3 },\n+\t{ 24000000, false, true,  1, 3 },\n+\t{ 25000000, true,  false, 0, 0 },\n+\t{ 27000000, false, false, 1, 3 },\n+\t{ 37125000, false, false, 2, 3 },\n+\t{ 74250000, false, false, 3, 3 },\n+};\n+\n+static unsigned long\n+max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)\n+{\n+\tstruct max96717_priv *priv = clk_hw_to_priv(hw);\n+\n+\treturn max96717_predef_freqs[priv->pll_predef_index].freq;\n+}\n+\n+static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv,\n+\t\t\t\t\t\t unsigned long rate)\n+{\n+\tunsigned int i, idx = 0;\n+\tunsigned long diff_new, diff_old = U32_MAX;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) {\n+\t\tdiff_new = abs(rate - max96717_predef_freqs[i].freq);\n+\t\tif (diff_new < diff_old) {\n+\t\t\tdiff_old = diff_new;\n+\t\t\tidx = i;\n+\t\t}\n+\t}\n+\n+\treturn idx;\n+}\n+\n+static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate,\n+\t\t\t\t    unsigned long *parent_rate)\n+{\n+\tstruct max96717_priv *priv = clk_hw_to_priv(hw);\n+\tstruct device *dev = &priv->client->dev;\n+\tunsigned int idx;\n+\n+\tidx = max96717_clk_find_best_index(priv, rate);\n+\n+\tif (rate != max96717_predef_freqs[idx].freq) {\n+\t\tdev_warn(dev, \"Request CLK freq:%lu, found CLK freq:%lu\\n\",\n+\t\t\t rate, max96717_predef_freqs[idx].freq);\n+\t}\n+\n+\treturn max96717_predef_freqs[idx].freq;\n+}\n+\n+static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate,\n+\t\t\t\t unsigned long parent_rate)\n+{\n+\tconst struct max96717_pll_predef_freq *predef_freq;\n+\tstruct max96717_priv *priv = clk_hw_to_priv(hw);\n+\tunsigned int val, idx;\n+\tint ret = 0;\n+\n+\tidx = max96717_clk_find_best_index(priv, rate);\n+\tpredef_freq = &max96717_predef_freqs[idx];\n+\n+\tret = regmap_update_bits(priv->regmap, MAX96717_REG3,\n+\t\t\t\t MAX96717_REG3_RCLKSEL,\n+\t\t\t\t FIELD_PREP(MAX96717_REG3_RCLKSEL,\n+\t\t\t\t\t    predef_freq->rclksel));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tval = FIELD_PREP(MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ,\n+\t\t\t predef_freq->val);\n+\n+\tif (predef_freq->is_alt)\n+\t\tval |= MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ_ALT;\n+\tif (!predef_freq->is_rclk)\n+\t\tval |= MAX96717_REF_VTG0_REFGEN_EN;\n+\n+\tval |= MAX96717_REF_VTG0_REFGEN_RST;\n+\n+\tret = regmap_write(priv->regmap, MAX96717_REF_VTG0, val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_clear_bits(priv->regmap, MAX96717_REF_VTG0,\n+\t\t\t\tMAX96717_REF_VTG0_REFGEN_RST);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tpriv->pll_predef_index = idx;\n+\n+\treturn 0;\n+}\n+\n+static int max96717_clk_prepare(struct clk_hw *hw)\n+{\n+\tstruct max96717_priv *priv = clk_hw_to_priv(hw);\n+\n+\treturn regmap_set_bits(priv->regmap, MAX96717_REG6, MAX96717_REG6_RCLKEN);\n+}\n+\n+static void max96717_clk_unprepare(struct clk_hw *hw)\n+{\n+\tstruct max96717_priv *priv = clk_hw_to_priv(hw);\n+\n+\tregmap_clear_bits(priv->regmap, MAX96717_REG6, MAX96717_REG6_RCLKEN);\n+}\n+\n+static const struct clk_ops max96717_clk_ops = {\n+\t.prepare     = max96717_clk_prepare,\n+\t.unprepare   = max96717_clk_unprepare,\n+\t.set_rate    = max96717_clk_set_rate,\n+\t.recalc_rate = max96717_clk_recalc_rate,\n+\t.round_rate  = max96717_clk_round_rate,\n+};\n+\n+static int max96717_register_clkout(struct max96717_priv *priv)\n+{\n+\tstruct device *dev = &priv->client->dev;\n+\tstruct clk_init_data init = { .ops = &max96717_clk_ops };\n+\tint ret;\n+\n+\tret = max96717_mux_set_rclkout(priv, MAX96717_RCLK_MFP);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tinit.name = kasprintf(GFP_KERNEL, \"max96717.%s.clk_out\", dev_name(dev));\n+\tif (!init.name)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->clk_hw.init = &init;\n+\n+\tret = max96717_clk_set_rate(&priv->clk_hw,\n+\t\t\t\t    MAX96717_DEFAULT_CLKOUT_RATE, 0);\n+\tif (ret)\n+\t\tgoto free_init_name;\n+\n+\tret = devm_clk_hw_register(dev, &priv->clk_hw);\n+\tkfree(init.name);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"Cannot register clock HW\\n\");\n+\n+\tret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,\n+\t\t\t\t\t  &priv->clk_hw);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret,\n+\t\t\t\t     \"Cannot add OF clock provider\\n\");\n+\n+\treturn 0;\n+\n+free_init_name:\n+\tkfree(init.name);\n+\treturn ret;\n+}\n+\n+static int max96717_gpiochip_probe(struct max96717_priv *priv)\n+{\n+\tstruct device *dev = priv->dev;\n+\tint ret;\n+\n+\tpriv->pctldesc = (struct pinctrl_desc) {\n+\t\t.owner = THIS_MODULE,\n+\t\t.name = MAX96717_PINCTRL_NAME,\n+\t\t.pins = max96717_pins,\n+\t\t.npins = ARRAY_SIZE(max96717_pins),\n+\t\t.pctlops = &max96717_ctrl_ops,\n+\t\t.confops = &max96717_conf_ops,\n+\t\t.pmxops = &max96717_mux_ops,\n+\t\t.custom_params = max96717_cfg_params,\n+\t\t.num_custom_params = ARRAY_SIZE(max96717_cfg_params),\n+\t};\n+\n+\tret = devm_pinctrl_register_and_init(dev, &priv->pctldesc, priv, &priv->pctldev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = pinctrl_enable(priv->pctldev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tpriv->gc = (struct gpio_chip) {\n+\t\t.owner = THIS_MODULE,\n+\t\t.label = MAX96717_GPIOCHIP_NAME,\n+\t\t.base = -1,\n+\t\t.ngpio = MAX96717_GPIO_NUM,\n+\t\t.parent = dev,\n+\t\t.can_sleep = true,\n+\t\t.request = gpiochip_generic_request,\n+\t\t.free = gpiochip_generic_free,\n+\t\t.set_config = gpiochip_generic_config,\n+\t\t.get_direction = max96717_gpio_get_direction,\n+\t\t.direction_input = max96717_gpio_direction_input,\n+\t\t.direction_output = max96717_gpio_direction_output,\n+\t\t.get = max96717_gpio_get,\n+\t\t.set = max96717_gpio_set,\n+\t};\n+\n+\treturn devm_gpiochip_add_data(dev, &priv->gc, priv);\n+}\n+\n+static int max96717_probe(struct i2c_client *client)\n+{\n+\tstruct device *dev = &client->dev;\n+\tstruct max96717_priv *priv;\n+\tstruct max_ser_ops *ops;\n+\tint ret;\n+\n+\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);\n+\tif (!ops)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->info = device_get_match_data(dev);\n+\tif (!priv->info) {\n+\t\tdev_err(dev, \"Failed to get match data\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tpriv->dev = dev;\n+\tpriv->client = client;\n+\ti2c_set_clientdata(client, priv);\n+\n+\tpriv->regmap = devm_regmap_init_i2c(client, &max96717_i2c_regmap);\n+\tif (IS_ERR(priv->regmap))\n+\t\treturn PTR_ERR(priv->regmap);\n+\n+\t*ops = max96717_ops;\n+\n+\tif (priv->info->modes & BIT(MAX_SERDES_GMSL_TUNNEL_MODE))\n+\t\tops->set_tunnel_enable = max96717_set_tunnel_enable;\n+\n+\tops->modes = priv->info->modes;\n+\tops->num_pipes = priv->info->num_pipes;\n+\tops->num_dts_per_pipe = priv->info->num_dts_per_pipe;\n+\tops->num_phys = priv->info->num_phys;\n+\tpriv->ser.ops = ops;\n+\n+\tret = max96717_wait_for_device(priv);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = max96717_gpiochip_probe(priv);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = max96717_register_clkout(priv);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn max_ser_probe(client, &priv->ser);\n+}\n+\n+static void max96717_remove(struct i2c_client *client)\n+{\n+\tstruct max96717_priv *priv = i2c_get_clientdata(client);\n+\n+\tmax_ser_remove(&priv->ser);\n+}\n+\n+static const struct max96717_chip_info max9295a_info = {\n+\t.modes = BIT(MAX_SERDES_GMSL_PIXEL_MODE),\n+\t.num_pipes = 4,\n+\t.num_dts_per_pipe = 2,\n+\t.pipe_hw_ids = { 0, 1, 2, 3 },\n+\t.num_phys = 1,\n+\t.phy_hw_ids = { 1 },\n+};\n+\n+static const struct max96717_chip_info max96717_info = {\n+\t.modes = BIT(MAX_SERDES_GMSL_PIXEL_MODE) |\n+\t\t BIT(MAX_SERDES_GMSL_TUNNEL_MODE),\n+\t.supports_3_data_lanes = true,\n+\t.supports_pkt_cnt = true,\n+\t.supports_noncontinuous_clock = true,\n+\t.num_pipes = 1,\n+\t.num_dts_per_pipe = 4,\n+\t.pipe_hw_ids = { 2 },\n+\t.num_phys = 1,\n+\t.phy_hw_ids = { 1 },\n+};\n+\n+static const struct of_device_id max96717_of_ids[] = {\n+\t{ .compatible = \"maxim,max9295a\", .data = &max9295a_info },\n+\t{ .compatible = \"maxim,max96717\", .data = &max96717_info },\n+\t{ .compatible = \"maxim,max96717f\", .data = &max96717_info },\n+\t{ .compatible = \"maxim,max96793\", .data = &max96717_info },\n+\t{ }\n+};\n+MODULE_DEVICE_TABLE(of, max96717_of_ids);\n+\n+static struct i2c_driver max96717_i2c_driver = {\n+\t.driver\t= {\n+\t\t.name = MAX96717_NAME,\n+\t\t.of_match_table = max96717_of_ids,\n+\t},\n+\t.probe = max96717_probe,\n+\t.remove = max96717_remove,\n+};\n+\n+module_i2c_driver(max96717_i2c_driver);\n+\n+MODULE_IMPORT_NS(\"MAX_SERDES\");\n+MODULE_DESCRIPTION(\"MAX96717 GMSL2 Serializer Driver\");\n+MODULE_AUTHOR(\"Cosmin Tanislav <cosmin.tanislav@analog.com>\");\n+MODULE_LICENSE(\"GPL\");\n","prefixes":["v10","16/22"]}