xref: /openbmc/linux/drivers/media/i2c/st-mipid02.c (revision 9399d61b)
1642bb5e8SMickael Guene // SPDX-License-Identifier: GPL-2.0
2642bb5e8SMickael Guene /*
3642bb5e8SMickael Guene  * Driver for ST MIPID02 CSI-2 to PARALLEL bridge
4642bb5e8SMickael Guene  *
5642bb5e8SMickael Guene  * Copyright (C) STMicroelectronics SA 2019
6642bb5e8SMickael Guene  * Authors: Mickael Guene <mickael.guene@st.com>
7642bb5e8SMickael Guene  *          for STMicroelectronics.
8642bb5e8SMickael Guene  *
9642bb5e8SMickael Guene  *
10642bb5e8SMickael Guene  */
11642bb5e8SMickael Guene 
12642bb5e8SMickael Guene #include <linux/clk.h>
13642bb5e8SMickael Guene #include <linux/delay.h>
14642bb5e8SMickael Guene #include <linux/gpio/consumer.h>
15642bb5e8SMickael Guene #include <linux/i2c.h>
16642bb5e8SMickael Guene #include <linux/module.h>
17642bb5e8SMickael Guene #include <linux/of_graph.h>
18642bb5e8SMickael Guene #include <linux/regulator/consumer.h>
19642bb5e8SMickael Guene #include <media/v4l2-async.h>
20642bb5e8SMickael Guene #include <media/v4l2-ctrls.h>
21642bb5e8SMickael Guene #include <media/v4l2-device.h>
22642bb5e8SMickael Guene #include <media/v4l2-fwnode.h>
23642bb5e8SMickael Guene #include <media/v4l2-subdev.h>
24642bb5e8SMickael Guene 
25642bb5e8SMickael Guene #define MIPID02_CLK_LANE_WR_REG1			0x01
26642bb5e8SMickael Guene #define MIPID02_CLK_LANE_REG1				0x02
27642bb5e8SMickael Guene #define MIPID02_CLK_LANE_REG3				0x04
28642bb5e8SMickael Guene #define MIPID02_DATA_LANE0_REG1				0x05
29642bb5e8SMickael Guene #define MIPID02_DATA_LANE0_REG2				0x06
30642bb5e8SMickael Guene #define MIPID02_DATA_LANE1_REG1				0x09
31642bb5e8SMickael Guene #define MIPID02_DATA_LANE1_REG2				0x0a
32642bb5e8SMickael Guene #define MIPID02_MODE_REG1				0x14
33642bb5e8SMickael Guene #define MIPID02_MODE_REG2				0x15
34642bb5e8SMickael Guene #define MIPID02_DATA_ID_RREG				0x17
35642bb5e8SMickael Guene #define MIPID02_DATA_SELECTION_CTRL			0x19
36642bb5e8SMickael Guene #define MIPID02_PIX_WIDTH_CTRL				0x1e
37642bb5e8SMickael Guene #define MIPID02_PIX_WIDTH_CTRL_EMB			0x1f
38642bb5e8SMickael Guene 
39642bb5e8SMickael Guene /* Bits definition for MIPID02_CLK_LANE_REG1 */
40642bb5e8SMickael Guene #define CLK_ENABLE					BIT(0)
41642bb5e8SMickael Guene /* Bits definition for MIPID02_CLK_LANE_REG3 */
42642bb5e8SMickael Guene #define CLK_MIPI_CSI					BIT(1)
43642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_LANE0_REG1 */
44642bb5e8SMickael Guene #define DATA_ENABLE					BIT(0)
45642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_LANEx_REG2 */
46642bb5e8SMickael Guene #define DATA_MIPI_CSI					BIT(0)
47642bb5e8SMickael Guene /* Bits definition for MIPID02_MODE_REG1 */
48642bb5e8SMickael Guene #define MODE_DATA_SWAP					BIT(2)
49642bb5e8SMickael Guene #define MODE_NO_BYPASS					BIT(6)
50642bb5e8SMickael Guene /* Bits definition for MIPID02_MODE_REG2 */
51642bb5e8SMickael Guene #define MODE_HSYNC_ACTIVE_HIGH				BIT(1)
52642bb5e8SMickael Guene #define MODE_VSYNC_ACTIVE_HIGH				BIT(2)
5381bf9e2eSHugues Fruchet #define MODE_PCLK_SAMPLE_RISING				BIT(3)
54642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_SELECTION_CTRL */
55642bb5e8SMickael Guene #define SELECTION_MANUAL_DATA				BIT(2)
56642bb5e8SMickael Guene #define SELECTION_MANUAL_WIDTH				BIT(3)
57642bb5e8SMickael Guene 
58642bb5e8SMickael Guene static const u32 mipid02_supported_fmt_codes[] = {
59642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
60642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
61642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
62642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
63642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12,
64642bb5e8SMickael Guene 	MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12,
65d0034926SHugues Fruchet 	MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16,
66d0034926SHugues Fruchet 	MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16,
67d0034926SHugues Fruchet 	MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24,
68197adee6SHugues Fruchet 	MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE,
695109fc8dSAlain Volmat 	MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8,
705109fc8dSAlain Volmat 	MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8,
7103aedb1dSHugues Fruchet 	MEDIA_BUS_FMT_JPEG_1X8
72642bb5e8SMickael Guene };
73642bb5e8SMickael Guene 
74642bb5e8SMickael Guene /* regulator supplies */
75642bb5e8SMickael Guene static const char * const mipid02_supply_name[] = {
76642bb5e8SMickael Guene 	"VDDE", /* 1.8V digital I/O supply */
77642bb5e8SMickael Guene 	"VDDIN", /* 1V8 voltage regulator supply */
78642bb5e8SMickael Guene };
79642bb5e8SMickael Guene 
80642bb5e8SMickael Guene #define MIPID02_NUM_SUPPLIES		ARRAY_SIZE(mipid02_supply_name)
81642bb5e8SMickael Guene 
82642bb5e8SMickael Guene #define MIPID02_SINK_0			0
83642bb5e8SMickael Guene #define MIPID02_SINK_1			1
84642bb5e8SMickael Guene #define MIPID02_SOURCE			2
85642bb5e8SMickael Guene #define MIPID02_PAD_NB			3
86642bb5e8SMickael Guene 
87642bb5e8SMickael Guene struct mipid02_dev {
88642bb5e8SMickael Guene 	struct i2c_client *i2c_client;
89642bb5e8SMickael Guene 	struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES];
90642bb5e8SMickael Guene 	struct v4l2_subdev sd;
91642bb5e8SMickael Guene 	struct media_pad pad[MIPID02_PAD_NB];
92642bb5e8SMickael Guene 	struct clk *xclk;
93642bb5e8SMickael Guene 	struct gpio_desc *reset_gpio;
94642bb5e8SMickael Guene 	/* endpoints info */
95642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint rx;
96642bb5e8SMickael Guene 	u64 link_frequency;
97642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint tx;
98642bb5e8SMickael Guene 	/* remote source */
99642bb5e8SMickael Guene 	struct v4l2_async_notifier notifier;
100642bb5e8SMickael Guene 	struct v4l2_subdev *s_subdev;
101642bb5e8SMickael Guene 	/* registers */
102642bb5e8SMickael Guene 	struct {
103642bb5e8SMickael Guene 		u8 clk_lane_reg1;
104642bb5e8SMickael Guene 		u8 data_lane0_reg1;
105642bb5e8SMickael Guene 		u8 data_lane1_reg1;
106642bb5e8SMickael Guene 		u8 mode_reg1;
107642bb5e8SMickael Guene 		u8 mode_reg2;
10803aedb1dSHugues Fruchet 		u8 data_selection_ctrl;
109642bb5e8SMickael Guene 		u8 data_id_rreg;
110642bb5e8SMickael Guene 		u8 pix_width_ctrl;
111642bb5e8SMickael Guene 		u8 pix_width_ctrl_emb;
112642bb5e8SMickael Guene 	} r;
113642bb5e8SMickael Guene 	/* lock to protect all members below */
114642bb5e8SMickael Guene 	struct mutex lock;
115642bb5e8SMickael Guene 	bool streaming;
116642bb5e8SMickael Guene 	struct v4l2_mbus_framefmt fmt;
117642bb5e8SMickael Guene };
118642bb5e8SMickael Guene 
bpp_from_code(__u32 code)119642bb5e8SMickael Guene static int bpp_from_code(__u32 code)
120642bb5e8SMickael Guene {
121642bb5e8SMickael Guene 	switch (code) {
122642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR8_1X8:
123642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG8_1X8:
124642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG8_1X8:
125642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB8_1X8:
126642bb5e8SMickael Guene 		return 8;
127642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR10_1X10:
128642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG10_1X10:
129642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG10_1X10:
130642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB10_1X10:
131642bb5e8SMickael Guene 		return 10;
132642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR12_1X12:
133642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG12_1X12:
134642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG12_1X12:
135642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB12_1X12:
136642bb5e8SMickael Guene 		return 12;
137d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_1X16:
138d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_YVYU8_1X16:
139642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_UYVY8_1X16:
140d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_VYUY8_1X16:
141d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_1X16:
142b9f343dfSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
1435109fc8dSAlain Volmat 	case MEDIA_BUS_FMT_YVYU8_2X8:
144b9f343dfSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
1455109fc8dSAlain Volmat 	case MEDIA_BUS_FMT_VYUY8_2X8:
146197adee6SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
147197adee6SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
148642bb5e8SMickael Guene 		return 16;
149642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_BGR888_1X24:
150642bb5e8SMickael Guene 		return 24;
151642bb5e8SMickael Guene 	default:
152642bb5e8SMickael Guene 		return 0;
153642bb5e8SMickael Guene 	}
154642bb5e8SMickael Guene }
155642bb5e8SMickael Guene 
data_type_from_code(__u32 code)156642bb5e8SMickael Guene static u8 data_type_from_code(__u32 code)
157642bb5e8SMickael Guene {
158642bb5e8SMickael Guene 	switch (code) {
159642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR8_1X8:
160642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG8_1X8:
161642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG8_1X8:
162642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB8_1X8:
163642bb5e8SMickael Guene 		return 0x2a;
164642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR10_1X10:
165642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG10_1X10:
166642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG10_1X10:
167642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB10_1X10:
168642bb5e8SMickael Guene 		return 0x2b;
169642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SBGGR12_1X12:
170642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGBRG12_1X12:
171642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SGRBG12_1X12:
172642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_SRGGB12_1X12:
173642bb5e8SMickael Guene 		return 0x2c;
174d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_1X16:
175d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_YVYU8_1X16:
176642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_UYVY8_1X16:
177d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_VYUY8_1X16:
178b9f343dfSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
1795109fc8dSAlain Volmat 	case MEDIA_BUS_FMT_YVYU8_2X8:
180b9f343dfSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
1815109fc8dSAlain Volmat 	case MEDIA_BUS_FMT_VYUY8_2X8:
182642bb5e8SMickael Guene 		return 0x1e;
183642bb5e8SMickael Guene 	case MEDIA_BUS_FMT_BGR888_1X24:
184642bb5e8SMickael Guene 		return 0x24;
185d0034926SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_1X16:
186197adee6SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
187197adee6SHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
188197adee6SHugues Fruchet 		return 0x22;
189642bb5e8SMickael Guene 	default:
190642bb5e8SMickael Guene 		return 0;
191642bb5e8SMickael Guene 	}
192642bb5e8SMickael Guene }
193642bb5e8SMickael Guene 
init_format(struct v4l2_mbus_framefmt * fmt)194642bb5e8SMickael Guene static void init_format(struct v4l2_mbus_framefmt *fmt)
195642bb5e8SMickael Guene {
196642bb5e8SMickael Guene 	fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
197642bb5e8SMickael Guene 	fmt->field = V4L2_FIELD_NONE;
198642bb5e8SMickael Guene 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
199642bb5e8SMickael Guene 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB);
200642bb5e8SMickael Guene 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
201642bb5e8SMickael Guene 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB);
202642bb5e8SMickael Guene 	fmt->width = 640;
203642bb5e8SMickael Guene 	fmt->height = 480;
204642bb5e8SMickael Guene }
205642bb5e8SMickael Guene 
get_fmt_code(__u32 code)206642bb5e8SMickael Guene static __u32 get_fmt_code(__u32 code)
207642bb5e8SMickael Guene {
208642bb5e8SMickael Guene 	unsigned int i;
209642bb5e8SMickael Guene 
210642bb5e8SMickael Guene 	for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) {
211642bb5e8SMickael Guene 		if (code == mipid02_supported_fmt_codes[i])
212642bb5e8SMickael Guene 			return code;
213642bb5e8SMickael Guene 	}
214642bb5e8SMickael Guene 
215642bb5e8SMickael Guene 	return mipid02_supported_fmt_codes[0];
216642bb5e8SMickael Guene }
217642bb5e8SMickael Guene 
serial_to_parallel_code(__u32 serial)218642bb5e8SMickael Guene static __u32 serial_to_parallel_code(__u32 serial)
219642bb5e8SMickael Guene {
220d0034926SHugues Fruchet 	if (serial == MEDIA_BUS_FMT_RGB565_1X16)
221d0034926SHugues Fruchet 		return MEDIA_BUS_FMT_RGB565_2X8_LE;
222d0034926SHugues Fruchet 	if (serial == MEDIA_BUS_FMT_YUYV8_1X16)
223d0034926SHugues Fruchet 		return MEDIA_BUS_FMT_YUYV8_2X8;
224d0034926SHugues Fruchet 	if (serial == MEDIA_BUS_FMT_YVYU8_1X16)
225d0034926SHugues Fruchet 		return MEDIA_BUS_FMT_YVYU8_2X8;
226642bb5e8SMickael Guene 	if (serial == MEDIA_BUS_FMT_UYVY8_1X16)
227642bb5e8SMickael Guene 		return MEDIA_BUS_FMT_UYVY8_2X8;
228d0034926SHugues Fruchet 	if (serial == MEDIA_BUS_FMT_VYUY8_1X16)
229d0034926SHugues Fruchet 		return MEDIA_BUS_FMT_VYUY8_2X8;
230642bb5e8SMickael Guene 	if (serial == MEDIA_BUS_FMT_BGR888_1X24)
231642bb5e8SMickael Guene 		return MEDIA_BUS_FMT_BGR888_3X8;
232642bb5e8SMickael Guene 
233642bb5e8SMickael Guene 	return serial;
234642bb5e8SMickael Guene }
235642bb5e8SMickael Guene 
to_mipid02_dev(struct v4l2_subdev * sd)236642bb5e8SMickael Guene static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd)
237642bb5e8SMickael Guene {
238642bb5e8SMickael Guene 	return container_of(sd, struct mipid02_dev, sd);
239642bb5e8SMickael Guene }
240642bb5e8SMickael Guene 
mipid02_read_reg(struct mipid02_dev * bridge,u16 reg,u8 * val)241642bb5e8SMickael Guene static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val)
242642bb5e8SMickael Guene {
243642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
244642bb5e8SMickael Guene 	struct i2c_msg msg[2];
245642bb5e8SMickael Guene 	u8 buf[2];
246642bb5e8SMickael Guene 	int ret;
247642bb5e8SMickael Guene 
248642bb5e8SMickael Guene 	buf[0] = reg >> 8;
249642bb5e8SMickael Guene 	buf[1] = reg & 0xff;
250642bb5e8SMickael Guene 
251642bb5e8SMickael Guene 	msg[0].addr = client->addr;
252642bb5e8SMickael Guene 	msg[0].flags = client->flags;
253642bb5e8SMickael Guene 	msg[0].buf = buf;
254642bb5e8SMickael Guene 	msg[0].len = sizeof(buf);
255642bb5e8SMickael Guene 
256642bb5e8SMickael Guene 	msg[1].addr = client->addr;
257642bb5e8SMickael Guene 	msg[1].flags = client->flags | I2C_M_RD;
258642bb5e8SMickael Guene 	msg[1].buf = val;
259642bb5e8SMickael Guene 	msg[1].len = 1;
260642bb5e8SMickael Guene 
261642bb5e8SMickael Guene 	ret = i2c_transfer(client->adapter, msg, 2);
262642bb5e8SMickael Guene 	if (ret < 0) {
263642bb5e8SMickael Guene 		dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n",
264642bb5e8SMickael Guene 			    __func__, client->addr, reg, ret);
265642bb5e8SMickael Guene 		return ret;
266642bb5e8SMickael Guene 	}
267642bb5e8SMickael Guene 
268642bb5e8SMickael Guene 	return 0;
269642bb5e8SMickael Guene }
270642bb5e8SMickael Guene 
mipid02_write_reg(struct mipid02_dev * bridge,u16 reg,u8 val)271642bb5e8SMickael Guene static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val)
272642bb5e8SMickael Guene {
273642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
274642bb5e8SMickael Guene 	struct i2c_msg msg;
275642bb5e8SMickael Guene 	u8 buf[3];
276642bb5e8SMickael Guene 	int ret;
277642bb5e8SMickael Guene 
278642bb5e8SMickael Guene 	buf[0] = reg >> 8;
279642bb5e8SMickael Guene 	buf[1] = reg & 0xff;
280642bb5e8SMickael Guene 	buf[2] = val;
281642bb5e8SMickael Guene 
282642bb5e8SMickael Guene 	msg.addr = client->addr;
283642bb5e8SMickael Guene 	msg.flags = client->flags;
284642bb5e8SMickael Guene 	msg.buf = buf;
285642bb5e8SMickael Guene 	msg.len = sizeof(buf);
286642bb5e8SMickael Guene 
287642bb5e8SMickael Guene 	ret = i2c_transfer(client->adapter, &msg, 1);
288642bb5e8SMickael Guene 	if (ret < 0) {
289642bb5e8SMickael Guene 		dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n",
290642bb5e8SMickael Guene 			    __func__, reg, ret);
291642bb5e8SMickael Guene 		return ret;
292642bb5e8SMickael Guene 	}
293642bb5e8SMickael Guene 
294642bb5e8SMickael Guene 	return 0;
295642bb5e8SMickael Guene }
296642bb5e8SMickael Guene 
mipid02_get_regulators(struct mipid02_dev * bridge)297642bb5e8SMickael Guene static int mipid02_get_regulators(struct mipid02_dev *bridge)
298642bb5e8SMickael Guene {
299642bb5e8SMickael Guene 	unsigned int i;
300642bb5e8SMickael Guene 
301642bb5e8SMickael Guene 	for (i = 0; i < MIPID02_NUM_SUPPLIES; i++)
302642bb5e8SMickael Guene 		bridge->supplies[i].supply = mipid02_supply_name[i];
303642bb5e8SMickael Guene 
304642bb5e8SMickael Guene 	return devm_regulator_bulk_get(&bridge->i2c_client->dev,
305642bb5e8SMickael Guene 				       MIPID02_NUM_SUPPLIES,
306642bb5e8SMickael Guene 				       bridge->supplies);
307642bb5e8SMickael Guene }
308642bb5e8SMickael Guene 
mipid02_apply_reset(struct mipid02_dev * bridge)309642bb5e8SMickael Guene static void mipid02_apply_reset(struct mipid02_dev *bridge)
310642bb5e8SMickael Guene {
311642bb5e8SMickael Guene 	gpiod_set_value_cansleep(bridge->reset_gpio, 0);
312642bb5e8SMickael Guene 	usleep_range(5000, 10000);
313642bb5e8SMickael Guene 	gpiod_set_value_cansleep(bridge->reset_gpio, 1);
314642bb5e8SMickael Guene 	usleep_range(5000, 10000);
315642bb5e8SMickael Guene 	gpiod_set_value_cansleep(bridge->reset_gpio, 0);
316642bb5e8SMickael Guene 	usleep_range(5000, 10000);
317642bb5e8SMickael Guene }
318642bb5e8SMickael Guene 
mipid02_set_power_on(struct mipid02_dev * bridge)319642bb5e8SMickael Guene static int mipid02_set_power_on(struct mipid02_dev *bridge)
320642bb5e8SMickael Guene {
321642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
322642bb5e8SMickael Guene 	int ret;
323642bb5e8SMickael Guene 
324642bb5e8SMickael Guene 	ret = clk_prepare_enable(bridge->xclk);
325642bb5e8SMickael Guene 	if (ret) {
326642bb5e8SMickael Guene 		dev_err(&client->dev, "%s: failed to enable clock\n", __func__);
327642bb5e8SMickael Guene 		return ret;
328642bb5e8SMickael Guene 	}
329642bb5e8SMickael Guene 
330642bb5e8SMickael Guene 	ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES,
331642bb5e8SMickael Guene 				    bridge->supplies);
332642bb5e8SMickael Guene 	if (ret) {
333642bb5e8SMickael Guene 		dev_err(&client->dev, "%s: failed to enable regulators\n",
334642bb5e8SMickael Guene 			    __func__);
335642bb5e8SMickael Guene 		goto xclk_off;
336642bb5e8SMickael Guene 	}
337642bb5e8SMickael Guene 
338642bb5e8SMickael Guene 	if (bridge->reset_gpio) {
339642bb5e8SMickael Guene 		dev_dbg(&client->dev, "apply reset");
340642bb5e8SMickael Guene 		mipid02_apply_reset(bridge);
341642bb5e8SMickael Guene 	} else {
342642bb5e8SMickael Guene 		dev_dbg(&client->dev, "don't apply reset");
343642bb5e8SMickael Guene 		usleep_range(5000, 10000);
344642bb5e8SMickael Guene 	}
345642bb5e8SMickael Guene 
346642bb5e8SMickael Guene 	return 0;
347642bb5e8SMickael Guene 
348642bb5e8SMickael Guene xclk_off:
349642bb5e8SMickael Guene 	clk_disable_unprepare(bridge->xclk);
350642bb5e8SMickael Guene 	return ret;
351642bb5e8SMickael Guene }
352642bb5e8SMickael Guene 
mipid02_set_power_off(struct mipid02_dev * bridge)353642bb5e8SMickael Guene static void mipid02_set_power_off(struct mipid02_dev *bridge)
354642bb5e8SMickael Guene {
355642bb5e8SMickael Guene 	regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies);
356642bb5e8SMickael Guene 	clk_disable_unprepare(bridge->xclk);
357642bb5e8SMickael Guene }
358642bb5e8SMickael Guene 
mipid02_detect(struct mipid02_dev * bridge)359642bb5e8SMickael Guene static int mipid02_detect(struct mipid02_dev *bridge)
360642bb5e8SMickael Guene {
361642bb5e8SMickael Guene 	u8 reg;
362642bb5e8SMickael Guene 
363642bb5e8SMickael Guene 	/*
364642bb5e8SMickael Guene 	 * There is no version registers. Just try to read register
365642bb5e8SMickael Guene 	 * MIPID02_CLK_LANE_WR_REG1.
366642bb5e8SMickael Guene 	 */
367642bb5e8SMickael Guene 	return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, &reg);
368642bb5e8SMickael Guene }
369642bb5e8SMickael Guene 
mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev * bridge,struct v4l2_subdev * subdev)3706a381d10SHugues Fruchet static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge,
3716a381d10SHugues Fruchet 						    struct v4l2_subdev *subdev)
3726a381d10SHugues Fruchet {
3736a381d10SHugues Fruchet 	struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, };
3746a381d10SHugues Fruchet 	struct v4l2_ctrl *ctrl;
3756a381d10SHugues Fruchet 	int ret;
3766a381d10SHugues Fruchet 
3776a381d10SHugues Fruchet 	ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ);
3786a381d10SHugues Fruchet 	if (!ctrl)
3796a381d10SHugues Fruchet 		return 0;
3806a381d10SHugues Fruchet 	qm.index = v4l2_ctrl_g_ctrl(ctrl);
3816a381d10SHugues Fruchet 
3826a381d10SHugues Fruchet 	ret = v4l2_querymenu(subdev->ctrl_handler, &qm);
3836a381d10SHugues Fruchet 	if (ret)
3846a381d10SHugues Fruchet 		return 0;
3856a381d10SHugues Fruchet 
3866a381d10SHugues Fruchet 	return qm.value;
3876a381d10SHugues Fruchet }
3886a381d10SHugues Fruchet 
mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev * bridge,struct v4l2_subdev * subdev)389642bb5e8SMickael Guene static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge,
390642bb5e8SMickael Guene 						     struct v4l2_subdev *subdev)
391642bb5e8SMickael Guene {
392642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint *ep = &bridge->rx;
393642bb5e8SMickael Guene 	struct v4l2_ctrl *ctrl;
394642bb5e8SMickael Guene 	u32 pixel_clock;
395642bb5e8SMickael Guene 	u32 bpp = bpp_from_code(bridge->fmt.code);
396642bb5e8SMickael Guene 
397642bb5e8SMickael Guene 	ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
398642bb5e8SMickael Guene 	if (!ctrl)
399642bb5e8SMickael Guene 		return 0;
400642bb5e8SMickael Guene 	pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl);
401642bb5e8SMickael Guene 
402642bb5e8SMickael Guene 	return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes);
403642bb5e8SMickael Guene }
404642bb5e8SMickael Guene 
405642bb5e8SMickael Guene /*
406642bb5e8SMickael Guene  * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency
407642bb5e8SMickael Guene  * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel
408642bb5e8SMickael Guene  * and number of lanes.
409642bb5e8SMickael Guene  */
mipid02_configure_from_rx_speed(struct mipid02_dev * bridge)410642bb5e8SMickael Guene static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge)
411642bb5e8SMickael Guene {
412642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
413642bb5e8SMickael Guene 	struct v4l2_subdev *subdev = bridge->s_subdev;
414642bb5e8SMickael Guene 	u32 link_freq;
415642bb5e8SMickael Guene 
4166a381d10SHugues Fruchet 	link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev);
417642bb5e8SMickael Guene 	if (!link_freq) {
4186a381d10SHugues Fruchet 		link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge,
4196a381d10SHugues Fruchet 								      subdev);
4206a381d10SHugues Fruchet 		if (!link_freq) {
4216a381d10SHugues Fruchet 			dev_err(&client->dev, "Failed to get link frequency");
422642bb5e8SMickael Guene 			return -EINVAL;
423642bb5e8SMickael Guene 		}
4246a381d10SHugues Fruchet 	}
425642bb5e8SMickael Guene 
426642bb5e8SMickael Guene 	dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq);
427642bb5e8SMickael Guene 	bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2;
428642bb5e8SMickael Guene 
429642bb5e8SMickael Guene 	return 0;
430642bb5e8SMickael Guene }
431642bb5e8SMickael Guene 
mipid02_configure_clk_lane(struct mipid02_dev * bridge)432642bb5e8SMickael Guene static int mipid02_configure_clk_lane(struct mipid02_dev *bridge)
433642bb5e8SMickael Guene {
434642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
435642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint *ep = &bridge->rx;
436642bb5e8SMickael Guene 	bool *polarities = ep->bus.mipi_csi2.lane_polarities;
437642bb5e8SMickael Guene 
438642bb5e8SMickael Guene 	/* midid02 doesn't support clock lane remapping */
439642bb5e8SMickael Guene 	if (ep->bus.mipi_csi2.clock_lane != 0) {
440642bb5e8SMickael Guene 		dev_err(&client->dev, "clk lane must be map to lane 0\n");
441642bb5e8SMickael Guene 		return -EINVAL;
442642bb5e8SMickael Guene 	}
443642bb5e8SMickael Guene 	bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE;
444642bb5e8SMickael Guene 
445642bb5e8SMickael Guene 	return 0;
446642bb5e8SMickael Guene }
447642bb5e8SMickael Guene 
mipid02_configure_data0_lane(struct mipid02_dev * bridge,int nb,bool are_lanes_swap,bool * polarities)448642bb5e8SMickael Guene static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb,
449642bb5e8SMickael Guene 					bool are_lanes_swap, bool *polarities)
450642bb5e8SMickael Guene {
451642bb5e8SMickael Guene 	bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1];
452642bb5e8SMickael Guene 
453642bb5e8SMickael Guene 	if (nb == 1 && are_lanes_swap)
454642bb5e8SMickael Guene 		return 0;
455642bb5e8SMickael Guene 
456642bb5e8SMickael Guene 	/*
457642bb5e8SMickael Guene 	 * data lane 0 as pin swap polarity reversed compared to clock and
458642bb5e8SMickael Guene 	 * data lane 1
459642bb5e8SMickael Guene 	 */
460642bb5e8SMickael Guene 	if (!are_pin_swap)
461642bb5e8SMickael Guene 		bridge->r.data_lane0_reg1 = 1 << 1;
462642bb5e8SMickael Guene 	bridge->r.data_lane0_reg1 |= DATA_ENABLE;
463642bb5e8SMickael Guene 
464642bb5e8SMickael Guene 	return 0;
465642bb5e8SMickael Guene }
466642bb5e8SMickael Guene 
mipid02_configure_data1_lane(struct mipid02_dev * bridge,int nb,bool are_lanes_swap,bool * polarities)467642bb5e8SMickael Guene static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb,
468642bb5e8SMickael Guene 					bool are_lanes_swap, bool *polarities)
469642bb5e8SMickael Guene {
470642bb5e8SMickael Guene 	bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2];
471642bb5e8SMickael Guene 
472642bb5e8SMickael Guene 	if (nb == 1 && !are_lanes_swap)
473642bb5e8SMickael Guene 		return 0;
474642bb5e8SMickael Guene 
475642bb5e8SMickael Guene 	if (are_pin_swap)
476642bb5e8SMickael Guene 		bridge->r.data_lane1_reg1 = 1 << 1;
477642bb5e8SMickael Guene 	bridge->r.data_lane1_reg1 |= DATA_ENABLE;
478642bb5e8SMickael Guene 
479642bb5e8SMickael Guene 	return 0;
480642bb5e8SMickael Guene }
481642bb5e8SMickael Guene 
mipid02_configure_from_rx(struct mipid02_dev * bridge)482642bb5e8SMickael Guene static int mipid02_configure_from_rx(struct mipid02_dev *bridge)
483642bb5e8SMickael Guene {
484642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint *ep = &bridge->rx;
485642bb5e8SMickael Guene 	bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2;
486642bb5e8SMickael Guene 	bool *polarities = ep->bus.mipi_csi2.lane_polarities;
487642bb5e8SMickael Guene 	int nb = ep->bus.mipi_csi2.num_data_lanes;
488642bb5e8SMickael Guene 	int ret;
489642bb5e8SMickael Guene 
490642bb5e8SMickael Guene 	ret = mipid02_configure_clk_lane(bridge);
491642bb5e8SMickael Guene 	if (ret)
492642bb5e8SMickael Guene 		return ret;
493642bb5e8SMickael Guene 
494642bb5e8SMickael Guene 	ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap,
495642bb5e8SMickael Guene 					   polarities);
496642bb5e8SMickael Guene 	if (ret)
497642bb5e8SMickael Guene 		return ret;
498642bb5e8SMickael Guene 
499642bb5e8SMickael Guene 	ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap,
500642bb5e8SMickael Guene 					   polarities);
501642bb5e8SMickael Guene 	if (ret)
502642bb5e8SMickael Guene 		return ret;
503642bb5e8SMickael Guene 
504642bb5e8SMickael Guene 	bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0;
505642bb5e8SMickael Guene 	bridge->r.mode_reg1 |= (nb - 1) << 1;
506642bb5e8SMickael Guene 
507642bb5e8SMickael Guene 	return mipid02_configure_from_rx_speed(bridge);
508642bb5e8SMickael Guene }
509642bb5e8SMickael Guene 
mipid02_configure_from_tx(struct mipid02_dev * bridge)510642bb5e8SMickael Guene static int mipid02_configure_from_tx(struct mipid02_dev *bridge)
511642bb5e8SMickael Guene {
512642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint *ep = &bridge->tx;
513642bb5e8SMickael Guene 
51403aedb1dSHugues Fruchet 	bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH;
515642bb5e8SMickael Guene 	bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width;
516642bb5e8SMickael Guene 	bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width;
517642bb5e8SMickael Guene 	if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
518642bb5e8SMickael Guene 		bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH;
519642bb5e8SMickael Guene 	if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
520642bb5e8SMickael Guene 		bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH;
52181bf9e2eSHugues Fruchet 	if (ep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
52281bf9e2eSHugues Fruchet 		bridge->r.mode_reg2 |= MODE_PCLK_SAMPLE_RISING;
523642bb5e8SMickael Guene 
524642bb5e8SMickael Guene 	return 0;
525642bb5e8SMickael Guene }
526642bb5e8SMickael Guene 
mipid02_configure_from_code(struct mipid02_dev * bridge)527642bb5e8SMickael Guene static int mipid02_configure_from_code(struct mipid02_dev *bridge)
528642bb5e8SMickael Guene {
529642bb5e8SMickael Guene 	u8 data_type;
530642bb5e8SMickael Guene 
531642bb5e8SMickael Guene 	bridge->r.data_id_rreg = 0;
53203aedb1dSHugues Fruchet 
53303aedb1dSHugues Fruchet 	if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) {
53403aedb1dSHugues Fruchet 		bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA;
53503aedb1dSHugues Fruchet 
536642bb5e8SMickael Guene 		data_type = data_type_from_code(bridge->fmt.code);
537642bb5e8SMickael Guene 		if (!data_type)
538642bb5e8SMickael Guene 			return -EINVAL;
539642bb5e8SMickael Guene 		bridge->r.data_id_rreg = data_type;
54003aedb1dSHugues Fruchet 	}
541642bb5e8SMickael Guene 
542642bb5e8SMickael Guene 	return 0;
543642bb5e8SMickael Guene }
544642bb5e8SMickael Guene 
mipid02_stream_disable(struct mipid02_dev * bridge)545642bb5e8SMickael Guene static int mipid02_stream_disable(struct mipid02_dev *bridge)
546642bb5e8SMickael Guene {
547642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
5487d0e95ebSAlain Volmat 	int ret = -EINVAL;
5497d0e95ebSAlain Volmat 
5507d0e95ebSAlain Volmat 	if (!bridge->s_subdev)
5517d0e95ebSAlain Volmat 		goto error;
5527d0e95ebSAlain Volmat 
5537d0e95ebSAlain Volmat 	ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0);
5547d0e95ebSAlain Volmat 	if (ret)
5557d0e95ebSAlain Volmat 		goto error;
556642bb5e8SMickael Guene 
557642bb5e8SMickael Guene 	/* Disable all lanes */
558642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0);
559642bb5e8SMickael Guene 	if (ret)
560642bb5e8SMickael Guene 		goto error;
561642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0);
562642bb5e8SMickael Guene 	if (ret)
563642bb5e8SMickael Guene 		goto error;
564642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0);
565642bb5e8SMickael Guene 	if (ret)
566642bb5e8SMickael Guene 		goto error;
567642bb5e8SMickael Guene error:
568642bb5e8SMickael Guene 	if (ret)
569642bb5e8SMickael Guene 		dev_err(&client->dev, "failed to stream off %d", ret);
570642bb5e8SMickael Guene 
571642bb5e8SMickael Guene 	return ret;
572642bb5e8SMickael Guene }
573642bb5e8SMickael Guene 
mipid02_stream_enable(struct mipid02_dev * bridge)574642bb5e8SMickael Guene static int mipid02_stream_enable(struct mipid02_dev *bridge)
575642bb5e8SMickael Guene {
576642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
577642bb5e8SMickael Guene 	int ret = -EINVAL;
578642bb5e8SMickael Guene 
579642bb5e8SMickael Guene 	if (!bridge->s_subdev)
580642bb5e8SMickael Guene 		goto error;
581642bb5e8SMickael Guene 
582642bb5e8SMickael Guene 	memset(&bridge->r, 0, sizeof(bridge->r));
583642bb5e8SMickael Guene 	/* build registers content */
584642bb5e8SMickael Guene 	ret = mipid02_configure_from_rx(bridge);
585642bb5e8SMickael Guene 	if (ret)
586642bb5e8SMickael Guene 		goto error;
587642bb5e8SMickael Guene 	ret = mipid02_configure_from_tx(bridge);
588642bb5e8SMickael Guene 	if (ret)
589642bb5e8SMickael Guene 		goto error;
590642bb5e8SMickael Guene 	ret = mipid02_configure_from_code(bridge);
591642bb5e8SMickael Guene 	if (ret)
592642bb5e8SMickael Guene 		goto error;
593642bb5e8SMickael Guene 
594642bb5e8SMickael Guene 	/* write mipi registers */
595642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1,
596642bb5e8SMickael Guene 		bridge->r.clk_lane_reg1);
597642bb5e8SMickael Guene 	if (ret)
598642bb5e8SMickael Guene 		goto error;
599642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI);
600642bb5e8SMickael Guene 	if (ret)
601642bb5e8SMickael Guene 		goto error;
602642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1,
603642bb5e8SMickael Guene 		bridge->r.data_lane0_reg1);
604642bb5e8SMickael Guene 	if (ret)
605642bb5e8SMickael Guene 		goto error;
606642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2,
607642bb5e8SMickael Guene 		DATA_MIPI_CSI);
608642bb5e8SMickael Guene 	if (ret)
609642bb5e8SMickael Guene 		goto error;
610642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1,
611642bb5e8SMickael Guene 		bridge->r.data_lane1_reg1);
612642bb5e8SMickael Guene 	if (ret)
613642bb5e8SMickael Guene 		goto error;
614642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2,
615642bb5e8SMickael Guene 		DATA_MIPI_CSI);
616642bb5e8SMickael Guene 	if (ret)
617642bb5e8SMickael Guene 		goto error;
618642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1,
619642bb5e8SMickael Guene 		MODE_NO_BYPASS | bridge->r.mode_reg1);
620642bb5e8SMickael Guene 	if (ret)
621642bb5e8SMickael Guene 		goto error;
622642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2,
623642bb5e8SMickael Guene 		bridge->r.mode_reg2);
624642bb5e8SMickael Guene 	if (ret)
625642bb5e8SMickael Guene 		goto error;
626642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG,
627642bb5e8SMickael Guene 		bridge->r.data_id_rreg);
628642bb5e8SMickael Guene 	if (ret)
629642bb5e8SMickael Guene 		goto error;
630642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL,
63103aedb1dSHugues Fruchet 		bridge->r.data_selection_ctrl);
632642bb5e8SMickael Guene 	if (ret)
633642bb5e8SMickael Guene 		goto error;
634642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL,
635642bb5e8SMickael Guene 		bridge->r.pix_width_ctrl);
636642bb5e8SMickael Guene 	if (ret)
637642bb5e8SMickael Guene 		goto error;
638642bb5e8SMickael Guene 	ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB,
639642bb5e8SMickael Guene 		bridge->r.pix_width_ctrl_emb);
640642bb5e8SMickael Guene 	if (ret)
641642bb5e8SMickael Guene 		goto error;
642642bb5e8SMickael Guene 
6437d0e95ebSAlain Volmat 	ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1);
6447d0e95ebSAlain Volmat 	if (ret)
6457d0e95ebSAlain Volmat 		goto error;
6467d0e95ebSAlain Volmat 
647642bb5e8SMickael Guene 	return 0;
648642bb5e8SMickael Guene 
649642bb5e8SMickael Guene error:
650642bb5e8SMickael Guene 	dev_err(&client->dev, "failed to stream on %d", ret);
651642bb5e8SMickael Guene 	mipid02_stream_disable(bridge);
652642bb5e8SMickael Guene 
653642bb5e8SMickael Guene 	return ret;
654642bb5e8SMickael Guene }
655642bb5e8SMickael Guene 
mipid02_s_stream(struct v4l2_subdev * sd,int enable)656642bb5e8SMickael Guene static int mipid02_s_stream(struct v4l2_subdev *sd, int enable)
657642bb5e8SMickael Guene {
658642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
659642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
660642bb5e8SMickael Guene 	int ret = 0;
661642bb5e8SMickael Guene 
662642bb5e8SMickael Guene 	dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__,
663642bb5e8SMickael Guene 		    enable, bridge->streaming);
664642bb5e8SMickael Guene 	mutex_lock(&bridge->lock);
665642bb5e8SMickael Guene 
666642bb5e8SMickael Guene 	if (bridge->streaming == enable)
667642bb5e8SMickael Guene 		goto out;
668642bb5e8SMickael Guene 
669642bb5e8SMickael Guene 	ret = enable ? mipid02_stream_enable(bridge) :
670642bb5e8SMickael Guene 		       mipid02_stream_disable(bridge);
671642bb5e8SMickael Guene 	if (!ret)
672642bb5e8SMickael Guene 		bridge->streaming = enable;
673642bb5e8SMickael Guene 
674642bb5e8SMickael Guene out:
675642bb5e8SMickael Guene 	dev_dbg(&client->dev, "%s current now = %d / %d", __func__,
676642bb5e8SMickael Guene 		    bridge->streaming, ret);
677642bb5e8SMickael Guene 	mutex_unlock(&bridge->lock);
678642bb5e8SMickael Guene 
679642bb5e8SMickael Guene 	return ret;
680642bb5e8SMickael Guene }
681642bb5e8SMickael Guene 
mipid02_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)682642bb5e8SMickael Guene static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
6830d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
684642bb5e8SMickael Guene 				 struct v4l2_subdev_mbus_code_enum *code)
685642bb5e8SMickael Guene {
686642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
687642bb5e8SMickael Guene 	int ret = 0;
688642bb5e8SMickael Guene 
689642bb5e8SMickael Guene 	switch (code->pad) {
690642bb5e8SMickael Guene 	case MIPID02_SINK_0:
691642bb5e8SMickael Guene 		if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes))
692642bb5e8SMickael Guene 			ret = -EINVAL;
693642bb5e8SMickael Guene 		else
694642bb5e8SMickael Guene 			code->code = mipid02_supported_fmt_codes[code->index];
695642bb5e8SMickael Guene 		break;
696642bb5e8SMickael Guene 	case MIPID02_SOURCE:
697642bb5e8SMickael Guene 		if (code->index == 0)
698642bb5e8SMickael Guene 			code->code = serial_to_parallel_code(bridge->fmt.code);
699642bb5e8SMickael Guene 		else
700642bb5e8SMickael Guene 			ret = -EINVAL;
701642bb5e8SMickael Guene 		break;
702642bb5e8SMickael Guene 	default:
703642bb5e8SMickael Guene 		ret = -EINVAL;
704642bb5e8SMickael Guene 	}
705642bb5e8SMickael Guene 
706642bb5e8SMickael Guene 	return ret;
707642bb5e8SMickael Guene }
708642bb5e8SMickael Guene 
mipid02_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)709642bb5e8SMickael Guene static int mipid02_get_fmt(struct v4l2_subdev *sd,
7100d346d2aSTomi Valkeinen 			   struct v4l2_subdev_state *sd_state,
711642bb5e8SMickael Guene 			   struct v4l2_subdev_format *format)
712642bb5e8SMickael Guene {
713642bb5e8SMickael Guene 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
714642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
715642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
716642bb5e8SMickael Guene 	struct v4l2_mbus_framefmt *fmt;
717642bb5e8SMickael Guene 
718642bb5e8SMickael Guene 	dev_dbg(&client->dev, "%s probe %d", __func__, format->pad);
719642bb5e8SMickael Guene 
720642bb5e8SMickael Guene 	if (format->pad >= MIPID02_PAD_NB)
721642bb5e8SMickael Guene 		return -EINVAL;
722642bb5e8SMickael Guene 	/* second CSI-2 pad not yet supported */
723642bb5e8SMickael Guene 	if (format->pad == MIPID02_SINK_1)
724642bb5e8SMickael Guene 		return -EINVAL;
725642bb5e8SMickael Guene 
726642bb5e8SMickael Guene 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
7270d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state,
7280d346d2aSTomi Valkeinen 						 format->pad);
729642bb5e8SMickael Guene 	else
730642bb5e8SMickael Guene 		fmt = &bridge->fmt;
731642bb5e8SMickael Guene 
732642bb5e8SMickael Guene 	mutex_lock(&bridge->lock);
733642bb5e8SMickael Guene 
734642bb5e8SMickael Guene 	*mbus_fmt = *fmt;
735642bb5e8SMickael Guene 	/* code may need to be converted for source */
736642bb5e8SMickael Guene 	if (format->pad == MIPID02_SOURCE)
737642bb5e8SMickael Guene 		mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code);
738642bb5e8SMickael Guene 
739642bb5e8SMickael Guene 	mutex_unlock(&bridge->lock);
740642bb5e8SMickael Guene 
741642bb5e8SMickael Guene 	return 0;
742642bb5e8SMickael Guene }
743642bb5e8SMickael Guene 
mipid02_set_fmt_source(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)744642bb5e8SMickael Guene static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
7450d346d2aSTomi Valkeinen 				   struct v4l2_subdev_state *sd_state,
746642bb5e8SMickael Guene 				   struct v4l2_subdev_format *format)
747642bb5e8SMickael Guene {
748642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
749642bb5e8SMickael Guene 
750306c3190SDaniel Scally 	/* source pad mirror sink pad */
751306c3190SDaniel Scally 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
752642bb5e8SMickael Guene 		format->format = bridge->fmt;
753306c3190SDaniel Scally 	else
754306c3190SDaniel Scally 		format->format = *v4l2_subdev_get_try_format(sd, sd_state,
755306c3190SDaniel Scally 							     MIPID02_SINK_0);
756306c3190SDaniel Scally 
757642bb5e8SMickael Guene 	/* but code may need to be converted */
758642bb5e8SMickael Guene 	format->format.code = serial_to_parallel_code(format->format.code);
759642bb5e8SMickael Guene 
760642bb5e8SMickael Guene 	/* only apply format for V4L2_SUBDEV_FORMAT_TRY case */
761642bb5e8SMickael Guene 	if (format->which != V4L2_SUBDEV_FORMAT_TRY)
762642bb5e8SMickael Guene 		return;
763642bb5e8SMickael Guene 
7646c01e6f3SDaniel Scally 	*v4l2_subdev_get_try_format(sd, sd_state, MIPID02_SOURCE) =
7656c01e6f3SDaniel Scally 		format->format;
766642bb5e8SMickael Guene }
767642bb5e8SMickael Guene 
mipid02_set_fmt_sink(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)768642bb5e8SMickael Guene static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
7690d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
770642bb5e8SMickael Guene 				 struct v4l2_subdev_format *format)
771642bb5e8SMickael Guene {
772642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
773*9399d61bSAlain Volmat 	struct v4l2_subdev_format source_fmt;
774642bb5e8SMickael Guene 	struct v4l2_mbus_framefmt *fmt;
775642bb5e8SMickael Guene 
776642bb5e8SMickael Guene 	format->format.code = get_fmt_code(format->format.code);
777642bb5e8SMickael Guene 
778642bb5e8SMickael Guene 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
7790d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
780642bb5e8SMickael Guene 	else
781642bb5e8SMickael Guene 		fmt = &bridge->fmt;
782642bb5e8SMickael Guene 
783642bb5e8SMickael Guene 	*fmt = format->format;
7846c01e6f3SDaniel Scally 
785*9399d61bSAlain Volmat 	/*
786*9399d61bSAlain Volmat 	 * Propagate the format change to the source pad, taking
787*9399d61bSAlain Volmat 	 * care not to update the format pointer given back to user
788*9399d61bSAlain Volmat 	 */
789*9399d61bSAlain Volmat 	source_fmt = *format;
790*9399d61bSAlain Volmat 	mipid02_set_fmt_source(sd, sd_state, &source_fmt);
791642bb5e8SMickael Guene }
792642bb5e8SMickael Guene 
mipid02_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)793642bb5e8SMickael Guene static int mipid02_set_fmt(struct v4l2_subdev *sd,
7940d346d2aSTomi Valkeinen 			   struct v4l2_subdev_state *sd_state,
795642bb5e8SMickael Guene 			   struct v4l2_subdev_format *format)
796642bb5e8SMickael Guene {
797642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
798642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
799642bb5e8SMickael Guene 	int ret = 0;
800642bb5e8SMickael Guene 
801642bb5e8SMickael Guene 	dev_dbg(&client->dev, "%s for %d", __func__, format->pad);
802642bb5e8SMickael Guene 
803642bb5e8SMickael Guene 	if (format->pad >= MIPID02_PAD_NB)
804642bb5e8SMickael Guene 		return -EINVAL;
805642bb5e8SMickael Guene 	/* second CSI-2 pad not yet supported */
806642bb5e8SMickael Guene 	if (format->pad == MIPID02_SINK_1)
807642bb5e8SMickael Guene 		return -EINVAL;
808642bb5e8SMickael Guene 
809642bb5e8SMickael Guene 	mutex_lock(&bridge->lock);
810642bb5e8SMickael Guene 
811642bb5e8SMickael Guene 	if (bridge->streaming) {
812642bb5e8SMickael Guene 		ret = -EBUSY;
813642bb5e8SMickael Guene 		goto error;
814642bb5e8SMickael Guene 	}
815642bb5e8SMickael Guene 
816642bb5e8SMickael Guene 	if (format->pad == MIPID02_SOURCE)
8170d346d2aSTomi Valkeinen 		mipid02_set_fmt_source(sd, sd_state, format);
818642bb5e8SMickael Guene 	else
8190d346d2aSTomi Valkeinen 		mipid02_set_fmt_sink(sd, sd_state, format);
820642bb5e8SMickael Guene 
821642bb5e8SMickael Guene error:
822642bb5e8SMickael Guene 	mutex_unlock(&bridge->lock);
823642bb5e8SMickael Guene 
824642bb5e8SMickael Guene 	return ret;
825642bb5e8SMickael Guene }
826642bb5e8SMickael Guene 
827642bb5e8SMickael Guene static const struct v4l2_subdev_video_ops mipid02_video_ops = {
828642bb5e8SMickael Guene 	.s_stream = mipid02_s_stream,
829642bb5e8SMickael Guene };
830642bb5e8SMickael Guene 
831642bb5e8SMickael Guene static const struct v4l2_subdev_pad_ops mipid02_pad_ops = {
832642bb5e8SMickael Guene 	.enum_mbus_code = mipid02_enum_mbus_code,
833642bb5e8SMickael Guene 	.get_fmt = mipid02_get_fmt,
834642bb5e8SMickael Guene 	.set_fmt = mipid02_set_fmt,
835642bb5e8SMickael Guene };
836642bb5e8SMickael Guene 
837642bb5e8SMickael Guene static const struct v4l2_subdev_ops mipid02_subdev_ops = {
838642bb5e8SMickael Guene 	.video = &mipid02_video_ops,
839642bb5e8SMickael Guene 	.pad = &mipid02_pad_ops,
840642bb5e8SMickael Guene };
841642bb5e8SMickael Guene 
842642bb5e8SMickael Guene static const struct media_entity_operations mipid02_subdev_entity_ops = {
843642bb5e8SMickael Guene 	.link_validate = v4l2_subdev_link_validate,
844642bb5e8SMickael Guene };
845642bb5e8SMickael Guene 
mipid02_async_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * s_subdev,struct v4l2_async_connection * asd)846642bb5e8SMickael Guene static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
847642bb5e8SMickael Guene 			       struct v4l2_subdev *s_subdev,
848adb2dcd5SSakari Ailus 			       struct v4l2_async_connection *asd)
849642bb5e8SMickael Guene {
850642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
851642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
852642bb5e8SMickael Guene 	int source_pad;
853642bb5e8SMickael Guene 	int ret;
854642bb5e8SMickael Guene 
855642bb5e8SMickael Guene 	dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev);
856642bb5e8SMickael Guene 
857642bb5e8SMickael Guene 	source_pad = media_entity_get_fwnode_pad(&s_subdev->entity,
858642bb5e8SMickael Guene 						 s_subdev->fwnode,
859642bb5e8SMickael Guene 						 MEDIA_PAD_FL_SOURCE);
860642bb5e8SMickael Guene 	if (source_pad < 0) {
861642bb5e8SMickael Guene 		dev_err(&client->dev, "Couldn't find output pad for subdev %s\n",
862642bb5e8SMickael Guene 			s_subdev->name);
863642bb5e8SMickael Guene 		return source_pad;
864642bb5e8SMickael Guene 	}
865642bb5e8SMickael Guene 
866642bb5e8SMickael Guene 	ret = media_create_pad_link(&s_subdev->entity, source_pad,
867642bb5e8SMickael Guene 				    &bridge->sd.entity, 0,
868642bb5e8SMickael Guene 				    MEDIA_LNK_FL_ENABLED |
869642bb5e8SMickael Guene 				    MEDIA_LNK_FL_IMMUTABLE);
870642bb5e8SMickael Guene 	if (ret) {
871642bb5e8SMickael Guene 		dev_err(&client->dev, "Couldn't create media link %d", ret);
872642bb5e8SMickael Guene 		return ret;
873642bb5e8SMickael Guene 	}
874642bb5e8SMickael Guene 
875642bb5e8SMickael Guene 	bridge->s_subdev = s_subdev;
876642bb5e8SMickael Guene 
877642bb5e8SMickael Guene 	return 0;
878642bb5e8SMickael Guene }
879642bb5e8SMickael Guene 
mipid02_async_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * s_subdev,struct v4l2_async_connection * asd)880642bb5e8SMickael Guene static void mipid02_async_unbind(struct v4l2_async_notifier *notifier,
881642bb5e8SMickael Guene 				 struct v4l2_subdev *s_subdev,
882adb2dcd5SSakari Ailus 				 struct v4l2_async_connection *asd)
883642bb5e8SMickael Guene {
884642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd);
885642bb5e8SMickael Guene 
886642bb5e8SMickael Guene 	bridge->s_subdev = NULL;
887642bb5e8SMickael Guene }
888642bb5e8SMickael Guene 
889642bb5e8SMickael Guene static const struct v4l2_async_notifier_operations mipid02_notifier_ops = {
890642bb5e8SMickael Guene 	.bound		= mipid02_async_bound,
891642bb5e8SMickael Guene 	.unbind		= mipid02_async_unbind,
892642bb5e8SMickael Guene };
893642bb5e8SMickael Guene 
mipid02_parse_rx_ep(struct mipid02_dev * bridge)894642bb5e8SMickael Guene static int mipid02_parse_rx_ep(struct mipid02_dev *bridge)
895642bb5e8SMickael Guene {
896642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
897642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
898adb2dcd5SSakari Ailus 	struct v4l2_async_connection *asd;
899642bb5e8SMickael Guene 	struct device_node *ep_node;
900642bb5e8SMickael Guene 	int ret;
901642bb5e8SMickael Guene 
902642bb5e8SMickael Guene 	/* parse rx (endpoint 0) */
903642bb5e8SMickael Guene 	ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node,
904642bb5e8SMickael Guene 						0, 0);
905642bb5e8SMickael Guene 	if (!ep_node) {
906642bb5e8SMickael Guene 		dev_err(&client->dev, "unable to find port0 ep");
907642bb5e8SMickael Guene 		ret = -EINVAL;
908642bb5e8SMickael Guene 		goto error;
909642bb5e8SMickael Guene 	}
910642bb5e8SMickael Guene 
911642bb5e8SMickael Guene 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep);
912642bb5e8SMickael Guene 	if (ret) {
913642bb5e8SMickael Guene 		dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n",
914642bb5e8SMickael Guene 			ret);
915642bb5e8SMickael Guene 		goto error_of_node_put;
916642bb5e8SMickael Guene 	}
917642bb5e8SMickael Guene 
918642bb5e8SMickael Guene 	/* do some sanity checks */
919642bb5e8SMickael Guene 	if (ep.bus.mipi_csi2.num_data_lanes > 2) {
920642bb5e8SMickael Guene 		dev_err(&client->dev, "max supported data lanes is 2 / got %d",
921642bb5e8SMickael Guene 			ep.bus.mipi_csi2.num_data_lanes);
922642bb5e8SMickael Guene 		ret = -EINVAL;
923642bb5e8SMickael Guene 		goto error_of_node_put;
924642bb5e8SMickael Guene 	}
925642bb5e8SMickael Guene 
926642bb5e8SMickael Guene 	/* register it for later use */
927642bb5e8SMickael Guene 	bridge->rx = ep;
928642bb5e8SMickael Guene 
929642bb5e8SMickael Guene 	/* register async notifier so we get noticed when sensor is connected */
930b8ec754aSSakari Ailus 	v4l2_async_subdev_nf_init(&bridge->notifier, &bridge->sd);
9313c8c1539SSakari Ailus 	asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier,
9325bbefdefSEzequiel Garcia 					      of_fwnode_handle(ep_node),
933adb2dcd5SSakari Ailus 					      struct v4l2_async_connection);
934642bb5e8SMickael Guene 	of_node_put(ep_node);
935642bb5e8SMickael Guene 
9365bbefdefSEzequiel Garcia 	if (IS_ERR(asd)) {
9375bbefdefSEzequiel Garcia 		dev_err(&client->dev, "fail to register asd to notifier %ld",
9385bbefdefSEzequiel Garcia 			PTR_ERR(asd));
9395bbefdefSEzequiel Garcia 		return PTR_ERR(asd);
940642bb5e8SMickael Guene 	}
941642bb5e8SMickael Guene 	bridge->notifier.ops = &mipid02_notifier_ops;
942642bb5e8SMickael Guene 
943b8ec754aSSakari Ailus 	ret = v4l2_async_nf_register(&bridge->notifier);
944642bb5e8SMickael Guene 	if (ret)
9453c8c1539SSakari Ailus 		v4l2_async_nf_cleanup(&bridge->notifier);
946642bb5e8SMickael Guene 
947642bb5e8SMickael Guene 	return ret;
948642bb5e8SMickael Guene 
949642bb5e8SMickael Guene error_of_node_put:
950642bb5e8SMickael Guene 	of_node_put(ep_node);
951642bb5e8SMickael Guene error:
952642bb5e8SMickael Guene 
953642bb5e8SMickael Guene 	return ret;
954642bb5e8SMickael Guene }
955642bb5e8SMickael Guene 
mipid02_parse_tx_ep(struct mipid02_dev * bridge)956642bb5e8SMickael Guene static int mipid02_parse_tx_ep(struct mipid02_dev *bridge)
957642bb5e8SMickael Guene {
958642bb5e8SMickael Guene 	struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL };
959642bb5e8SMickael Guene 	struct i2c_client *client = bridge->i2c_client;
960642bb5e8SMickael Guene 	struct device_node *ep_node;
961642bb5e8SMickael Guene 	int ret;
962642bb5e8SMickael Guene 
963642bb5e8SMickael Guene 	/* parse tx (endpoint 2) */
964642bb5e8SMickael Guene 	ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node,
965642bb5e8SMickael Guene 						2, 0);
966642bb5e8SMickael Guene 	if (!ep_node) {
967642bb5e8SMickael Guene 		dev_err(&client->dev, "unable to find port1 ep");
968642bb5e8SMickael Guene 		ret = -EINVAL;
969642bb5e8SMickael Guene 		goto error;
970642bb5e8SMickael Guene 	}
971642bb5e8SMickael Guene 
972642bb5e8SMickael Guene 	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep);
973642bb5e8SMickael Guene 	if (ret) {
974642bb5e8SMickael Guene 		dev_err(&client->dev, "Could not parse v4l2 endpoint\n");
975642bb5e8SMickael Guene 		goto error_of_node_put;
976642bb5e8SMickael Guene 	}
977642bb5e8SMickael Guene 
978642bb5e8SMickael Guene 	of_node_put(ep_node);
979642bb5e8SMickael Guene 	bridge->tx = ep;
980642bb5e8SMickael Guene 
981642bb5e8SMickael Guene 	return 0;
982642bb5e8SMickael Guene 
983642bb5e8SMickael Guene error_of_node_put:
984642bb5e8SMickael Guene 	of_node_put(ep_node);
985642bb5e8SMickael Guene error:
986642bb5e8SMickael Guene 
987642bb5e8SMickael Guene 	return -EINVAL;
988642bb5e8SMickael Guene }
989642bb5e8SMickael Guene 
mipid02_probe(struct i2c_client * client)990642bb5e8SMickael Guene static int mipid02_probe(struct i2c_client *client)
991642bb5e8SMickael Guene {
992642bb5e8SMickael Guene 	struct device *dev = &client->dev;
993642bb5e8SMickael Guene 	struct mipid02_dev *bridge;
994642bb5e8SMickael Guene 	u32 clk_freq;
995642bb5e8SMickael Guene 	int ret;
996642bb5e8SMickael Guene 
997642bb5e8SMickael Guene 	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
998642bb5e8SMickael Guene 	if (!bridge)
999642bb5e8SMickael Guene 		return -ENOMEM;
1000642bb5e8SMickael Guene 
1001642bb5e8SMickael Guene 	init_format(&bridge->fmt);
1002642bb5e8SMickael Guene 
1003642bb5e8SMickael Guene 	bridge->i2c_client = client;
1004642bb5e8SMickael Guene 	v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops);
1005642bb5e8SMickael Guene 
1006642bb5e8SMickael Guene 	/* got and check clock */
1007642bb5e8SMickael Guene 	bridge->xclk = devm_clk_get(dev, "xclk");
1008642bb5e8SMickael Guene 	if (IS_ERR(bridge->xclk)) {
1009642bb5e8SMickael Guene 		dev_err(dev, "failed to get xclk\n");
1010642bb5e8SMickael Guene 		return PTR_ERR(bridge->xclk);
1011642bb5e8SMickael Guene 	}
1012642bb5e8SMickael Guene 
1013642bb5e8SMickael Guene 	clk_freq = clk_get_rate(bridge->xclk);
1014642bb5e8SMickael Guene 	if (clk_freq < 6000000 || clk_freq > 27000000) {
1015642bb5e8SMickael Guene 		dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n",
1016642bb5e8SMickael Guene 			clk_freq);
1017642bb5e8SMickael Guene 		return -EINVAL;
1018642bb5e8SMickael Guene 	}
1019642bb5e8SMickael Guene 
1020642bb5e8SMickael Guene 	bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset",
1021642bb5e8SMickael Guene 						     GPIOD_OUT_HIGH);
1022642bb5e8SMickael Guene 
102361c03b63SChuhong Yuan 	if (IS_ERR(bridge->reset_gpio)) {
102461c03b63SChuhong Yuan 		dev_err(dev, "failed to get reset GPIO\n");
102561c03b63SChuhong Yuan 		return PTR_ERR(bridge->reset_gpio);
102661c03b63SChuhong Yuan 	}
102761c03b63SChuhong Yuan 
1028642bb5e8SMickael Guene 	ret = mipid02_get_regulators(bridge);
1029642bb5e8SMickael Guene 	if (ret) {
1030642bb5e8SMickael Guene 		dev_err(dev, "failed to get regulators %d", ret);
1031642bb5e8SMickael Guene 		return ret;
1032642bb5e8SMickael Guene 	}
1033642bb5e8SMickael Guene 
1034642bb5e8SMickael Guene 	mutex_init(&bridge->lock);
1035642bb5e8SMickael Guene 	bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1036642bb5e8SMickael Guene 	bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
1037642bb5e8SMickael Guene 	bridge->sd.entity.ops = &mipid02_subdev_entity_ops;
1038642bb5e8SMickael Guene 	bridge->pad[0].flags = MEDIA_PAD_FL_SINK;
1039642bb5e8SMickael Guene 	bridge->pad[1].flags = MEDIA_PAD_FL_SINK;
1040642bb5e8SMickael Guene 	bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE;
1041642bb5e8SMickael Guene 	ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB,
1042642bb5e8SMickael Guene 				     bridge->pad);
1043642bb5e8SMickael Guene 	if (ret) {
1044642bb5e8SMickael Guene 		dev_err(&client->dev, "pads init failed %d", ret);
1045642bb5e8SMickael Guene 		goto mutex_cleanup;
1046642bb5e8SMickael Guene 	}
1047642bb5e8SMickael Guene 
1048642bb5e8SMickael Guene 	/* enable clock, power and reset device if available */
1049642bb5e8SMickael Guene 	ret = mipid02_set_power_on(bridge);
1050642bb5e8SMickael Guene 	if (ret)
1051642bb5e8SMickael Guene 		goto entity_cleanup;
1052642bb5e8SMickael Guene 
1053642bb5e8SMickael Guene 	ret = mipid02_detect(bridge);
1054642bb5e8SMickael Guene 	if (ret) {
1055642bb5e8SMickael Guene 		dev_err(&client->dev, "failed to detect mipid02 %d", ret);
1056642bb5e8SMickael Guene 		goto power_off;
1057642bb5e8SMickael Guene 	}
1058642bb5e8SMickael Guene 
1059642bb5e8SMickael Guene 	ret = mipid02_parse_tx_ep(bridge);
1060642bb5e8SMickael Guene 	if (ret) {
1061642bb5e8SMickael Guene 		dev_err(&client->dev, "failed to parse tx %d", ret);
1062642bb5e8SMickael Guene 		goto power_off;
1063642bb5e8SMickael Guene 	}
1064642bb5e8SMickael Guene 
1065642bb5e8SMickael Guene 	ret = mipid02_parse_rx_ep(bridge);
1066642bb5e8SMickael Guene 	if (ret) {
1067642bb5e8SMickael Guene 		dev_err(&client->dev, "failed to parse rx %d", ret);
1068642bb5e8SMickael Guene 		goto power_off;
1069642bb5e8SMickael Guene 	}
1070642bb5e8SMickael Guene 
1071642bb5e8SMickael Guene 	ret = v4l2_async_register_subdev(&bridge->sd);
1072642bb5e8SMickael Guene 	if (ret < 0) {
1073642bb5e8SMickael Guene 		dev_err(&client->dev, "v4l2_async_register_subdev failed %d",
1074642bb5e8SMickael Guene 			    ret);
1075642bb5e8SMickael Guene 		goto unregister_notifier;
1076642bb5e8SMickael Guene 	}
1077642bb5e8SMickael Guene 
1078642bb5e8SMickael Guene 	dev_info(&client->dev, "mipid02 device probe successfully");
1079642bb5e8SMickael Guene 
1080642bb5e8SMickael Guene 	return 0;
1081642bb5e8SMickael Guene 
1082642bb5e8SMickael Guene unregister_notifier:
10833c8c1539SSakari Ailus 	v4l2_async_nf_unregister(&bridge->notifier);
10843c8c1539SSakari Ailus 	v4l2_async_nf_cleanup(&bridge->notifier);
1085642bb5e8SMickael Guene power_off:
1086642bb5e8SMickael Guene 	mipid02_set_power_off(bridge);
1087642bb5e8SMickael Guene entity_cleanup:
1088642bb5e8SMickael Guene 	media_entity_cleanup(&bridge->sd.entity);
1089642bb5e8SMickael Guene mutex_cleanup:
1090642bb5e8SMickael Guene 	mutex_destroy(&bridge->lock);
1091642bb5e8SMickael Guene 
1092642bb5e8SMickael Guene 	return ret;
1093642bb5e8SMickael Guene }
1094642bb5e8SMickael Guene 
mipid02_remove(struct i2c_client * client)1095ed5c2f5fSUwe Kleine-König static void mipid02_remove(struct i2c_client *client)
1096642bb5e8SMickael Guene {
1097642bb5e8SMickael Guene 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1098642bb5e8SMickael Guene 	struct mipid02_dev *bridge = to_mipid02_dev(sd);
1099642bb5e8SMickael Guene 
11003c8c1539SSakari Ailus 	v4l2_async_nf_unregister(&bridge->notifier);
11013c8c1539SSakari Ailus 	v4l2_async_nf_cleanup(&bridge->notifier);
1102642bb5e8SMickael Guene 	v4l2_async_unregister_subdev(&bridge->sd);
1103642bb5e8SMickael Guene 	mipid02_set_power_off(bridge);
1104642bb5e8SMickael Guene 	media_entity_cleanup(&bridge->sd.entity);
1105642bb5e8SMickael Guene 	mutex_destroy(&bridge->lock);
1106642bb5e8SMickael Guene }
1107642bb5e8SMickael Guene 
1108642bb5e8SMickael Guene static const struct of_device_id mipid02_dt_ids[] = {
1109642bb5e8SMickael Guene 	{ .compatible = "st,st-mipid02" },
1110642bb5e8SMickael Guene 	{ /* sentinel */ }
1111642bb5e8SMickael Guene };
1112642bb5e8SMickael Guene MODULE_DEVICE_TABLE(of, mipid02_dt_ids);
1113642bb5e8SMickael Guene 
1114642bb5e8SMickael Guene static struct i2c_driver mipid02_i2c_driver = {
1115642bb5e8SMickael Guene 	.driver = {
1116642bb5e8SMickael Guene 		.name  = "st-mipid02",
1117642bb5e8SMickael Guene 		.of_match_table = mipid02_dt_ids,
1118642bb5e8SMickael Guene 	},
1119aaeb31c0SUwe Kleine-König 	.probe = mipid02_probe,
1120642bb5e8SMickael Guene 	.remove = mipid02_remove,
1121642bb5e8SMickael Guene };
1122642bb5e8SMickael Guene 
1123642bb5e8SMickael Guene module_i2c_driver(mipid02_i2c_driver);
1124642bb5e8SMickael Guene 
1125642bb5e8SMickael Guene MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>");
1126642bb5e8SMickael Guene MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver");
1127642bb5e8SMickael Guene MODULE_LICENSE("GPL v2");
1128