162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Maxim MAX9286 GMSL Deserializer Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017-2019 Jacopo Mondi
662306a36Sopenharmony_ci * Copyright (C) 2017-2019 Kieran Bingham
762306a36Sopenharmony_ci * Copyright (C) 2017-2019 Laurent Pinchart
862306a36Sopenharmony_ci * Copyright (C) 2017-2019 Niklas Söderlund
962306a36Sopenharmony_ci * Copyright (C) 2016 Renesas Electronics Corporation
1062306a36Sopenharmony_ci * Copyright (C) 2015 Cogent Embedded, Inc.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/fwnode.h>
1662306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1762306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1862306a36Sopenharmony_ci#include <linux/gpio/machine.h>
1962306a36Sopenharmony_ci#include <linux/i2c.h>
2062306a36Sopenharmony_ci#include <linux/i2c-mux.h>
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/mutex.h>
2362306a36Sopenharmony_ci#include <linux/of_graph.h>
2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <media/v4l2-async.h>
2862306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
2962306a36Sopenharmony_ci#include <media/v4l2-device.h>
3062306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
3162306a36Sopenharmony_ci#include <media/v4l2-subdev.h>
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Register 0x00 */
3462306a36Sopenharmony_ci#define MAX9286_MSTLINKSEL_AUTO		(7 << 5)
3562306a36Sopenharmony_ci#define MAX9286_MSTLINKSEL(n)		((n) << 5)
3662306a36Sopenharmony_ci#define MAX9286_EN_VS_GEN		BIT(4)
3762306a36Sopenharmony_ci#define MAX9286_LINKEN(n)		(1 << (n))
3862306a36Sopenharmony_ci/* Register 0x01 */
3962306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_ECU		(3 << 6)
4062306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_EXT		(2 << 6)
4162306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_INT_OUT	(1 << 6)
4262306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_INT_HIZ	(0 << 6)
4362306a36Sopenharmony_ci#define MAX9286_GPIEN			BIT(5)
4462306a36Sopenharmony_ci#define MAX9286_ENLMO_RSTFSYNC		BIT(2)
4562306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_AUTO		(2 << 0)
4662306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_SEMI_AUTO	(1 << 0)
4762306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_MANUAL	(0 << 0)
4862306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_L	0x06
4962306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_M	0x07
5062306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_H	0x08
5162306a36Sopenharmony_ci/* Register 0x0a */
5262306a36Sopenharmony_ci#define MAX9286_FWDCCEN(n)		(1 << ((n) + 4))
5362306a36Sopenharmony_ci#define MAX9286_REVCCEN(n)		(1 << (n))
5462306a36Sopenharmony_ci/* Register 0x0c */
5562306a36Sopenharmony_ci#define MAX9286_HVEN			BIT(7)
5662306a36Sopenharmony_ci#define MAX9286_EDC_6BIT_HAMMING	(2 << 5)
5762306a36Sopenharmony_ci#define MAX9286_EDC_6BIT_CRC		(1 << 5)
5862306a36Sopenharmony_ci#define MAX9286_EDC_1BIT_PARITY		(0 << 5)
5962306a36Sopenharmony_ci#define MAX9286_DESEL			BIT(4)
6062306a36Sopenharmony_ci#define MAX9286_INVVS			BIT(3)
6162306a36Sopenharmony_ci#define MAX9286_INVHS			BIT(2)
6262306a36Sopenharmony_ci#define MAX9286_HVSRC_D0		(2 << 0)
6362306a36Sopenharmony_ci#define MAX9286_HVSRC_D14		(1 << 0)
6462306a36Sopenharmony_ci#define MAX9286_HVSRC_D18		(0 << 0)
6562306a36Sopenharmony_ci/* Register 0x0f */
6662306a36Sopenharmony_ci#define MAX9286_0X0F_RESERVED		BIT(3)
6762306a36Sopenharmony_ci/* Register 0x12 */
6862306a36Sopenharmony_ci#define MAX9286_CSILANECNT(n)		(((n) - 1) << 6)
6962306a36Sopenharmony_ci#define MAX9286_CSIDBL			BIT(5)
7062306a36Sopenharmony_ci#define MAX9286_DBL			BIT(4)
7162306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_8BIT	(11 << 0)
7262306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_YUV_12BIT	(10 << 0)
7362306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_24BIT	(9 << 0)
7462306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW14		(8 << 0)
7562306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW12		(7 << 0)
7662306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW10		(6 << 0)
7762306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW8		(5 << 0)
7862306a36Sopenharmony_ci#define MAX9286_DATATYPE_YUV422_10BIT	(4 << 0)
7962306a36Sopenharmony_ci#define MAX9286_DATATYPE_YUV422_8BIT	(3 << 0)
8062306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB555		(2 << 0)
8162306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB565		(1 << 0)
8262306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB888		(0 << 0)
8362306a36Sopenharmony_ci/* Register 0x15 */
8462306a36Sopenharmony_ci#define MAX9286_CSI_IMAGE_TYP		BIT(7)
8562306a36Sopenharmony_ci#define MAX9286_VC(n)			((n) << 5)
8662306a36Sopenharmony_ci#define MAX9286_VCTYPE			BIT(4)
8762306a36Sopenharmony_ci#define MAX9286_CSIOUTEN		BIT(3)
8862306a36Sopenharmony_ci#define MAX9286_SWP_ENDIAN		BIT(2)
8962306a36Sopenharmony_ci#define MAX9286_EN_CCBSYB_CLK_STR	BIT(1)
9062306a36Sopenharmony_ci#define MAX9286_EN_GPI_CCBSYB		BIT(0)
9162306a36Sopenharmony_ci/* Register 0x1b */
9262306a36Sopenharmony_ci#define MAX9286_SWITCHIN(n)		(1 << ((n) + 4))
9362306a36Sopenharmony_ci#define MAX9286_ENEQ(n)			(1 << (n))
9462306a36Sopenharmony_ci/* Register 0x1c */
9562306a36Sopenharmony_ci#define MAX9286_HIGHIMM(n)		BIT((n) + 4)
9662306a36Sopenharmony_ci#define MAX9286_I2CSEL			BIT(2)
9762306a36Sopenharmony_ci#define MAX9286_HIBW			BIT(1)
9862306a36Sopenharmony_ci#define MAX9286_BWS			BIT(0)
9962306a36Sopenharmony_ci/* Register 0x27 */
10062306a36Sopenharmony_ci#define MAX9286_LOCKED			BIT(7)
10162306a36Sopenharmony_ci/* Register 0x31 */
10262306a36Sopenharmony_ci#define MAX9286_FSYNC_LOCKED		BIT(6)
10362306a36Sopenharmony_ci/* Register 0x34 */
10462306a36Sopenharmony_ci#define MAX9286_I2CLOCACK		BIT(7)
10562306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_1046NS_469NS	(3 << 5)
10662306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_938NS_352NS	(2 << 5)
10762306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_469NS_234NS	(1 << 5)
10862306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_352NS_117NS	(0 << 5)
10962306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_837KBPS	(7 << 2)
11062306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_533KBPS	(6 << 2)
11162306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_339KBPS	(5 << 2)
11262306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_173KBPS	(4 << 2)
11362306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_105KBPS	(3 << 2)
11462306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_84KBPS		(2 << 2)
11562306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_28KBPS		(1 << 2)
11662306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_8KBPS		(0 << 2)
11762306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_NONE		(3 << 0)
11862306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_1024US		(2 << 0)
11962306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_256US		(1 << 0)
12062306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_64US		(0 << 0)
12162306a36Sopenharmony_ci/* Register 0x3b */
12262306a36Sopenharmony_ci#define MAX9286_REV_TRF(n)		((n) << 4)
12362306a36Sopenharmony_ci#define MAX9286_REV_AMP(n)		((((n) - 30) / 10) << 1) /* in mV */
12462306a36Sopenharmony_ci#define MAX9286_REV_AMP_X		BIT(0)
12562306a36Sopenharmony_ci#define MAX9286_REV_AMP_HIGH		170
12662306a36Sopenharmony_ci/* Register 0x3f */
12762306a36Sopenharmony_ci#define MAX9286_EN_REV_CFG		BIT(6)
12862306a36Sopenharmony_ci#define MAX9286_REV_FLEN(n)		((n) - 20)
12962306a36Sopenharmony_ci/* Register 0x49 */
13062306a36Sopenharmony_ci#define MAX9286_VIDEO_DETECT_MASK	0x0f
13162306a36Sopenharmony_ci/* Register 0x69 */
13262306a36Sopenharmony_ci#define MAX9286_LFLTBMONMASKED		BIT(7)
13362306a36Sopenharmony_ci#define MAX9286_LOCKMONMASKED		BIT(6)
13462306a36Sopenharmony_ci#define MAX9286_AUTOCOMBACKEN		BIT(5)
13562306a36Sopenharmony_ci#define MAX9286_AUTOMASKEN		BIT(4)
13662306a36Sopenharmony_ci#define MAX9286_MASKLINK(n)		((n) << 0)
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * The sink and source pads are created to match the OF graph port numbers so
14062306a36Sopenharmony_ci * that their indexes can be used interchangeably.
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_ci#define MAX9286_NUM_GMSL		4
14362306a36Sopenharmony_ci#define MAX9286_N_SINKS			4
14462306a36Sopenharmony_ci#define MAX9286_N_PADS			5
14562306a36Sopenharmony_ci#define MAX9286_SRC_PAD			4
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct max9286_format_info {
14862306a36Sopenharmony_ci	u32 code;
14962306a36Sopenharmony_ci	u8 datatype;
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistruct max9286_i2c_speed {
15362306a36Sopenharmony_ci	u32 rate;
15462306a36Sopenharmony_ci	u8 mstbt;
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct max9286_source {
15862306a36Sopenharmony_ci	struct v4l2_subdev *sd;
15962306a36Sopenharmony_ci	struct fwnode_handle *fwnode;
16062306a36Sopenharmony_ci	struct regulator *regulator;
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct max9286_asd {
16462306a36Sopenharmony_ci	struct v4l2_async_connection base;
16562306a36Sopenharmony_ci	struct max9286_source *source;
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic inline struct max9286_asd *
16962306a36Sopenharmony_cito_max9286_asd(struct v4l2_async_connection *asd)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	return container_of(asd, struct max9286_asd, base);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistruct max9286_priv {
17562306a36Sopenharmony_ci	struct i2c_client *client;
17662306a36Sopenharmony_ci	struct gpio_desc *gpiod_pwdn;
17762306a36Sopenharmony_ci	struct v4l2_subdev sd;
17862306a36Sopenharmony_ci	struct media_pad pads[MAX9286_N_PADS];
17962306a36Sopenharmony_ci	struct regulator *regulator;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	struct gpio_chip gpio;
18262306a36Sopenharmony_ci	u8 gpio_state;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	struct i2c_mux_core *mux;
18562306a36Sopenharmony_ci	unsigned int mux_channel;
18662306a36Sopenharmony_ci	bool mux_open;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* The initial reverse control channel amplitude. */
18962306a36Sopenharmony_ci	u32 init_rev_chan_mv;
19062306a36Sopenharmony_ci	u32 rev_chan_mv;
19162306a36Sopenharmony_ci	u8 i2c_mstbt;
19262306a36Sopenharmony_ci	u32 bus_width;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	bool use_gpio_poc;
19562306a36Sopenharmony_ci	u32 gpio_poc[2];
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	struct v4l2_ctrl_handler ctrls;
19862306a36Sopenharmony_ci	struct v4l2_ctrl *pixelrate_ctrl;
19962306a36Sopenharmony_ci	unsigned int pixelrate;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
20262306a36Sopenharmony_ci	struct v4l2_fract interval;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Protects controls and fmt structures */
20562306a36Sopenharmony_ci	struct mutex mutex;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	unsigned int nsources;
20862306a36Sopenharmony_ci	unsigned int source_mask;
20962306a36Sopenharmony_ci	unsigned int route_mask;
21062306a36Sopenharmony_ci	unsigned int bound_sources;
21162306a36Sopenharmony_ci	unsigned int csi2_data_lanes;
21262306a36Sopenharmony_ci	struct max9286_source sources[MAX9286_NUM_GMSL];
21362306a36Sopenharmony_ci	struct v4l2_async_notifier notifier;
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic struct max9286_source *next_source(struct max9286_priv *priv,
21762306a36Sopenharmony_ci					  struct max9286_source *source)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	if (!source)
22062306a36Sopenharmony_ci		source = &priv->sources[0];
22162306a36Sopenharmony_ci	else
22262306a36Sopenharmony_ci		source++;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	for (; source < &priv->sources[MAX9286_NUM_GMSL]; source++) {
22562306a36Sopenharmony_ci		if (source->fwnode)
22662306a36Sopenharmony_ci			return source;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return NULL;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci#define for_each_source(priv, source) \
23362306a36Sopenharmony_ci	for ((source) = NULL; ((source) = next_source((priv), (source))); )
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define to_index(priv, source) ((source) - &(priv)->sources[0])
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	return container_of(sd, struct max9286_priv, sd);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic const struct max9286_format_info max9286_formats[] = {
24362306a36Sopenharmony_ci	{
24462306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_UYVY8_1X16,
24562306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_YUV422_8BIT,
24662306a36Sopenharmony_ci	}, {
24762306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_VYUY8_1X16,
24862306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_YUV422_8BIT,
24962306a36Sopenharmony_ci	}, {
25062306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_YUYV8_1X16,
25162306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_YUV422_8BIT,
25262306a36Sopenharmony_ci	}, {
25362306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_YVYU8_1X16,
25462306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_YUV422_8BIT,
25562306a36Sopenharmony_ci	}, {
25662306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SBGGR12_1X12,
25762306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_RAW12,
25862306a36Sopenharmony_ci	}, {
25962306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SGBRG12_1X12,
26062306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_RAW12,
26162306a36Sopenharmony_ci	}, {
26262306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SGRBG12_1X12,
26362306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_RAW12,
26462306a36Sopenharmony_ci	}, {
26562306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SRGGB12_1X12,
26662306a36Sopenharmony_ci		.datatype = MAX9286_DATATYPE_RAW12,
26762306a36Sopenharmony_ci	},
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic const struct max9286_i2c_speed max9286_i2c_speeds[] = {
27162306a36Sopenharmony_ci	{ .rate =   8470, .mstbt = MAX9286_I2CMSTBT_8KBPS },
27262306a36Sopenharmony_ci	{ .rate =  28300, .mstbt = MAX9286_I2CMSTBT_28KBPS },
27362306a36Sopenharmony_ci	{ .rate =  84700, .mstbt = MAX9286_I2CMSTBT_84KBPS },
27462306a36Sopenharmony_ci	{ .rate = 105000, .mstbt = MAX9286_I2CMSTBT_105KBPS },
27562306a36Sopenharmony_ci	{ .rate = 173000, .mstbt = MAX9286_I2CMSTBT_173KBPS },
27662306a36Sopenharmony_ci	{ .rate = 339000, .mstbt = MAX9286_I2CMSTBT_339KBPS },
27762306a36Sopenharmony_ci	{ .rate = 533000, .mstbt = MAX9286_I2CMSTBT_533KBPS },
27862306a36Sopenharmony_ci	{ .rate = 837000, .mstbt = MAX9286_I2CMSTBT_837KBPS },
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
28262306a36Sopenharmony_ci * I2C IO
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int max9286_read(struct max9286_priv *priv, u8 reg)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int ret;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(priv->client, reg);
29062306a36Sopenharmony_ci	if (ret < 0)
29162306a36Sopenharmony_ci		dev_err(&priv->client->dev,
29262306a36Sopenharmony_ci			"%s: register 0x%02x read failed (%d)\n",
29362306a36Sopenharmony_ci			__func__, reg, ret);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return ret;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int max9286_write(struct max9286_priv *priv, u8 reg, u8 val)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	int ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(priv->client, reg, val);
30362306a36Sopenharmony_ci	if (ret < 0)
30462306a36Sopenharmony_ci		dev_err(&priv->client->dev,
30562306a36Sopenharmony_ci			"%s: register 0x%02x write failed (%d)\n",
30662306a36Sopenharmony_ci			__func__, reg, ret);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return ret;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
31262306a36Sopenharmony_ci * I2C Multiplexer
31362306a36Sopenharmony_ci */
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic void max9286_i2c_mux_configure(struct max9286_priv *priv, u8 conf)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	max9286_write(priv, 0x0a, conf);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * We must sleep after any change to the forward or reverse channel
32162306a36Sopenharmony_ci	 * configuration.
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	usleep_range(3000, 5000);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void max9286_i2c_mux_open(struct max9286_priv *priv)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	/* Open all channels on the MAX9286 */
32962306a36Sopenharmony_ci	max9286_i2c_mux_configure(priv, 0xff);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	priv->mux_open = true;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void max9286_i2c_mux_close(struct max9286_priv *priv)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	/*
33762306a36Sopenharmony_ci	 * Ensure that both the forward and reverse channel are disabled on the
33862306a36Sopenharmony_ci	 * mux, and that the channel ID is invalidated to ensure we reconfigure
33962306a36Sopenharmony_ci	 * on the next max9286_i2c_mux_select() call.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	max9286_i2c_mux_configure(priv, 0x00);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	priv->mux_open = false;
34462306a36Sopenharmony_ci	priv->mux_channel = -1;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct max9286_priv *priv = i2c_mux_priv(muxc);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Channel select is disabled when configured in the opened state. */
35262306a36Sopenharmony_ci	if (priv->mux_open)
35362306a36Sopenharmony_ci		return 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (priv->mux_channel == chan)
35662306a36Sopenharmony_ci		return 0;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	priv->mux_channel = chan;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) |
36162306a36Sopenharmony_ci					MAX9286_REVCCEN(chan));
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int max9286_i2c_mux_init(struct max9286_priv *priv)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct max9286_source *source;
36962306a36Sopenharmony_ci	int ret;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!i2c_check_functionality(priv->client->adapter,
37262306a36Sopenharmony_ci				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
37362306a36Sopenharmony_ci		return -ENODEV;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
37662306a36Sopenharmony_ci				  priv->nsources, 0, I2C_MUX_LOCKED,
37762306a36Sopenharmony_ci				  max9286_i2c_mux_select, NULL);
37862306a36Sopenharmony_ci	if (!priv->mux)
37962306a36Sopenharmony_ci		return -ENOMEM;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	priv->mux->priv = priv;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	for_each_source(priv, source) {
38462306a36Sopenharmony_ci		unsigned int index = to_index(priv, source);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		ret = i2c_mux_add_adapter(priv->mux, 0, index, 0);
38762306a36Sopenharmony_ci		if (ret < 0)
38862306a36Sopenharmony_ci			goto error;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return 0;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cierror:
39462306a36Sopenharmony_ci	i2c_mux_del_adapters(priv->mux);
39562306a36Sopenharmony_ci	return ret;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void max9286_configure_i2c(struct max9286_priv *priv, bool localack)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US |
40162306a36Sopenharmony_ci		    priv->i2c_mstbt;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (localack)
40462306a36Sopenharmony_ci		config |= MAX9286_I2CLOCACK;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	max9286_write(priv, 0x34, config);
40762306a36Sopenharmony_ci	usleep_range(3000, 5000);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic void max9286_reverse_channel_setup(struct max9286_priv *priv,
41162306a36Sopenharmony_ci					  unsigned int chan_amplitude)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	u8 chan_config;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (priv->rev_chan_mv == chan_amplitude)
41662306a36Sopenharmony_ci		return;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	priv->rev_chan_mv = chan_amplitude;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Reverse channel transmission time: default to 1. */
42162306a36Sopenharmony_ci	chan_config = MAX9286_REV_TRF(1);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/*
42462306a36Sopenharmony_ci	 * Reverse channel setup.
42562306a36Sopenharmony_ci	 *
42662306a36Sopenharmony_ci	 * - Enable custom reverse channel configuration (through register 0x3f)
42762306a36Sopenharmony_ci	 *   and set the first pulse length to 35 clock cycles.
42862306a36Sopenharmony_ci	 * - Adjust reverse channel amplitude: values > 130 are programmed
42962306a36Sopenharmony_ci	 *   using the additional +100mV REV_AMP_X boost flag
43062306a36Sopenharmony_ci	 */
43162306a36Sopenharmony_ci	max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35));
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (chan_amplitude > 100) {
43462306a36Sopenharmony_ci		/* It is not possible to express values (100 < x < 130) */
43562306a36Sopenharmony_ci		chan_amplitude = max(30U, chan_amplitude - 100);
43662306a36Sopenharmony_ci		chan_config |= MAX9286_REV_AMP_X;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci	max9286_write(priv, 0x3b, chan_config | MAX9286_REV_AMP(chan_amplitude));
43962306a36Sopenharmony_ci	usleep_range(2000, 2500);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/*
44362306a36Sopenharmony_ci * max9286_check_video_links() - Make sure video links are detected and locked
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * Performs safety checks on video link status. Make sure they are detected
44662306a36Sopenharmony_ci * and all enabled links are locked.
44762306a36Sopenharmony_ci *
44862306a36Sopenharmony_ci * Returns 0 for success, -EIO for errors.
44962306a36Sopenharmony_ci */
45062306a36Sopenharmony_cistatic int max9286_check_video_links(struct max9286_priv *priv)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	unsigned int i;
45362306a36Sopenharmony_ci	int ret;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/*
45662306a36Sopenharmony_ci	 * Make sure valid video links are detected.
45762306a36Sopenharmony_ci	 * The delay is not characterized in de-serializer manual, wait up
45862306a36Sopenharmony_ci	 * to 5 ms.
45962306a36Sopenharmony_ci	 */
46062306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
46162306a36Sopenharmony_ci		ret = max9286_read(priv, 0x49);
46262306a36Sopenharmony_ci		if (ret < 0)
46362306a36Sopenharmony_ci			return -EIO;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if ((ret & MAX9286_VIDEO_DETECT_MASK) == priv->source_mask)
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		usleep_range(350, 500);
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (i == 10) {
47262306a36Sopenharmony_ci		dev_err(&priv->client->dev,
47362306a36Sopenharmony_ci			"Unable to detect video links: 0x%02x\n", ret);
47462306a36Sopenharmony_ci		return -EIO;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Make sure all enabled links are locked (4ms max). */
47862306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
47962306a36Sopenharmony_ci		ret = max9286_read(priv, 0x27);
48062306a36Sopenharmony_ci		if (ret < 0)
48162306a36Sopenharmony_ci			return -EIO;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		if (ret & MAX9286_LOCKED)
48462306a36Sopenharmony_ci			break;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		usleep_range(350, 450);
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (i == 10) {
49062306a36Sopenharmony_ci		dev_err(&priv->client->dev, "Not all enabled links locked\n");
49162306a36Sopenharmony_ci		return -EIO;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci * max9286_check_config_link() - Detect and wait for configuration links
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * Determine if the configuration channel is up and settled for a link.
50162306a36Sopenharmony_ci *
50262306a36Sopenharmony_ci * Returns 0 for success, -EIO for errors.
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_cistatic int max9286_check_config_link(struct max9286_priv *priv,
50562306a36Sopenharmony_ci				     unsigned int source_mask)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	unsigned int conflink_mask = (source_mask & 0x0f) << 4;
50862306a36Sopenharmony_ci	unsigned int i;
50962306a36Sopenharmony_ci	int ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/*
51262306a36Sopenharmony_ci	 * Make sure requested configuration links are detected.
51362306a36Sopenharmony_ci	 * The delay is not characterized in the chip manual: wait up
51462306a36Sopenharmony_ci	 * to 5 milliseconds.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
51762306a36Sopenharmony_ci		ret = max9286_read(priv, 0x49);
51862306a36Sopenharmony_ci		if (ret < 0)
51962306a36Sopenharmony_ci			return -EIO;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		ret &= 0xf0;
52262306a36Sopenharmony_ci		if (ret == conflink_mask)
52362306a36Sopenharmony_ci			break;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		usleep_range(350, 500);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (ret != conflink_mask) {
52962306a36Sopenharmony_ci		dev_err(&priv->client->dev,
53062306a36Sopenharmony_ci			"Unable to detect configuration links: 0x%02x expected 0x%02x\n",
53162306a36Sopenharmony_ci			ret, conflink_mask);
53262306a36Sopenharmony_ci		return -EIO;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	dev_info(&priv->client->dev,
53662306a36Sopenharmony_ci		 "Successfully detected configuration links after %u loops: 0x%02x\n",
53762306a36Sopenharmony_ci		 i, conflink_mask);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void max9286_set_video_format(struct max9286_priv *priv,
54362306a36Sopenharmony_ci				     const struct v4l2_mbus_framefmt *format)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	const struct max9286_format_info *info = NULL;
54662306a36Sopenharmony_ci	unsigned int i;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
54962306a36Sopenharmony_ci		if (max9286_formats[i].code == format->code) {
55062306a36Sopenharmony_ci			info = &max9286_formats[i];
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (WARN_ON(!info))
55662306a36Sopenharmony_ci		return;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/*
55962306a36Sopenharmony_ci	 * Video format setup: disable CSI output, set VC according to Link
56062306a36Sopenharmony_ci	 * number, enable I2C clock stretching when CCBSY is low, enable CCBSY
56162306a36Sopenharmony_ci	 * in external GPI-to-GPO mode.
56262306a36Sopenharmony_ci	 */
56362306a36Sopenharmony_ci	max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_EN_CCBSYB_CLK_STR |
56462306a36Sopenharmony_ci		      MAX9286_EN_GPI_CCBSYB);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/* Enable CSI-2 Lane D0-D3 only, DBL mode. */
56762306a36Sopenharmony_ci	max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL |
56862306a36Sopenharmony_ci		      MAX9286_CSILANECNT(priv->csi2_data_lanes) |
56962306a36Sopenharmony_ci		      info->datatype);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * Enable HS/VS encoding, use HS as line valid source, use D14/15 for
57362306a36Sopenharmony_ci	 * HS/VS, invert VS.
57462306a36Sopenharmony_ci	 */
57562306a36Sopenharmony_ci	max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_DESEL |
57662306a36Sopenharmony_ci		      MAX9286_INVVS | MAX9286_HVSRC_D14);
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic void max9286_set_fsync_period(struct max9286_priv *priv)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	u32 fsync;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (!priv->interval.numerator || !priv->interval.denominator) {
58462306a36Sopenharmony_ci		/*
58562306a36Sopenharmony_ci		 * Special case, a null interval enables automatic FRAMESYNC
58662306a36Sopenharmony_ci		 * mode. FRAMESYNC is taken from the slowest link.
58762306a36Sopenharmony_ci		 */
58862306a36Sopenharmony_ci		max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ |
58962306a36Sopenharmony_ci			      MAX9286_FSYNCMETH_AUTO);
59062306a36Sopenharmony_ci		return;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/*
59462306a36Sopenharmony_ci	 * Manual FRAMESYNC
59562306a36Sopenharmony_ci	 *
59662306a36Sopenharmony_ci	 * The FRAMESYNC generator is configured with a period expressed as a
59762306a36Sopenharmony_ci	 * number of PCLK periods.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
60062306a36Sopenharmony_ci			priv->interval.denominator);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
60362306a36Sopenharmony_ci		priv->pixelrate);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT |
60662306a36Sopenharmony_ci		      MAX9286_FSYNCMETH_MANUAL);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	max9286_write(priv, 0x06, (fsync >> 0) & 0xff);
60962306a36Sopenharmony_ci	max9286_write(priv, 0x07, (fsync >> 8) & 0xff);
61062306a36Sopenharmony_ci	max9286_write(priv, 0x08, (fsync >> 16) & 0xff);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
61462306a36Sopenharmony_ci * V4L2 Subdev
61562306a36Sopenharmony_ci */
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic int max9286_set_pixelrate(struct max9286_priv *priv)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct max9286_source *source = NULL;
62062306a36Sopenharmony_ci	u64 pixelrate = 0;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	for_each_source(priv, source) {
62362306a36Sopenharmony_ci		struct v4l2_ctrl *ctrl;
62462306a36Sopenharmony_ci		u64 source_rate = 0;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		/* Pixel rate is mandatory to be reported by sources. */
62762306a36Sopenharmony_ci		ctrl = v4l2_ctrl_find(source->sd->ctrl_handler,
62862306a36Sopenharmony_ci				      V4L2_CID_PIXEL_RATE);
62962306a36Sopenharmony_ci		if (!ctrl) {
63062306a36Sopenharmony_ci			pixelrate = 0;
63162306a36Sopenharmony_ci			break;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		/* All source must report the same pixel rate. */
63562306a36Sopenharmony_ci		source_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
63662306a36Sopenharmony_ci		if (!pixelrate) {
63762306a36Sopenharmony_ci			pixelrate = source_rate;
63862306a36Sopenharmony_ci		} else if (pixelrate != source_rate) {
63962306a36Sopenharmony_ci			dev_err(&priv->client->dev,
64062306a36Sopenharmony_ci				"Unable to calculate pixel rate\n");
64162306a36Sopenharmony_ci			return -EINVAL;
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (!pixelrate) {
64662306a36Sopenharmony_ci		dev_err(&priv->client->dev,
64762306a36Sopenharmony_ci			"No pixel rate control available in sources\n");
64862306a36Sopenharmony_ci		return -EINVAL;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	priv->pixelrate = pixelrate;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/*
65462306a36Sopenharmony_ci	 * The CSI-2 transmitter pixel rate is the single source rate multiplied
65562306a36Sopenharmony_ci	 * by the number of available sources.
65662306a36Sopenharmony_ci	 */
65762306a36Sopenharmony_ci	return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl,
65862306a36Sopenharmony_ci				      pixelrate * priv->nsources);
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int max9286_notify_bound(struct v4l2_async_notifier *notifier,
66262306a36Sopenharmony_ci				struct v4l2_subdev *subdev,
66362306a36Sopenharmony_ci				struct v4l2_async_connection *asd)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(notifier->sd);
66662306a36Sopenharmony_ci	struct max9286_source *source = to_max9286_asd(asd)->source;
66762306a36Sopenharmony_ci	unsigned int index = to_index(priv, source);
66862306a36Sopenharmony_ci	unsigned int src_pad;
66962306a36Sopenharmony_ci	int ret;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	ret = media_entity_get_fwnode_pad(&subdev->entity,
67262306a36Sopenharmony_ci					  source->fwnode,
67362306a36Sopenharmony_ci					  MEDIA_PAD_FL_SOURCE);
67462306a36Sopenharmony_ci	if (ret < 0) {
67562306a36Sopenharmony_ci		dev_err(&priv->client->dev,
67662306a36Sopenharmony_ci			"Failed to find pad for %s\n", subdev->name);
67762306a36Sopenharmony_ci		return ret;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	priv->bound_sources |= BIT(index);
68162306a36Sopenharmony_ci	source->sd = subdev;
68262306a36Sopenharmony_ci	src_pad = ret;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	ret = media_create_pad_link(&source->sd->entity, src_pad,
68562306a36Sopenharmony_ci				    &priv->sd.entity, index,
68662306a36Sopenharmony_ci				    MEDIA_LNK_FL_ENABLED |
68762306a36Sopenharmony_ci				    MEDIA_LNK_FL_IMMUTABLE);
68862306a36Sopenharmony_ci	if (ret) {
68962306a36Sopenharmony_ci		dev_err(&priv->client->dev,
69062306a36Sopenharmony_ci			"Unable to link %s:%u -> %s:%u\n",
69162306a36Sopenharmony_ci			source->sd->name, src_pad, priv->sd.name, index);
69262306a36Sopenharmony_ci		return ret;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	dev_dbg(&priv->client->dev, "Bound %s pad: %u on index %u\n",
69662306a36Sopenharmony_ci		subdev->name, src_pad, index);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/*
69962306a36Sopenharmony_ci	 * As we register a subdev notifiers we won't get a .complete() callback
70062306a36Sopenharmony_ci	 * here, so we have to use bound_sources to identify when all remote
70162306a36Sopenharmony_ci	 * serializers have probed.
70262306a36Sopenharmony_ci	 */
70362306a36Sopenharmony_ci	if (priv->bound_sources != priv->source_mask)
70462306a36Sopenharmony_ci		return 0;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/*
70762306a36Sopenharmony_ci	 * All enabled sources have probed and enabled their reverse control
70862306a36Sopenharmony_ci	 * channels:
70962306a36Sopenharmony_ci	 *
71062306a36Sopenharmony_ci	 * - Increase the reverse channel amplitude to compensate for the
71162306a36Sopenharmony_ci	 *   remote ends high threshold
71262306a36Sopenharmony_ci	 * - Verify all configuration links are properly detected
71362306a36Sopenharmony_ci	 * - Disable auto-ack as communication on the control channel are now
71462306a36Sopenharmony_ci	 *   stable.
71562306a36Sopenharmony_ci	 */
71662306a36Sopenharmony_ci	max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH);
71762306a36Sopenharmony_ci	max9286_check_config_link(priv, priv->source_mask);
71862306a36Sopenharmony_ci	max9286_configure_i2c(priv, false);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return max9286_set_pixelrate(priv);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic void max9286_notify_unbind(struct v4l2_async_notifier *notifier,
72462306a36Sopenharmony_ci				  struct v4l2_subdev *subdev,
72562306a36Sopenharmony_ci				  struct v4l2_async_connection *asd)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(notifier->sd);
72862306a36Sopenharmony_ci	struct max9286_source *source = to_max9286_asd(asd)->source;
72962306a36Sopenharmony_ci	unsigned int index = to_index(priv, source);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	source->sd = NULL;
73262306a36Sopenharmony_ci	priv->bound_sources &= ~BIT(index);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations max9286_notify_ops = {
73662306a36Sopenharmony_ci	.bound = max9286_notify_bound,
73762306a36Sopenharmony_ci	.unbind = max9286_notify_unbind,
73862306a36Sopenharmony_ci};
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic int max9286_v4l2_notifier_register(struct max9286_priv *priv)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
74362306a36Sopenharmony_ci	struct max9286_source *source = NULL;
74462306a36Sopenharmony_ci	int ret;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (!priv->nsources)
74762306a36Sopenharmony_ci		return 0;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	for_each_source(priv, source) {
75262306a36Sopenharmony_ci		unsigned int i = to_index(priv, source);
75362306a36Sopenharmony_ci		struct max9286_asd *mas;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		mas = v4l2_async_nf_add_fwnode(&priv->notifier, source->fwnode,
75662306a36Sopenharmony_ci					       struct max9286_asd);
75762306a36Sopenharmony_ci		if (IS_ERR(mas)) {
75862306a36Sopenharmony_ci			dev_err(dev, "Failed to add subdev for source %u: %ld",
75962306a36Sopenharmony_ci				i, PTR_ERR(mas));
76062306a36Sopenharmony_ci			v4l2_async_nf_cleanup(&priv->notifier);
76162306a36Sopenharmony_ci			return PTR_ERR(mas);
76262306a36Sopenharmony_ci		}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		mas->source = source;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	priv->notifier.ops = &max9286_notify_ops;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	ret = v4l2_async_nf_register(&priv->notifier);
77062306a36Sopenharmony_ci	if (ret) {
77162306a36Sopenharmony_ci		dev_err(dev, "Failed to register subdev_notifier");
77262306a36Sopenharmony_ci		v4l2_async_nf_cleanup(&priv->notifier);
77362306a36Sopenharmony_ci		return ret;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	return 0;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic void max9286_v4l2_notifier_unregister(struct max9286_priv *priv)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	if (!priv->nsources)
78262306a36Sopenharmony_ci		return;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	v4l2_async_nf_unregister(&priv->notifier);
78562306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&priv->notifier);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic int max9286_s_stream(struct v4l2_subdev *sd, int enable)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(sd);
79162306a36Sopenharmony_ci	struct max9286_source *source;
79262306a36Sopenharmony_ci	unsigned int i;
79362306a36Sopenharmony_ci	bool sync = false;
79462306a36Sopenharmony_ci	int ret;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (enable) {
79762306a36Sopenharmony_ci		const struct v4l2_mbus_framefmt *format;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		/*
80062306a36Sopenharmony_ci		 * Get the format from the first used sink pad, as all sink
80162306a36Sopenharmony_ci		 * formats must be identical.
80262306a36Sopenharmony_ci		 */
80362306a36Sopenharmony_ci		format = &priv->fmt[__ffs(priv->bound_sources)];
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		max9286_set_video_format(priv, format);
80662306a36Sopenharmony_ci		max9286_set_fsync_period(priv);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		/*
80962306a36Sopenharmony_ci		 * The frame sync between cameras is transmitted across the
81062306a36Sopenharmony_ci		 * reverse channel as GPIO. We must open all channels while
81162306a36Sopenharmony_ci		 * streaming to allow this synchronisation signal to be shared.
81262306a36Sopenharmony_ci		 */
81362306a36Sopenharmony_ci		max9286_i2c_mux_open(priv);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		/* Start all cameras. */
81662306a36Sopenharmony_ci		for_each_source(priv, source) {
81762306a36Sopenharmony_ci			ret = v4l2_subdev_call(source->sd, video, s_stream, 1);
81862306a36Sopenharmony_ci			if (ret)
81962306a36Sopenharmony_ci				return ret;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		ret = max9286_check_video_links(priv);
82362306a36Sopenharmony_ci		if (ret)
82462306a36Sopenharmony_ci			return ret;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		/*
82762306a36Sopenharmony_ci		 * Wait until frame synchronization is locked.
82862306a36Sopenharmony_ci		 *
82962306a36Sopenharmony_ci		 * Manual says frame sync locking should take ~6 VTS.
83062306a36Sopenharmony_ci		 * From practical experience at least 8 are required. Give
83162306a36Sopenharmony_ci		 * 12 complete frames time (~400ms at 30 fps) to achieve frame
83262306a36Sopenharmony_ci		 * locking before returning error.
83362306a36Sopenharmony_ci		 */
83462306a36Sopenharmony_ci		for (i = 0; i < 40; i++) {
83562306a36Sopenharmony_ci			if (max9286_read(priv, 0x31) & MAX9286_FSYNC_LOCKED) {
83662306a36Sopenharmony_ci				sync = true;
83762306a36Sopenharmony_ci				break;
83862306a36Sopenharmony_ci			}
83962306a36Sopenharmony_ci			usleep_range(9000, 11000);
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		if (!sync) {
84362306a36Sopenharmony_ci			dev_err(&priv->client->dev,
84462306a36Sopenharmony_ci				"Failed to get frame synchronization\n");
84562306a36Sopenharmony_ci			return -EXDEV; /* Invalid cross-device link */
84662306a36Sopenharmony_ci		}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		/*
84962306a36Sopenharmony_ci		 * Configure the CSI-2 output to line interleaved mode (W x (N
85062306a36Sopenharmony_ci		 * x H), as opposed to the (N x W) x H mode that outputs the
85162306a36Sopenharmony_ci		 * images stitched side-by-side) and enable it.
85262306a36Sopenharmony_ci		 */
85362306a36Sopenharmony_ci		max9286_write(priv, 0x15, MAX9286_CSI_IMAGE_TYP | MAX9286_VCTYPE |
85462306a36Sopenharmony_ci			      MAX9286_CSIOUTEN | MAX9286_EN_CCBSYB_CLK_STR |
85562306a36Sopenharmony_ci			      MAX9286_EN_GPI_CCBSYB);
85662306a36Sopenharmony_ci	} else {
85762306a36Sopenharmony_ci		max9286_write(priv, 0x15, MAX9286_VCTYPE |
85862306a36Sopenharmony_ci			      MAX9286_EN_CCBSYB_CLK_STR |
85962306a36Sopenharmony_ci			      MAX9286_EN_GPI_CCBSYB);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		/* Stop all cameras. */
86262306a36Sopenharmony_ci		for_each_source(priv, source)
86362306a36Sopenharmony_ci			v4l2_subdev_call(source->sd, video, s_stream, 0);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		max9286_i2c_mux_close(priv);
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	return 0;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic int max9286_g_frame_interval(struct v4l2_subdev *sd,
87262306a36Sopenharmony_ci				    struct v4l2_subdev_frame_interval *interval)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(sd);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (interval->pad != MAX9286_SRC_PAD)
87762306a36Sopenharmony_ci		return -EINVAL;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	interval->interval = priv->interval;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	return 0;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic int max9286_s_frame_interval(struct v4l2_subdev *sd,
88562306a36Sopenharmony_ci				    struct v4l2_subdev_frame_interval *interval)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(sd);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (interval->pad != MAX9286_SRC_PAD)
89062306a36Sopenharmony_ci		return -EINVAL;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	priv->interval = interval->interval;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int max9286_enum_mbus_code(struct v4l2_subdev *sd,
89862306a36Sopenharmony_ci				  struct v4l2_subdev_state *sd_state,
89962306a36Sopenharmony_ci				  struct v4l2_subdev_mbus_code_enum *code)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	if (code->pad || code->index > 0)
90262306a36Sopenharmony_ci		return -EINVAL;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	code->code = MEDIA_BUS_FMT_UYVY8_1X16;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	return 0;
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic struct v4l2_mbus_framefmt *
91062306a36Sopenharmony_cimax9286_get_pad_format(struct max9286_priv *priv,
91162306a36Sopenharmony_ci		       struct v4l2_subdev_state *sd_state,
91262306a36Sopenharmony_ci		       unsigned int pad, u32 which)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	switch (which) {
91562306a36Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_TRY:
91662306a36Sopenharmony_ci		return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
91762306a36Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_ACTIVE:
91862306a36Sopenharmony_ci		return &priv->fmt[pad];
91962306a36Sopenharmony_ci	default:
92062306a36Sopenharmony_ci		return NULL;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int max9286_set_fmt(struct v4l2_subdev *sd,
92562306a36Sopenharmony_ci			   struct v4l2_subdev_state *sd_state,
92662306a36Sopenharmony_ci			   struct v4l2_subdev_format *format)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(sd);
92962306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *cfg_fmt;
93062306a36Sopenharmony_ci	unsigned int i;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (format->pad == MAX9286_SRC_PAD)
93362306a36Sopenharmony_ci		return -EINVAL;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Validate the format. */
93662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
93762306a36Sopenharmony_ci		if (max9286_formats[i].code == format->format.code)
93862306a36Sopenharmony_ci			break;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (i == ARRAY_SIZE(max9286_formats))
94262306a36Sopenharmony_ci		format->format.code = max9286_formats[0].code;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
94562306a36Sopenharmony_ci					 format->which);
94662306a36Sopenharmony_ci	if (!cfg_fmt)
94762306a36Sopenharmony_ci		return -EINVAL;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
95062306a36Sopenharmony_ci	*cfg_fmt = format->format;
95162306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	return 0;
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int max9286_get_fmt(struct v4l2_subdev *sd,
95762306a36Sopenharmony_ci			   struct v4l2_subdev_state *sd_state,
95862306a36Sopenharmony_ci			   struct v4l2_subdev_format *format)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(sd);
96162306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *cfg_fmt;
96262306a36Sopenharmony_ci	unsigned int pad = format->pad;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	/*
96562306a36Sopenharmony_ci	 * Multiplexed Stream Support: Support link validation by returning the
96662306a36Sopenharmony_ci	 * format of the first bound link. All links must have the same format,
96762306a36Sopenharmony_ci	 * as we do not support mixing and matching of cameras connected to the
96862306a36Sopenharmony_ci	 * max9286.
96962306a36Sopenharmony_ci	 */
97062306a36Sopenharmony_ci	if (pad == MAX9286_SRC_PAD)
97162306a36Sopenharmony_ci		pad = __ffs(priv->bound_sources);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
97462306a36Sopenharmony_ci	if (!cfg_fmt)
97562306a36Sopenharmony_ci		return -EINVAL;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
97862306a36Sopenharmony_ci	format->format = *cfg_fmt;
97962306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return 0;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops max9286_video_ops = {
98562306a36Sopenharmony_ci	.s_stream	= max9286_s_stream,
98662306a36Sopenharmony_ci	.g_frame_interval = max9286_g_frame_interval,
98762306a36Sopenharmony_ci	.s_frame_interval = max9286_s_frame_interval,
98862306a36Sopenharmony_ci};
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops max9286_pad_ops = {
99162306a36Sopenharmony_ci	.enum_mbus_code = max9286_enum_mbus_code,
99262306a36Sopenharmony_ci	.get_fmt	= max9286_get_fmt,
99362306a36Sopenharmony_ci	.set_fmt	= max9286_set_fmt,
99462306a36Sopenharmony_ci};
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistatic const struct v4l2_subdev_ops max9286_subdev_ops = {
99762306a36Sopenharmony_ci	.video		= &max9286_video_ops,
99862306a36Sopenharmony_ci	.pad		= &max9286_pad_ops,
99962306a36Sopenharmony_ci};
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic const struct v4l2_mbus_framefmt max9286_default_format = {
100262306a36Sopenharmony_ci	.width		= 1280,
100362306a36Sopenharmony_ci	.height		= 800,
100462306a36Sopenharmony_ci	.code		= MEDIA_BUS_FMT_UYVY8_1X16,
100562306a36Sopenharmony_ci	.colorspace	= V4L2_COLORSPACE_SRGB,
100662306a36Sopenharmony_ci	.field		= V4L2_FIELD_NONE,
100762306a36Sopenharmony_ci	.ycbcr_enc	= V4L2_YCBCR_ENC_DEFAULT,
100862306a36Sopenharmony_ci	.quantization	= V4L2_QUANTIZATION_DEFAULT,
100962306a36Sopenharmony_ci	.xfer_func	= V4L2_XFER_FUNC_DEFAULT,
101062306a36Sopenharmony_ci};
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cistatic void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	*fmt = max9286_default_format;
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *format;
102062306a36Sopenharmony_ci	unsigned int i;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	for (i = 0; i < MAX9286_N_SINKS; i++) {
102362306a36Sopenharmony_ci		format = v4l2_subdev_get_try_format(subdev, fh->state, i);
102462306a36Sopenharmony_ci		max9286_init_format(format);
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return 0;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = {
103162306a36Sopenharmony_ci	.open = max9286_open,
103262306a36Sopenharmony_ci};
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic const struct media_entity_operations max9286_media_ops = {
103562306a36Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate
103662306a36Sopenharmony_ci};
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic int max9286_s_ctrl(struct v4l2_ctrl *ctrl)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	switch (ctrl->id) {
104162306a36Sopenharmony_ci	case V4L2_CID_PIXEL_RATE:
104262306a36Sopenharmony_ci		return 0;
104362306a36Sopenharmony_ci	default:
104462306a36Sopenharmony_ci		return -EINVAL;
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops max9286_ctrl_ops = {
104962306a36Sopenharmony_ci	.s_ctrl = max9286_s_ctrl,
105062306a36Sopenharmony_ci};
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic int max9286_v4l2_register(struct max9286_priv *priv)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
105562306a36Sopenharmony_ci	int ret;
105662306a36Sopenharmony_ci	int i;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* Register v4l2 async notifiers for connected Camera subdevices */
105962306a36Sopenharmony_ci	ret = max9286_v4l2_notifier_register(priv);
106062306a36Sopenharmony_ci	if (ret) {
106162306a36Sopenharmony_ci		dev_err(dev, "Unable to register V4L2 async notifiers\n");
106262306a36Sopenharmony_ci		return ret;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/* Configure V4L2 for the MAX9286 itself */
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	for (i = 0; i < MAX9286_N_SINKS; i++)
106862306a36Sopenharmony_ci		max9286_init_format(&priv->fmt[i]);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops);
107162306a36Sopenharmony_ci	priv->sd.internal_ops = &max9286_subdev_internal_ops;
107262306a36Sopenharmony_ci	priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	v4l2_ctrl_handler_init(&priv->ctrls, 1);
107562306a36Sopenharmony_ci	priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls,
107662306a36Sopenharmony_ci						 &max9286_ctrl_ops,
107762306a36Sopenharmony_ci						 V4L2_CID_PIXEL_RATE,
107862306a36Sopenharmony_ci						 1, INT_MAX, 1, 50000000);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	priv->sd.ctrl_handler = &priv->ctrls;
108162306a36Sopenharmony_ci	ret = priv->ctrls.error;
108262306a36Sopenharmony_ci	if (ret)
108362306a36Sopenharmony_ci		goto err_async;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
108662306a36Sopenharmony_ci	priv->sd.entity.ops = &max9286_media_ops;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	priv->pads[MAX9286_SRC_PAD].flags = MEDIA_PAD_FL_SOURCE;
108962306a36Sopenharmony_ci	for (i = 0; i < MAX9286_SRC_PAD; i++)
109062306a36Sopenharmony_ci		priv->pads[i].flags = MEDIA_PAD_FL_SINK;
109162306a36Sopenharmony_ci	ret = media_entity_pads_init(&priv->sd.entity, MAX9286_N_PADS,
109262306a36Sopenharmony_ci				     priv->pads);
109362306a36Sopenharmony_ci	if (ret)
109462306a36Sopenharmony_ci		goto err_async;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	ret = v4l2_async_register_subdev(&priv->sd);
109762306a36Sopenharmony_ci	if (ret < 0) {
109862306a36Sopenharmony_ci		dev_err(dev, "Unable to register subdevice\n");
109962306a36Sopenharmony_ci		goto err_async;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return 0;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cierr_async:
110562306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&priv->ctrls);
110662306a36Sopenharmony_ci	max9286_v4l2_notifier_unregister(priv);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return ret;
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic void max9286_v4l2_unregister(struct max9286_priv *priv)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	v4l2_ctrl_handler_free(&priv->ctrls);
111462306a36Sopenharmony_ci	v4l2_async_unregister_subdev(&priv->sd);
111562306a36Sopenharmony_ci	max9286_v4l2_notifier_unregister(priv);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
111962306a36Sopenharmony_ci * Probe/Remove
112062306a36Sopenharmony_ci */
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic int max9286_setup(struct max9286_priv *priv)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	/*
112562306a36Sopenharmony_ci	 * Link ordering values for all enabled links combinations. Orders must
112662306a36Sopenharmony_ci	 * be assigned sequentially from 0 to the number of enabled links
112762306a36Sopenharmony_ci	 * without leaving any hole for disabled links. We thus assign orders to
112862306a36Sopenharmony_ci	 * enabled links first, and use the remaining order values for disabled
112962306a36Sopenharmony_ci	 * links are all links must have a different order value;
113062306a36Sopenharmony_ci	 */
113162306a36Sopenharmony_ci	static const u8 link_order[] = {
113262306a36Sopenharmony_ci		(3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxxx */
113362306a36Sopenharmony_ci		(3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxx0 */
113462306a36Sopenharmony_ci		(3 << 6) | (2 << 4) | (0 << 2) | (1 << 0), /* xx0x */
113562306a36Sopenharmony_ci		(3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xx10 */
113662306a36Sopenharmony_ci		(3 << 6) | (0 << 4) | (2 << 2) | (1 << 0), /* x0xx */
113762306a36Sopenharmony_ci		(3 << 6) | (1 << 4) | (2 << 2) | (0 << 0), /* x1x0 */
113862306a36Sopenharmony_ci		(3 << 6) | (1 << 4) | (0 << 2) | (2 << 0), /* x10x */
113962306a36Sopenharmony_ci		(3 << 6) | (1 << 4) | (1 << 2) | (0 << 0), /* x210 */
114062306a36Sopenharmony_ci		(0 << 6) | (3 << 4) | (2 << 2) | (1 << 0), /* 0xxx */
114162306a36Sopenharmony_ci		(1 << 6) | (3 << 4) | (2 << 2) | (0 << 0), /* 1xx0 */
114262306a36Sopenharmony_ci		(1 << 6) | (3 << 4) | (0 << 2) | (2 << 0), /* 1x0x */
114362306a36Sopenharmony_ci		(2 << 6) | (3 << 4) | (1 << 2) | (0 << 0), /* 2x10 */
114462306a36Sopenharmony_ci		(1 << 6) | (0 << 4) | (3 << 2) | (2 << 0), /* 10xx */
114562306a36Sopenharmony_ci		(2 << 6) | (1 << 4) | (3 << 2) | (0 << 0), /* 21x0 */
114662306a36Sopenharmony_ci		(2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */
114762306a36Sopenharmony_ci		(3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */
114862306a36Sopenharmony_ci	};
114962306a36Sopenharmony_ci	int cfg;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	/*
115262306a36Sopenharmony_ci	 * Set the I2C bus speed.
115362306a36Sopenharmony_ci	 *
115462306a36Sopenharmony_ci	 * Enable I2C Local Acknowledge during the probe sequences of the camera
115562306a36Sopenharmony_ci	 * only. This should be disabled after the mux is initialised.
115662306a36Sopenharmony_ci	 */
115762306a36Sopenharmony_ci	max9286_configure_i2c(priv, true);
115862306a36Sopenharmony_ci	max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	/*
116162306a36Sopenharmony_ci	 * Enable GMSL links, mask unused ones and autodetect link
116262306a36Sopenharmony_ci	 * used as CSI clock source.
116362306a36Sopenharmony_ci	 */
116462306a36Sopenharmony_ci	max9286_write(priv, 0x00, MAX9286_MSTLINKSEL_AUTO | priv->route_mask);
116562306a36Sopenharmony_ci	max9286_write(priv, 0x0b, link_order[priv->route_mask]);
116662306a36Sopenharmony_ci	max9286_write(priv, 0x69, (0xf & ~priv->route_mask));
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	max9286_set_video_format(priv, &max9286_default_format);
116962306a36Sopenharmony_ci	max9286_set_fsync_period(priv);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	cfg = max9286_read(priv, 0x1c);
117262306a36Sopenharmony_ci	if (cfg < 0)
117362306a36Sopenharmony_ci		return cfg;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	dev_dbg(&priv->client->dev, "power-up config: %s immunity, %u-bit bus\n",
117662306a36Sopenharmony_ci		cfg & MAX9286_HIGHIMM(0) ? "high" : "legacy",
117762306a36Sopenharmony_ci		cfg & MAX9286_BWS ? 32 : cfg & MAX9286_HIBW ? 27 : 24);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (priv->bus_width) {
118062306a36Sopenharmony_ci		cfg &= ~(MAX9286_HIBW | MAX9286_BWS);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		if (priv->bus_width == 27)
118362306a36Sopenharmony_ci			cfg |= MAX9286_HIBW;
118462306a36Sopenharmony_ci		else if (priv->bus_width == 32)
118562306a36Sopenharmony_ci			cfg |= MAX9286_BWS;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci		max9286_write(priv, 0x1c, cfg);
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/*
119162306a36Sopenharmony_ci	 * The overlap window seems to provide additional validation by tracking
119262306a36Sopenharmony_ci	 * the delay between vsync and frame sync, generating an error if the
119362306a36Sopenharmony_ci	 * delay is bigger than the programmed window, though it's not yet clear
119462306a36Sopenharmony_ci	 * what value should be set.
119562306a36Sopenharmony_ci	 *
119662306a36Sopenharmony_ci	 * As it's an optional value and can be disabled, we do so by setting
119762306a36Sopenharmony_ci	 * a 0 overlap value.
119862306a36Sopenharmony_ci	 */
119962306a36Sopenharmony_ci	max9286_write(priv, 0x63, 0);
120062306a36Sopenharmony_ci	max9286_write(priv, 0x64, 0);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/*
120362306a36Sopenharmony_ci	 * Wait for 2ms to allow the link to resynchronize after the
120462306a36Sopenharmony_ci	 * configuration change.
120562306a36Sopenharmony_ci	 */
120662306a36Sopenharmony_ci	usleep_range(2000, 5000);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	return 0;
120962306a36Sopenharmony_ci}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset,
121262306a36Sopenharmony_ci			    int value)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	if (value)
121562306a36Sopenharmony_ci		priv->gpio_state |= BIT(offset);
121662306a36Sopenharmony_ci	else
121762306a36Sopenharmony_ci		priv->gpio_state &= ~BIT(offset);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return max9286_write(priv, 0x0f,
122062306a36Sopenharmony_ci			     MAX9286_0X0F_RESERVED | priv->gpio_state);
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic void max9286_gpiochip_set(struct gpio_chip *chip,
122462306a36Sopenharmony_ci				 unsigned int offset, int value)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	struct max9286_priv *priv = gpiochip_get_data(chip);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	max9286_gpio_set(priv, offset, value);
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset)
123262306a36Sopenharmony_ci{
123362306a36Sopenharmony_ci	struct max9286_priv *priv = gpiochip_get_data(chip);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	return priv->gpio_state & BIT(offset);
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic int max9286_register_gpio(struct max9286_priv *priv)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
124162306a36Sopenharmony_ci	struct gpio_chip *gpio = &priv->gpio;
124262306a36Sopenharmony_ci	int ret;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/* Configure the GPIO */
124562306a36Sopenharmony_ci	gpio->label = dev_name(dev);
124662306a36Sopenharmony_ci	gpio->parent = dev;
124762306a36Sopenharmony_ci	gpio->owner = THIS_MODULE;
124862306a36Sopenharmony_ci	gpio->ngpio = 2;
124962306a36Sopenharmony_ci	gpio->base = -1;
125062306a36Sopenharmony_ci	gpio->set = max9286_gpiochip_set;
125162306a36Sopenharmony_ci	gpio->get = max9286_gpiochip_get;
125262306a36Sopenharmony_ci	gpio->can_sleep = true;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(dev, gpio, priv);
125562306a36Sopenharmony_ci	if (ret)
125662306a36Sopenharmony_ci		dev_err(dev, "Unable to create gpio_chip\n");
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	return ret;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic int max9286_parse_gpios(struct max9286_priv *priv)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
126462306a36Sopenharmony_ci	int ret;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/*
126762306a36Sopenharmony_ci	 * Parse the "gpio-poc" vendor property. If the property is not
126862306a36Sopenharmony_ci	 * specified the camera power is controlled by a regulator.
126962306a36Sopenharmony_ci	 */
127062306a36Sopenharmony_ci	ret = of_property_read_u32_array(dev->of_node, "maxim,gpio-poc",
127162306a36Sopenharmony_ci					 priv->gpio_poc, 2);
127262306a36Sopenharmony_ci	if (ret == -EINVAL) {
127362306a36Sopenharmony_ci		/*
127462306a36Sopenharmony_ci		 * If gpio lines are not used for the camera power, register
127562306a36Sopenharmony_ci		 * a gpio controller for consumers.
127662306a36Sopenharmony_ci		 */
127762306a36Sopenharmony_ci		return max9286_register_gpio(priv);
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	/* If the property is specified make sure it is well formed. */
128162306a36Sopenharmony_ci	if (ret || priv->gpio_poc[0] > 1 ||
128262306a36Sopenharmony_ci	    (priv->gpio_poc[1] != GPIO_ACTIVE_HIGH &&
128362306a36Sopenharmony_ci	     priv->gpio_poc[1] != GPIO_ACTIVE_LOW)) {
128462306a36Sopenharmony_ci		dev_err(dev, "Invalid 'gpio-poc' property\n");
128562306a36Sopenharmony_ci		return -EINVAL;
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	priv->use_gpio_poc = true;
128962306a36Sopenharmony_ci	return 0;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic int max9286_poc_power_on(struct max9286_priv *priv)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct max9286_source *source;
129562306a36Sopenharmony_ci	unsigned int enabled = 0;
129662306a36Sopenharmony_ci	int ret;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	/* Enable the global regulator if available. */
129962306a36Sopenharmony_ci	if (priv->regulator)
130062306a36Sopenharmony_ci		return regulator_enable(priv->regulator);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (priv->use_gpio_poc)
130362306a36Sopenharmony_ci		return max9286_gpio_set(priv, priv->gpio_poc[0],
130462306a36Sopenharmony_ci					!priv->gpio_poc[1]);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* Otherwise use the per-port regulators. */
130762306a36Sopenharmony_ci	for_each_source(priv, source) {
130862306a36Sopenharmony_ci		ret = regulator_enable(source->regulator);
130962306a36Sopenharmony_ci		if (ret < 0)
131062306a36Sopenharmony_ci			goto error;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		enabled |= BIT(to_index(priv, source));
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	return 0;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cierror:
131862306a36Sopenharmony_ci	for_each_source(priv, source) {
131962306a36Sopenharmony_ci		if (enabled & BIT(to_index(priv, source)))
132062306a36Sopenharmony_ci			regulator_disable(source->regulator);
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return ret;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic int max9286_poc_power_off(struct max9286_priv *priv)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	struct max9286_source *source;
132962306a36Sopenharmony_ci	int ret = 0;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (priv->regulator)
133262306a36Sopenharmony_ci		return regulator_disable(priv->regulator);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if (priv->use_gpio_poc)
133562306a36Sopenharmony_ci		return max9286_gpio_set(priv, priv->gpio_poc[0],
133662306a36Sopenharmony_ci					priv->gpio_poc[1]);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	for_each_source(priv, source) {
133962306a36Sopenharmony_ci		int err;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci		err = regulator_disable(source->regulator);
134262306a36Sopenharmony_ci		if (!ret)
134362306a36Sopenharmony_ci			ret = err;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return ret;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic int max9286_poc_enable(struct max9286_priv *priv, bool enable)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	int ret;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (enable)
135462306a36Sopenharmony_ci		ret = max9286_poc_power_on(priv);
135562306a36Sopenharmony_ci	else
135662306a36Sopenharmony_ci		ret = max9286_poc_power_off(priv);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	if (ret < 0)
135962306a36Sopenharmony_ci		dev_err(&priv->client->dev, "Unable to turn power %s\n",
136062306a36Sopenharmony_ci			enable ? "on" : "off");
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	return ret;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic int max9286_init(struct max9286_priv *priv)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	struct i2c_client *client = priv->client;
136862306a36Sopenharmony_ci	int ret;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	ret = max9286_poc_enable(priv, true);
137162306a36Sopenharmony_ci	if (ret)
137262306a36Sopenharmony_ci		return ret;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	ret = max9286_setup(priv);
137562306a36Sopenharmony_ci	if (ret) {
137662306a36Sopenharmony_ci		dev_err(&client->dev, "Unable to setup max9286\n");
137762306a36Sopenharmony_ci		goto err_poc_disable;
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	/*
138162306a36Sopenharmony_ci	 * Register all V4L2 interactions for the MAX9286 and notifiers for
138262306a36Sopenharmony_ci	 * any subdevices connected.
138362306a36Sopenharmony_ci	 */
138462306a36Sopenharmony_ci	ret = max9286_v4l2_register(priv);
138562306a36Sopenharmony_ci	if (ret) {
138662306a36Sopenharmony_ci		dev_err(&client->dev, "Failed to register with V4L2\n");
138762306a36Sopenharmony_ci		goto err_poc_disable;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	ret = max9286_i2c_mux_init(priv);
139162306a36Sopenharmony_ci	if (ret) {
139262306a36Sopenharmony_ci		dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
139362306a36Sopenharmony_ci		goto err_v4l2_register;
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/* Leave the mux channels disabled until they are selected. */
139762306a36Sopenharmony_ci	max9286_i2c_mux_close(priv);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	return 0;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cierr_v4l2_register:
140262306a36Sopenharmony_ci	max9286_v4l2_unregister(priv);
140362306a36Sopenharmony_cierr_poc_disable:
140462306a36Sopenharmony_ci	max9286_poc_enable(priv, false);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return ret;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic void max9286_cleanup_dt(struct max9286_priv *priv)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	struct max9286_source *source;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	for_each_source(priv, source) {
141462306a36Sopenharmony_ci		fwnode_handle_put(source->fwnode);
141562306a36Sopenharmony_ci		source->fwnode = NULL;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic int max9286_parse_dt(struct max9286_priv *priv)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
142262306a36Sopenharmony_ci	struct device_node *i2c_mux;
142362306a36Sopenharmony_ci	struct device_node *node = NULL;
142462306a36Sopenharmony_ci	unsigned int i2c_mux_mask = 0;
142562306a36Sopenharmony_ci	u32 reverse_channel_microvolt;
142662306a36Sopenharmony_ci	u32 i2c_clk_freq = 105000;
142762306a36Sopenharmony_ci	unsigned int i;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/* Balance the of_node_put() performed by of_find_node_by_name(). */
143062306a36Sopenharmony_ci	of_node_get(dev->of_node);
143162306a36Sopenharmony_ci	i2c_mux = of_find_node_by_name(dev->of_node, "i2c-mux");
143262306a36Sopenharmony_ci	if (!i2c_mux) {
143362306a36Sopenharmony_ci		dev_err(dev, "Failed to find i2c-mux node\n");
143462306a36Sopenharmony_ci		return -EINVAL;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* Identify which i2c-mux channels are enabled */
143862306a36Sopenharmony_ci	for_each_child_of_node(i2c_mux, node) {
143962306a36Sopenharmony_ci		u32 id = 0;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		of_property_read_u32(node, "reg", &id);
144262306a36Sopenharmony_ci		if (id >= MAX9286_NUM_GMSL)
144362306a36Sopenharmony_ci			continue;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci		if (!of_device_is_available(node)) {
144662306a36Sopenharmony_ci			dev_dbg(dev, "Skipping disabled I2C bus port %u\n", id);
144762306a36Sopenharmony_ci			continue;
144862306a36Sopenharmony_ci		}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci		i2c_mux_mask |= BIT(id);
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci	of_node_put(i2c_mux);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	/* Parse the endpoints */
145562306a36Sopenharmony_ci	for_each_endpoint_of_node(dev->of_node, node) {
145662306a36Sopenharmony_ci		struct max9286_source *source;
145762306a36Sopenharmony_ci		struct of_endpoint ep;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		of_graph_parse_endpoint(node, &ep);
146062306a36Sopenharmony_ci		dev_dbg(dev, "Endpoint %pOF on port %d",
146162306a36Sopenharmony_ci			ep.local_node, ep.port);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		if (ep.port > MAX9286_NUM_GMSL) {
146462306a36Sopenharmony_ci			dev_err(dev, "Invalid endpoint %s on port %d",
146562306a36Sopenharmony_ci				of_node_full_name(ep.local_node), ep.port);
146662306a36Sopenharmony_ci			continue;
146762306a36Sopenharmony_ci		}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		/* For the source endpoint just parse the bus configuration. */
147062306a36Sopenharmony_ci		if (ep.port == MAX9286_SRC_PAD) {
147162306a36Sopenharmony_ci			struct v4l2_fwnode_endpoint vep = {
147262306a36Sopenharmony_ci				.bus_type = V4L2_MBUS_CSI2_DPHY
147362306a36Sopenharmony_ci			};
147462306a36Sopenharmony_ci			int ret;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci			ret = v4l2_fwnode_endpoint_parse(
147762306a36Sopenharmony_ci					of_fwnode_handle(node), &vep);
147862306a36Sopenharmony_ci			if (ret) {
147962306a36Sopenharmony_ci				of_node_put(node);
148062306a36Sopenharmony_ci				return ret;
148162306a36Sopenharmony_ci			}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci			priv->csi2_data_lanes =
148462306a36Sopenharmony_ci				vep.bus.mipi_csi2.num_data_lanes;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci			continue;
148762306a36Sopenharmony_ci		}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		/* Skip if the corresponding GMSL link is unavailable. */
149062306a36Sopenharmony_ci		if (!(i2c_mux_mask & BIT(ep.port)))
149162306a36Sopenharmony_ci			continue;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		if (priv->sources[ep.port].fwnode) {
149462306a36Sopenharmony_ci			dev_err(dev,
149562306a36Sopenharmony_ci				"Multiple port endpoints are not supported: %d",
149662306a36Sopenharmony_ci				ep.port);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci			continue;
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		source = &priv->sources[ep.port];
150262306a36Sopenharmony_ci		source->fwnode = fwnode_graph_get_remote_endpoint(
150362306a36Sopenharmony_ci						of_fwnode_handle(node));
150462306a36Sopenharmony_ci		if (!source->fwnode) {
150562306a36Sopenharmony_ci			dev_err(dev,
150662306a36Sopenharmony_ci				"Endpoint %pOF has no remote endpoint connection\n",
150762306a36Sopenharmony_ci				ep.local_node);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci			continue;
151062306a36Sopenharmony_ci		}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci		priv->source_mask |= BIT(ep.port);
151362306a36Sopenharmony_ci		priv->nsources++;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width);
151762306a36Sopenharmony_ci	switch (priv->bus_width) {
151862306a36Sopenharmony_ci	case 0:
151962306a36Sopenharmony_ci		/*
152062306a36Sopenharmony_ci		 * The property isn't specified in the device tree, the driver
152162306a36Sopenharmony_ci		 * will keep the default value selected by the BWS pin.
152262306a36Sopenharmony_ci		 */
152362306a36Sopenharmony_ci	case 24:
152462306a36Sopenharmony_ci	case 27:
152562306a36Sopenharmony_ci	case 32:
152662306a36Sopenharmony_ci		break;
152762306a36Sopenharmony_ci	default:
152862306a36Sopenharmony_ci		dev_err(dev, "Invalid %s value %u\n", "maxim,bus-width",
152962306a36Sopenharmony_ci			priv->bus_width);
153062306a36Sopenharmony_ci		return -EINVAL;
153162306a36Sopenharmony_ci	}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	of_property_read_u32(dev->of_node, "maxim,i2c-remote-bus-hz",
153462306a36Sopenharmony_ci			     &i2c_clk_freq);
153562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(max9286_i2c_speeds); ++i) {
153662306a36Sopenharmony_ci		const struct max9286_i2c_speed *speed = &max9286_i2c_speeds[i];
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		if (speed->rate == i2c_clk_freq) {
153962306a36Sopenharmony_ci			priv->i2c_mstbt = speed->mstbt;
154062306a36Sopenharmony_ci			break;
154162306a36Sopenharmony_ci		}
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (i == ARRAY_SIZE(max9286_i2c_speeds)) {
154562306a36Sopenharmony_ci		dev_err(dev, "Invalid %s value %u\n", "maxim,i2c-remote-bus-hz",
154662306a36Sopenharmony_ci			i2c_clk_freq);
154762306a36Sopenharmony_ci		return -EINVAL;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/*
155162306a36Sopenharmony_ci	 * Parse the initial value of the reverse channel amplitude from
155262306a36Sopenharmony_ci	 * the firmware interface and convert it to millivolts.
155362306a36Sopenharmony_ci	 *
155462306a36Sopenharmony_ci	 * Default it to 170mV for backward compatibility with DTBs that do not
155562306a36Sopenharmony_ci	 * provide the property.
155662306a36Sopenharmony_ci	 */
155762306a36Sopenharmony_ci	if (of_property_read_u32(dev->of_node,
155862306a36Sopenharmony_ci				 "maxim,reverse-channel-microvolt",
155962306a36Sopenharmony_ci				 &reverse_channel_microvolt))
156062306a36Sopenharmony_ci		priv->init_rev_chan_mv = 170;
156162306a36Sopenharmony_ci	else
156262306a36Sopenharmony_ci		priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	priv->route_mask = priv->source_mask;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	return 0;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic int max9286_get_poc_supplies(struct max9286_priv *priv)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	struct device *dev = &priv->client->dev;
157262306a36Sopenharmony_ci	struct max9286_source *source;
157362306a36Sopenharmony_ci	int ret;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	/* Start by getting the global regulator. */
157662306a36Sopenharmony_ci	priv->regulator = devm_regulator_get_optional(dev, "poc");
157762306a36Sopenharmony_ci	if (!IS_ERR(priv->regulator))
157862306a36Sopenharmony_ci		return 0;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (PTR_ERR(priv->regulator) != -ENODEV)
158162306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(priv->regulator),
158262306a36Sopenharmony_ci				     "Unable to get PoC regulator\n");
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* If there's no global regulator, get per-port regulators. */
158562306a36Sopenharmony_ci	dev_dbg(dev,
158662306a36Sopenharmony_ci		"No global PoC regulator, looking for per-port regulators\n");
158762306a36Sopenharmony_ci	priv->regulator = NULL;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	for_each_source(priv, source) {
159062306a36Sopenharmony_ci		unsigned int index = to_index(priv, source);
159162306a36Sopenharmony_ci		char name[10];
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci		snprintf(name, sizeof(name), "port%u-poc", index);
159462306a36Sopenharmony_ci		source->regulator = devm_regulator_get(dev, name);
159562306a36Sopenharmony_ci		if (IS_ERR(source->regulator)) {
159662306a36Sopenharmony_ci			ret = PTR_ERR(source->regulator);
159762306a36Sopenharmony_ci			dev_err_probe(dev, ret,
159862306a36Sopenharmony_ci				      "Unable to get port %u PoC regulator\n",
159962306a36Sopenharmony_ci				      index);
160062306a36Sopenharmony_ci			return ret;
160162306a36Sopenharmony_ci		}
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	return 0;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic int max9286_probe(struct i2c_client *client)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	struct max9286_priv *priv;
161062306a36Sopenharmony_ci	int ret;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
161362306a36Sopenharmony_ci	if (!priv)
161462306a36Sopenharmony_ci		return -ENOMEM;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	mutex_init(&priv->mutex);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	priv->client = client;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* GPIO values default to high */
162162306a36Sopenharmony_ci	priv->gpio_state = BIT(0) | BIT(1);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	ret = max9286_parse_dt(priv);
162462306a36Sopenharmony_ci	if (ret)
162562306a36Sopenharmony_ci		goto err_cleanup_dt;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable",
162862306a36Sopenharmony_ci						   GPIOD_OUT_HIGH);
162962306a36Sopenharmony_ci	if (IS_ERR(priv->gpiod_pwdn)) {
163062306a36Sopenharmony_ci		ret = PTR_ERR(priv->gpiod_pwdn);
163162306a36Sopenharmony_ci		goto err_cleanup_dt;
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn");
163562306a36Sopenharmony_ci	gpiod_set_value_cansleep(priv->gpiod_pwdn, 1);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	/* Wait at least 4ms before the I2C lines latch to the address */
163862306a36Sopenharmony_ci	if (priv->gpiod_pwdn)
163962306a36Sopenharmony_ci		usleep_range(4000, 5000);
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	/*
164262306a36Sopenharmony_ci	 * The MAX9286 starts by default with all ports enabled, we disable all
164362306a36Sopenharmony_ci	 * ports early to ensure that all channels are disabled if we error out
164462306a36Sopenharmony_ci	 * and keep the bus consistent.
164562306a36Sopenharmony_ci	 */
164662306a36Sopenharmony_ci	max9286_i2c_mux_close(priv);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/*
164962306a36Sopenharmony_ci	 * The MAX9286 initialises with auto-acknowledge enabled by default.
165062306a36Sopenharmony_ci	 * This can be invasive to other transactions on the same bus, so
165162306a36Sopenharmony_ci	 * disable it early. It will be enabled only as and when needed.
165262306a36Sopenharmony_ci	 */
165362306a36Sopenharmony_ci	max9286_configure_i2c(priv, false);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	ret = max9286_parse_gpios(priv);
165662306a36Sopenharmony_ci	if (ret)
165762306a36Sopenharmony_ci		goto err_powerdown;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	if (!priv->use_gpio_poc) {
166062306a36Sopenharmony_ci		ret = max9286_get_poc_supplies(priv);
166162306a36Sopenharmony_ci		if (ret)
166262306a36Sopenharmony_ci			goto err_cleanup_dt;
166362306a36Sopenharmony_ci	}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	ret = max9286_init(priv);
166662306a36Sopenharmony_ci	if (ret < 0)
166762306a36Sopenharmony_ci		goto err_cleanup_dt;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return 0;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cierr_powerdown:
167262306a36Sopenharmony_ci	gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
167362306a36Sopenharmony_cierr_cleanup_dt:
167462306a36Sopenharmony_ci	max9286_cleanup_dt(priv);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	return ret;
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic void max9286_remove(struct i2c_client *client)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client));
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	i2c_mux_del_adapters(priv->mux);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	max9286_v4l2_unregister(priv);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	max9286_poc_enable(priv, false);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	max9286_cleanup_dt(priv);
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic const struct of_device_id max9286_dt_ids[] = {
169562306a36Sopenharmony_ci	{ .compatible = "maxim,max9286" },
169662306a36Sopenharmony_ci	{},
169762306a36Sopenharmony_ci};
169862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max9286_dt_ids);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_cistatic struct i2c_driver max9286_i2c_driver = {
170162306a36Sopenharmony_ci	.driver	= {
170262306a36Sopenharmony_ci		.name		= "max9286",
170362306a36Sopenharmony_ci		.of_match_table	= max9286_dt_ids,
170462306a36Sopenharmony_ci	},
170562306a36Sopenharmony_ci	.probe		= max9286_probe,
170662306a36Sopenharmony_ci	.remove		= max9286_remove,
170762306a36Sopenharmony_ci};
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cimodule_i2c_driver(max9286_i2c_driver);
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ciMODULE_DESCRIPTION("Maxim MAX9286 GMSL Deserializer Driver");
171262306a36Sopenharmony_ciMODULE_AUTHOR("Jacopo Mondi, Kieran Bingham, Laurent Pinchart, Niklas Söderlund, Vladimir Barinov");
171362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1714