xref: /linux/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c (revision 1d1ba4d390141d602dbce8f5f0ac19a384d10a64)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip MIPI RX Innosilicon DPHY driver
4  *
5  * Copyright (C) 2021 Fuzhou Rockchip Electronics Co., Ltd.
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/io.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/of_platform.h>
16 #include <linux/phy/phy.h>
17 #include <linux/phy/phy-mipi-dphy.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
22 
23 /* GRF */
24 #define RK1808_GRF_PD_VI_CON_OFFSET	0x0430
25 
26 #define RK3326_GRF_PD_VI_CON_OFFSET	0x0430
27 
28 #define RK3368_GRF_SOC_CON6_OFFSET	0x0418
29 
30 #define RK3568_GRF_VI_CON0		0x0340
31 #define RK3568_GRF_VI_CON1		0x0344
32 
33 #define RK3588_CSIDPHY_GRF_CON0		0x0000
34 
35 /* PHY */
36 #define CSIDPHY_CTRL_LANE_ENABLE		0x00
37 #define CSIDPHY_CTRL_LANE_ENABLE_CK		BIT(6)
38 #define CSIDPHY_CTRL_LANE_ENABLE_MASK		GENMASK(5, 2)
39 #define CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED	BIT(0)
40 
41 /* not present on all variants */
42 #define CSIDPHY_CTRL_PWRCTL			0x04
43 #define CSIDPHY_CTRL_PWRCTL_UNDEFINED		GENMASK(7, 5)
44 #define CSIDPHY_CTRL_PWRCTL_SYNCRST		BIT(2)
45 #define CSIDPHY_CTRL_PWRCTL_LDO_PD		BIT(1)
46 #define CSIDPHY_CTRL_PWRCTL_PLL_PD		BIT(0)
47 
48 #define CSIDPHY_CTRL_DIG_RST			0x80
49 #define CSIDPHY_CTRL_DIG_RST_UNDEFINED		0x1e
50 #define CSIDPHY_CTRL_DIG_RST_RESET		BIT(0)
51 
52 /* offset after ths_settle_offset */
53 #define CSIDPHY_CLK_THS_SETTLE			0
54 #define CSIDPHY_LANE_THS_SETTLE(n)		(((n) + 1) * 0x80)
55 #define CSIDPHY_THS_SETTLE_MASK			GENMASK(6, 0)
56 
57 /* offset after calib_offset */
58 #define CSIDPHY_CLK_CALIB_EN			0
59 #define CSIDPHY_LANE_CALIB_EN(n)		(((n) + 1) * 0x80)
60 #define CSIDPHY_CALIB_EN			BIT(7)
61 
62 /* Configure the count time of the THS-SETTLE by protocol. */
63 #define RK1808_CSIDPHY_CLK_WR_THS_SETTLE	0x160
64 #define RK3326_CSIDPHY_CLK_WR_THS_SETTLE	0x100
65 #define RK3368_CSIDPHY_CLK_WR_THS_SETTLE	0x100
66 #define RK3568_CSIDPHY_CLK_WR_THS_SETTLE	0x160
67 
68 /* Calibration reception enable */
69 #define RK1808_CSIDPHY_CLK_CALIB_EN		0x168
70 #define RK3568_CSIDPHY_CLK_CALIB_EN		0x168
71 
72 #define RESETS_MAX				2
73 
74 /*
75  * The higher 16-bit of this register is used for write protection
76  * only if BIT(x + 16) set to 1 the BIT(x) can be written.
77  */
78 #define HIWORD_UPDATE(val, mask, shift) \
79 		((val) << (shift) | (mask) << ((shift) + 16))
80 
81 #define HZ_TO_MHZ(freq)				div_u64(freq, 1000 * 1000)
82 
83 enum dphy_reg_id {
84 	/* rk1808 & rk3326 */
85 	GRF_DPHY_CSIPHY_FORCERXMODE,
86 	GRF_DPHY_CSIPHY_CLKLANE_EN,
87 	GRF_DPHY_CSIPHY_DATALANE_EN,
88 };
89 
90 struct dphy_reg {
91 	u32 offset;
92 	u32 mask;
93 	u32 shift;
94 	u8 valid;
95 };
96 
97 #define PHY_REG(_offset, _width, _shift) \
98 	{ .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, .valid = 1, }
99 
100 static const struct dphy_reg rk1808_grf_dphy_regs[] = {
101 	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 0),
102 	[GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 1, 8),
103 	[GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK1808_GRF_PD_VI_CON_OFFSET, 4, 4),
104 };
105 
106 static const struct dphy_reg rk3326_grf_dphy_regs[] = {
107 	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 0),
108 	[GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 1, 8),
109 	[GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 4),
110 };
111 
112 static const struct dphy_reg rk3368_grf_dphy_regs[] = {
113 	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8),
114 };
115 
116 static const struct dphy_reg rk3568_grf_dphy_regs[] = {
117 	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3568_GRF_VI_CON0, 4, 0),
118 	[GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3568_GRF_VI_CON0, 4, 4),
119 	[GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3568_GRF_VI_CON0, 1, 8),
120 };
121 
122 static const struct dphy_reg rk3588_grf_dphy_regs[] = {
123 	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 4, 0),
124 	[GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 4, 4),
125 	[GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3588_CSIDPHY_GRF_CON0, 1, 8),
126 };
127 
128 struct hsfreq_range {
129 	u32 range_h;
130 	u8 cfg_bit;
131 };
132 
133 struct dphy_drv_data {
134 	int pwrctl_offset;
135 	int ths_settle_offset;
136 	int calib_offset;
137 	const struct hsfreq_range *hsfreq_ranges;
138 	int num_hsfreq_ranges;
139 	const struct dphy_reg *grf_regs;
140 	const char *const *resets;
141 	unsigned int resets_num;
142 };
143 
144 struct rockchip_inno_csidphy {
145 	struct device *dev;
146 	void __iomem *phy_base;
147 	struct clk *pclk;
148 	struct regmap *grf;
149 	struct reset_control_bulk_data resets[RESETS_MAX];
150 	unsigned int resets_num;
151 	const struct dphy_drv_data *drv_data;
152 	struct phy_configure_opts_mipi_dphy config;
153 	u8 hsfreq;
154 };
155 
write_grf_reg(struct rockchip_inno_csidphy * priv,int index,u8 value)156 static inline void write_grf_reg(struct rockchip_inno_csidphy *priv,
157 				 int index, u8 value)
158 {
159 	const struct dphy_drv_data *drv_data = priv->drv_data;
160 	const struct dphy_reg *reg = &drv_data->grf_regs[index];
161 
162 	if (reg->valid)
163 		regmap_write(priv->grf, reg->offset,
164 			     HIWORD_UPDATE(value, reg->mask, reg->shift));
165 }
166 
167 /* These tables must be sorted by .range_h ascending. */
168 static const struct hsfreq_range rk1808_mipidphy_hsfreq_ranges[] = {
169 	{ 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06},
170 	{ 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e},
171 	{ 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e},
172 	{1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37},
173 	{2199, 0x3c}, {2399, 0x41}, {2499, 0x46}
174 };
175 
176 static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = {
177 	{ 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
178 	{ 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
179 	{ 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
180 	{1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
181 };
182 
183 static const struct hsfreq_range rk3368_mipidphy_hsfreq_ranges[] = {
184 	{ 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03},
185 	{ 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07},
186 	{ 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b},
187 	{1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e}
188 };
189 
190 static const char *const rk3368_reset_names[] = {
191 	"apb"
192 };
193 
194 static const char *const rk3588_reset_names[] = {
195 	"apb",
196 	"phy"
197 };
198 
rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy * priv,int hsfreq,int offset)199 static void rockchip_inno_csidphy_ths_settle(struct rockchip_inno_csidphy *priv,
200 					     int hsfreq, int offset)
201 {
202 	const struct dphy_drv_data *drv_data = priv->drv_data;
203 	u32 val;
204 
205 	val = readl(priv->phy_base + drv_data->ths_settle_offset + offset);
206 	val &= ~CSIDPHY_THS_SETTLE_MASK;
207 	val |= hsfreq;
208 	writel(val, priv->phy_base + drv_data->ths_settle_offset + offset);
209 }
210 
rockchip_inno_csidphy_configure(struct phy * phy,union phy_configure_opts * opts)211 static int rockchip_inno_csidphy_configure(struct phy *phy,
212 					   union phy_configure_opts *opts)
213 {
214 	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
215 	const struct dphy_drv_data *drv_data = priv->drv_data;
216 	struct phy_configure_opts_mipi_dphy *config = &opts->mipi_dphy;
217 	unsigned int hsfreq = 0;
218 	unsigned int i;
219 	u64 data_rate_mbps;
220 	int ret;
221 
222 	/* pass with phy_mipi_dphy_get_default_config (with pixel rate?) */
223 	ret = phy_mipi_dphy_config_validate(config);
224 	if (ret)
225 		return ret;
226 
227 	data_rate_mbps = HZ_TO_MHZ(config->hs_clk_rate);
228 
229 	dev_dbg(priv->dev, "lanes %d - data_rate_mbps %llu\n",
230 		config->lanes, data_rate_mbps);
231 	for (i = 0; i < drv_data->num_hsfreq_ranges; i++) {
232 		if (drv_data->hsfreq_ranges[i].range_h >= data_rate_mbps) {
233 			hsfreq = drv_data->hsfreq_ranges[i].cfg_bit;
234 			break;
235 		}
236 	}
237 	if (!hsfreq)
238 		return -EINVAL;
239 
240 	priv->hsfreq = hsfreq;
241 	priv->config = *config;
242 	return 0;
243 }
244 
rockchip_inno_csidphy_power_on(struct phy * phy)245 static int rockchip_inno_csidphy_power_on(struct phy *phy)
246 {
247 	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
248 	const struct dphy_drv_data *drv_data = priv->drv_data;
249 	u64 data_rate_mbps = HZ_TO_MHZ(priv->config.hs_clk_rate);
250 	u32 val;
251 	int ret, i;
252 
253 	ret = clk_enable(priv->pclk);
254 	if (ret < 0)
255 		return ret;
256 
257 	ret = pm_runtime_resume_and_get(priv->dev);
258 	if (ret < 0) {
259 		clk_disable(priv->pclk);
260 		return ret;
261 	}
262 
263 	/* phy start */
264 	if (drv_data->pwrctl_offset >= 0)
265 		writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
266 		       CSIDPHY_CTRL_PWRCTL_SYNCRST,
267 		       priv->phy_base + drv_data->pwrctl_offset);
268 
269 	/* set data lane num and enable clock lane */
270 	val = FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_MASK, GENMASK(priv->config.lanes - 1, 0)) |
271 	      FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_CK, 1) |
272 	      FIELD_PREP(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED, 1);
273 	writel(val, priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
274 
275 	/* Reset dphy analog part */
276 	if (drv_data->pwrctl_offset >= 0)
277 		writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED,
278 		       priv->phy_base + drv_data->pwrctl_offset);
279 	usleep_range(500, 1000);
280 
281 	/* Reset dphy digital part */
282 	writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED,
283 	       priv->phy_base + CSIDPHY_CTRL_DIG_RST);
284 	writel(CSIDPHY_CTRL_DIG_RST_UNDEFINED + CSIDPHY_CTRL_DIG_RST_RESET,
285 	       priv->phy_base + CSIDPHY_CTRL_DIG_RST);
286 
287 	/* not into receive mode/wait stopstate */
288 	write_grf_reg(priv, GRF_DPHY_CSIPHY_FORCERXMODE, 0x0);
289 
290 	/* enable calibration */
291 	if (data_rate_mbps > 1500 && drv_data->calib_offset >= 0) {
292 		writel(CSIDPHY_CALIB_EN,
293 		       priv->phy_base + drv_data->calib_offset +
294 					CSIDPHY_CLK_CALIB_EN);
295 		for (i = 0; i < priv->config.lanes; i++)
296 			writel(CSIDPHY_CALIB_EN,
297 			       priv->phy_base + drv_data->calib_offset +
298 						CSIDPHY_LANE_CALIB_EN(i));
299 	}
300 
301 	rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
302 					 CSIDPHY_CLK_THS_SETTLE);
303 	for (i = 0; i < priv->config.lanes; i++)
304 		rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq,
305 						 CSIDPHY_LANE_THS_SETTLE(i));
306 
307 	write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1);
308 	write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN,
309 		      GENMASK(priv->config.lanes - 1, 0));
310 
311 	return 0;
312 }
313 
rockchip_inno_csidphy_power_off(struct phy * phy)314 static int rockchip_inno_csidphy_power_off(struct phy *phy)
315 {
316 	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
317 	const struct dphy_drv_data *drv_data = priv->drv_data;
318 
319 	/* disable all lanes */
320 	writel(CSIDPHY_CTRL_LANE_ENABLE_UNDEFINED,
321 	       priv->phy_base + CSIDPHY_CTRL_LANE_ENABLE);
322 
323 	/* disable pll and ldo */
324 	if (drv_data->pwrctl_offset >= 0)
325 		writel(CSIDPHY_CTRL_PWRCTL_UNDEFINED |
326 		       CSIDPHY_CTRL_PWRCTL_LDO_PD |
327 		       CSIDPHY_CTRL_PWRCTL_PLL_PD,
328 		       priv->phy_base + drv_data->pwrctl_offset);
329 	usleep_range(500, 1000);
330 
331 	pm_runtime_put(priv->dev);
332 	clk_disable(priv->pclk);
333 
334 	return 0;
335 }
336 
rockchip_inno_csidphy_init(struct phy * phy)337 static int rockchip_inno_csidphy_init(struct phy *phy)
338 {
339 	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
340 
341 	return clk_prepare(priv->pclk);
342 }
343 
rockchip_inno_csidphy_exit(struct phy * phy)344 static int rockchip_inno_csidphy_exit(struct phy *phy)
345 {
346 	struct rockchip_inno_csidphy *priv = phy_get_drvdata(phy);
347 
348 	clk_unprepare(priv->pclk);
349 
350 	return 0;
351 }
352 
353 static const struct phy_ops rockchip_inno_csidphy_ops = {
354 	.power_on	= rockchip_inno_csidphy_power_on,
355 	.power_off	= rockchip_inno_csidphy_power_off,
356 	.init		= rockchip_inno_csidphy_init,
357 	.exit		= rockchip_inno_csidphy_exit,
358 	.configure	= rockchip_inno_csidphy_configure,
359 	.owner		= THIS_MODULE,
360 };
361 
362 static const struct dphy_drv_data rk1808_mipidphy_drv_data = {
363 	.pwrctl_offset = -1,
364 	.ths_settle_offset = RK1808_CSIDPHY_CLK_WR_THS_SETTLE,
365 	.calib_offset = RK1808_CSIDPHY_CLK_CALIB_EN,
366 	.hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges,
367 	.num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges),
368 	.grf_regs = rk1808_grf_dphy_regs,
369 	.resets = rk3368_reset_names,
370 	.resets_num = ARRAY_SIZE(rk3368_reset_names),
371 };
372 
373 static const struct dphy_drv_data rk3326_mipidphy_drv_data = {
374 	.pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
375 	.ths_settle_offset = RK3326_CSIDPHY_CLK_WR_THS_SETTLE,
376 	.calib_offset = -1,
377 	.hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges,
378 	.num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges),
379 	.grf_regs = rk3326_grf_dphy_regs,
380 	.resets = rk3368_reset_names,
381 	.resets_num = ARRAY_SIZE(rk3368_reset_names),
382 };
383 
384 static const struct dphy_drv_data rk3368_mipidphy_drv_data = {
385 	.pwrctl_offset = CSIDPHY_CTRL_PWRCTL,
386 	.ths_settle_offset = RK3368_CSIDPHY_CLK_WR_THS_SETTLE,
387 	.calib_offset = -1,
388 	.hsfreq_ranges = rk3368_mipidphy_hsfreq_ranges,
389 	.num_hsfreq_ranges = ARRAY_SIZE(rk3368_mipidphy_hsfreq_ranges),
390 	.grf_regs = rk3368_grf_dphy_regs,
391 	.resets = rk3368_reset_names,
392 	.resets_num = ARRAY_SIZE(rk3368_reset_names),
393 };
394 
395 static const struct dphy_drv_data rk3568_mipidphy_drv_data = {
396 	.pwrctl_offset = -1,
397 	.ths_settle_offset = RK3568_CSIDPHY_CLK_WR_THS_SETTLE,
398 	.calib_offset = RK3568_CSIDPHY_CLK_CALIB_EN,
399 	.hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges,
400 	.num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges),
401 	.grf_regs = rk3568_grf_dphy_regs,
402 	.resets = rk3368_reset_names,
403 	.resets_num = ARRAY_SIZE(rk3368_reset_names),
404 };
405 
406 static const struct dphy_drv_data rk3588_mipidphy_drv_data = {
407 	.pwrctl_offset = -1,
408 	.ths_settle_offset = RK3568_CSIDPHY_CLK_WR_THS_SETTLE,
409 	.calib_offset = RK3568_CSIDPHY_CLK_CALIB_EN,
410 	.hsfreq_ranges = rk1808_mipidphy_hsfreq_ranges,
411 	.num_hsfreq_ranges = ARRAY_SIZE(rk1808_mipidphy_hsfreq_ranges),
412 	.grf_regs = rk3588_grf_dphy_regs,
413 	.resets = rk3588_reset_names,
414 	.resets_num = ARRAY_SIZE(rk3588_reset_names),
415 };
416 
417 static const struct of_device_id rockchip_inno_csidphy_match_id[] = {
418 	{
419 		.compatible = "rockchip,px30-csi-dphy",
420 		.data = &rk3326_mipidphy_drv_data,
421 	},
422 	{
423 		.compatible = "rockchip,rk1808-csi-dphy",
424 		.data = &rk1808_mipidphy_drv_data,
425 	},
426 	{
427 		.compatible = "rockchip,rk3326-csi-dphy",
428 		.data = &rk3326_mipidphy_drv_data,
429 	},
430 	{
431 		.compatible = "rockchip,rk3368-csi-dphy",
432 		.data = &rk3368_mipidphy_drv_data,
433 	},
434 	{
435 		.compatible = "rockchip,rk3568-csi-dphy",
436 		.data = &rk3568_mipidphy_drv_data,
437 	},
438 	{
439 		.compatible = "rockchip,rk3588-csi-dphy",
440 		.data = &rk3588_mipidphy_drv_data,
441 	},
442 	{}
443 };
444 MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);
445 
rockchip_inno_csidphy_probe(struct platform_device * pdev)446 static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
447 {
448 	struct rockchip_inno_csidphy *priv;
449 	struct device *dev = &pdev->dev;
450 	struct phy_provider *phy_provider;
451 	struct phy *phy;
452 	int ret;
453 
454 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
455 	if (!priv)
456 		return -ENOMEM;
457 
458 	priv->dev = dev;
459 	platform_set_drvdata(pdev, priv);
460 
461 	priv->drv_data = of_device_get_match_data(dev);
462 	if (!priv->drv_data) {
463 		dev_err(dev, "Can't find device data\n");
464 		return -ENODEV;
465 	}
466 
467 	priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
468 						    "rockchip,grf");
469 	if (IS_ERR(priv->grf)) {
470 		dev_err(dev, "Can't find GRF syscon\n");
471 		return PTR_ERR(priv->grf);
472 	}
473 
474 	priv->phy_base = devm_platform_ioremap_resource(pdev, 0);
475 	if (IS_ERR(priv->phy_base))
476 		return PTR_ERR(priv->phy_base);
477 
478 	priv->pclk = devm_clk_get(dev, "pclk");
479 	if (IS_ERR(priv->pclk)) {
480 		dev_err(dev, "failed to get pclk\n");
481 		return PTR_ERR(priv->pclk);
482 	}
483 
484 	if (priv->drv_data->resets_num > RESETS_MAX) {
485 		dev_err(dev, "invalid number of resets\n");
486 		return -EINVAL;
487 	}
488 	priv->resets_num = priv->drv_data->resets_num;
489 	for (unsigned int i = 0; i < priv->resets_num; i++)
490 		priv->resets[i].id = priv->drv_data->resets[i];
491 	ret = devm_reset_control_bulk_get_exclusive(dev, priv->resets_num,
492 						    priv->resets);
493 	if (ret) {
494 		dev_err(dev, "failed to get system reset control\n");
495 		return ret;
496 	}
497 
498 	phy = devm_phy_create(dev, NULL, &rockchip_inno_csidphy_ops);
499 	if (IS_ERR(phy)) {
500 		dev_err(dev, "failed to create phy\n");
501 		return PTR_ERR(phy);
502 	}
503 
504 	phy_set_drvdata(phy, priv);
505 
506 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
507 	if (IS_ERR(phy_provider)) {
508 		dev_err(dev, "failed to register phy provider\n");
509 		return PTR_ERR(phy_provider);
510 	}
511 
512 	pm_runtime_enable(dev);
513 
514 	return 0;
515 }
516 
rockchip_inno_csidphy_remove(struct platform_device * pdev)517 static void rockchip_inno_csidphy_remove(struct platform_device *pdev)
518 {
519 	struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev);
520 
521 	pm_runtime_disable(priv->dev);
522 }
523 
524 static struct platform_driver rockchip_inno_csidphy_driver = {
525 	.driver = {
526 		.name = "rockchip-inno-csidphy",
527 		.of_match_table = rockchip_inno_csidphy_match_id,
528 	},
529 	.probe = rockchip_inno_csidphy_probe,
530 	.remove = rockchip_inno_csidphy_remove,
531 };
532 
533 module_platform_driver(rockchip_inno_csidphy_driver);
534 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
535 MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
536 MODULE_LICENSE("GPL v2");
537