File Index
Files and directories
Sign in
FILE

phy-rockchip-inno-csidphy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c C
  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
 83enum 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
 90struct 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
100static 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
106static 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
112static const struct dphy_reg rk3368_grf_dphy_regs[] = {
113	[GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3368_GRF_SOC_CON6_OFFSET, 4, 8),
114};
115
116static 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
122static 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
128struct hsfreq_range {
129	u32 range_h;
130	u8 cfg_bit;
131};
132
133struct 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
144struct 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
156static 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. */
168static 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
176static 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
183static 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
190static const char *const rk3368_reset_names[] = {
191	"apb"
192};
193
194static const char *const rk3588_reset_names[] = {
195	"apb",
196	"phy"
197};
198
199static 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
211static 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
245static 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
314static 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
337static 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
344static 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
353static 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
362static 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
373static 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
384static 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
395static 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
406static 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
417static 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};
444MODULE_DEVICE_TABLE(of, rockchip_inno_csidphy_match_id);
445
446static 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
517static 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
524static 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
533module_platform_driver(rockchip_inno_csidphy_driver);
534MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
535MODULE_DESCRIPTION("Rockchip MIPI Innosilicon CSI-DPHY driver");
536MODULE_LICENSE("GPL v2");
~/ Read-only file preview.