xref: /linux/drivers/media/platform/amlogic/c3/mipi-csi2/c3-mipi-csi2.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1b63ef604SKeke Li // SPDX-License-Identifier: (GPL-2.0-only OR MIT)
2b63ef604SKeke Li /*
3b63ef604SKeke Li  * Copyright (C) 2024 Amlogic, Inc. All rights reserved
4b63ef604SKeke Li  */
5b63ef604SKeke Li 
6b63ef604SKeke Li #include <linux/clk.h>
7b63ef604SKeke Li #include <linux/device.h>
8*1b83a9f4SJacopo Mondi #include <linux/math.h>
9b63ef604SKeke Li #include <linux/module.h>
10b63ef604SKeke Li #include <linux/mutex.h>
11b63ef604SKeke Li #include <linux/platform_device.h>
12b63ef604SKeke Li #include <linux/pm_runtime.h>
13b63ef604SKeke Li 
14b63ef604SKeke Li #include <media/v4l2-async.h>
15b63ef604SKeke Li #include <media/v4l2-common.h>
16b63ef604SKeke Li #include <media/v4l2-device.h>
17b63ef604SKeke Li #include <media/v4l2-fwnode.h>
18b63ef604SKeke Li #include <media/v4l2-mc.h>
19b63ef604SKeke Li #include <media/v4l2-subdev.h>
20b63ef604SKeke Li 
21b63ef604SKeke Li /* C3 CSI-2 submodule definition */
22b63ef604SKeke Li enum {
23b63ef604SKeke Li 	SUBMD_APHY,
24b63ef604SKeke Li 	SUBMD_DPHY,
25b63ef604SKeke Li 	SUBMD_HOST,
26b63ef604SKeke Li };
27b63ef604SKeke Li 
28b63ef604SKeke Li #define CSI2_SUBMD_MASK		GENMASK(17, 16)
29b63ef604SKeke Li #define CSI2_SUBMD_SHIFT	16
30b63ef604SKeke Li #define CSI2_SUBMD(x)	(((x) & (CSI2_SUBMD_MASK)) >> (CSI2_SUBMD_SHIFT))
31b63ef604SKeke Li #define CSI2_REG_ADDR_MASK	GENMASK(15, 0)
32b63ef604SKeke Li #define CSI2_REG_ADDR(x)	((x) & (CSI2_REG_ADDR_MASK))
33b63ef604SKeke Li #define CSI2_REG_A(x)		((SUBMD_APHY << CSI2_SUBMD_SHIFT) | (x))
34b63ef604SKeke Li #define CSI2_REG_D(x)		((SUBMD_DPHY << CSI2_SUBMD_SHIFT) | (x))
35b63ef604SKeke Li #define CSI2_REG_H(x)		((SUBMD_HOST << CSI2_SUBMD_SHIFT) | (x))
36b63ef604SKeke Li 
37b63ef604SKeke Li #define MIPI_CSI2_CLOCK_NUM_MAX			3
38b63ef604SKeke Li #define MIPI_CSI2_SUBDEV_NAME			"c3-mipi-csi2"
39b63ef604SKeke Li 
40b63ef604SKeke Li /* C3 CSI-2 APHY register */
41b63ef604SKeke Li #define CSI_PHY_CNTL0				CSI2_REG_A(0x44)
42b63ef604SKeke Li #define CSI_PHY_CNTL0_HS_LP_BIAS_EN		BIT(10)
43b63ef604SKeke Li #define CSI_PHY_CNTL0_HS_RX_TRIM_11		(11 << 11)
44b63ef604SKeke Li #define CSI_PHY_CNTL0_LP_LOW_VTH_2		(2 << 16)
45b63ef604SKeke Li #define CSI_PHY_CNTL0_LP_HIGH_VTH_4		(4 << 20)
46b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE0_HS_DIG_EN	BIT(24)
47b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE1_HS_DIG_EN	BIT(25)
48b63ef604SKeke Li #define CSI_PHY_CNTL0_CLK0_LANE_HS_DIG_EN	BIT(26)
49b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE2_HS_DIG_EN	BIT(27)
50b63ef604SKeke Li #define CSI_PHY_CNTL0_DATA_LANE3_HS_DIG_EN	BIT(28)
51b63ef604SKeke Li 
52b63ef604SKeke Li #define CSI_PHY_CNTL1				CSI2_REG_A(0x48)
53b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_CAP_SMALL		(2 << 16)
54b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_CAP_BIG		(3 << 16)
55b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MIN		(3 << 18)
56b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MED		(2 << 18)
57b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_EQ_RES_MAX		BIT(18)
58b63ef604SKeke Li #define CSI_PHY_CNTL1_CLK_CHN_EQ_MAX_GAIN	BIT(20)
59b63ef604SKeke Li #define CSI_PHY_CNTL1_DATA_CHN_EQ_MAX_GAIN	BIT(21)
60b63ef604SKeke Li #define CSI_PHY_CNTL1_COM_BG_EN			BIT(24)
61b63ef604SKeke Li #define CSI_PHY_CNTL1_HS_SYNC_EN		BIT(25)
62b63ef604SKeke Li 
63b63ef604SKeke Li /* C3 CSI-2 DPHY register */
64b63ef604SKeke Li #define MIPI_PHY_CTRL				CSI2_REG_D(0x00)
65b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE0_EN		(0 << 0)
66b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE0_DIS		BIT(0)
67b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE1_EN		(0 << 1)
68b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE1_DIS		BIT(1)
69b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE2_EN		(0 << 2)
70b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE2_DIS		BIT(2)
71b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE3_EN		(0 << 3)
72b63ef604SKeke Li #define MIPI_PHY_CTRL_DATA_LANE3_DIS		BIT(3)
73b63ef604SKeke Li #define MIPI_PHY_CTRL_CLOCK_LANE_EN		(0 << 4)
74b63ef604SKeke Li #define MIPI_PHY_CTRL_CLOCK_LANE_DIS		BIT(4)
75b63ef604SKeke Li 
76b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL			CSI2_REG_D(0x04)
77b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_FORCE_ULPS_ENTER	BIT(0)
78b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_FORCE_ULPS_EXIT	BIT(1)
79b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS	(0 << 3)
80b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_2	BIT(3)
81b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_4	(2 << 3)
82b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_8	(3 << 3)
83b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_16	(4 << 3)
84b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_EN	BIT(6)
85b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_LPEN_DIS		BIT(7)
86b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_END_EN		BIT(8)
87b63ef604SKeke Li #define MIPI_PHY_CLK_LANE_CTRL_HS_RX_EN		BIT(9)
88b63ef604SKeke Li 
89b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1		CSI2_REG_D(0x0c)
90b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_INSERT_ERRESC	BIT(0)
91b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_HS_SYNC_CHK_EN	BIT(1)
92b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_MASK	GENMASK(6, 2)
93b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_ALL_EN	(0x1f << 2)
94b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_MASK	GENMASK(9, 7)
95b63ef604SKeke Li #define MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_3	(3 << 7)
96b63ef604SKeke Li 
97b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS			CSI2_REG_D(0x10)
98b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS_CYCLES_MASK		GENMASK(7, 0)
99b63ef604SKeke Li #define MIPI_PHY_TCLK_MISS_CYCLES_9		(9 << 0)
100b63ef604SKeke Li 
101b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE			CSI2_REG_D(0x14)
102b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE_CYCLES_MASK	GENMASK(7, 0)
103b63ef604SKeke Li #define MIPI_PHY_TCLK_SETTLE_CYCLES_31		(31 << 0)
104b63ef604SKeke Li 
105b63ef604SKeke Li #define MIPI_PHY_THS_EXIT			CSI2_REG_D(0x18)
106b63ef604SKeke Li #define MIPI_PHY_THS_EXIT_CYCLES_MASK		GENMASK(7, 0)
107b63ef604SKeke Li #define MIPI_PHY_THS_EXIT_CYCLES_8		(8 << 0)
108b63ef604SKeke Li 
109b63ef604SKeke Li #define MIPI_PHY_THS_SKIP			CSI2_REG_D(0x1c)
110b63ef604SKeke Li #define MIPI_PHY_THS_SKIP_CYCLES_MASK		GENMASK(7, 0)
111b63ef604SKeke Li #define MIPI_PHY_THS_SKIP_CYCLES_10		(10 << 0)
112b63ef604SKeke Li 
113b63ef604SKeke Li #define MIPI_PHY_THS_SETTLE			CSI2_REG_D(0x20)
114b63ef604SKeke Li #define MIPI_PHY_THS_SETTLE_CYCLES_MASK		GENMASK(7, 0)
115b63ef604SKeke Li 
116b63ef604SKeke Li #define MIPI_PHY_TINIT				CSI2_REG_D(0x24)
117b63ef604SKeke Li #define MIPI_PHY_TINIT_CYCLES_MASK		GENMASK(31, 0)
118b63ef604SKeke Li #define MIPI_PHY_TINIT_CYCLES_20000		(20000 << 0)
119b63ef604SKeke Li 
120b63ef604SKeke Li #define MIPI_PHY_TULPS_C			CSI2_REG_D(0x28)
121b63ef604SKeke Li #define MIPI_PHY_TULPS_C_CYCLES_MASK		GENMASK(31, 0)
122b63ef604SKeke Li #define MIPI_PHY_TULPS_C_CYCLES_4096		(4096 << 0)
123b63ef604SKeke Li 
124b63ef604SKeke Li #define MIPI_PHY_TULPS_S			CSI2_REG_D(0x2c)
125b63ef604SKeke Li #define MIPI_PHY_TULPS_S_CYCLES_MASK		GENMASK(31, 0)
126b63ef604SKeke Li #define MIPI_PHY_TULPS_S_CYCLES_256		(256 << 0)
127b63ef604SKeke Li 
128b63ef604SKeke Li #define MIPI_PHY_TMBIAS				CSI2_REG_D(0x30)
129b63ef604SKeke Li #define MIPI_PHY_TMBIAS_CYCLES_MASK		GENMASK(31, 0)
130b63ef604SKeke Li #define MIPI_PHY_TMBIAS_CYCLES_256		(256 << 0)
131b63ef604SKeke Li 
132b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W			CSI2_REG_D(0x34)
133b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W_CYCLES_MASK		GENMASK(31, 0)
134b63ef604SKeke Li #define MIPI_PHY_TLP_EN_W_CYCLES_12		(12 << 0)
135b63ef604SKeke Li 
136b63ef604SKeke Li #define MIPI_PHY_TLPOK				CSI2_REG_D(0x38)
137b63ef604SKeke Li #define MIPI_PHY_TLPOK_CYCLES_MASK		GENMASK(31, 0)
138b63ef604SKeke Li #define MIPI_PHY_TLPOK_CYCLES_256		(256 << 0)
139b63ef604SKeke Li 
140b63ef604SKeke Li #define MIPI_PHY_TWD_INIT			CSI2_REG_D(0x3c)
141b63ef604SKeke Li #define MIPI_PHY_TWD_INIT_DOG_MASK		GENMASK(31, 0)
142b63ef604SKeke Li #define MIPI_PHY_TWD_INIT_DOG_0X400000		(0x400000 << 0)
143b63ef604SKeke Li 
144b63ef604SKeke Li #define MIPI_PHY_TWD_HS				CSI2_REG_D(0x40)
145b63ef604SKeke Li #define MIPI_PHY_TWD_HS_DOG_MASK		GENMASK(31, 0)
146b63ef604SKeke Li #define MIPI_PHY_TWD_HS_DOG_0X400000		(0x400000 << 0)
147b63ef604SKeke Li 
148b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0			CSI2_REG_D(0x284)
149b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_MASK	GENMASK(3, 0)
150b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE0	(0 << 0)
151b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE1	BIT(0)
152b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE2	(2 << 0)
153b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE3	(3 << 0)
154b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_MASK	GENMASK(7, 4)
155b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE0	(0 << 4)
156b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE1	BIT(4)
157b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE2	(2 << 4)
158b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE3	(3 << 4)
159b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_MASK	GENMASK(11, 8)
160b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE0	(0 << 8)
161b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE1	BIT(8)
162b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE2	(2 << 8)
163b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE3	(3 << 8)
164b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_MASK	GENMASK(14, 12)
165b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE0	(0 << 12)
166b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE1	BIT(12)
167b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE2	(2 << 12)
168b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE3	(3 << 12)
169b63ef604SKeke Li 
170b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1			CSI2_REG_D(0x288)
171b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_MASK	GENMASK(3, 0)
172b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN0	(0 << 0)
173b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN1	BIT(0)
174b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN2	(2 << 0)
175b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN3	(3 << 0)
176b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_MASK	GENMASK(7, 4)
177b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN0	(0 << 4)
178b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN1	BIT(4)
179b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN2	(2 << 4)
180b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN3	(3 << 4)
181b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_MASK	GENMASK(11, 8)
182b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN0	(0 << 8)
183b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN1	BIT(8)
184b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN2	(2 << 8)
185b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN3	(3 << 8)
186b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_MASK	GENMASK(14, 12)
187b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN0	(0 << 12)
188b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN1	BIT(12)
189b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN2	(2 << 12)
190b63ef604SKeke Li #define MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN3	(3 << 12)
191b63ef604SKeke Li 
192b63ef604SKeke Li /* C3 CSI-2 HOST register */
193b63ef604SKeke Li #define CSI2_HOST_N_LANES			CSI2_REG_H(0x04)
194b63ef604SKeke Li #define CSI2_HOST_N_LANES_MASK			GENMASK(1, 0)
195b63ef604SKeke Li #define CSI2_HOST_N_LANES_1			(0 << 0)
196b63ef604SKeke Li #define CSI2_HOST_N_LANES_2			BIT(0)
197b63ef604SKeke Li #define CSI2_HOST_N_LANES_3			(2 << 0)
198b63ef604SKeke Li #define CSI2_HOST_N_LANES_4			(3 << 0)
199b63ef604SKeke Li 
200b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN			CSI2_REG_H(0x10)
201b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_MASK		BIT(0)
202b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_ACTIVE		(0 << 0)
203b63ef604SKeke Li #define CSI2_HOST_CSI2_RESETN_EXIT		BIT(0)
204b63ef604SKeke Li 
205b63ef604SKeke Li #define C3_MIPI_CSI2_MAX_WIDTH			2888
206b63ef604SKeke Li #define C3_MIPI_CSI2_MIN_WIDTH			160
207b63ef604SKeke Li #define C3_MIPI_CSI2_MAX_HEIGHT			2240
208b63ef604SKeke Li #define C3_MIPI_CSI2_MIN_HEIGHT			120
209b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_WIDTH		1920
210b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_HEIGHT		1080
211b63ef604SKeke Li #define C3_MIPI_CSI2_DEFAULT_FMT		MEDIA_BUS_FMT_SRGGB10_1X10
212b63ef604SKeke Li 
213b63ef604SKeke Li /* C3 CSI-2 pad list */
214b63ef604SKeke Li enum {
215b63ef604SKeke Li 	C3_MIPI_CSI2_PAD_SINK,
216b63ef604SKeke Li 	C3_MIPI_CSI2_PAD_SRC,
217b63ef604SKeke Li 	C3_MIPI_CSI2_PAD_MAX
218b63ef604SKeke Li };
219b63ef604SKeke Li 
220b63ef604SKeke Li /*
221b63ef604SKeke Li  * struct c3_csi_info - MIPI CSI2 information
222b63ef604SKeke Li  *
223b63ef604SKeke Li  * @clocks: array of MIPI CSI2 clock names
224b63ef604SKeke Li  * @clock_num: actual clock number
225b63ef604SKeke Li  */
226b63ef604SKeke Li struct c3_csi_info {
227b63ef604SKeke Li 	char *clocks[MIPI_CSI2_CLOCK_NUM_MAX];
228b63ef604SKeke Li 	u32 clock_num;
229b63ef604SKeke Li };
230b63ef604SKeke Li 
231b63ef604SKeke Li /*
232b63ef604SKeke Li  * struct c3_csi_device - MIPI CSI2 platform device
233b63ef604SKeke Li  *
234b63ef604SKeke Li  * @dev: pointer to the struct device
235b63ef604SKeke Li  * @aphy: MIPI CSI2 aphy register address
236b63ef604SKeke Li  * @dphy: MIPI CSI2 dphy register address
237b63ef604SKeke Li  * @host: MIPI CSI2 host register address
238b63ef604SKeke Li  * @clks: array of MIPI CSI2 clocks
239b63ef604SKeke Li  * @sd: MIPI CSI2 sub-device
240b63ef604SKeke Li  * @pads: MIPI CSI2 sub-device pads
241b63ef604SKeke Li  * @notifier: notifier to register on the v4l2-async API
242b63ef604SKeke Li  * @src_pad: source sub-device pad
243b63ef604SKeke Li  * @bus: MIPI CSI2 bus information
244b63ef604SKeke Li  * @info: version-specific MIPI CSI2 information
245b63ef604SKeke Li  */
246b63ef604SKeke Li struct c3_csi_device {
247b63ef604SKeke Li 	struct device *dev;
248b63ef604SKeke Li 	void __iomem *aphy;
249b63ef604SKeke Li 	void __iomem *dphy;
250b63ef604SKeke Li 	void __iomem *host;
251b63ef604SKeke Li 	struct clk_bulk_data clks[MIPI_CSI2_CLOCK_NUM_MAX];
252b63ef604SKeke Li 
253b63ef604SKeke Li 	struct v4l2_subdev sd;
254b63ef604SKeke Li 	struct media_pad pads[C3_MIPI_CSI2_PAD_MAX];
255b63ef604SKeke Li 	struct v4l2_async_notifier notifier;
256b63ef604SKeke Li 	struct media_pad *src_pad;
257b63ef604SKeke Li 	struct v4l2_mbus_config_mipi_csi2 bus;
258b63ef604SKeke Li 
259b63ef604SKeke Li 	const struct c3_csi_info *info;
260b63ef604SKeke Li };
261b63ef604SKeke Li 
262b63ef604SKeke Li static const u32 c3_mipi_csi_formats[] = {
263b63ef604SKeke Li 	MEDIA_BUS_FMT_SBGGR10_1X10,
264b63ef604SKeke Li 	MEDIA_BUS_FMT_SGBRG10_1X10,
265b63ef604SKeke Li 	MEDIA_BUS_FMT_SGRBG10_1X10,
266b63ef604SKeke Li 	MEDIA_BUS_FMT_SRGGB10_1X10,
267b63ef604SKeke Li 	MEDIA_BUS_FMT_SBGGR12_1X12,
268b63ef604SKeke Li 	MEDIA_BUS_FMT_SGBRG12_1X12,
269b63ef604SKeke Li 	MEDIA_BUS_FMT_SGRBG12_1X12,
270b63ef604SKeke Li 	MEDIA_BUS_FMT_SRGGB12_1X12,
271b63ef604SKeke Li };
272b63ef604SKeke Li 
273b63ef604SKeke Li /* Hardware configuration */
274b63ef604SKeke Li 
275b63ef604SKeke Li static void c3_mipi_csi_write(struct c3_csi_device *csi, u32 reg, u32 val)
276b63ef604SKeke Li {
277b63ef604SKeke Li 	void __iomem *addr;
278b63ef604SKeke Li 
279b63ef604SKeke Li 	switch (CSI2_SUBMD(reg)) {
280b63ef604SKeke Li 	case SUBMD_APHY:
281b63ef604SKeke Li 		addr = csi->aphy + CSI2_REG_ADDR(reg);
282b63ef604SKeke Li 		break;
283b63ef604SKeke Li 	case SUBMD_DPHY:
284b63ef604SKeke Li 		addr = csi->dphy + CSI2_REG_ADDR(reg);
285b63ef604SKeke Li 		break;
286b63ef604SKeke Li 	case SUBMD_HOST:
287b63ef604SKeke Li 		addr = csi->host + CSI2_REG_ADDR(reg);
288b63ef604SKeke Li 		break;
289b63ef604SKeke Li 	default:
290b63ef604SKeke Li 		dev_err(csi->dev, "Invalid sub-module: %lu\n", CSI2_SUBMD(reg));
291b63ef604SKeke Li 		return;
292b63ef604SKeke Li 	}
293b63ef604SKeke Li 
294b63ef604SKeke Li 	writel(val, addr);
295b63ef604SKeke Li }
296b63ef604SKeke Li 
297b63ef604SKeke Li static void c3_mipi_csi_cfg_aphy(struct c3_csi_device *csi)
298b63ef604SKeke Li {
299b63ef604SKeke Li 	c3_mipi_csi_write(csi, CSI_PHY_CNTL0,
300b63ef604SKeke Li 			  CSI_PHY_CNTL0_HS_LP_BIAS_EN |
301b63ef604SKeke Li 			  CSI_PHY_CNTL0_HS_RX_TRIM_11 |
302b63ef604SKeke Li 			  CSI_PHY_CNTL0_LP_LOW_VTH_2 |
303b63ef604SKeke Li 			  CSI_PHY_CNTL0_LP_HIGH_VTH_4 |
304b63ef604SKeke Li 			  CSI_PHY_CNTL0_DATA_LANE0_HS_DIG_EN |
305b63ef604SKeke Li 			  CSI_PHY_CNTL0_DATA_LANE1_HS_DIG_EN |
306b63ef604SKeke Li 			  CSI_PHY_CNTL0_CLK0_LANE_HS_DIG_EN |
307b63ef604SKeke Li 			  CSI_PHY_CNTL0_DATA_LANE2_HS_DIG_EN |
308b63ef604SKeke Li 			  CSI_PHY_CNTL0_DATA_LANE3_HS_DIG_EN);
309b63ef604SKeke Li 
310b63ef604SKeke Li 	c3_mipi_csi_write(csi, CSI_PHY_CNTL1,
311b63ef604SKeke Li 			  CSI_PHY_CNTL1_HS_EQ_CAP_SMALL |
312b63ef604SKeke Li 			  CSI_PHY_CNTL1_HS_EQ_RES_MED |
313b63ef604SKeke Li 			  CSI_PHY_CNTL1_CLK_CHN_EQ_MAX_GAIN |
314b63ef604SKeke Li 			  CSI_PHY_CNTL1_DATA_CHN_EQ_MAX_GAIN |
315b63ef604SKeke Li 			  CSI_PHY_CNTL1_COM_BG_EN |
316b63ef604SKeke Li 			  CSI_PHY_CNTL1_HS_SYNC_EN);
317b63ef604SKeke Li }
318b63ef604SKeke Li 
319b63ef604SKeke Li static void c3_mipi_csi_cfg_dphy(struct c3_csi_device *csi, s64 rate)
320b63ef604SKeke Li {
321b63ef604SKeke Li 	u32 val;
322b63ef604SKeke Li 	u32 settle;
323b63ef604SKeke Li 
324b63ef604SKeke Li 	/* Calculate the high speed settle */
325*1b83a9f4SJacopo Mondi 	val = DIV_ROUND_UP_ULL(1000000000, rate);
326b63ef604SKeke Li 	settle = (16 * val + 230) / 10;
327b63ef604SKeke Li 
328b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_CLK_LANE_CTRL,
329b63ef604SKeke Li 			  MIPI_PHY_CLK_LANE_CTRL_HS_RX_EN |
330b63ef604SKeke Li 			  MIPI_PHY_CLK_LANE_CTRL_END_EN |
331b63ef604SKeke Li 			  MIPI_PHY_CLK_LANE_CTRL_LPEN_DIS |
332b63ef604SKeke Li 			  MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_EN |
333b63ef604SKeke Li 			  MIPI_PHY_CLK_LANE_CTRL_TCLK_ZERO_HS_8);
334b63ef604SKeke Li 
335b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TCLK_MISS, MIPI_PHY_TCLK_MISS_CYCLES_9);
336b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TCLK_SETTLE,
337b63ef604SKeke Li 			  MIPI_PHY_TCLK_SETTLE_CYCLES_31);
338b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_THS_EXIT, MIPI_PHY_THS_EXIT_CYCLES_8);
339b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_THS_SKIP, MIPI_PHY_THS_SKIP_CYCLES_10);
340b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_THS_SETTLE, settle);
341b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TINIT, MIPI_PHY_TINIT_CYCLES_20000);
342b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TMBIAS, MIPI_PHY_TMBIAS_CYCLES_256);
343b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TULPS_C, MIPI_PHY_TULPS_C_CYCLES_4096);
344b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TULPS_S, MIPI_PHY_TULPS_S_CYCLES_256);
345b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TLP_EN_W, MIPI_PHY_TLP_EN_W_CYCLES_12);
346b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TLPOK, MIPI_PHY_TLPOK_CYCLES_256);
347b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TWD_INIT,
348b63ef604SKeke Li 			  MIPI_PHY_TWD_INIT_DOG_0X400000);
349b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_TWD_HS, MIPI_PHY_TWD_HS_DOG_0X400000);
350b63ef604SKeke Li 
351b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_DATA_LANE_CTRL1,
352b63ef604SKeke Li 			  MIPI_PHY_DATA_LANE_CTRL1_INSERT_ERRESC |
353b63ef604SKeke Li 			  MIPI_PHY_DATA_LANE_CTRL1_HS_SYNC_CHK_EN |
354b63ef604SKeke Li 			  MIPI_PHY_DATA_LANE_CTRL1_PIPE_ALL_EN |
355b63ef604SKeke Li 			  MIPI_PHY_DATA_LANE_CTRL1_PIPE_DELAY_3);
356b63ef604SKeke Li 
357b63ef604SKeke Li 	/* Set the order of lanes */
358b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_MUX_CTRL0,
359b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL0_SFEN3_SRC_LANE3 |
360b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL0_SFEN2_SRC_LANE2 |
361b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL0_SFEN1_SRC_LANE1 |
362b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL0_SFEN0_SRC_LANE0);
363b63ef604SKeke Li 
364b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_MUX_CTRL1,
365b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL1_LANE3_SRC_SFEN3 |
366b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL1_LANE2_SRC_SFEN2 |
367b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL1_LANE1_SRC_SFEN1 |
368b63ef604SKeke Li 			  MIPI_PHY_MUX_CTRL1_LANE0_SRC_SFEN0);
369b63ef604SKeke Li 
370b63ef604SKeke Li 	/* Enable digital data and clock lanes */
371b63ef604SKeke Li 	c3_mipi_csi_write(csi, MIPI_PHY_CTRL,
372b63ef604SKeke Li 			  MIPI_PHY_CTRL_DATA_LANE0_EN |
373b63ef604SKeke Li 			  MIPI_PHY_CTRL_DATA_LANE1_EN |
374b63ef604SKeke Li 			  MIPI_PHY_CTRL_DATA_LANE2_EN |
375b63ef604SKeke Li 			  MIPI_PHY_CTRL_DATA_LANE3_EN |
376b63ef604SKeke Li 			  MIPI_PHY_CTRL_CLOCK_LANE_EN);
377b63ef604SKeke Li }
378b63ef604SKeke Li 
379b63ef604SKeke Li static void c3_mipi_csi_cfg_host(struct c3_csi_device *csi)
380b63ef604SKeke Li {
381b63ef604SKeke Li 	/* Reset CSI-2 controller output */
382b63ef604SKeke Li 	c3_mipi_csi_write(csi, CSI2_HOST_CSI2_RESETN,
383b63ef604SKeke Li 			  CSI2_HOST_CSI2_RESETN_ACTIVE);
384b63ef604SKeke Li 	c3_mipi_csi_write(csi, CSI2_HOST_CSI2_RESETN,
385b63ef604SKeke Li 			  CSI2_HOST_CSI2_RESETN_EXIT);
386b63ef604SKeke Li 
387b63ef604SKeke Li 	/* Set data lane number */
388b63ef604SKeke Li 	c3_mipi_csi_write(csi, CSI2_HOST_N_LANES, csi->bus.num_data_lanes - 1);
389b63ef604SKeke Li }
390b63ef604SKeke Li 
391b63ef604SKeke Li static int c3_mipi_csi_start_stream(struct c3_csi_device *csi,
392b63ef604SKeke Li 				    struct v4l2_subdev *src_sd)
393b63ef604SKeke Li {
394b63ef604SKeke Li 	s64 link_freq;
395b63ef604SKeke Li 	s64 lane_rate;
396b63ef604SKeke Li 
397b63ef604SKeke Li 	link_freq = v4l2_get_link_freq(src_sd->ctrl_handler, 0, 0);
398b63ef604SKeke Li 	if (link_freq < 0) {
399b63ef604SKeke Li 		dev_err(csi->dev,
400b63ef604SKeke Li 			"Unable to obtain link frequency: %lld\n", link_freq);
401b63ef604SKeke Li 		return link_freq;
402b63ef604SKeke Li 	}
403b63ef604SKeke Li 
404b63ef604SKeke Li 	lane_rate = link_freq * 2;
405b63ef604SKeke Li 	if (lane_rate > 1500000000) {
406b63ef604SKeke Li 		dev_err(csi->dev, "Invalid lane rate: %lld\n", lane_rate);
407b63ef604SKeke Li 		return -EINVAL;
408b63ef604SKeke Li 	}
409b63ef604SKeke Li 
410b63ef604SKeke Li 	c3_mipi_csi_cfg_aphy(csi);
411b63ef604SKeke Li 	c3_mipi_csi_cfg_dphy(csi, lane_rate);
412b63ef604SKeke Li 	c3_mipi_csi_cfg_host(csi);
413b63ef604SKeke Li 
414b63ef604SKeke Li 	return 0;
415b63ef604SKeke Li }
416b63ef604SKeke Li 
417b63ef604SKeke Li static int c3_mipi_csi_enable_streams(struct v4l2_subdev *sd,
418b63ef604SKeke Li 				      struct v4l2_subdev_state *state,
419b63ef604SKeke Li 				      u32 pad, u64 streams_mask)
420b63ef604SKeke Li {
421b63ef604SKeke Li 	struct c3_csi_device *csi = v4l2_get_subdevdata(sd);
422b63ef604SKeke Li 	struct media_pad *sink_pad;
423b63ef604SKeke Li 	struct v4l2_subdev *src_sd;
424b63ef604SKeke Li 	int ret;
425b63ef604SKeke Li 
426b63ef604SKeke Li 	sink_pad = &csi->pads[C3_MIPI_CSI2_PAD_SINK];
427b63ef604SKeke Li 	csi->src_pad = media_pad_remote_pad_unique(sink_pad);
428b63ef604SKeke Li 	if (IS_ERR(csi->src_pad)) {
429b63ef604SKeke Li 		dev_dbg(csi->dev, "Failed to get source pad for MIPI CSI-2\n");
430b63ef604SKeke Li 		return -EPIPE;
431b63ef604SKeke Li 	}
432b63ef604SKeke Li 
433b63ef604SKeke Li 	src_sd = media_entity_to_v4l2_subdev(csi->src_pad->entity);
434b63ef604SKeke Li 
435b63ef604SKeke Li 	pm_runtime_resume_and_get(csi->dev);
436b63ef604SKeke Li 
437b63ef604SKeke Li 	c3_mipi_csi_start_stream(csi, src_sd);
438b63ef604SKeke Li 
439b63ef604SKeke Li 	ret = v4l2_subdev_enable_streams(src_sd, csi->src_pad->index, BIT(0));
440b63ef604SKeke Li 	if (ret) {
441b63ef604SKeke Li 		pm_runtime_put(csi->dev);
442b63ef604SKeke Li 		return ret;
443b63ef604SKeke Li 	}
444b63ef604SKeke Li 
445b63ef604SKeke Li 	return 0;
446b63ef604SKeke Li }
447b63ef604SKeke Li 
448b63ef604SKeke Li static int c3_mipi_csi_disable_streams(struct v4l2_subdev *sd,
449b63ef604SKeke Li 				       struct v4l2_subdev_state *state,
450b63ef604SKeke Li 				       u32 pad, u64 streams_mask)
451b63ef604SKeke Li {
452b63ef604SKeke Li 	struct c3_csi_device *csi = v4l2_get_subdevdata(sd);
453b63ef604SKeke Li 	struct v4l2_subdev *src_sd;
454b63ef604SKeke Li 
455b63ef604SKeke Li 	if (csi->src_pad) {
456b63ef604SKeke Li 		src_sd = media_entity_to_v4l2_subdev(csi->src_pad->entity);
457b63ef604SKeke Li 		v4l2_subdev_disable_streams(src_sd, csi->src_pad->index,
458b63ef604SKeke Li 					    BIT(0));
459b63ef604SKeke Li 	}
460b63ef604SKeke Li 	csi->src_pad = NULL;
461b63ef604SKeke Li 
462b63ef604SKeke Li 	pm_runtime_put(csi->dev);
463b63ef604SKeke Li 
464b63ef604SKeke Li 	return 0;
465b63ef604SKeke Li }
466b63ef604SKeke Li 
467b63ef604SKeke Li static int c3_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd,
468b63ef604SKeke Li 				      struct v4l2_subdev_state *state,
469b63ef604SKeke Li 				      struct v4l2_subdev_mbus_code_enum *code)
470b63ef604SKeke Li {
471b63ef604SKeke Li 	struct v4l2_mbus_framefmt *fmt;
472b63ef604SKeke Li 
473b63ef604SKeke Li 	switch (code->pad) {
474b63ef604SKeke Li 	case C3_MIPI_CSI2_PAD_SINK:
475b63ef604SKeke Li 		if (code->index >= ARRAY_SIZE(c3_mipi_csi_formats))
476b63ef604SKeke Li 			return -EINVAL;
477b63ef604SKeke Li 
478b63ef604SKeke Li 		code->code = c3_mipi_csi_formats[code->index];
479b63ef604SKeke Li 		break;
480b63ef604SKeke Li 	case C3_MIPI_CSI2_PAD_SRC:
481b63ef604SKeke Li 		if (code->index)
482b63ef604SKeke Li 			return -EINVAL;
483b63ef604SKeke Li 
484b63ef604SKeke Li 		fmt = v4l2_subdev_state_get_format(state, code->pad);
485b63ef604SKeke Li 		code->code = fmt->code;
486b63ef604SKeke Li 		break;
487b63ef604SKeke Li 	default:
488b63ef604SKeke Li 		return -EINVAL;
489b63ef604SKeke Li 	}
490b63ef604SKeke Li 
491b63ef604SKeke Li 	return 0;
492b63ef604SKeke Li }
493b63ef604SKeke Li 
494b63ef604SKeke Li static int c3_mipi_csi_set_fmt(struct v4l2_subdev *sd,
495b63ef604SKeke Li 			       struct v4l2_subdev_state *state,
496b63ef604SKeke Li 			       struct v4l2_subdev_format *format)
497b63ef604SKeke Li {
498b63ef604SKeke Li 	struct v4l2_mbus_framefmt *fmt;
499b63ef604SKeke Li 	unsigned int i;
500b63ef604SKeke Li 
501b63ef604SKeke Li 	if (format->pad != C3_MIPI_CSI2_PAD_SINK)
502b63ef604SKeke Li 		return v4l2_subdev_get_fmt(sd, state, format);
503b63ef604SKeke Li 
504b63ef604SKeke Li 	fmt = v4l2_subdev_state_get_format(state, format->pad);
505b63ef604SKeke Li 
506b63ef604SKeke Li 	for (i = 0; i < ARRAY_SIZE(c3_mipi_csi_formats); i++) {
507b63ef604SKeke Li 		if (format->format.code == c3_mipi_csi_formats[i]) {
508b63ef604SKeke Li 			fmt->code = c3_mipi_csi_formats[i];
509b63ef604SKeke Li 			break;
510b63ef604SKeke Li 		}
511b63ef604SKeke Li 	}
512b63ef604SKeke Li 
513b63ef604SKeke Li 	if (i == ARRAY_SIZE(c3_mipi_csi_formats))
514b63ef604SKeke Li 		fmt->code = c3_mipi_csi_formats[0];
515b63ef604SKeke Li 
516b63ef604SKeke Li 	fmt->width = clamp_t(u32, format->format.width,
517b63ef604SKeke Li 			     C3_MIPI_CSI2_MIN_WIDTH, C3_MIPI_CSI2_MAX_WIDTH);
518b63ef604SKeke Li 	fmt->height = clamp_t(u32, format->format.height,
519b63ef604SKeke Li 			      C3_MIPI_CSI2_MIN_HEIGHT, C3_MIPI_CSI2_MAX_HEIGHT);
520b63ef604SKeke Li 	fmt->colorspace = V4L2_COLORSPACE_RAW;
521b63ef604SKeke Li 	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
522b63ef604SKeke Li 	fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
523b63ef604SKeke Li 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
524b63ef604SKeke Li 
525b63ef604SKeke Li 	format->format = *fmt;
526b63ef604SKeke Li 
527b63ef604SKeke Li 	/* Synchronize the format to source pad */
528b63ef604SKeke Li 	fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SRC);
529b63ef604SKeke Li 	*fmt = format->format;
530b63ef604SKeke Li 
531b63ef604SKeke Li 	return 0;
532b63ef604SKeke Li }
533b63ef604SKeke Li 
534b63ef604SKeke Li static int c3_mipi_csi_init_state(struct v4l2_subdev *sd,
535b63ef604SKeke Li 				  struct v4l2_subdev_state *state)
536b63ef604SKeke Li {
537b63ef604SKeke Li 	struct v4l2_mbus_framefmt *sink_fmt;
538b63ef604SKeke Li 	struct v4l2_mbus_framefmt *src_fmt;
539b63ef604SKeke Li 
540b63ef604SKeke Li 	sink_fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SINK);
541b63ef604SKeke Li 	src_fmt = v4l2_subdev_state_get_format(state, C3_MIPI_CSI2_PAD_SRC);
542b63ef604SKeke Li 
543b63ef604SKeke Li 	sink_fmt->width = C3_MIPI_CSI2_DEFAULT_WIDTH;
544b63ef604SKeke Li 	sink_fmt->height = C3_MIPI_CSI2_DEFAULT_HEIGHT;
545b63ef604SKeke Li 	sink_fmt->field = V4L2_FIELD_NONE;
546b63ef604SKeke Li 	sink_fmt->code = C3_MIPI_CSI2_DEFAULT_FMT;
547b63ef604SKeke Li 	sink_fmt->colorspace = V4L2_COLORSPACE_RAW;
548b63ef604SKeke Li 	sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE;
549b63ef604SKeke Li 	sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
550b63ef604SKeke Li 	sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
551b63ef604SKeke Li 
552b63ef604SKeke Li 	*src_fmt = *sink_fmt;
553b63ef604SKeke Li 
554b63ef604SKeke Li 	return 0;
555b63ef604SKeke Li }
556b63ef604SKeke Li 
557b63ef604SKeke Li static const struct v4l2_subdev_pad_ops c3_mipi_csi_pad_ops = {
558b63ef604SKeke Li 	.enum_mbus_code = c3_mipi_csi_enum_mbus_code,
559b63ef604SKeke Li 	.get_fmt = v4l2_subdev_get_fmt,
560b63ef604SKeke Li 	.set_fmt = c3_mipi_csi_set_fmt,
561b63ef604SKeke Li 	.enable_streams = c3_mipi_csi_enable_streams,
562b63ef604SKeke Li 	.disable_streams = c3_mipi_csi_disable_streams,
563b63ef604SKeke Li };
564b63ef604SKeke Li 
565b63ef604SKeke Li static const struct v4l2_subdev_ops c3_mipi_csi_subdev_ops = {
566b63ef604SKeke Li 	.pad = &c3_mipi_csi_pad_ops,
567b63ef604SKeke Li };
568b63ef604SKeke Li 
569b63ef604SKeke Li static const struct v4l2_subdev_internal_ops c3_mipi_csi_internal_ops = {
570b63ef604SKeke Li 	.init_state = c3_mipi_csi_init_state,
571b63ef604SKeke Li };
572b63ef604SKeke Li 
573b63ef604SKeke Li /* Media entity operations */
574b63ef604SKeke Li static const struct media_entity_operations c3_mipi_csi_entity_ops = {
575b63ef604SKeke Li 	.link_validate = v4l2_subdev_link_validate,
576b63ef604SKeke Li };
577b63ef604SKeke Li 
578b63ef604SKeke Li /* PM runtime */
579b63ef604SKeke Li 
580b63ef604SKeke Li static int c3_mipi_csi_runtime_suspend(struct device *dev)
581b63ef604SKeke Li {
582b63ef604SKeke Li 	struct c3_csi_device *csi = dev_get_drvdata(dev);
583b63ef604SKeke Li 
584b63ef604SKeke Li 	clk_bulk_disable_unprepare(csi->info->clock_num, csi->clks);
585b63ef604SKeke Li 
586b63ef604SKeke Li 	return 0;
587b63ef604SKeke Li }
588b63ef604SKeke Li 
589b63ef604SKeke Li static int c3_mipi_csi_runtime_resume(struct device *dev)
590b63ef604SKeke Li {
591b63ef604SKeke Li 	struct c3_csi_device *csi = dev_get_drvdata(dev);
592b63ef604SKeke Li 
593b63ef604SKeke Li 	return clk_bulk_prepare_enable(csi->info->clock_num, csi->clks);
594b63ef604SKeke Li }
595b63ef604SKeke Li 
596b63ef604SKeke Li static const struct dev_pm_ops c3_mipi_csi_pm_ops = {
597b63ef604SKeke Li 	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
598b63ef604SKeke Li 			    pm_runtime_force_resume)
599b63ef604SKeke Li 	RUNTIME_PM_OPS(c3_mipi_csi_runtime_suspend,
600b63ef604SKeke Li 		       c3_mipi_csi_runtime_resume, NULL)
601b63ef604SKeke Li };
602b63ef604SKeke Li 
603b63ef604SKeke Li /* Probe/remove & platform driver */
604b63ef604SKeke Li 
605b63ef604SKeke Li static int c3_mipi_csi_subdev_init(struct c3_csi_device *csi)
606b63ef604SKeke Li {
607b63ef604SKeke Li 	struct v4l2_subdev *sd = &csi->sd;
608b63ef604SKeke Li 	int ret;
609b63ef604SKeke Li 
610b63ef604SKeke Li 	v4l2_subdev_init(sd, &c3_mipi_csi_subdev_ops);
611b63ef604SKeke Li 	sd->owner = THIS_MODULE;
612b63ef604SKeke Li 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
613b63ef604SKeke Li 	sd->internal_ops = &c3_mipi_csi_internal_ops;
614b63ef604SKeke Li 	snprintf(sd->name, sizeof(sd->name), "%s", MIPI_CSI2_SUBDEV_NAME);
615b63ef604SKeke Li 
616b63ef604SKeke Li 	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
617b63ef604SKeke Li 	sd->entity.ops = &c3_mipi_csi_entity_ops;
618b63ef604SKeke Li 
619b63ef604SKeke Li 	sd->dev = csi->dev;
620b63ef604SKeke Li 	v4l2_set_subdevdata(sd, csi);
621b63ef604SKeke Li 
622b63ef604SKeke Li 	csi->pads[C3_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
623b63ef604SKeke Li 	csi->pads[C3_MIPI_CSI2_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
624b63ef604SKeke Li 	ret = media_entity_pads_init(&sd->entity, C3_MIPI_CSI2_PAD_MAX,
625b63ef604SKeke Li 				     csi->pads);
626b63ef604SKeke Li 	if (ret)
627b63ef604SKeke Li 		return ret;
628b63ef604SKeke Li 
629b63ef604SKeke Li 	ret = v4l2_subdev_init_finalize(sd);
630b63ef604SKeke Li 	if (ret) {
631b63ef604SKeke Li 		media_entity_cleanup(&sd->entity);
632b63ef604SKeke Li 		return ret;
633b63ef604SKeke Li 	}
634b63ef604SKeke Li 
635b63ef604SKeke Li 	return 0;
636b63ef604SKeke Li }
637b63ef604SKeke Li 
638b63ef604SKeke Li static void c3_mipi_csi_subdev_deinit(struct c3_csi_device *csi)
639b63ef604SKeke Li {
640b63ef604SKeke Li 	v4l2_subdev_cleanup(&csi->sd);
641b63ef604SKeke Li 	media_entity_cleanup(&csi->sd.entity);
642b63ef604SKeke Li }
643b63ef604SKeke Li 
644b63ef604SKeke Li /* Subdev notifier register */
645b63ef604SKeke Li static int c3_mipi_csi_notify_bound(struct v4l2_async_notifier *notifier,
646b63ef604SKeke Li 				    struct v4l2_subdev *sd,
647b63ef604SKeke Li 				    struct v4l2_async_connection *asc)
648b63ef604SKeke Li {
649b63ef604SKeke Li 	struct c3_csi_device *csi = v4l2_get_subdevdata(notifier->sd);
650b63ef604SKeke Li 	struct media_pad *sink = &csi->sd.entity.pads[C3_MIPI_CSI2_PAD_SINK];
651b63ef604SKeke Li 
652b63ef604SKeke Li 	return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED |
653b63ef604SKeke Li 					       MEDIA_LNK_FL_IMMUTABLE);
654b63ef604SKeke Li }
655b63ef604SKeke Li 
656b63ef604SKeke Li static const struct v4l2_async_notifier_operations c3_mipi_csi_notify_ops = {
657b63ef604SKeke Li 	.bound = c3_mipi_csi_notify_bound,
658b63ef604SKeke Li };
659b63ef604SKeke Li 
660b63ef604SKeke Li static int c3_mipi_csi_async_register(struct c3_csi_device *csi)
661b63ef604SKeke Li {
662b63ef604SKeke Li 	struct v4l2_fwnode_endpoint vep = {
663b63ef604SKeke Li 		.bus_type = V4L2_MBUS_CSI2_DPHY,
664b63ef604SKeke Li 	};
665b63ef604SKeke Li 	struct v4l2_async_connection *asc;
666b63ef604SKeke Li 	struct fwnode_handle *ep;
667b63ef604SKeke Li 	int ret;
668b63ef604SKeke Li 
669b63ef604SKeke Li 	v4l2_async_subdev_nf_init(&csi->notifier, &csi->sd);
670b63ef604SKeke Li 
671b63ef604SKeke Li 	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
672b63ef604SKeke Li 					     FWNODE_GRAPH_ENDPOINT_NEXT);
673b63ef604SKeke Li 	if (!ep)
674b63ef604SKeke Li 		return -ENOTCONN;
675b63ef604SKeke Li 
676b63ef604SKeke Li 	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
677b63ef604SKeke Li 	if (ret)
678b63ef604SKeke Li 		goto err_put_handle;
679b63ef604SKeke Li 
680b63ef604SKeke Li 	csi->bus = vep.bus.mipi_csi2;
681b63ef604SKeke Li 
682b63ef604SKeke Li 	asc = v4l2_async_nf_add_fwnode_remote(&csi->notifier, ep,
683b63ef604SKeke Li 					      struct v4l2_async_connection);
684b63ef604SKeke Li 	if (IS_ERR(asc)) {
685b63ef604SKeke Li 		ret = PTR_ERR(asc);
686b63ef604SKeke Li 		goto err_put_handle;
687b63ef604SKeke Li 	}
688b63ef604SKeke Li 
689b63ef604SKeke Li 	csi->notifier.ops = &c3_mipi_csi_notify_ops;
690b63ef604SKeke Li 	ret = v4l2_async_nf_register(&csi->notifier);
691b63ef604SKeke Li 	if (ret)
692b63ef604SKeke Li 		goto err_cleanup_nf;
693b63ef604SKeke Li 
694b63ef604SKeke Li 	ret = v4l2_async_register_subdev(&csi->sd);
695b63ef604SKeke Li 	if (ret)
696b63ef604SKeke Li 		goto err_unregister_nf;
697b63ef604SKeke Li 
698b63ef604SKeke Li 	fwnode_handle_put(ep);
699b63ef604SKeke Li 
700b63ef604SKeke Li 	return 0;
701b63ef604SKeke Li 
702b63ef604SKeke Li err_unregister_nf:
703b63ef604SKeke Li 	v4l2_async_nf_unregister(&csi->notifier);
704b63ef604SKeke Li err_cleanup_nf:
705b63ef604SKeke Li 	v4l2_async_nf_cleanup(&csi->notifier);
706b63ef604SKeke Li err_put_handle:
707b63ef604SKeke Li 	fwnode_handle_put(ep);
708b63ef604SKeke Li 	return ret;
709b63ef604SKeke Li }
710b63ef604SKeke Li 
711b63ef604SKeke Li static void c3_mipi_csi_async_unregister(struct c3_csi_device *csi)
712b63ef604SKeke Li {
713b63ef604SKeke Li 	v4l2_async_unregister_subdev(&csi->sd);
714b63ef604SKeke Li 	v4l2_async_nf_unregister(&csi->notifier);
715b63ef604SKeke Li 	v4l2_async_nf_cleanup(&csi->notifier);
716b63ef604SKeke Li }
717b63ef604SKeke Li 
718b63ef604SKeke Li static int c3_mipi_csi_ioremap_resource(struct c3_csi_device *csi)
719b63ef604SKeke Li {
720b63ef604SKeke Li 	struct device *dev = csi->dev;
721b63ef604SKeke Li 	struct platform_device *pdev = to_platform_device(dev);
722b63ef604SKeke Li 
723b63ef604SKeke Li 	csi->aphy = devm_platform_ioremap_resource_byname(pdev, "aphy");
724b63ef604SKeke Li 	if (IS_ERR(csi->aphy))
725b63ef604SKeke Li 		return PTR_ERR(csi->aphy);
726b63ef604SKeke Li 
727b63ef604SKeke Li 	csi->dphy = devm_platform_ioremap_resource_byname(pdev, "dphy");
728b63ef604SKeke Li 	if (IS_ERR(csi->dphy))
729b63ef604SKeke Li 		return PTR_ERR(csi->dphy);
730b63ef604SKeke Li 
731b63ef604SKeke Li 	csi->host = devm_platform_ioremap_resource_byname(pdev, "host");
732b63ef604SKeke Li 	if (IS_ERR(csi->host))
733b63ef604SKeke Li 		return PTR_ERR(csi->host);
734b63ef604SKeke Li 
735b63ef604SKeke Li 	return 0;
736b63ef604SKeke Li }
737b63ef604SKeke Li 
738b63ef604SKeke Li static int c3_mipi_csi_get_clocks(struct c3_csi_device *csi)
739b63ef604SKeke Li {
740b63ef604SKeke Li 	const struct c3_csi_info *info = csi->info;
741b63ef604SKeke Li 
742b63ef604SKeke Li 	for (unsigned int i = 0; i < info->clock_num; i++)
743b63ef604SKeke Li 		csi->clks[i].id = info->clocks[i];
744b63ef604SKeke Li 
745b63ef604SKeke Li 	return devm_clk_bulk_get(csi->dev, info->clock_num, csi->clks);
746b63ef604SKeke Li }
747b63ef604SKeke Li 
748b63ef604SKeke Li static int c3_mipi_csi_probe(struct platform_device *pdev)
749b63ef604SKeke Li {
750b63ef604SKeke Li 	struct device *dev = &pdev->dev;
751b63ef604SKeke Li 	struct c3_csi_device *csi;
752b63ef604SKeke Li 	int ret;
753b63ef604SKeke Li 
754b63ef604SKeke Li 	csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
755b63ef604SKeke Li 	if (!csi)
756b63ef604SKeke Li 		return -ENOMEM;
757b63ef604SKeke Li 
758b63ef604SKeke Li 	csi->info = of_device_get_match_data(dev);
759b63ef604SKeke Li 	csi->dev = dev;
760b63ef604SKeke Li 
761b63ef604SKeke Li 	ret = c3_mipi_csi_ioremap_resource(csi);
762b63ef604SKeke Li 	if (ret)
763b63ef604SKeke Li 		return dev_err_probe(dev, ret, "Failed to ioremap resource\n");
764b63ef604SKeke Li 
765b63ef604SKeke Li 	ret = c3_mipi_csi_get_clocks(csi);
766b63ef604SKeke Li 	if (ret)
767b63ef604SKeke Li 		return dev_err_probe(dev, ret, "Failed to get clocks\n");
768b63ef604SKeke Li 
769b63ef604SKeke Li 	platform_set_drvdata(pdev, csi);
770b63ef604SKeke Li 
771b63ef604SKeke Li 	pm_runtime_enable(dev);
772b63ef604SKeke Li 
773b63ef604SKeke Li 	ret = c3_mipi_csi_subdev_init(csi);
774b63ef604SKeke Li 	if (ret)
775b63ef604SKeke Li 		goto err_disable_runtime_pm;
776b63ef604SKeke Li 
777b63ef604SKeke Li 	ret = c3_mipi_csi_async_register(csi);
778b63ef604SKeke Li 	if (ret)
779b63ef604SKeke Li 		goto err_deinit_subdev;
780b63ef604SKeke Li 
781b63ef604SKeke Li 	return 0;
782b63ef604SKeke Li 
783b63ef604SKeke Li err_deinit_subdev:
784b63ef604SKeke Li 	c3_mipi_csi_subdev_deinit(csi);
785b63ef604SKeke Li err_disable_runtime_pm:
786b63ef604SKeke Li 	pm_runtime_disable(dev);
787b63ef604SKeke Li 	return ret;
788b63ef604SKeke Li };
789b63ef604SKeke Li 
790b63ef604SKeke Li static void c3_mipi_csi_remove(struct platform_device *pdev)
791b63ef604SKeke Li {
792b63ef604SKeke Li 	struct c3_csi_device *csi = platform_get_drvdata(pdev);
793b63ef604SKeke Li 
794b63ef604SKeke Li 	c3_mipi_csi_async_unregister(csi);
795b63ef604SKeke Li 	c3_mipi_csi_subdev_deinit(csi);
796b63ef604SKeke Li 
797b63ef604SKeke Li 	pm_runtime_disable(&pdev->dev);
798b63ef604SKeke Li };
799b63ef604SKeke Li 
800b63ef604SKeke Li static const struct c3_csi_info c3_mipi_csi_info = {
801b63ef604SKeke Li 	.clocks = {"vapb", "phy0"},
802b63ef604SKeke Li 	.clock_num = 2
803b63ef604SKeke Li };
804b63ef604SKeke Li 
805b63ef604SKeke Li static const struct of_device_id c3_mipi_csi_of_match[] = {
806b63ef604SKeke Li 	{
807b63ef604SKeke Li 		.compatible = "amlogic,c3-mipi-csi2",
808b63ef604SKeke Li 		.data = &c3_mipi_csi_info,
809b63ef604SKeke Li 	},
810b63ef604SKeke Li 	{ },
811b63ef604SKeke Li };
812b63ef604SKeke Li MODULE_DEVICE_TABLE(of, c3_mipi_csi_of_match);
813b63ef604SKeke Li 
814b63ef604SKeke Li static struct platform_driver c3_mipi_csi_driver = {
815b63ef604SKeke Li 	.probe = c3_mipi_csi_probe,
816b63ef604SKeke Li 	.remove = c3_mipi_csi_remove,
817b63ef604SKeke Li 	.driver = {
818b63ef604SKeke Li 		.name = "c3-mipi-csi2",
819b63ef604SKeke Li 		.of_match_table = c3_mipi_csi_of_match,
820b63ef604SKeke Li 		.pm = pm_ptr(&c3_mipi_csi_pm_ops),
821b63ef604SKeke Li 	},
822b63ef604SKeke Li };
823b63ef604SKeke Li 
824b63ef604SKeke Li module_platform_driver(c3_mipi_csi_driver);
825b63ef604SKeke Li 
826b63ef604SKeke Li MODULE_AUTHOR("Keke Li <keke.li@amlogic.com>");
827b63ef604SKeke Li MODULE_DESCRIPTION("Amlogic C3 MIPI CSI-2 receiver");
828b63ef604SKeke Li MODULE_LICENSE("GPL");
829