Linux GPIO subsystem development
 help / color / mirror / Atom feed
From: "Niklas Söderlund" <niklas.soderlund@ragnatech.se>
To: dumitru.ceclan@analog.com
Cc: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Sakari Ailus <sakari.ailus@linux.intel.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Julien Massot <julien.massot@collabora.com>,
	Rob Herring <robh@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Cosmin Tanislav <cosmin.tanislav@analog.com>,
	mitrutzceclan@gmail.com, linux-media@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-staging@lists.linux.dev, linux-gpio@vger.kernel.org,
	Martin Hecht <Martin.Hecht@avnet.eu>,
	Cosmin Tanislav <demonsingur@gmail.com>
Subject: Re: [PATCH v11 16/22] media: i2c: maxim-serdes: add MAX96717 driver
Date: Fri, 15 May 2026 20:12:32 +0200	[thread overview]
Message-ID: <20260515181232.GP332351@ragnatech.se> (raw)
In-Reply-To: <20260511-gmsl2-3_serdes-v11-16-fc163073c16b@analog.com>

Hi Dumitru,

Thanks for your work.

On 2026-05-11 15:26:39 +0300, Dumitru Ceclan via B4 Relay wrote:
> From: Cosmin Tanislav <demonsingur@gmail.com>
> 
> Add a new MAX96717 driver that also supports MAX9295A, MAX96717F and
> MAX96793.
> 
> Integrate it with the common serializer framework, while keeping
> compatibility with existing usecases, avoiding code duplication, and
> also enabling more features across all chips.
> 
> Signed-off-by: Cosmin Tanislav <demonsingur@gmail.com>
> ---
>  drivers/media/i2c/maxim-serdes/Kconfig    |   18 +
>  drivers/media/i2c/maxim-serdes/Makefile   |    1 +
>  drivers/media/i2c/maxim-serdes/max96717.c | 1686 +++++++++++++++++++++++++++++
>  3 files changed, 1705 insertions(+)
> 
> diff --git a/drivers/media/i2c/maxim-serdes/Kconfig b/drivers/media/i2c/maxim-serdes/Kconfig
> index f5a4ca80a263..ddbb5791e934 100644
> --- a/drivers/media/i2c/maxim-serdes/Kconfig
> +++ b/drivers/media/i2c/maxim-serdes/Kconfig
> @@ -15,3 +15,21 @@ config VIDEO_MAXIM_SERDES
>  
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called max_serdes.
> +
> +config VIDEO_MAX96717
> +	tristate "Maxim MAX96717 Serializer support"
> +	depends on COMMON_CLK
> +	depends on I2C
> +	depends on PINCTRL
> +	select VIDEO_MAXIM_SERDES
> +	select GENERIC_PINCONF
> +	select GENERIC_PINCTRL_GROUPS
> +	select GENERIC_PINMUX_FUNCTIONS
> +	select GPIOLIB
> +	help
> +	  This driver supports the Maxim MAX9295A, MAX96717, MAX96717F,
> +	  MAX96793 Serializers, which receive video on a MIPI CSI-2
> +	  interface and output it on a GMSL2/3 link.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called max96717.
> diff --git a/drivers/media/i2c/maxim-serdes/Makefile b/drivers/media/i2c/maxim-serdes/Makefile
> index b54326a5c81b..04abda6a5437 100644
> --- a/drivers/media/i2c/maxim-serdes/Makefile
> +++ b/drivers/media/i2c/maxim-serdes/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0
>  max-serdes-objs := max_serdes.o max_ser.o max_des.o
>  obj-$(CONFIG_VIDEO_MAXIM_SERDES) += max-serdes.o
> +obj-$(CONFIG_VIDEO_MAX96717) += max96717.o
> diff --git a/drivers/media/i2c/maxim-serdes/max96717.c b/drivers/media/i2c/maxim-serdes/max96717.c
> new file mode 100644
> index 000000000000..a23aa2784713
> --- /dev/null
> +++ b/drivers/media/i2c/maxim-serdes/max96717.c
> @@ -0,0 +1,1686 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Maxim MAX96717 GMSL2 Serializer Driver
> + *
> + * Copyright (C) 2025 Analog Devices Inc.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/iopoll.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/pinconf.h>
> +#include <linux/pinctrl/pinconf-generic.h>
> +#include <linux/regmap.h>
> +
> +#include "max_ser.h"
> +
> +#define MAX96717_REG0				0x0
> +
> +#define MAX96717_REG2				0x2
> +#define MAX96717_REG2_VID_TX_EN_P(p)		BIT(4 + (p))
> +
> +#define MAX96717_REG3				0x3
> +#define MAX96717_REG3_RCLKSEL			GENMASK(1, 0)
> +#define MAX96717_REG3_RCLK_ALT			BIT(2)
> +
> +#define MAX96717_REG6				0x6
> +#define MAX96717_REG6_RCLKEN			BIT(5)
> +
> +#define MAX96717_I2C_2(x)			(0x42 + (x) * 0x2)
> +#define MAX96717_I2C_2_SRC			GENMASK(7, 1)
> +
> +#define MAX96717_I2C_3(x)			(0x43 + (x) * 0x2)
> +#define MAX96717_I2C_3_DST			GENMASK(7, 1)
> +
> +#define MAX96717_TX3(p)				(0x53 + (p) * 0x4)
> +#define MAX96717_TX3_TX_STR_SEL			GENMASK(1, 0)
> +
> +#define MAX96717_VIDEO_TX0(p)			(0x100 + (p) * 0x8)
> +#define MAX96717_VIDEO_TX0_AUTO_BPP		BIT(3)
> +
> +#define MAX96717_VIDEO_TX1(p)			(0x101 + (p) * 0x8)
> +#define MAX96717_VIDEO_TX1_BPP			GENMASK(5, 0)
> +
> +#define MAX96717_VIDEO_TX2(p)			(0x102 + (p) * 0x8)
> +#define MAX96717_VIDEO_TX2_PCLKDET		BIT(7)
> +#define MAX96717_VIDEO_TX2_DRIFT_DET_EN		BIT(1)
> +
> +#define MAX96717_VTX0(p)			(0x1c8 + (p) * 0x43)
> +#define MAX96717_VTX0_VTG_MODE			GENMASK(1, 0)
> +#define MAX96717_VTX0_VTG_MODE_FREE_RUNNING	0b11
> +#define MAX96717_VTX0_DE_INV			BIT(2)
> +#define MAX96717_VTX0_HS_INV			BIT(3)
> +#define MAX96717_VTX0_VS_INV			BIT(4)
> +#define MAX96717_VTX0_GEN_DE			BIT(5)
> +#define MAX96717_VTX0_GEN_HS			BIT(6)
> +#define MAX96717_VTX0_GEN_VS			BIT(7)
> +
> +#define MAX96717_VTX1(p)			(0x1c9 + (p) * 0x43)
> +#define MAX96717_VTX1_PATGEN_CLK_SRC		GENMASK(3, 1)
> +#define MAX96717_VTX1_PATGEN_CLK_SRC_25MHZ	0b100
> +#define MAX96717_VTX1_PATGEN_CLK_SRC_75MHZ	0b101
> +#define MAX96717_VTX1_PATGEN_CLK_SRC_150MHZ	0b110
> +#define MAX96717_VTX1_PATGEN_CLK_SRC_375MHZ	0b111
> +
> +#define MAX96717_VTX2_VS_DLY_2(p)		(0x1ca + (p) * 0x43)
> +#define MAX96717_VTX5_VS_HIGH_2(p)		(0x1cd + (p) * 0x43)
> +#define MAX96717_VTX8_VS_LOW_2(p)		(0x1d0 + (p) * 0x43)
> +#define MAX96717_VTX11_V2H_2(p)			(0x1d3 + (p) * 0x43)
> +#define MAX96717_VTX14_HS_HIGH_1(p)		(0x1d6 + (p) * 0x43)
> +#define MAX96717_VTX16_HS_LOW_1(p)		(0x1d8 + (p) * 0x43)
> +#define MAX96717_VTX18_HS_CNT_1(p)		(0x1da + (p) * 0x43)
> +#define MAX96717_VTX20_V2D_2(p)			(0x1dc + (p) * 0x43)
> +#define MAX96717_VTX23_DE_HIGH_1(p)		(0x1df + (p) * 0x43)
> +#define MAX96717_VTX25_DE_LOW_1(p)		(0x1e1 + (p) * 0x43)
> +#define MAX96717_VTX27_DE_CNT_1(p)		(0x1e3 + (p) * 0x43)
> +#define MAX96717_VTX29(p)			(0x1e5 + (p) * 0x43)
> +
> +#define MAX96717_VTX29_PATGEN_MODE		GENMASK(1, 0)
> +#define MAX96717_VTX29_PATGEN_MODE_DISABLED	0b00
> +#define MAX96717_VTX29_PATGEN_MODE_CHECKER	0b01
> +#define MAX96717_VTX29_PATGEN_MODE_GRADIENT	0b10
> +
> +#define MAX96717_VTX30_GRAD_INCR(p)		(0x1e6 + (p) * 0x43)
> +#define MAX96717_VTX31_CHKR_A_L(p)		(0x1e7 + (p) * 0x43)
> +#define MAX96717_VTX34_CHKR_B_L(p)		(0x1ea + (p) * 0x43)
> +#define MAX96717_VTX37_CHKR_RPT_A(p)		(0x1ed + (p) * 0x43)
> +#define MAX96717_VTX38_CHKR_RPT_B(p)		(0x1ee + (p) * 0x43)
> +#define MAX96717_VTX39_CHKR_ALT(p)		(0x1ef + (p) * 0x43)
> +
> +#define MAX96717_GPIO_A(x)			(0x2be + (x) * 0x3)
> +#define MAX96717_GPIO_A_GPIO_OUT_DIS		BIT(0)
> +#define MAX96717_GPIO_A_GPIO_TX_EN		BIT(1)
> +#define MAX96717_GPIO_A_GPIO_RX_EN		BIT(2)
> +#define MAX96717_GPIO_A_GPIO_IN			BIT(3)
> +#define MAX96717_GPIO_A_GPIO_OUT		BIT(4)
> +#define MAX96717_GPIO_A_TX_COMP_EN		BIT(5)
> +#define MAX96717_GPIO_A_RES_CFG			BIT(7)
> +
> +#define MAX96717_GPIO_B(x)			(0x2bf + (x) * 0x3)
> +#define MAX96717_GPIO_B_GPIO_TX_ID		GENMASK(4, 0)
> +#define MAX96717_GPIO_B_OUT_TYPE		BIT(5)
> +#define MAX96717_GPIO_B_PULL_UPDN_SEL		GENMASK(7, 6)
> +#define MAX96717_GPIO_B_PULL_UPDN_SEL_NONE	0b00
> +#define MAX96717_GPIO_B_PULL_UPDN_SEL_PU	0b01
> +#define MAX96717_GPIO_B_PULL_UPDN_SEL_PD	0b10
> +
> +#define MAX96717_GPIO_C(x)			(0x2c0 + (x) * 0x3)
> +#define MAX96717_GPIO_C_GPIO_RX_ID		GENMASK(4, 0)
> +
> +#define MAX96717_CMU2				0x302
> +#define MAX96717_CMU2_PFDDIV_RSHORT		GENMASK(6, 4)
> +#define MAX96717_CMU2_PFDDIV_RSHORT_1_1V	0b001
> +
> +#define MAX96717_FRONTTOP_0			0x308
> +#define MAX96717_FRONTTOP_0_CLK_SEL_P(x)	BIT(x)
> +#define MAX96717_FRONTTOP_0_START_PORT(x)	BIT((x) + 4)
> +
> +#define MAX96717_FRONTTOP_1(p)			(0x309 + (p) * 0x2)
> +#define MAX96717_FRONTTOP_2(p)			(0x30a + (p) * 0x2)
> +
> +#define MAX96717_FRONTTOP_9			0x311
> +#define MAX96717_FRONTTOP_9_START_PORT(p, x)	BIT((p) + (x) * 4)
> +
> +#define MAX96717_FRONTTOP_10			0x312
> +#define MAX96717_FRONTTOP_10_BPP8DBL(p)		BIT(p)
> +
> +#define MAX96717_FRONTTOP_11			0x313
> +#define MAX96717_FRONTTOP_11_BPP10DBL(p)	BIT(p)
> +#define MAX96717_FRONTTOP_11_BPP12DBL(p)	BIT((p) + 4)
> +
> +#define MAX96717_FRONTTOP_12(p, x)		(0x314 + (p) * 0x2 + (x))
> +#define MAX96717_MEM_DT_SEL			GENMASK(5, 0)
> +#define MAX96717_MEM_DT_EN			BIT(6)
> +
> +#define MAX96717_FRONTTOP_20(p)			(0x31c + (p) * 0x1)
> +#define MAX96717_FRONTTOP_20_SOFT_BPP_EN	BIT(5)
> +#define MAX96717_FRONTTOP_20_SOFT_BPP		GENMASK(4, 0)
> +
> +#define MAX96717_MIPI_RX0			0x330
> +#define MAX96717_MIPI_RX0_NONCONTCLK_EN		BIT(6)
> +
> +#define MAX96717_MIPI_RX1			0x331
> +#define MAX96717_MIPI_RX1_CTRL_NUM_LANES	GENMASK(5, 4)
> +
> +#define MAX96717_MIPI_RX2			0x332
> +#define MAX96717_MIPI_RX2_PHY1_LANE_MAP		GENMASK(7, 4)
> +
> +#define MAX96717_MIPI_RX3			0x333
> +#define MAX96717_MIPI_RX3_PHY2_LANE_MAP		GENMASK(3, 0)
> +
> +#define MAX96717_MIPI_RX4			0x334
> +#define MAX96717_MIPI_RX4_PHY1_POL_MAP		GENMASK(5, 4)
> +
> +#define MAX96717_MIPI_RX5			0x335
> +#define MAX96717_MIPI_RX5_PHY2_POL_MAP		GENMASK(1, 0)
> +#define MAX96717_MIPI_RX5_PHY2_POL_MAP_CLK	BIT(2)
> +
> +#define MAX96717_EXTA(x)			(0x3dc + (x))
> +
> +#define MAX96717_EXT11				0x383
> +#define MAX96717_EXT11_TUN_MODE			BIT(7)
> +
> +#define MAX96717_EXT21				0x38d
> +#define MAX96717_EXT22				0x38e
> +#define MAX96717_EXT23				0x38f
> +#define MAX96717_EXT24				0x390
> +
> +#define MAX96717_REF_VTG0			0x3f0
> +#define MAX96717_REF_VTG0_REFGEN_EN		BIT(0)
> +#define MAX96717_REF_VTG0_REFGEN_RST		BIT(1)
> +#define MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ_ALT\
> +						BIT(3)
> +#define MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ	GENMASK(5, 4)
> +
> +#define MAX96717_PIO_SLEW_0			0x56f
> +#define MAX96717_PIO_SLEW_0_PIO00_SLEW		GENMASK(1, 0)
> +#define MAX96717_PIO_SLEW_0_PIO01_SLEW		GENMASK(3, 2)
> +#define MAX96717_PIO_SLEW_0_PIO02_SLEW		GENMASK(5, 4)
> +
> +#define MAX96717_PIO_SLEW_1			0x570
> +#define MAX96717_PIO_SLEW_1_PIO05_SLEW		GENMASK(3, 2)
> +#define MAX96717_PIO_SLEW_1_PIO06_SLEW		GENMASK(5, 4)
> +
> +#define MAX96717_PIO_SLEW_2			0x571
> +#define MAX96717_PIO_SLEW_2_PIO010_SLEW		GENMASK(5, 4)
> +#define MAX96717_PIO_SLEW_2_PIO011_SLEW		GENMASK(7, 6)
> +
> +#define MAX96717_PIO_SLEW_FASTEST		0b00
> +
> +#define MAX96717_BIAS_PULL_STRENGTH_1000000_OHM	1000000U
> +#define MAX96717_BIAS_PULL_STRENGTH_40000_OHM	40000U
> +
> +#define MAX96717_DEFAULT_CLKOUT_RATE		24000000UL
> +
> +#define MAX96717_NAME				"max96717"
> +#define MAX96717_PINCTRL_NAME			MAX96717_NAME "-pinctrl"
> +#define MAX96717_GPIOCHIP_NAME			MAX96717_NAME "-gpiochip"
> +#define MAX96717_GPIO_NUM			11
> +#define MAX96717_RCLK_ALT_MFP			2
> +#define MAX96717_RCLK_MFP			4
> +#define MAX96717_PIPES_NUM			4
> +#define MAX96717_PHYS_NUM			2
> +
> +struct max96717_priv {
> +	struct max_ser ser;
> +	struct pinctrl_desc pctldesc;
> +	struct gpio_chip gc;
> +	const struct max96717_chip_info *info;
> +
> +	struct device *dev;
> +	struct i2c_client *client;
> +	struct regmap *regmap;
> +	struct pinctrl_dev *pctldev;
> +
> +	struct clk_hw clk_hw;
> +	u8 pll_predef_index;
> +};
> +
> +struct max96717_chip_info {
> +	bool supports_3_data_lanes;
> +	bool supports_noncontinuous_clock;
> +	bool supports_pkt_cnt;
> +	unsigned int modes;
> +	unsigned int num_pipes;
> +	unsigned int num_dts_per_pipe;
> +	unsigned int pipe_hw_ids[MAX96717_PIPES_NUM];
> +	unsigned int num_phys;
> +	unsigned int phy_hw_ids[MAX96717_PHYS_NUM];
> +};
> +
> +#define ser_to_priv(_ser) \
> +	container_of(_ser, struct max96717_priv, ser)
> +
> +static inline struct max96717_priv *clk_hw_to_priv(struct clk_hw *hw)
> +{
> +	return container_of(hw, struct max96717_priv, clk_hw);
> +}
> +
> +static const struct regmap_config max96717_i2c_regmap = {
> +	.reg_bits = 16,
> +	.val_bits = 8,
> +	.max_register = 0x1f00,
> +};
> +
> +static int max96717_wait_for_device(struct max96717_priv *priv)
> +{
> +	unsigned int val;
> +	int ret, err;
> +
> +	err = read_poll_timeout(regmap_read, ret,
> +				!ret && val,
> +				100 * USEC_PER_MSEC,
> +				1 * USEC_PER_SEC, false,
> +				priv->regmap, MAX96717_REG0, &val);
> +	if (err)
> +		dev_err(priv->dev, "Timeout waiting for serializer: %d\n", ret);
> +
> +	return err;
> +}
> +
> +#define MAX96717_PIN(n) \
> +	PINCTRL_PIN(n, "mfp" __stringify(n))
> +
> +static const struct pinctrl_pin_desc max96717_pins[] = {
> +	MAX96717_PIN(0),
> +	MAX96717_PIN(1),
> +	MAX96717_PIN(2),
> +	MAX96717_PIN(3),
> +	MAX96717_PIN(4),
> +	MAX96717_PIN(5),
> +	MAX96717_PIN(6),
> +	MAX96717_PIN(7),
> +	MAX96717_PIN(8),
> +	MAX96717_PIN(9),
> +	MAX96717_PIN(10),
> +};
> +
> +#define MAX96717_GROUP_PINS(name, ...) \
> +	static const unsigned int name ## _pins[] = { __VA_ARGS__ }
> +
> +MAX96717_GROUP_PINS(mfp0, 0);
> +MAX96717_GROUP_PINS(mfp1, 1);
> +MAX96717_GROUP_PINS(mfp2, 2);
> +MAX96717_GROUP_PINS(mfp3, 3);
> +MAX96717_GROUP_PINS(mfp4, 4);
> +MAX96717_GROUP_PINS(mfp5, 5);
> +MAX96717_GROUP_PINS(mfp6, 6);
> +MAX96717_GROUP_PINS(mfp7, 7);
> +MAX96717_GROUP_PINS(mfp8, 8);
> +MAX96717_GROUP_PINS(mfp9, 9);
> +MAX96717_GROUP_PINS(mfp10, 10);
> +
> +#define MAX96717_GROUP(name) \
> +	PINCTRL_PINGROUP(__stringify(name), name ## _pins, ARRAY_SIZE(name ## _pins))
> +
> +static const struct pingroup max96717_ctrl_groups[] = {
> +	MAX96717_GROUP(mfp0),
> +	MAX96717_GROUP(mfp1),
> +	MAX96717_GROUP(mfp2),
> +	MAX96717_GROUP(mfp3),
> +	MAX96717_GROUP(mfp4),
> +	MAX96717_GROUP(mfp5),
> +	MAX96717_GROUP(mfp6),
> +	MAX96717_GROUP(mfp7),
> +	MAX96717_GROUP(mfp8),
> +	MAX96717_GROUP(mfp9),
> +	MAX96717_GROUP(mfp10),
> +};
> +
> +#define MAX96717_FUNC_GROUPS(name, ...) \
> +	static const char * const name ## _groups[] = { __VA_ARGS__ }
> +
> +MAX96717_FUNC_GROUPS(gpio, "mfp0", "mfp1", "mfp2", "mfp3", "mfp4", "mfp5",
> +		     "mfp6", "mfp7", "mfp8", "mfp9", "mfp10");
> +MAX96717_FUNC_GROUPS(rclkout, "mfp2", "mfp4");
> +
> +enum max96717_func {
> +	max96717_func_gpio,
> +	max96717_func_rclkout,
> +};
> +
> +#define MAX96717_FUNC(name)						\
> +	[max96717_func_ ## name] =					\
> +		PINCTRL_PINFUNCTION(__stringify(name), name ## _groups,	\
> +				    ARRAY_SIZE(name ## _groups))
> +
> +static const struct pinfunction max96717_functions[] = {
> +	MAX96717_FUNC(gpio),
> +	MAX96717_FUNC(rclkout),
> +};
> +
> +#define MAX96717_PINCTRL_X(x)			(PIN_CONFIG_END + (x))
> +#define MAX96717_PINCTRL_JITTER_COMPENSATION_EN	MAX96717_PINCTRL_X(1)
> +#define MAX96717_PINCTRL_TX_ID			MAX96717_PINCTRL_X(2)
> +#define MAX96717_PINCTRL_RX_ID			MAX96717_PINCTRL_X(3)
> +#define MAX96717_PINCTRL_PULL_STRENGTH_HIGH	MAX96717_PINCTRL_X(4)
> +#define MAX96717_PINCTRL_INPUT_VALUE		MAX96717_PINCTRL_X(5)
> +#define MAX96717_PINCTRL_TX_EN			MAX96717_PINCTRL_X(6)
> +#define MAX96717_PINCTRL_RX_EN			MAX96717_PINCTRL_X(7)
> +
> +static const struct pinconf_generic_params max96717_cfg_params[] = {
> +	{ "maxim,jitter-compensation", MAX96717_PINCTRL_JITTER_COMPENSATION_EN, 0 },
> +	{ "maxim,tx-id", MAX96717_PINCTRL_TX_ID, 0 },
> +	{ "maxim,rx-id", MAX96717_PINCTRL_RX_ID, 0 },
> +};
> +
> +static int max96717_ctrl_get_groups_count(struct pinctrl_dev *pctldev)
> +{
> +	return ARRAY_SIZE(max96717_ctrl_groups);
> +}
> +
> +static const char *max96717_ctrl_get_group_name(struct pinctrl_dev *pctldev,
> +						unsigned int selector)
> +{
> +	return max96717_ctrl_groups[selector].name;
> +}
> +
> +static int max96717_ctrl_get_group_pins(struct pinctrl_dev *pctldev,
> +					unsigned int selector,
> +					const unsigned int **pins,
> +					unsigned int *num_pins)
> +{
> +	*pins = (unsigned int *)max96717_ctrl_groups[selector].pins;
> +	*num_pins = max96717_ctrl_groups[selector].npins;
> +
> +	return 0;
> +}
> +
> +static int max96717_get_pin_config_reg(unsigned int offset, u32 param,
> +				       unsigned int *reg, unsigned int *mask,
> +				       unsigned int *val)
> +{
> +	*reg = MAX96717_GPIO_A(offset);
> +
> +	switch (param) {
> +	case PIN_CONFIG_OUTPUT_ENABLE:
> +		*mask = MAX96717_GPIO_A_GPIO_OUT_DIS;
> +		*val = 0b0;
> +		return 0;
> +	case PIN_CONFIG_INPUT_ENABLE:
> +		*mask = MAX96717_GPIO_A_GPIO_OUT_DIS;
> +		*val = 0b1;
> +		return 0;
> +	case MAX96717_PINCTRL_TX_EN:
> +		*mask = MAX96717_GPIO_A_GPIO_TX_EN;
> +		*val = 0b1;
> +		return 0;
> +	case MAX96717_PINCTRL_RX_EN:
> +		*mask = MAX96717_GPIO_A_GPIO_RX_EN;
> +		*val = 0b1;
> +		return 0;
> +	case MAX96717_PINCTRL_INPUT_VALUE:
> +		*mask = MAX96717_GPIO_A_GPIO_IN;
> +		*val = 0b1;
> +		return 0;
> +	case PIN_CONFIG_LEVEL:
> +		*mask = MAX96717_GPIO_A_GPIO_OUT;
> +		*val = 0b1;
> +		return 0;
> +	case MAX96717_PINCTRL_JITTER_COMPENSATION_EN:
> +		*mask = MAX96717_GPIO_A_TX_COMP_EN;
> +		*val = 0b1;
> +		return 0;
> +	case MAX96717_PINCTRL_PULL_STRENGTH_HIGH:
> +		*mask = MAX96717_GPIO_A_RES_CFG;
> +		*val = 0b1;
> +		return 0;
> +	}
> +
> +	*reg = MAX96717_GPIO_B(offset);
> +
> +	switch (param) {
> +	case MAX96717_PINCTRL_TX_ID:
> +		*mask = MAX96717_GPIO_B_GPIO_TX_ID;
> +		return 0;
> +	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
> +		*mask = MAX96717_GPIO_B_OUT_TYPE;
> +		*val = 0b0;
> +		return 0;
> +	case PIN_CONFIG_DRIVE_PUSH_PULL:
> +		*mask = MAX96717_GPIO_B_OUT_TYPE;
> +		*val = 0b1;
> +		return 0;
> +	case PIN_CONFIG_BIAS_DISABLE:
> +		*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;
> +		*val = MAX96717_GPIO_B_PULL_UPDN_SEL_NONE;
> +		return 0;
> +	case PIN_CONFIG_BIAS_PULL_DOWN:
> +		*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;
> +		*val = MAX96717_GPIO_B_PULL_UPDN_SEL_PD;
> +		return 0;
> +	case PIN_CONFIG_BIAS_PULL_UP:
> +		*mask = MAX96717_GPIO_B_PULL_UPDN_SEL;
> +		*val = MAX96717_GPIO_B_PULL_UPDN_SEL_PU;
> +		return 0;
> +	}
> +
> +	switch (param) {
> +	case PIN_CONFIG_SLEW_RATE:
> +		if (offset < 3) {
> +			*reg = MAX96717_PIO_SLEW_0;
> +			if (offset == 0)
> +				*mask = MAX96717_PIO_SLEW_0_PIO00_SLEW;
> +			else if (offset == 1)
> +				*mask = MAX96717_PIO_SLEW_0_PIO01_SLEW;
> +			else
> +				*mask = MAX96717_PIO_SLEW_0_PIO02_SLEW;
> +		} else if (offset < 5) {
> +			*reg = MAX96717_PIO_SLEW_1;
> +			if (offset == 3)
> +				*mask = MAX96717_PIO_SLEW_1_PIO05_SLEW;
> +			else
> +				*mask = MAX96717_PIO_SLEW_1_PIO06_SLEW;
> +		} else if (offset < 7) {
> +			return -EINVAL;
> +		} else if (offset < 9) {
> +			*reg  = MAX96717_PIO_SLEW_2;
> +			if (offset == 7)
> +				*mask = MAX96717_PIO_SLEW_2_PIO010_SLEW;
> +			else
> +				*mask = MAX96717_PIO_SLEW_2_PIO011_SLEW;
> +		} else {
> +			return -EINVAL;
> +		}
> +		return 0;
> +	case MAX96717_PINCTRL_RX_ID:
> +		*reg = MAX96717_GPIO_C(offset);
> +		*mask = MAX96717_GPIO_C_GPIO_RX_ID;
> +		return 0;
> +	default:
> +		return -ENOTSUPP;
> +	}
> +}
> +
> +static int max96717_conf_pin_config_get(struct pinctrl_dev *pctldev,
> +					unsigned int offset,
> +					unsigned long *config)
> +{
> +	struct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);
> +	u32 param = pinconf_to_config_param(*config);
> +	unsigned int reg, mask, val, en_val;
> +	int ret;
> +
> +	ret = max96717_get_pin_config_reg(offset, param, &reg, &mask, &en_val);
> +	if (ret)
> +		return ret;
> +
> +	switch (param) {
> +	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
> +	case PIN_CONFIG_DRIVE_PUSH_PULL:
> +	case PIN_CONFIG_BIAS_DISABLE:
> +	case PIN_CONFIG_BIAS_PULL_DOWN:
> +	case PIN_CONFIG_BIAS_PULL_UP:
> +	case MAX96717_PINCTRL_JITTER_COMPENSATION_EN:
> +	case MAX96717_PINCTRL_TX_EN:
> +	case MAX96717_PINCTRL_RX_EN:
> +	case PIN_CONFIG_OUTPUT_ENABLE:
> +	case PIN_CONFIG_INPUT_ENABLE:
> +		ret = regmap_read(priv->regmap, reg, &val);
> +		if (ret)
> +			return ret;
> +
> +		val = field_get(mask, val) == en_val;
> +		if (!val)
> +			return -EINVAL;
> +
> +		break;
> +	case MAX96717_PINCTRL_PULL_STRENGTH_HIGH:
> +	case MAX96717_PINCTRL_INPUT_VALUE:
> +	case PIN_CONFIG_LEVEL:
> +		ret = regmap_read(priv->regmap, reg, &val);
> +		if (ret)
> +			return ret;
> +
> +		val = field_get(mask, val) == en_val;
> +		break;
> +	case MAX96717_PINCTRL_TX_ID:
> +	case MAX96717_PINCTRL_RX_ID:
> +	case PIN_CONFIG_SLEW_RATE:
> +		ret = regmap_read(priv->regmap, reg, &val);
> +		if (ret)
> +			return ret;
> +
> +		val = field_get(mask, val);
> +		break;
> +	default:
> +		return -ENOTSUPP;
> +	}
> +
> +	switch (param) {
> +	case PIN_CONFIG_BIAS_PULL_DOWN:
> +	case PIN_CONFIG_BIAS_PULL_UP:
> +		*config = pinconf_to_config_packed(MAX96717_PINCTRL_PULL_STRENGTH_HIGH, 0);
> +
> +		ret = max96717_conf_pin_config_get(pctldev, offset, config);
> +		if (ret)
> +			return ret;
> +
> +		val = pinconf_to_config_argument(*config);
> +		if (val)
> +			val = MAX96717_BIAS_PULL_STRENGTH_1000000_OHM;
> +		else
> +			val = MAX96717_BIAS_PULL_STRENGTH_40000_OHM;
> +
> +		break;
> +	case MAX96717_PINCTRL_TX_ID:
> +		*config = pinconf_to_config_packed(MAX96717_PINCTRL_TX_EN, 0);
> +
> +		ret = max96717_conf_pin_config_get(pctldev, offset, config);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +	case MAX96717_PINCTRL_RX_ID:
> +		*config = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 0);
> +
> +		ret = max96717_conf_pin_config_get(pctldev, offset, config);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	*config = pinconf_to_config_packed(param, val);
> +
> +	return 0;
> +}
> +
> +static int max96717_conf_pin_config_set_one(struct max96717_priv *priv,
> +					    unsigned int offset,
> +					    unsigned long config)
> +{
> +	u32 param = pinconf_to_config_param(config);
> +	u32 arg = pinconf_to_config_argument(config);
> +	unsigned int reg, mask, val, en_val;
> +	int ret;
> +
> +	ret = max96717_get_pin_config_reg(offset, param, &reg, &mask, &en_val);
> +	if (ret)
> +		return ret;
> +
> +	switch (param) {
> +	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
> +	case PIN_CONFIG_DRIVE_PUSH_PULL:
> +	case PIN_CONFIG_BIAS_DISABLE:
> +	case PIN_CONFIG_BIAS_PULL_DOWN:
> +	case PIN_CONFIG_BIAS_PULL_UP:
> +		val = field_prep(mask, en_val);
> +
> +		ret = regmap_update_bits(priv->regmap, reg, mask, val);
> +		break;
> +	case MAX96717_PINCTRL_JITTER_COMPENSATION_EN:
> +	case MAX96717_PINCTRL_PULL_STRENGTH_HIGH:
> +	case MAX96717_PINCTRL_TX_EN:
> +	case MAX96717_PINCTRL_RX_EN:
> +	case PIN_CONFIG_OUTPUT_ENABLE:
> +	case PIN_CONFIG_INPUT_ENABLE:
> +	case PIN_CONFIG_LEVEL:
> +		val = field_prep(mask, arg ? en_val : ~en_val);
> +
> +		ret = regmap_update_bits(priv->regmap, reg, mask, val);
> +		break;
> +	case MAX96717_PINCTRL_TX_ID:
> +	case MAX96717_PINCTRL_RX_ID:
> +	case PIN_CONFIG_SLEW_RATE:
> +		val = field_prep(mask, arg);
> +
> +		ret = regmap_update_bits(priv->regmap, reg, mask, val);
> +		break;
> +	default:
> +		return -ENOTSUPP;
> +	}
> +
> +	if (ret)
> +		return ret;
> +
> +	switch (param) {
> +	case PIN_CONFIG_BIAS_PULL_DOWN:
> +	case PIN_CONFIG_BIAS_PULL_UP:
> +		arg = arg >= MAX96717_BIAS_PULL_STRENGTH_1000000_OHM;
> +		config = pinconf_to_config_packed(MAX96717_PINCTRL_PULL_STRENGTH_HIGH, arg);
> +		return max96717_conf_pin_config_set_one(priv, offset, config);
> +	case PIN_CONFIG_LEVEL:
> +		config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT_ENABLE, 1);
> +		return max96717_conf_pin_config_set_one(priv, offset, config);
> +	case PIN_CONFIG_OUTPUT_ENABLE:
> +		config = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 0);
> +		return max96717_conf_pin_config_set_one(priv, offset, config);
> +	case MAX96717_PINCTRL_TX_ID:
> +		config = pinconf_to_config_packed(MAX96717_PINCTRL_TX_EN, 1);
> +		return max96717_conf_pin_config_set_one(priv, offset, config);
> +	case MAX96717_PINCTRL_RX_ID:
> +		config = pinconf_to_config_packed(MAX96717_PINCTRL_RX_EN, 1);
> +		return max96717_conf_pin_config_set_one(priv, offset, config);
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max96717_conf_pin_config_set(struct pinctrl_dev *pctldev,
> +					unsigned int offset,
> +					unsigned long *configs,
> +					unsigned int num_configs)
> +{
> +	struct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);
> +	int ret;
> +
> +	while (num_configs--) {
> +		unsigned long config = *configs;
> +
> +		ret = max96717_conf_pin_config_set_one(priv, offset, config);
> +		if (ret)
> +			return ret;
> +
> +		configs++;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max96717_mux_get_functions_count(struct pinctrl_dev *pctldev)
> +{
> +	return ARRAY_SIZE(max96717_functions);
> +}
> +
> +static const char *max96717_mux_get_function_name(struct pinctrl_dev *pctldev,
> +						  unsigned int selector)
> +{
> +	return max96717_functions[selector].name;
> +}
> +
> +static int max96717_mux_get_groups(struct pinctrl_dev *pctldev,
> +				   unsigned int selector,
> +				   const char * const **groups,
> +				   unsigned int * const num_groups)
> +{
> +	*groups = max96717_functions[selector].groups;
> +	*num_groups = max96717_functions[selector].ngroups;
> +
> +	return 0;
> +}
> +
> +static int max96717_mux_set_rclkout(struct max96717_priv *priv, unsigned int group)
> +{
> +	unsigned long config;
> +	int ret;
> +
> +	config = pinconf_to_config_packed(PIN_CONFIG_SLEW_RATE,
> +					  MAX96717_PIO_SLEW_FASTEST);
> +	ret = max96717_conf_pin_config_set_one(priv, group, config);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_assign_bits(priv->regmap, MAX96717_REG3,
> +				  MAX96717_REG3_RCLK_ALT,
> +				  group == MAX96717_RCLK_ALT_MFP);
> +}
> +
> +static int max96717_mux_set(struct pinctrl_dev *pctldev, unsigned int selector,
> +			    unsigned int group)
> +{
> +	struct max96717_priv *priv = pinctrl_dev_get_drvdata(pctldev);
> +
> +	switch (selector) {
> +	case max96717_func_rclkout:
> +		return max96717_mux_set_rclkout(priv, group);
> +	}
> +
> +	return 0;
> +}
> +
> +static int max96717_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
> +{
> +	unsigned long config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT_ENABLE, 0);
> +	struct max96717_priv *priv = gpiochip_get_data(gc);
> +	int ret;
> +
> +	ret = max96717_conf_pin_config_get(priv->pctldev, offset, &config);
> +	if (ret)
> +		return ret;
> +
> +	return pinconf_to_config_argument(config) ? GPIO_LINE_DIRECTION_OUT
> +						  : GPIO_LINE_DIRECTION_IN;
> +}
> +
> +static int max96717_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
> +{
> +	unsigned long config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
> +	struct max96717_priv *priv = gpiochip_get_data(gc);
> +
> +	return max96717_conf_pin_config_set_one(priv, offset, config);
> +}
> +
> +static int max96717_gpio_direction_output(struct gpio_chip *gc, unsigned int offset,
> +					  int value)
> +{
> +	unsigned long config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, value);
> +	struct max96717_priv *priv = gpiochip_get_data(gc);
> +
> +	return max96717_conf_pin_config_set_one(priv, offset, config);
> +}
> +
> +static int max96717_gpio_get(struct gpio_chip *gc, unsigned int offset)
> +{
> +	unsigned long config = pinconf_to_config_packed(MAX96717_PINCTRL_INPUT_VALUE, 0);
> +	struct max96717_priv *priv = gpiochip_get_data(gc);
> +	int ret;
> +
> +	ret = max96717_conf_pin_config_get(priv->pctldev, offset, &config);
> +	if (ret)
> +		return ret;
> +
> +	return pinconf_to_config_argument(config);
> +}
> +
> +static int max96717_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
> +{
> +	unsigned long config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, value);
> +	struct max96717_priv *priv = gpiochip_get_data(gc);
> +
> +	return max96717_conf_pin_config_set_one(priv, offset, config);
> +}
> +
> +static unsigned int max96717_pipe_id(struct max96717_priv *priv,
> +				     struct max_ser_pipe *pipe)
> +{
> +	return priv->info->pipe_hw_ids[pipe->index];
> +}
> +
> +static unsigned int max96717_phy_id(struct max96717_priv *priv,
> +				    struct max_ser_phy *phy)
> +{
> +	return priv->info->phy_hw_ids[phy->index];
> +}
> +
> +static int max96717_set_pipe_enable(struct max_ser *ser,
> +				    struct max_ser_pipe *pipe, bool enable)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	unsigned int mask = MAX96717_REG2_VID_TX_EN_P(index);
> +
> +	return regmap_assign_bits(priv->regmap, MAX96717_REG2, mask, enable);
> +}
> +
> +static int __maybe_unused max96717_reg_read(struct max_ser *ser, unsigned int reg,
> +					    unsigned int *val)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +
> +	return regmap_read(priv->regmap, reg, val);
> +}
> +
> +static int __maybe_unused max96717_reg_write(struct max_ser *ser, unsigned int reg,
> +					     unsigned int val)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +
> +	return regmap_write(priv->regmap, reg, val);
> +}
> +
> +static int max96717_set_pipe_dt_en(struct max_ser *ser, struct max_ser_pipe *pipe,
> +				   unsigned int i, bool enable)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	unsigned int reg;
> +
> +	if (i < 2)
> +		reg = MAX96717_FRONTTOP_12(index, i);
> +	else
> +		/*
> +		 * DT 7 and 8 are only supported on MAX96717, no need for pipe
> +		 * index to be taken into account.
> +		 */
> +		reg = MAX96717_EXTA(i - 2);
> +
> +	return regmap_assign_bits(priv->regmap, reg, MAX96717_MEM_DT_EN, enable);
> +}
> +
> +static int max96717_set_pipe_dt(struct max_ser *ser, struct max_ser_pipe *pipe,
> +				unsigned int i, unsigned int dt)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	unsigned int reg;
> +
> +	if (i < 2)
> +		reg = MAX96717_FRONTTOP_12(index,  i);
> +	else
> +		reg = MAX96717_EXTA(i - 2);
> +
> +	return regmap_update_bits(priv->regmap, reg, MAX96717_MEM_DT_SEL,
> +				  FIELD_PREP(MAX96717_MEM_DT_SEL, dt));
> +}
> +
> +static int max96717_set_pipe_vcs(struct max_ser *ser,
> +				 struct max_ser_pipe *pipe,
> +				 unsigned int vcs)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	int ret;
> +
> +	ret = regmap_write(priv->regmap, MAX96717_FRONTTOP_1(index),
> +			   (vcs >> 0) & 0xff);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_write(priv->regmap, MAX96717_FRONTTOP_2(index),
> +			      (vcs >> 8) & 0xff);
> +}
> +
> +static int max96717_log_status(struct max_ser *ser)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int val;
> +	int ret;
> +
> +	if (!(priv->info->modes & BIT(MAX_SERDES_GMSL_TUNNEL_MODE)))
> +		return 0;
> +
> +	ret = regmap_read(priv->regmap, MAX96717_EXT23, &val);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "tun_pkt_cnt: %u\n", val);
> +
> +	return 0;
> +}
> +
> +static int max96717_log_pipe_status(struct max_ser *ser,
> +				    struct max_ser_pipe *pipe)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_read(priv->regmap, MAX96717_VIDEO_TX2(index), &val);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "\tpclkdet: %u\n",
> +		 !!(val & MAX96717_VIDEO_TX2_PCLKDET));
> +
> +	return 0;
> +}
> +
> +static int max96717_log_phy_status(struct max_ser *ser,
> +				   struct max_ser_phy *phy)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int val;
> +	int ret;
> +
> +	if (!priv->info->supports_pkt_cnt)
> +		return 0;
> +
> +	ret = regmap_read(priv->regmap, MAX96717_EXT21, &val);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "\tphy_pkt_cnt: %u\n", val);
> +
> +	ret = regmap_read(priv->regmap, MAX96717_EXT22, &val);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "\tcsi_pkt_cnt: %u\n", val);
> +
> +	ret = regmap_read(priv->regmap, MAX96717_EXT24, &val);
> +	if (ret)
> +		return ret;
> +
> +	dev_info(priv->dev, "\tphy_clk_cnt: %u\n", val);
> +
> +	return 0;
> +}
> +
> +static int max96717_init_phy(struct max_ser *ser,
> +			     struct max_ser_phy *phy)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int num_data_lanes = phy->mipi.num_data_lanes;
> +	unsigned int used_data_lanes = 0;
> +	unsigned int val;
> +	unsigned int i;
> +	int ret;
> +
> +	if (num_data_lanes == 3 && !priv->info->supports_3_data_lanes) {
> +		dev_err(priv->dev, "Unsupported 3 data lane mode\n");
> +		return -EINVAL;
> +	}
> +
> +	if (phy->mipi.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK &&
> +	    !priv->info->supports_noncontinuous_clock) {
> +		dev_err(priv->dev, "Unsupported non-continuous mode\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Configure a lane count. */
> +	ret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX1,
> +				 MAX96717_MIPI_RX1_CTRL_NUM_LANES,
> +				 FIELD_PREP(MAX96717_MIPI_RX1_CTRL_NUM_LANES,
> +					    num_data_lanes - 1));
> +	if (ret)
> +		return ret;
> +
> +	/* Configure lane mapping. */
> +	val = 0;
> +	for (i = 0; i < 4; i++) {
> +		unsigned int map;
> +
> +		if (i < num_data_lanes)
> +			map = phy->mipi.data_lanes[i] - 1;
> +		else
> +			map = ffz(used_data_lanes);
> +
> +		val |= map << (i * 2);
> +		used_data_lanes |= BIT(map);
> +	}
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX3,
> +				 MAX96717_MIPI_RX3_PHY2_LANE_MAP,
> +				 FIELD_PREP(MAX96717_MIPI_RX3_PHY2_LANE_MAP, val));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX2,
> +				 MAX96717_MIPI_RX2_PHY1_LANE_MAP,
> +				 FIELD_PREP(MAX96717_MIPI_RX2_PHY1_LANE_MAP, val >> 4));
> +	if (ret)
> +		return ret;
> +
> +	/* Configure lane polarity. */
> +	for (i = 0, val = 0; i < num_data_lanes; i++)
> +		if (phy->mipi.lane_polarities[i + 1])
> +			val |= BIT(i);
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX5,
> +				 MAX96717_MIPI_RX5_PHY2_POL_MAP,
> +				 FIELD_PREP(MAX96717_MIPI_RX5_PHY2_POL_MAP, val));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_MIPI_RX4,
> +				 MAX96717_MIPI_RX4_PHY1_POL_MAP,
> +				 FIELD_PREP(MAX96717_MIPI_RX4_PHY1_POL_MAP, val >> 2));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_MIPI_RX5,
> +				 MAX96717_MIPI_RX5_PHY2_POL_MAP_CLK,
> +				 phy->mipi.lane_polarities[0]);
> +	if (ret)
> +		return ret;
> +
> +	if (priv->info->supports_noncontinuous_clock) {
> +		ret = regmap_assign_bits(priv->regmap, MAX96717_MIPI_RX0,
> +					 MAX96717_MIPI_RX0_NONCONTCLK_EN,
> +					 phy->mipi.flags &
> +					 V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max96717_set_phy_active(struct max_ser *ser, struct max_ser_phy *phy,
> +				   bool enable)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_phy_id(priv, phy);
> +
> +	return regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_0,
> +				  MAX96717_FRONTTOP_0_START_PORT(index), enable);
> +}
> +
> +static int max96717_set_pipe_stream_id(struct max_ser *ser,
> +				       struct max_ser_pipe *pipe,
> +				       unsigned int stream_id)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +
> +	return regmap_update_bits(priv->regmap, MAX96717_TX3(index),
> +				  MAX96717_TX3_TX_STR_SEL,
> +				  FIELD_PREP(MAX96717_TX3_TX_STR_SEL, stream_id));
> +}
> +
> +static int max96717_set_pipe_phy(struct max_ser *ser, struct max_ser_pipe *pipe,
> +				 struct max_ser_phy *phy)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	unsigned int phy_id = max96717_phy_id(priv, phy);
> +	int ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_0,
> +				 MAX96717_FRONTTOP_0_CLK_SEL_P(index),
> +				 phy_id == 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_9,
> +				 MAX96717_FRONTTOP_9_START_PORT(index, 0),
> +				 phy_id == 0);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_9,
> +				  MAX96717_FRONTTOP_9_START_PORT(index, 1),
> +				  phy_id == 1);
> +}
> +
> +static int max96717_set_pipe_mode(struct max_ser *ser,
> +				  struct max_ser_pipe *pipe,
> +				  struct max_ser_pipe_mode *mode)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	unsigned int index = max96717_pipe_id(priv, pipe);
> +	int ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_VIDEO_TX0(index),
> +				 MAX96717_VIDEO_TX0_AUTO_BPP, !mode->bpp);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_VIDEO_TX1(index),
> +				 MAX96717_VIDEO_TX1_BPP,
> +				 FIELD_PREP(MAX96717_VIDEO_TX1_BPP, mode->bpp));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_VIDEO_TX2(index),
> +				 MAX96717_VIDEO_TX2_DRIFT_DET_EN, !mode->bpp);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_10,
> +				 MAX96717_FRONTTOP_10_BPP8DBL(index),
> +				 mode->dbl8);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_11,
> +				 MAX96717_FRONTTOP_11_BPP10DBL(index),
> +				 mode->dbl10);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_assign_bits(priv->regmap, MAX96717_FRONTTOP_11,
> +				 MAX96717_FRONTTOP_11_BPP12DBL(index),
> +				 mode->dbl12);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(priv->regmap, MAX96717_FRONTTOP_20(index),
> +				  MAX96717_FRONTTOP_20_SOFT_BPP |
> +				  MAX96717_FRONTTOP_20_SOFT_BPP_EN,
> +				  FIELD_PREP(MAX96717_FRONTTOP_20_SOFT_BPP,
> +					     mode->soft_bpp) |
> +				  FIELD_PREP(MAX96717_FRONTTOP_20_SOFT_BPP_EN,
> +					     !!mode->soft_bpp));
> +}
> +
> +static int max96717_set_i2c_xlate(struct max_ser *ser, unsigned int i,
> +				  struct max_serdes_i2c_xlate *xlate)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	int ret;
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_I2C_2(i),
> +				 MAX96717_I2C_2_SRC,
> +				 FIELD_PREP(MAX96717_I2C_2_SRC, xlate->src));
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(priv->regmap, MAX96717_I2C_3(i),
> +				  MAX96717_I2C_3_DST,
> +				  FIELD_PREP(MAX96717_I2C_3_DST, xlate->dst));
> +}
> +
> +static int max96717_set_tunnel_enable(struct max_ser *ser, bool enable)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +
> +	return regmap_assign_bits(priv->regmap, MAX96717_EXT11,
> +				  MAX96717_EXT11_TUN_MODE, enable);
> +}
> +
> +static int max96717_set_tpg_timings(struct max96717_priv *priv,
> +				    const struct max_serdes_tpg_timings *tm,
> +				    unsigned int index)
> +{
> +	const struct reg_sequence regs[] = {
> +		REG_SEQUENCE_3(MAX96717_VTX2_VS_DLY_2(index), tm->vs_dly),
> +		REG_SEQUENCE_3(MAX96717_VTX5_VS_HIGH_2(index), tm->vs_high),
> +		REG_SEQUENCE_3(MAX96717_VTX8_VS_LOW_2(index), tm->vs_low),
> +		REG_SEQUENCE_3(MAX96717_VTX11_V2H_2(index), tm->v2h),
> +		REG_SEQUENCE_2(MAX96717_VTX14_HS_HIGH_1(index), tm->hs_high),
> +		REG_SEQUENCE_2(MAX96717_VTX16_HS_LOW_1(index), tm->hs_low),
> +		REG_SEQUENCE_2(MAX96717_VTX18_HS_CNT_1(index), tm->hs_cnt),
> +		REG_SEQUENCE_3(MAX96717_VTX20_V2D_2(index), tm->v2d),
> +		REG_SEQUENCE_2(MAX96717_VTX23_DE_HIGH_1(index), tm->de_high),
> +		REG_SEQUENCE_2(MAX96717_VTX25_DE_LOW_1(index), tm->de_low),
> +		REG_SEQUENCE_2(MAX96717_VTX27_DE_CNT_1(index), tm->de_cnt),
> +	};
> +	int ret;
> +
> +	ret = regmap_multi_reg_write(priv->regmap, regs, ARRAY_SIZE(regs));
> +	if (ret)
> +		return ret;
> +
> +	return regmap_write(priv->regmap, MAX96717_VTX0(index),
> +			    FIELD_PREP(MAX96717_VTX0_VTG_MODE,
> +				       MAX96717_VTX0_VTG_MODE_FREE_RUNNING) |
> +			    FIELD_PREP(MAX96717_VTX0_DE_INV, tm->de_inv) |
> +			    FIELD_PREP(MAX96717_VTX0_HS_INV, tm->hs_inv) |
> +			    FIELD_PREP(MAX96717_VTX0_VS_INV, tm->vs_inv) |
> +			    FIELD_PREP(MAX96717_VTX0_GEN_DE, tm->gen_de) |
> +			    FIELD_PREP(MAX96717_VTX0_GEN_HS, tm->gen_hs) |
> +			    FIELD_PREP(MAX96717_VTX0_GEN_VS, tm->gen_vs));
> +}
> +
> +static int max96717_set_tpg_clk(struct max96717_priv *priv, u32 clock,
> +				unsigned int index)
> +{
> +	u8 pclk_src;
> +
> +	switch (clock) {
> +	case 25000000:
> +		pclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_25MHZ;
> +		break;
> +	case 75000000:
> +		pclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_75MHZ;
> +		break;
> +	case 150000000:
> +		pclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_150MHZ;
> +		break;
> +	case 375000000:
> +		pclk_src = MAX96717_VTX1_PATGEN_CLK_SRC_375MHZ;
> +		break;
> +	case 0:
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return regmap_update_bits(priv->regmap, MAX96717_VTX1(index),
> +				  MAX96717_VTX1_PATGEN_CLK_SRC,
> +				  FIELD_PREP(MAX96717_VTX1_PATGEN_CLK_SRC,
> +					     pclk_src));
> +}
> +
> +static int max96717_set_tpg_mode(struct max96717_priv *priv, bool enable,
> +				 unsigned int index)
> +{
> +	unsigned int patgen_mode;
> +
> +	switch (priv->ser.tpg_pattern) {
> +	case MAX_SERDES_TPG_PATTERN_GRADIENT:
> +		patgen_mode = MAX96717_VTX29_PATGEN_MODE_GRADIENT;
> +		break;
> +	case MAX_SERDES_TPG_PATTERN_CHECKERBOARD:
> +		patgen_mode = MAX96717_VTX29_PATGEN_MODE_CHECKER;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return regmap_update_bits(priv->regmap, MAX96717_VTX29(index),
> +				  MAX96717_VTX29_PATGEN_MODE,
> +				  FIELD_PREP(MAX96717_VTX29_PATGEN_MODE,
> +					     enable ? patgen_mode
> +						    : MAX96717_VTX29_PATGEN_MODE_DISABLED));
> +}
> +
> +static int max96717_set_tpg(struct max_ser *ser,
> +			    const struct max_serdes_tpg_entry *entry)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	/*
> +	 * MAX9295A supports multiple pipes, each with a pattern generator,
> +	 * use only the first pipe for simplicity.
> +	 */
> +	unsigned int index = max96717_pipe_id(priv, &ser->pipes[0]);
> +	struct max_serdes_tpg_timings timings = { 0 };
> +	int ret;
> +
> +	ret = max_serdes_get_tpg_timings(entry, &timings);
> +	if (ret)
> +		return ret;
> +
> +	ret = max96717_set_tpg_timings(priv, &timings, index);
> +	if (ret)
> +		return ret;
> +
> +	ret = max96717_set_tpg_clk(priv, timings.clock, index);
> +	if (ret)
> +		return ret;
> +
> +	return max96717_set_tpg_mode(priv, entry, index);
> +}
> +
> +static const struct max_serdes_phys_config max96717_phys_configs[] = {
> +	{ { 4 } },
> +};
> +
> +static int max96717_init_tpg(struct max_ser *ser)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	/*
> +	 * MAX9295A supports multiple pipes, each with a pattern generator,
> +	 * use only the first pipe for simplicity.
> +	 */
> +	unsigned int index = max96717_pipe_id(priv, &ser->pipes[0]);
> +
> +	const struct reg_sequence regs[] = {
> +		{ MAX96717_VTX30_GRAD_INCR(index), MAX_SERDES_GRAD_INCR },
> +		REG_SEQUENCE_3_LE(MAX96717_VTX31_CHKR_A_L(index),
> +				  MAX_SERDES_CHECKER_COLOR_A),
> +		REG_SEQUENCE_3_LE(MAX96717_VTX34_CHKR_B_L(index),
> +				  MAX_SERDES_CHECKER_COLOR_B),
> +		{ MAX96717_VTX37_CHKR_RPT_A(index), MAX_SERDES_CHECKER_SIZE },
> +		{ MAX96717_VTX38_CHKR_RPT_B(index), MAX_SERDES_CHECKER_SIZE },
> +		{ MAX96717_VTX39_CHKR_ALT(index), MAX_SERDES_CHECKER_SIZE },
> +	};
> +
> +	return regmap_multi_reg_write(priv->regmap, regs, ARRAY_SIZE(regs));
> +}
> +
> +static int max96717_init(struct max_ser *ser)
> +{
> +	struct max96717_priv *priv = ser_to_priv(ser);
> +	int ret;
> +
> +	/*
> +	 * Set CMU2 PFDDIV to 1.1V for correct functionality of the device,
> +	 * as mentioned in the datasheet, under section MANDATORY REGISTER PROGRAMMING.
> +	 */
> +	ret = regmap_update_bits(priv->regmap, MAX96717_CMU2,
> +				 MAX96717_CMU2_PFDDIV_RSHORT,
> +				 FIELD_PREP(MAX96717_CMU2_PFDDIV_RSHORT,
> +					    MAX96717_CMU2_PFDDIV_RSHORT_1_1V));
> +	if (ret)
> +		return ret;
> +
> +	if (ser->ops->set_tunnel_enable) {
> +		ret = ser->ops->set_tunnel_enable(ser, false);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return max96717_init_tpg(ser);
> +}
> +
> +static const struct pinctrl_ops max96717_ctrl_ops = {
> +	.get_groups_count = max96717_ctrl_get_groups_count,
> +	.get_group_name = max96717_ctrl_get_group_name,
> +	.get_group_pins = max96717_ctrl_get_group_pins,
> +	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
> +	.dt_free_map = pinconf_generic_dt_free_map,
> +};
> +
> +static const struct pinconf_ops max96717_conf_ops = {
> +	.pin_config_get = max96717_conf_pin_config_get,
> +	.pin_config_set = max96717_conf_pin_config_set,
> +	.is_generic = true,
> +};
> +
> +static const struct pinmux_ops max96717_mux_ops = {
> +	.get_functions_count = max96717_mux_get_functions_count,
> +	.get_function_name = max96717_mux_get_function_name,
> +	.get_function_groups = max96717_mux_get_groups,
> +	.set_mux = max96717_mux_set,
> +};
> +
> +static const struct max_serdes_tpg_entry max96717_tpg_entries[] = {
> +	MAX_TPG_ENTRY_640X480P60_RGB888,
> +	MAX_TPG_ENTRY_1920X1080P30_RGB888,
> +	MAX_TPG_ENTRY_1920X1080P60_RGB888,
> +};
> +
> +static const struct max_ser_ops max96717_ops = {
> +	.num_i2c_xlates = 2,
> +	.phys_configs = {
> +		.num_configs = ARRAY_SIZE(max96717_phys_configs),
> +		.configs = max96717_phys_configs,
> +	},
> +	.tpg_entries = {
> +		.num_entries = ARRAY_SIZE(max96717_tpg_entries),
> +		.entries = max96717_tpg_entries,
> +	},
> +	.tpg_mode = MAX_SERDES_GMSL_PIXEL_MODE,
> +	.tpg_patterns = BIT(MAX_SERDES_TPG_PATTERN_CHECKERBOARD) |
> +			BIT(MAX_SERDES_TPG_PATTERN_GRADIENT),
> +#ifdef CONFIG_VIDEO_ADV_DEBUG
> +	.reg_read = max96717_reg_read,
> +	.reg_write = max96717_reg_write,
> +#endif
> +	.log_status = max96717_log_status,
> +	.log_pipe_status = max96717_log_pipe_status,
> +	.log_phy_status = max96717_log_phy_status,
> +	.init = max96717_init,
> +	.set_i2c_xlate = max96717_set_i2c_xlate,
> +	.set_tpg = max96717_set_tpg,
> +	.init_phy = max96717_init_phy,
> +	.set_phy_active = max96717_set_phy_active,
> +	.set_pipe_enable = max96717_set_pipe_enable,
> +	.set_pipe_dt = max96717_set_pipe_dt,
> +	.set_pipe_dt_en = max96717_set_pipe_dt_en,
> +	.set_pipe_vcs = max96717_set_pipe_vcs,
> +	.set_pipe_mode = max96717_set_pipe_mode,
> +	.set_pipe_stream_id = max96717_set_pipe_stream_id,
> +	.set_pipe_phy = max96717_set_pipe_phy,
> +};
> +
> +struct max96717_pll_predef_freq {
> +	unsigned long freq;
> +	bool is_rclk;
> +	bool is_alt;
> +	u8 val;
> +	u8 rclksel;
> +};
> +
> +static const struct max96717_pll_predef_freq max96717_predef_freqs[] = {
> +	{  6250000, true,  false, 0, 2 },
> +	{ 12500000, true,  false, 0, 1 },
> +	{ 13500000, false, true,  0, 3 },
> +	{ 19200000, false, false, 0, 3 },
> +	{ 24000000, false, true,  1, 3 },
> +	{ 25000000, true,  false, 0, 0 },
> +	{ 27000000, false, false, 1, 3 },
> +	{ 37125000, false, false, 2, 3 },
> +	{ 74250000, false, false, 3, 3 },
> +};
> +
> +static unsigned long
> +max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> +	struct max96717_priv *priv = clk_hw_to_priv(hw);
> +
> +	return max96717_predef_freqs[priv->pll_predef_index].freq;
> +}
> +
> +static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv,
> +						 unsigned long rate)
> +{
> +	unsigned int i, idx = 0;
> +	unsigned long diff_new, diff_old = U32_MAX;
> +
> +	for (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) {
> +		diff_new = abs(rate - max96717_predef_freqs[i].freq);
> +		if (diff_new < diff_old) {
> +			diff_old = diff_new;
> +			idx = i;
> +		}
> +	}
> +
> +	return idx;
> +}
> +
> +static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate,
> +				    unsigned long *parent_rate)
> +{
> +	struct max96717_priv *priv = clk_hw_to_priv(hw);
> +	struct device *dev = &priv->client->dev;
> +	unsigned int idx;
> +
> +	idx = max96717_clk_find_best_index(priv, rate);
> +
> +	if (rate != max96717_predef_freqs[idx].freq) {
> +		dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n",
> +			 rate, max96717_predef_freqs[idx].freq);
> +	}
> +
> +	return max96717_predef_freqs[idx].freq;
> +}
> +
> +static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate,
> +				 unsigned long parent_rate)
> +{
> +	const struct max96717_pll_predef_freq *predef_freq;
> +	struct max96717_priv *priv = clk_hw_to_priv(hw);
> +	unsigned int val, idx;
> +	int ret = 0;
> +
> +	idx = max96717_clk_find_best_index(priv, rate);
> +	predef_freq = &max96717_predef_freqs[idx];
> +
> +	ret = regmap_update_bits(priv->regmap, MAX96717_REG3,
> +				 MAX96717_REG3_RCLKSEL,
> +				 FIELD_PREP(MAX96717_REG3_RCLKSEL,
> +					    predef_freq->rclksel));
> +	if (ret)
> +		return ret;
> +
> +	val = FIELD_PREP(MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ,
> +			 predef_freq->val);
> +
> +	if (predef_freq->is_alt)
> +		val |= MAX96717_REF_VTG0_REFGEN_PREDEF_FREQ_ALT;
> +	if (!predef_freq->is_rclk)
> +		val |= MAX96717_REF_VTG0_REFGEN_EN;
> +
> +	val |= MAX96717_REF_VTG0_REFGEN_RST;
> +
> +	ret = regmap_write(priv->regmap, MAX96717_REF_VTG0, val);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_clear_bits(priv->regmap, MAX96717_REF_VTG0,
> +				MAX96717_REF_VTG0_REFGEN_RST);
> +	if (ret)
> +		return ret;
> +
> +	priv->pll_predef_index = idx;
> +
> +	return 0;
> +}
> +
> +static int max96717_clk_prepare(struct clk_hw *hw)
> +{
> +	struct max96717_priv *priv = clk_hw_to_priv(hw);
> +
> +	return regmap_set_bits(priv->regmap, MAX96717_REG6, MAX96717_REG6_RCLKEN);
> +}
> +
> +static void max96717_clk_unprepare(struct clk_hw *hw)
> +{
> +	struct max96717_priv *priv = clk_hw_to_priv(hw);
> +
> +	regmap_clear_bits(priv->regmap, MAX96717_REG6, MAX96717_REG6_RCLKEN);
> +}
> +
> +static const struct clk_ops max96717_clk_ops = {
> +	.prepare     = max96717_clk_prepare,
> +	.unprepare   = max96717_clk_unprepare,
> +	.set_rate    = max96717_clk_set_rate,
> +	.recalc_rate = max96717_clk_recalc_rate,
> +	.round_rate  = max96717_clk_round_rate,

The round_rate() callback seems to have been dropped as of v7.1-rc1.

Also the last there patches in this series does not apply cleanly to 
media-next anymore.

> +};
> +
> +static int max96717_register_clkout(struct max96717_priv *priv)
> +{
> +	struct device *dev = &priv->client->dev;
> +	struct clk_init_data init = { .ops = &max96717_clk_ops };
> +	int ret;
> +
> +	ret = max96717_mux_set_rclkout(priv, MAX96717_RCLK_MFP);
> +	if (ret)
> +		return ret;
> +
> +	init.name = kasprintf(GFP_KERNEL, "max96717.%s.clk_out", dev_name(dev));
> +	if (!init.name)
> +		return -ENOMEM;
> +
> +	priv->clk_hw.init = &init;
> +
> +	ret = max96717_clk_set_rate(&priv->clk_hw,
> +				    MAX96717_DEFAULT_CLKOUT_RATE, 0);
> +	if (ret)
> +		goto free_init_name;
> +
> +	ret = devm_clk_hw_register(dev, &priv->clk_hw);
> +	kfree(init.name);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Cannot register clock HW\n");
> +
> +	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
> +					  &priv->clk_hw);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Cannot add OF clock provider\n");
> +
> +	return 0;
> +
> +free_init_name:
> +	kfree(init.name);
> +	return ret;
> +}
> +
> +static int max96717_gpiochip_probe(struct max96717_priv *priv)
> +{
> +	struct device *dev = priv->dev;
> +	int ret;
> +
> +	priv->pctldesc = (struct pinctrl_desc) {
> +		.owner = THIS_MODULE,
> +		.name = MAX96717_PINCTRL_NAME,
> +		.pins = max96717_pins,
> +		.npins = ARRAY_SIZE(max96717_pins),
> +		.pctlops = &max96717_ctrl_ops,
> +		.confops = &max96717_conf_ops,
> +		.pmxops = &max96717_mux_ops,
> +		.custom_params = max96717_cfg_params,
> +		.num_custom_params = ARRAY_SIZE(max96717_cfg_params),
> +	};
> +
> +	ret = devm_pinctrl_register_and_init(dev, &priv->pctldesc, priv, &priv->pctldev);
> +	if (ret)
> +		return ret;
> +
> +	ret = pinctrl_enable(priv->pctldev);
> +	if (ret)
> +		return ret;
> +
> +	priv->gc = (struct gpio_chip) {
> +		.owner = THIS_MODULE,
> +		.label = MAX96717_GPIOCHIP_NAME,
> +		.base = -1,
> +		.ngpio = MAX96717_GPIO_NUM,
> +		.parent = dev,
> +		.can_sleep = true,
> +		.request = gpiochip_generic_request,
> +		.free = gpiochip_generic_free,
> +		.set_config = gpiochip_generic_config,
> +		.get_direction = max96717_gpio_get_direction,
> +		.direction_input = max96717_gpio_direction_input,
> +		.direction_output = max96717_gpio_direction_output,
> +		.get = max96717_gpio_get,
> +		.set = max96717_gpio_set,
> +	};
> +
> +	return devm_gpiochip_add_data(dev, &priv->gc, priv);
> +}
> +
> +static int max96717_probe(struct i2c_client *client)
> +{
> +	struct device *dev = &client->dev;
> +	struct max96717_priv *priv;
> +	struct max_ser_ops *ops;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
> +	if (!ops)
> +		return -ENOMEM;
> +
> +	priv->info = device_get_match_data(dev);
> +	if (!priv->info) {
> +		dev_err(dev, "Failed to get match data\n");
> +		return -ENODEV;
> +	}
> +
> +	priv->dev = dev;
> +	priv->client = client;
> +	i2c_set_clientdata(client, priv);
> +
> +	priv->regmap = devm_regmap_init_i2c(client, &max96717_i2c_regmap);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	*ops = max96717_ops;
> +
> +	if (priv->info->modes & BIT(MAX_SERDES_GMSL_TUNNEL_MODE))
> +		ops->set_tunnel_enable = max96717_set_tunnel_enable;
> +
> +	ops->modes = priv->info->modes;
> +	ops->num_pipes = priv->info->num_pipes;
> +	ops->num_dts_per_pipe = priv->info->num_dts_per_pipe;
> +	ops->num_phys = priv->info->num_phys;
> +	priv->ser.ops = ops;
> +
> +	ret = max96717_wait_for_device(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = max96717_gpiochip_probe(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = max96717_register_clkout(priv);
> +	if (ret)
> +		return ret;
> +
> +	return max_ser_probe(client, &priv->ser);
> +}
> +
> +static void max96717_remove(struct i2c_client *client)
> +{
> +	struct max96717_priv *priv = i2c_get_clientdata(client);
> +
> +	max_ser_remove(&priv->ser);
> +}
> +
> +static const struct max96717_chip_info max9295a_info = {
> +	.modes = BIT(MAX_SERDES_GMSL_PIXEL_MODE),
> +	.num_pipes = 4,
> +	.num_dts_per_pipe = 2,
> +	.pipe_hw_ids = { 0, 1, 2, 3 },
> +	.num_phys = 1,
> +	.phy_hw_ids = { 1 },
> +};
> +
> +static const struct max96717_chip_info max96717_info = {
> +	.modes = BIT(MAX_SERDES_GMSL_PIXEL_MODE) |
> +		 BIT(MAX_SERDES_GMSL_TUNNEL_MODE),
> +	.supports_3_data_lanes = true,
> +	.supports_pkt_cnt = true,
> +	.supports_noncontinuous_clock = true,
> +	.num_pipes = 1,
> +	.num_dts_per_pipe = 4,
> +	.pipe_hw_ids = { 2 },
> +	.num_phys = 1,
> +	.phy_hw_ids = { 1 },
> +};
> +
> +static const struct of_device_id max96717_of_ids[] = {
> +	{ .compatible = "maxim,max9295a", .data = &max9295a_info },
> +	{ .compatible = "maxim,max96717", .data = &max96717_info },
> +	{ .compatible = "maxim,max96717f", .data = &max96717_info },
> +	{ .compatible = "maxim,max96793", .data = &max96717_info },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, max96717_of_ids);
> +
> +static struct i2c_driver max96717_i2c_driver = {
> +	.driver	= {
> +		.name = MAX96717_NAME,
> +		.of_match_table = max96717_of_ids,
> +	},
> +	.probe = max96717_probe,
> +	.remove = max96717_remove,
> +};
> +
> +module_i2c_driver(max96717_i2c_driver);
> +
> +MODULE_IMPORT_NS("MAX_SERDES");
> +MODULE_DESCRIPTION("MAX96717 GMSL2 Serializer Driver");
> +MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
> +MODULE_LICENSE("GPL");
> 
> -- 
> 2.51.0
> 
> 

-- 
Kind Regards,
Niklas Söderlund

  reply	other threads:[~2026-05-15 18:12 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-11 12:26 [PATCH v11 00/22] media: i2c: add Maxim GMSL2/3 serializer and deserializer drivers Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 01/22] media: mc: Add INTERNAL pad flag Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 02/22] dt-bindings: media: i2c: max96717: add support for I2C ATR Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 03/22] dt-bindings: media: i2c: max96717: add support for pinctrl/pinconf Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 04/22] dt-bindings: media: i2c: max96717: add support for MAX9295A Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 05/22] dt-bindings: media: i2c: max96717: add support for MAX96793 Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 06/22] dt-bindings: media: i2c: max96712: use pattern properties for ports Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 07/22] dt-bindings: media: i2c: max96712: add support for I2C ATR Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 08/22] dt-bindings: media: i2c: max96712: add support for POC supplies Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 09/22] dt-bindings: media: i2c: max96712: add support for MAX96724F/R Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 10/22] dt-bindings: media: i2c: max96712: add control-channel-port property Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 11/22] dt-bindings: media: i2c: max96714: add support for MAX96714R Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 12/22] dt-bindings: media: i2c: add MAX9296A, MAX96716A, MAX96792A Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 13/22] media: i2c: add Maxim GMSL2/3 serializer and deserializer framework Dumitru Ceclan via B4 Relay
2026-05-15 18:09   ` Niklas Söderlund
2026-05-11 12:26 ` [PATCH v11 14/22] media: i2c: add Maxim GMSL2/3 serializer framework Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 15/22] media: i2c: add Maxim GMSL2/3 deserializer framework Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 16/22] media: i2c: maxim-serdes: add MAX96717 driver Dumitru Ceclan via B4 Relay
2026-05-15 18:12   ` Niklas Söderlund [this message]
2026-05-11 12:26 ` [PATCH v11 17/22] media: i2c: maxim-serdes: add MAX96724 driver Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 18/22] media: i2c: maxim-serdes: add MAX9296A driver Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 19/22] arm64: defconfig: disable deprecated MAX96712 driver Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 20/22] staging: media: remove " Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 21/22] media: i2c: remove MAX96717 driver Dumitru Ceclan via B4 Relay
2026-05-11 12:26 ` [PATCH v11 22/22] media: i2c: remove MAX96714 driver Dumitru Ceclan via B4 Relay
2026-05-15 20:00 ` [PATCH v11 00/22] media: i2c: add Maxim GMSL2/3 serializer and deserializer drivers Dayananda, Vivekananda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260515181232.GP332351@ragnatech.se \
    --to=niklas.soderlund@ragnatech.se \
    --cc=Martin.Hecht@avnet.eu \
    --cc=cosmin.tanislav@analog.com \
    --cc=demonsingur@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dumitru.ceclan@analog.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=julien.massot@collabora.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-staging@lists.linux.dev \
    --cc=mchehab@kernel.org \
    --cc=mitrutzceclan@gmail.com \
    --cc=robh@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    --cc=tomi.valkeinen+renesas@ideasonboard.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox