2 * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/kernel.h>
16 #include <linux/clk.h>
17 #include <linux/clk-provider.h>
18 #include <linux/delay.h>
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/regmap.h>
23 #include <linux/reset.h>
24 #include <linux/phy/phy.h>
26 #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
28 /* Innosilicon MIPI D-PHY registers */
29 #define INNO_PHY_LANE_CTRL 0x00000
30 #define INNO_PHY_POWER_CTRL 0x00004
31 #define ANALOG_RESET_MASK BIT(2)
32 #define ANALOG_RESET BIT(2)
33 #define ANALOG_NORMAL 0
34 #define LDO_POWER_MASK BIT(1)
35 #define LDO_POWER_DOWN BIT(1)
36 #define LDO_POWER_ON 0
37 #define PLL_POWER_MASK BIT(0)
38 #define PLL_POWER_DOWN BIT(0)
39 #define PLL_POWER_ON 0
40 #define INNO_PHY_PLL_CTRL_0 0x0000c
41 #define FBDIV_HI_MASK BIT(5)
42 #define FBDIV_HI(x) UPDATE(x, 5, 5)
43 #define PREDIV_MASK GENMASK(4, 0)
44 #define PREDIV(x) UPDATE(x, 4, 0)
45 #define INNO_PHY_PLL_CTRL_1 0x00010
46 #define FBDIV_LO_MASK GENMASK(7, 0)
47 #define FBDIV_LO(x) UPDATE(x, 7, 0)
48 #define INNO_PHY_DIG_CTRL 0x00080
49 #define DIGITAL_RESET_MASK BIT(0)
50 #define DIGITAL_NORMAL BIT(0)
51 #define DIGITAL_RESET 0
53 #define INNO_CLOCK_LANE_REG_BASE 0x00100
54 #define INNO_DATA_LANE_0_REG_BASE 0x00180
55 #define INNO_DATA_LANE_1_REG_BASE 0x00200
56 #define INNO_DATA_LANE_2_REG_BASE 0x00280
57 #define INNO_DATA_LANE_3_REG_BASE 0x00300
58 #define INNO_MIPI_DPHY_MAX_REGISTER (INNO_DATA_LANE_3_REG_BASE + \
61 #define T_LPX_OFFSET 0x00014
62 #define T_HS_PREPARE_OFFSET 0x00018
63 #define T_HS_ZERO_OFFSET 0x0001c
64 #define T_HS_TRAIL_OFFSET 0x00020
65 #define T_HS_EXIT_OFFSET 0x00024
66 #define T_CLK_POST_OFFSET 0x00028
67 #define T_WAKUP_H_OFFSET 0x00030
68 #define T_WAKUP_L_OFFSET 0x00034
69 #define T_CLK_PRE_OFFSET 0x00038
70 #define T_TA_GO_OFFSET 0x00040
71 #define T_TA_SURE_OFFSET 0x00044
72 #define T_TA_WAIT_OFFSET 0x00048
74 #define T_LPX_MASK GENMASK(5, 0)
75 #define T_LPX(x) UPDATE(x, 5, 0)
76 #define T_HS_PREPARE_MASK GENMASK(6, 0)
77 #define T_HS_PREPARE(x) UPDATE(x, 6, 0)
78 #define T_HS_ZERO_MASK GENMASK(5, 0)
79 #define T_HS_ZERO(x) UPDATE(x, 5, 0)
80 #define T_HS_TRAIL_MASK GENMASK(6, 0)
81 #define T_HS_TRAIL(x) UPDATE(x, 6, 0)
82 #define T_HS_EXIT_MASK GENMASK(4, 0)
83 #define T_HS_EXIT(x) UPDATE(x, 4, 0)
84 #define T_CLK_POST_MASK GENMASK(3, 0)
85 #define T_CLK_POST(x) UPDATE(x, 3, 0)
86 #define T_WAKUP_H_MASK GENMASK(1, 0)
87 #define T_WAKUP_H(x) UPDATE(x, 1, 0)
88 #define T_WAKUP_L_MASK GENMASK(7, 0)
89 #define T_WAKUP_L(x) UPDATE(x, 7, 0)
90 #define T_CLK_PRE_MASK GENMASK(3, 0)
91 #define T_CLK_PRE(x) UPDATE(x, 3, 0)
92 #define T_TA_GO_MASK GENMASK(5, 0)
93 #define T_TA_GO(x) UPDATE(x, 5, 0)
94 #define T_TA_SURE_MASK GENMASK(5, 0)
95 #define T_TA_SURE(x) UPDATE(x, 5, 0)
96 #define T_TA_WAIT_MASK GENMASK(5, 0)
97 #define T_TA_WAIT(x) UPDATE(x, 5, 0)
107 struct mipi_dphy_timing {
108 unsigned int clkmiss;
109 unsigned int clkpost;
111 unsigned int clkprepare;
112 unsigned int clksettle;
113 unsigned int clktermen;
114 unsigned int clktrail;
115 unsigned int clkzero;
116 unsigned int dtermen;
119 unsigned int hsprepare;
121 unsigned int hssettle;
123 unsigned int hstrail;
132 struct inno_mipi_dphy_timing {
147 struct inno_mipi_dphy {
150 struct regmap *regmap;
151 struct reset_control *rst;
154 unsigned long lane_rate;
163 static const u32 lane_reg_offset[] = {
164 [CLOCK_LANE] = INNO_CLOCK_LANE_REG_BASE,
165 [DATA_LANE_0] = INNO_DATA_LANE_0_REG_BASE,
166 [DATA_LANE_1] = INNO_DATA_LANE_1_REG_BASE,
167 [DATA_LANE_2] = INNO_DATA_LANE_2_REG_BASE,
168 [DATA_LANE_3] = INNO_DATA_LANE_3_REG_BASE,
171 #define FIXED_PARAM(_freq, _prepare, _clk_zero, _data_zero, _trail) \
174 .hs_prepare = _prepare, \
176 .hs_zero = _clk_zero, \
179 .hs_zero = _data_zero, \
181 .hs_trail = _trail, \
184 static const struct {
185 unsigned long max_freq;
194 } fixed_param_table[] = {
195 FIXED_PARAM(110, 0x20, 0x16, 0x02, 0x22),
196 FIXED_PARAM(150, 0x06, 0x16, 0x03, 0x45),
197 FIXED_PARAM(200, 0x18, 0x17, 0x04, 0x0b),
198 FIXED_PARAM(250, 0x05, 0x17, 0x05, 0x16),
199 FIXED_PARAM(300, 0x51, 0x18, 0x06, 0x2c),
200 FIXED_PARAM(400, 0x64, 0x19, 0x07, 0x33),
201 FIXED_PARAM(500, 0x20, 0x1b, 0x07, 0x4e),
202 FIXED_PARAM(600, 0x6a, 0x1d, 0x08, 0x3a),
203 FIXED_PARAM(700, 0x3e, 0x1e, 0x08, 0x6a),
204 FIXED_PARAM(800, 0x21, 0x1f, 0x09, 0x29),
205 FIXED_PARAM(1000, 0x09, 0x20, 0x09, 0x27),
208 static inline struct inno_mipi_dphy *hw_to_inno(struct clk_hw *hw)
210 return container_of(hw, struct inno_mipi_dphy, pll.hw);
213 static inline void inno_mipi_dphy_reset(struct inno_mipi_dphy *inno)
216 regmap_update_bits(inno->regmap, INNO_PHY_POWER_CTRL,
217 ANALOG_RESET_MASK, ANALOG_RESET);
219 regmap_update_bits(inno->regmap, INNO_PHY_POWER_CTRL,
220 ANALOG_RESET_MASK, ANALOG_NORMAL);
222 regmap_update_bits(inno->regmap, INNO_PHY_DIG_CTRL,
223 DIGITAL_RESET_MASK, DIGITAL_RESET);
225 regmap_update_bits(inno->regmap, INNO_PHY_DIG_CTRL,
226 DIGITAL_RESET_MASK, DIGITAL_NORMAL);
229 static inline void inno_mipi_dphy_lane_enable(struct inno_mipi_dphy *inno)
231 u8 map[] = {0x44, 0x4c, 0x5c, 0x7c};
233 regmap_update_bits(inno->regmap, INNO_PHY_LANE_CTRL,
234 0x7c, map[inno->lanes - 1]);
237 static inline void inno_mipi_dphy_lane_disable(struct inno_mipi_dphy *inno)
239 regmap_update_bits(inno->regmap, INNO_PHY_LANE_CTRL, 0x7c, 0x00);
242 static void inno_mipi_dphy_pll_enable(struct inno_mipi_dphy *inno)
244 regmap_update_bits(inno->regmap, INNO_PHY_PLL_CTRL_0, FBDIV_HI_MASK |
245 PREDIV_MASK, FBDIV_HI(inno->pll.fbdiv >> 8) |
246 PREDIV(inno->pll.prediv));
247 regmap_update_bits(inno->regmap, INNO_PHY_PLL_CTRL_1,
248 FBDIV_LO_MASK, FBDIV_LO(inno->pll.fbdiv));
249 regmap_update_bits(inno->regmap, INNO_PHY_POWER_CTRL,
250 PLL_POWER_MASK | LDO_POWER_MASK,
251 PLL_POWER_ON | LDO_POWER_ON);
254 static void inno_mipi_dphy_pll_disable(struct inno_mipi_dphy *inno)
256 regmap_update_bits(inno->regmap, INNO_PHY_POWER_CTRL,
257 PLL_POWER_MASK | LDO_POWER_MASK,
258 PLL_POWER_DOWN | LDO_POWER_DOWN);
261 static void mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
262 unsigned long period)
264 /* Global Operation Timing Parameters */
266 timing->clkpost = 70 + 52 * period;
267 timing->clkpre = 8 * period;
268 timing->clkprepare = 65;
269 timing->clksettle = 95;
270 timing->clktermen = 0;
271 timing->clktrail = 80;
272 timing->clkzero = 260;
275 timing->hsexit = 120;
276 timing->hsprepare = 65 + 4 * period;
277 timing->hszero = 145 + 6 * period;
278 timing->hssettle = 85 + 6 * period;
280 timing->hstrail = max(8 * period, 60 + 4 * period);
281 timing->init = 100000;
283 timing->taget = 5 * timing->lpx;
284 timing->tago = 4 * timing->lpx;
285 timing->tasure = 2 * timing->lpx;
286 timing->wakeup = 1000000;
289 static void inno_mipi_dphy_timing_update(struct inno_mipi_dphy *inno,
290 enum lane_type lane_type,
291 struct inno_mipi_dphy_timing *t)
293 u32 base = lane_reg_offset[lane_type];
295 regmap_update_bits(inno->regmap, base + T_HS_PREPARE_OFFSET,
296 T_HS_PREPARE_MASK, T_HS_PREPARE(t->hs_prepare));
297 regmap_update_bits(inno->regmap, base + T_HS_ZERO_OFFSET,
298 T_HS_ZERO_MASK, T_HS_ZERO(t->hs_zero));
299 regmap_update_bits(inno->regmap, base + T_HS_TRAIL_OFFSET,
300 T_HS_TRAIL_MASK, T_HS_TRAIL(t->hs_trail));
301 regmap_update_bits(inno->regmap, base + T_HS_EXIT_OFFSET,
302 T_HS_EXIT_MASK, T_HS_EXIT(t->hs_exit));
304 if (lane_type == CLOCK_LANE) {
305 regmap_update_bits(inno->regmap, base + T_CLK_POST_OFFSET,
306 T_CLK_POST_MASK, T_CLK_POST(t->clk_post));
307 regmap_update_bits(inno->regmap, base + T_CLK_PRE_OFFSET,
308 T_CLK_PRE_MASK, T_CLK_PRE(t->clk_pre));
311 regmap_update_bits(inno->regmap, base + T_WAKUP_H_OFFSET,
312 T_WAKUP_H_MASK, T_WAKUP_H(t->wakup_h));
313 regmap_update_bits(inno->regmap, base + T_WAKUP_L_OFFSET,
314 T_WAKUP_L_MASK, T_WAKUP_L(t->wakup_l));
315 regmap_update_bits(inno->regmap, base + T_LPX_OFFSET,
316 T_LPX_MASK, T_LPX(t->lpx));
317 regmap_update_bits(inno->regmap, base + T_TA_GO_OFFSET,
318 T_TA_GO_MASK, T_TA_GO(t->ta_go));
319 regmap_update_bits(inno->regmap, base + T_TA_SURE_OFFSET,
320 T_TA_SURE_MASK, T_TA_SURE(t->ta_sure));
321 regmap_update_bits(inno->regmap, base + T_TA_WAIT_OFFSET,
322 T_TA_WAIT_MASK, T_TA_WAIT(t->ta_wait));
325 static void inno_mipi_dphy_get_fixed_param(struct inno_mipi_dphy_timing *t,
327 enum lane_type lane_type)
331 for (i = 0; i < ARRAY_SIZE(fixed_param_table); i++)
332 if (freq <= fixed_param_table[i].max_freq)
335 if (i == ARRAY_SIZE(fixed_param_table))
338 if (lane_type == CLOCK_LANE)
339 t->hs_zero = fixed_param_table[i].clk_lane.hs_zero;
341 t->hs_zero = fixed_param_table[i].data_lane.hs_zero;
343 t->hs_prepare = fixed_param_table[i].hs_prepare;
344 t->hs_trail = fixed_param_table[i].hs_trail;
347 static void inno_mipi_dphy_lane_timing_init(struct inno_mipi_dphy *inno,
348 enum lane_type lane_type)
350 struct mipi_dphy_timing timing;
351 struct inno_mipi_dphy_timing data;
352 unsigned long txbyteclk, txclkesc, UI;
353 unsigned int esc_clk_div;
355 memset(&timing, 0, sizeof(timing));
356 memset(&data, 0, sizeof(data));
358 txbyteclk = inno->lane_rate / 8;
359 esc_clk_div = DIV_ROUND_UP(txbyteclk, 20000000);
360 txclkesc = txbyteclk / esc_clk_div;
361 UI = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, inno->lane_rate);
363 mipi_dphy_timing_get_default(&timing, UI);
364 inno_mipi_dphy_get_fixed_param(&data, inno->lane_rate / USEC_PER_SEC,
367 data.hs_exit = DIV_ROUND_UP(timing.hsexit * txbyteclk, NSEC_PER_SEC);
368 data.clk_post = DIV_ROUND_UP(timing.clkpost * txbyteclk, NSEC_PER_SEC);
369 data.clk_pre = DIV_ROUND_UP(timing.clkpre * txbyteclk, NSEC_PER_SEC);
372 data.lpx = DIV_ROUND_UP(txbyteclk * timing.lpx, NSEC_PER_SEC);
375 data.ta_go = DIV_ROUND_UP(timing.tago * txclkesc, NSEC_PER_SEC);
376 data.ta_sure = DIV_ROUND_UP(timing.tasure * txclkesc, NSEC_PER_SEC);
377 data.ta_wait = DIV_ROUND_UP(timing.taget * txclkesc, NSEC_PER_SEC);
379 inno_mipi_dphy_timing_update(inno, lane_type, &data);
381 #define TIMING_NS(x, freq) (((x) * (DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq))))
382 dev_dbg(inno->dev, "hs-exit=%lu, clk-post=%lu, clk-pre=%lu, lpx=%lu\n",
383 TIMING_NS(data.hs_exit, txbyteclk),
384 TIMING_NS(data.clk_post, txbyteclk),
385 TIMING_NS(data.clk_pre, txbyteclk),
386 TIMING_NS(data.lpx + 2, txbyteclk));
387 dev_dbg(inno->dev, "ta-go=%lu, ta-sure=%lu, ta-wait=%lu\n",
388 TIMING_NS(data.ta_go, txclkesc),
389 TIMING_NS(data.ta_sure, txclkesc),
390 TIMING_NS(data.ta_wait, txclkesc));
393 static unsigned long inno_mipi_dphy_pll_rate_fixup(unsigned long fin,
395 u8 *prediv, u16 *fbdiv)
397 unsigned long best_freq = 0;
399 u8 min_prediv, max_prediv;
400 u8 _prediv, uninitialized_var(best_prediv);
401 u16 _fbdiv, uninitialized_var(best_fbdiv);
402 u32 min_delta = UINT_MAX;
405 * The PLL output frequency can be calculated using a simple formula:
406 * PLL_Output_Frequency = (FREF / PREDIV * FBDIV) / 2
407 * PLL_Output_Frequency: it is equal to DDR-Clock-Frequency * 2
411 /* constraint: 5Mhz < Fref / prediv < 40MHz */
412 min_prediv = DIV_ROUND_UP(fin, 40000000);
413 max_prediv = fin / 5000000;
415 for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
419 tmp = (u64)fout * _prediv;
423 * The all possible settings of feedback divider are
424 * 12, 13, 14, 16, ~ 511
426 if ((_fbdiv == 15) || (_fbdiv < 12) || (_fbdiv > 511))
428 tmp = (u64)_fbdiv * fin;
429 do_div(tmp, _prediv);
431 delta = abs(fout - tmp);
432 if (delta < min_delta) {
433 best_prediv = _prediv;
441 *prediv = best_prediv;
445 return best_freq / 2;
448 static void inno_mipi_dphy_timing_init(struct inno_mipi_dphy *inno)
450 switch (inno->lanes) {
452 inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_3);
455 inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_2);
458 inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_1);
462 inno_mipi_dphy_lane_timing_init(inno, DATA_LANE_0);
463 inno_mipi_dphy_lane_timing_init(inno, CLOCK_LANE);
468 static int inno_mipi_dphy_power_on(struct phy *phy)
470 struct inno_mipi_dphy *inno = phy_get_drvdata(phy);
472 inno_mipi_dphy_pll_enable(inno);
473 inno_mipi_dphy_lane_enable(inno);
474 inno_mipi_dphy_reset(inno);
475 inno_mipi_dphy_timing_init(inno);
481 static int inno_mipi_dphy_power_off(struct phy *phy)
483 struct inno_mipi_dphy *inno = phy_get_drvdata(phy);
485 inno_mipi_dphy_lane_disable(inno);
486 inno_mipi_dphy_pll_disable(inno);
491 static const struct phy_ops inno_mipi_dphy_ops = {
492 .power_on = inno_mipi_dphy_power_on,
493 .power_off = inno_mipi_dphy_power_off,
494 .owner = THIS_MODULE,
497 static long inno_mipi_dphy_pll_clk_round_rate(struct clk_hw *hw,
499 unsigned long *prate)
501 struct inno_mipi_dphy *inno = hw_to_inno(hw);
502 unsigned long fin = *prate;
507 fout = inno_mipi_dphy_pll_rate_fixup(fin, rate, &prediv, &fbdiv);
509 dev_dbg(inno->dev, "%s: fin=%lu, req_rate=%lu\n",
510 __func__, *prate, rate);
511 dev_dbg(inno->dev, "%s: fout=%lu, prediv=%u, fbdiv=%u\n",
512 __func__, fout, prediv, fbdiv);
514 inno->pll.prediv = prediv;
515 inno->pll.fbdiv = fbdiv;
520 static int inno_mipi_dphy_pll_clk_set_rate(struct clk_hw *hw,
522 unsigned long parent_rate)
524 struct inno_mipi_dphy *inno = hw_to_inno(hw);
526 dev_dbg(inno->dev, "%s: rate: %lu Hz\n", __func__, rate);
528 inno->lane_rate = rate;
534 inno_mipi_dphy_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
536 struct inno_mipi_dphy *inno = hw_to_inno(hw);
538 dev_dbg(inno->dev, "%s: rate: %lu Hz\n", __func__, inno->lane_rate);
540 return inno->lane_rate;
543 static const struct clk_ops inno_mipi_dphy_pll_clk_ops = {
544 .round_rate = inno_mipi_dphy_pll_clk_round_rate,
545 .set_rate = inno_mipi_dphy_pll_clk_set_rate,
546 .recalc_rate = inno_mipi_dphy_pll_clk_recalc_rate,
549 static int inno_mipi_dphy_pll_register(struct inno_mipi_dphy *inno)
551 struct device *dev = inno->dev;
552 struct device_node *np = dev->of_node;
554 const char *parent_name;
555 struct clk_init_data init;
558 parent_name = __clk_get_name(inno->ref_clk);
560 ret = of_property_read_string(np, "clock-output-names", &init.name);
562 dev_err(dev, "Missing clock-output-names property: %d\n", ret);
566 init.ops = &inno_mipi_dphy_pll_clk_ops;
567 init.parent_names = (const char * const *)&parent_name;
568 init.num_parents = 1;
571 inno->pll.hw.init = &init;
572 clk = devm_clk_register(dev, &inno->pll.hw);
575 dev_err(dev, "failed to register PLL: %d\n", ret);
579 return of_clk_add_provider(np, of_clk_src_simple_get, clk);
582 static int inno_mipi_dphy_parse_dt(struct device_node *np,
583 struct inno_mipi_dphy *inno)
585 if (of_property_read_u32(np, "inno,lanes", &inno->lanes))
591 static struct regmap_config inno_mipi_dphy_regmap_cfg = {
595 .max_register = INNO_MIPI_DPHY_MAX_REGISTER,
598 static int inno_mipi_dphy_probe(struct platform_device *pdev)
600 struct device *dev = &pdev->dev;
601 struct inno_mipi_dphy *inno;
602 struct phy_provider *phy_provider;
604 struct resource *res;
608 inno = devm_kzalloc(dev, sizeof(*inno), GFP_KERNEL);
613 platform_set_drvdata(pdev, inno);
615 ret = inno_mipi_dphy_parse_dt(dev->of_node, inno);
617 dev_err(dev, "failed to parse DT\n");
621 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
622 regs = devm_ioremap_resource(dev, res);
624 return PTR_ERR(regs);
626 inno->regmap = devm_regmap_init_mmio_clk(dev, "pclk", regs,
627 &inno_mipi_dphy_regmap_cfg);
628 if (IS_ERR(inno->regmap)) {
629 ret = PTR_ERR(inno->regmap);
630 dev_err(dev, "failed to init regmap: %d\n", ret);
634 inno->ref_clk = devm_clk_get(dev, "ref");
635 if (IS_ERR(inno->ref_clk)) {
636 dev_err(dev, "failed to get reference clock\n");
637 return PTR_ERR(inno->ref_clk);
640 inno->rst = devm_reset_control_get(dev, "apb");
641 if (IS_ERR(inno->rst)) {
642 dev_err(dev, "failed to get system reset control\n");
643 return PTR_ERR(inno->rst);
646 phy = devm_phy_create(dev, NULL, &inno_mipi_dphy_ops);
648 dev_err(dev, "failed to create MIPI D-PHY\n");
652 phy_set_drvdata(phy, inno);
654 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
655 if (IS_ERR(phy_provider)) {
656 dev_err(dev, "failed to register phy provider\n");
657 return PTR_ERR(phy_provider);
660 clk_prepare_enable(inno->ref_clk);
662 ret = inno_mipi_dphy_pll_register(inno);
664 clk_disable_unprepare(inno->ref_clk);
671 static int inno_mipi_dphy_remove(struct platform_device *pdev)
673 struct inno_mipi_dphy *inno = platform_get_drvdata(pdev);
675 of_clk_del_provider(inno->dev->of_node);
676 clk_disable_unprepare(inno->ref_clk);
681 static const struct of_device_id inno_mipi_dphy_of_match[] = {
682 { .compatible = "rockchip,rk3366-mipi-dphy", },
683 { .compatible = "rockchip,rk3368-mipi-dphy", },
686 MODULE_DEVICE_TABLE(of, inno_mipi_dphy_of_match);
688 static struct platform_driver inno_mipi_dphy_driver = {
690 .name = "inno-mipi-dphy",
691 .of_match_table = of_match_ptr(inno_mipi_dphy_of_match),
693 .probe = inno_mipi_dphy_probe,
694 .remove = inno_mipi_dphy_remove,
697 module_platform_driver(inno_mipi_dphy_driver);
699 MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
700 MODULE_DESCRIPTION("Innosilicon MIPI D-PHY Driver");
701 MODULE_LICENSE("GPL v2");