drm/rockchip: fix some warning from smatch check
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_lvds.c
1 /*
2  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3  * Author:
4  *      Mark Yao <mark.yao@rock-chips.com>
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <drm/drmP.h>
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_dp_helper.h>
20 #include <drm/drm_panel.h>
21 #include <drm/drm_of.h>
22
23 #include <linux/component.h>
24 #include <linux/clk.h>
25 #include <linux/mfd/syscon.h>
26 #include <linux/of_graph.h>
27 #include <linux/pm_runtime.h>
28 #include <linux/regmap.h>
29 #include <linux/reset.h>
30
31 #include <video/display_timing.h>
32
33 #include "rockchip_drm_drv.h"
34 #include "rockchip_drm_vop.h"
35 #include "rockchip_lvds.h"
36
37 #define DISPLAY_OUTPUT_RGB              0
38 #define DISPLAY_OUTPUT_LVDS             1
39 #define DISPLAY_OUTPUT_DUAL_LVDS        2
40
41 #define connector_to_lvds(c) \
42                 container_of(c, struct rockchip_lvds, connector)
43
44 #define encoder_to_lvds(c) \
45                 container_of(c, struct rockchip_lvds, encoder)
46
47 /*
48  * @grf_offset: offset inside the grf regmap for setting the rockchip lvds
49  */
50 struct rockchip_lvds_soc_data {
51         int grf_soc_con6;
52         int grf_soc_con7;
53 };
54
55 struct rockchip_lvds {
56         void *base;
57         struct device *dev;
58         void __iomem *regs;
59         struct regmap *grf;
60         struct clk *pclk;
61         const struct rockchip_lvds_soc_data *soc_data;
62
63         int output;
64         int format;
65
66         struct drm_device *drm_dev;
67         struct drm_panel *panel;
68         struct drm_connector connector;
69         struct drm_encoder encoder;
70
71         struct mutex suspend_lock;
72         int suspend;
73 };
74
75 static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val)
76 {
77         writel_relaxed(val, lvds->regs + offset);
78         writel_relaxed(val, lvds->regs + offset + 0x100);
79 }
80
81 static inline int lvds_name_to_format(const char *s)
82 {
83         if (!s)
84                 return -EINVAL;
85
86         if (strncmp(s, "jeida", 6) == 0)
87                 return LVDS_FORMAT_JEIDA;
88         else if (strncmp(s, "vesa", 5) == 0)
89                 return LVDS_FORMAT_VESA;
90
91         return -EINVAL;
92 }
93
94 static inline int lvds_name_to_output(const char *s)
95 {
96         if (!s)
97                 return -EINVAL;
98
99         if (strncmp(s, "rgb", 3) == 0)
100                 return DISPLAY_OUTPUT_RGB;
101         else if (strncmp(s, "lvds", 4) == 0)
102                 return DISPLAY_OUTPUT_LVDS;
103         else if (strncmp(s, "duallvds", 8) == 0)
104                 return DISPLAY_OUTPUT_DUAL_LVDS;
105
106         return -EINVAL;
107 }
108
109 static int rockchip_lvds_poweron(struct rockchip_lvds *lvds)
110 {
111         int ret;
112
113         ret = clk_enable(lvds->pclk);
114         if (ret < 0) {
115                 dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret);
116                 return ret;
117         }
118
119         ret = pm_runtime_get_sync(lvds->dev);
120         if (ret < 0) {
121                 dev_err(lvds->dev, "failed to get pm runtime: %d\n", ret);
122                 return ret;
123         }
124
125         if (lvds->output == DISPLAY_OUTPUT_RGB) {
126                 lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
127                             RK3288_LVDS_CH0_REG0_TTL_EN |
128                             RK3288_LVDS_CH0_REG0_LANECK_EN |
129                             RK3288_LVDS_CH0_REG0_LANE4_EN |
130                             RK3288_LVDS_CH0_REG0_LANE3_EN |
131                             RK3288_LVDS_CH0_REG0_LANE2_EN |
132                             RK3288_LVDS_CH0_REG0_LANE1_EN |
133                             RK3288_LVDS_CH0_REG0_LANE0_EN);
134                 lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
135                             RK3288_LVDS_PLL_FBDIV_REG2(0x46));
136
137                 lvds_writel(lvds, RK3288_LVDS_CH0_REG3,
138                             RK3288_LVDS_PLL_FBDIV_REG3(0x46));
139                 lvds_writel(lvds, RK3288_LVDS_CH0_REG4,
140                             RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
141                             RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
142                             RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
143                             RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
144                             RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
145                             RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
146                 lvds_writel(lvds, RK3288_LVDS_CH0_REG5,
147                             RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
148                             RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
149                             RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
150                             RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
151                             RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
152                             RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
153                 lvds_writel(lvds, RK3288_LVDS_CH0_REGD,
154                             RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
155                 lvds_writel(lvds, RK3288_LVDS_CH0_REG20,
156                             RK3288_LVDS_CH0_REG20_LSB);
157         } else {
158                 lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
159                             RK3288_LVDS_CH0_REG0_LVDS_EN |
160                             RK3288_LVDS_CH0_REG0_LANECK_EN |
161                             RK3288_LVDS_CH0_REG0_LANE4_EN |
162                             RK3288_LVDS_CH0_REG0_LANE3_EN |
163                             RK3288_LVDS_CH0_REG0_LANE2_EN |
164                             RK3288_LVDS_CH0_REG0_LANE1_EN |
165                             RK3288_LVDS_CH0_REG0_LANE0_EN);
166                 lvds_writel(lvds, RK3288_LVDS_CH0_REG1,
167                             RK3288_LVDS_CH0_REG1_LANECK_BIAS |
168                             RK3288_LVDS_CH0_REG1_LANE4_BIAS |
169                             RK3288_LVDS_CH0_REG1_LANE3_BIAS |
170                             RK3288_LVDS_CH0_REG1_LANE2_BIAS |
171                             RK3288_LVDS_CH0_REG1_LANE1_BIAS |
172                             RK3288_LVDS_CH0_REG1_LANE0_BIAS);
173                 lvds_writel(lvds, RK3288_LVDS_CH0_REG2,
174                             RK3288_LVDS_CH0_REG2_RESERVE_ON |
175                             RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
176                             RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
177                             RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
178                             RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
179                             RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
180                             RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
181                             RK3288_LVDS_PLL_FBDIV_REG2(0x46));
182                 lvds_writel(lvds, RK3288_LVDS_CH0_REG3,
183                             RK3288_LVDS_PLL_FBDIV_REG3(0x46));
184                 lvds_writel(lvds, RK3288_LVDS_CH0_REG4, 0x00);
185                 lvds_writel(lvds, RK3288_LVDS_CH0_REG5, 0x00);
186                 lvds_writel(lvds, RK3288_LVDS_CH0_REGD,
187                             RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
188                 lvds_writel(lvds, RK3288_LVDS_CH0_REG20,
189                             RK3288_LVDS_CH0_REG20_LSB);
190         }
191
192         writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
193                lvds->regs + RK3288_LVDS_CFG_REGC);
194         writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
195                lvds->regs + RK3288_LVDS_CFG_REG21);
196
197         return 0;
198 }
199
200 static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds)
201 {
202         int ret;
203
204         ret = regmap_write(lvds->grf,
205                            lvds->soc_data->grf_soc_con7, 0xffff8000);
206         if (ret != 0)
207                 dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
208
209         writel(RK3288_LVDS_CFG_REG21_TX_DISABLE,
210                lvds->regs + RK3288_LVDS_CFG_REG21);
211         writel(RK3288_LVDS_CFG_REGC_PLL_DISABLE,
212                lvds->regs + RK3288_LVDS_CFG_REGC);
213
214         pm_runtime_put(lvds->dev);
215         clk_disable(lvds->pclk);
216 }
217
218 static enum drm_connector_status
219 rockchip_lvds_connector_detect(struct drm_connector *connector, bool force)
220 {
221         return connector_status_connected;
222 }
223
224 static void rockchip_lvds_connector_destroy(struct drm_connector *connector)
225 {
226         drm_connector_cleanup(connector);
227 }
228
229 static struct drm_connector_funcs rockchip_lvds_connector_funcs = {
230         .dpms = drm_atomic_helper_connector_dpms,
231         .detect = rockchip_lvds_connector_detect,
232         .fill_modes = drm_helper_probe_single_connector_modes,
233         .destroy = rockchip_lvds_connector_destroy,
234         .reset = drm_atomic_helper_connector_reset,
235         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
236         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
237 };
238
239 static int rockchip_lvds_connector_get_modes(struct drm_connector *connector)
240 {
241         struct rockchip_lvds *lvds = connector_to_lvds(connector);
242         struct drm_panel *panel = lvds->panel;
243
244         return panel->funcs->get_modes(panel);
245 }
246
247 static struct drm_encoder *
248 rockchip_lvds_connector_best_encoder(struct drm_connector *connector)
249 {
250         struct rockchip_lvds *lvds = connector_to_lvds(connector);
251
252         return &lvds->encoder;
253 }
254
255 static enum drm_mode_status rockchip_lvds_connector_mode_valid(
256                 struct drm_connector *connector,
257                 struct drm_display_mode *mode)
258 {
259         return MODE_OK;
260 }
261
262 static
263 struct drm_connector_helper_funcs rockchip_lvds_connector_helper_funcs = {
264         .get_modes = rockchip_lvds_connector_get_modes,
265         .mode_valid = rockchip_lvds_connector_mode_valid,
266         .best_encoder = rockchip_lvds_connector_best_encoder,
267 };
268
269 static void rockchip_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
270 {
271         struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
272         int ret;
273
274         mutex_lock(&lvds->suspend_lock);
275
276         switch (mode) {
277         case DRM_MODE_DPMS_ON:
278                 if (!lvds->suspend)
279                         goto out;
280
281                 drm_panel_prepare(lvds->panel);
282                 ret = rockchip_lvds_poweron(lvds);
283                 if (ret < 0) {
284                         drm_panel_unprepare(lvds->panel);
285                         goto out;
286                 }
287                 drm_panel_enable(lvds->panel);
288
289                 lvds->suspend = false;
290                 break;
291         case DRM_MODE_DPMS_STANDBY:
292         case DRM_MODE_DPMS_SUSPEND:
293         case DRM_MODE_DPMS_OFF:
294                 if (lvds->suspend)
295                         goto out;
296
297                 drm_panel_disable(lvds->panel);
298                 rockchip_lvds_poweroff(lvds);
299                 drm_panel_unprepare(lvds->panel);
300
301                 lvds->suspend = true;
302                 break;
303         default:
304                 break;
305         }
306
307 out:
308         mutex_unlock(&lvds->suspend_lock);
309 }
310
311 static bool
312 rockchip_lvds_encoder_mode_fixup(struct drm_encoder *encoder,
313                                 const struct drm_display_mode *mode,
314                                 struct drm_display_mode *adjusted_mode)
315 {
316         return true;
317 }
318
319 static void rockchip_lvds_encoder_mode_set(struct drm_encoder *encoder,
320                                           struct drm_display_mode *mode,
321                                           struct drm_display_mode *adjusted)
322 {
323         struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
324         u32 h_bp = mode->htotal - mode->hsync_start;
325         u8 pin_hsync = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 1 : 0;
326         u8 pin_dclk = (mode->flags & DRM_MODE_FLAG_PCSYNC) ? 1 : 0;
327         u32 val;
328         int ret;
329
330         val = lvds->format;
331         if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
332                 val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
333         else if (lvds->output == DISPLAY_OUTPUT_LVDS)
334                 val |= LVDS_CH0_EN;
335         else if (lvds->output == DISPLAY_OUTPUT_RGB)
336                 val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
337
338         if (h_bp & 0x01)
339                 val |= LVDS_START_PHASE_RST_1;
340
341         val |= (pin_dclk << 8) | (pin_hsync << 9);
342         val |= (0xffff << 16);
343         ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
344         if (ret != 0) {
345                 dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
346                 return;
347         }
348 }
349
350 static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds,
351                                         struct drm_encoder *encoder)
352 {
353         u32 val;
354         int ret;
355
356         ret = drm_of_encoder_active_endpoint_id(lvds->dev->of_node, encoder);
357         if (ret < 0)
358                 return ret;
359
360         if (ret)
361                 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
362                       (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
363         else
364                 val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
365
366         ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val);
367         if (ret < 0)
368                 return ret;
369
370         return 0;
371 }
372
373 static int
374 rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,
375                                    struct drm_crtc_state *crtc_state,
376                                    struct drm_connector_state *conn_state)
377 {
378         struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
379         struct drm_connector *connector = conn_state->connector;
380         struct drm_display_info *info = &connector->display_info;
381
382         s->output_mode = ROCKCHIP_OUT_MODE_P888;
383         s->output_type = DRM_MODE_CONNECTOR_LVDS;
384         if (info->num_bus_formats)
385                 s->bus_format = info->bus_formats[0];
386
387         return 0;
388 }
389
390 static void rockchip_lvds_encoder_commit(struct drm_encoder *encoder)
391 {
392         struct rockchip_lvds *lvds = encoder_to_lvds(encoder);
393
394         rockchip_lvds_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
395         rockchip_lvds_set_vop_source(lvds, encoder);
396 }
397
398 static void rockchip_lvds_encoder_disable(struct drm_encoder *encoder)
399 {
400         rockchip_lvds_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
401 }
402
403 static struct drm_encoder_helper_funcs rockchip_lvds_encoder_helper_funcs = {
404         .dpms = rockchip_lvds_encoder_dpms,
405         .mode_fixup = rockchip_lvds_encoder_mode_fixup,
406         .mode_set = rockchip_lvds_encoder_mode_set,
407         .commit = rockchip_lvds_encoder_commit,
408         .disable = rockchip_lvds_encoder_disable,
409         .atomic_check = rockchip_lvds_encoder_atomic_check,
410 };
411
412 static void rockchip_lvds_encoder_destroy(struct drm_encoder *encoder)
413 {
414         drm_encoder_cleanup(encoder);
415 }
416
417 static struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
418         .destroy = rockchip_lvds_encoder_destroy,
419 };
420
421 static struct rockchip_lvds_soc_data rk3288_lvds_data = {
422         .grf_soc_con6 = 0x025c,
423         .grf_soc_con7 = 0x0260,
424 };
425
426 static const struct of_device_id rockchip_lvds_dt_ids[] = {
427         {
428                 .compatible = "rockchip,rk3288-lvds",
429                 .data = &rk3288_lvds_data
430         },
431         {}
432 };
433 MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids);
434
435 static int rockchip_lvds_bind(struct device *dev, struct device *master,
436                              void *data)
437 {
438         struct rockchip_lvds *lvds = dev_get_drvdata(dev);
439         struct drm_device *drm_dev = data;
440         struct drm_encoder *encoder;
441         struct drm_connector *connector;
442         int ret;
443
444         lvds->drm_dev = drm_dev;
445
446         encoder = &lvds->encoder;
447         encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
448                                                              dev->of_node);
449
450         ret = drm_encoder_init(drm_dev, encoder, &rockchip_lvds_encoder_funcs,
451                                DRM_MODE_ENCODER_LVDS, NULL);
452         if (ret < 0) {
453                 DRM_ERROR("failed to initialize encoder with drm\n");
454                 return ret;
455         }
456
457         drm_encoder_helper_add(encoder, &rockchip_lvds_encoder_helper_funcs);
458
459         connector = &lvds->connector;
460         connector->dpms = DRM_MODE_DPMS_OFF;
461
462         ret = drm_connector_init(drm_dev, connector,
463                                  &rockchip_lvds_connector_funcs,
464                                  DRM_MODE_CONNECTOR_LVDS);
465         if (ret < 0) {
466                 DRM_ERROR("failed to initialize connector with drm\n");
467                 goto err_free_encoder;
468         }
469
470         drm_connector_helper_add(connector,
471                                  &rockchip_lvds_connector_helper_funcs);
472
473         ret = drm_mode_connector_attach_encoder(connector, encoder);
474         if (ret < 0) {
475                 DRM_ERROR("failed to attach connector and encoder\n");
476                 goto err_free_connector;
477         }
478
479         ret = drm_panel_attach(lvds->panel, connector);
480         if (ret < 0) {
481                 DRM_ERROR("failed to attach connector and encoder\n");
482                 goto err_free_connector;
483         }
484
485         pm_runtime_enable(dev);
486
487         return 0;
488
489 err_free_connector:
490         drm_connector_cleanup(connector);
491 err_free_encoder:
492         drm_encoder_cleanup(encoder);
493         return ret;
494 }
495
496 static void rockchip_lvds_unbind(struct device *dev, struct device *master,
497                                 void *data)
498 {
499         struct rockchip_lvds *lvds = dev_get_drvdata(dev);
500
501         rockchip_lvds_encoder_dpms(&lvds->encoder, DRM_MODE_DPMS_OFF);
502
503         drm_panel_detach(lvds->panel);
504
505         drm_connector_cleanup(&lvds->connector);
506         drm_encoder_cleanup(&lvds->encoder);
507
508         pm_runtime_disable(dev);
509 }
510
511 static const struct component_ops rockchip_lvds_component_ops = {
512         .bind = rockchip_lvds_bind,
513         .unbind = rockchip_lvds_unbind,
514 };
515
516 static int rockchip_lvds_probe(struct platform_device *pdev)
517 {
518         struct device *dev = &pdev->dev;
519         struct rockchip_lvds *lvds;
520         struct device_node *output_node = NULL;
521         const struct of_device_id *match;
522         struct resource *res;
523         const char *name;
524         int i, ret;
525
526         if (!dev->of_node)
527                 return -ENODEV;
528
529         lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
530         if (!lvds)
531                 return -ENOMEM;
532
533         lvds->dev = dev;
534         lvds->suspend = true;
535
536         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
537         lvds->regs = devm_ioremap_resource(&pdev->dev, res);
538         if (IS_ERR(lvds->regs))
539                 return PTR_ERR(lvds->regs);
540
541         lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
542                                                     "rockchip,grf");
543         if (IS_ERR(lvds->grf)) {
544                 dev_err(dev, "missing rockchip,grf property\n");
545                 return PTR_ERR(lvds->grf);
546         }
547
548         lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds");
549         if (IS_ERR(lvds->pclk)) {
550                 dev_err(dev, "could not get pclk_lvds\n");
551                 return PTR_ERR(lvds->pclk);
552         }
553
554         match = of_match_node(rockchip_lvds_dt_ids, dev->of_node);
555         lvds->soc_data = match->data;
556
557         dev_set_drvdata(dev, lvds);
558         mutex_init(&lvds->suspend_lock);
559
560         if (of_property_read_string(dev->of_node, "rockchip,output", &name))
561                 /* default set it as output rgb */
562                 lvds->output = DISPLAY_OUTPUT_RGB;
563         else
564                 lvds->output = lvds_name_to_output(name);
565
566         if (lvds->output < 0) {
567                 dev_err(dev, "invalid output type [%s]\n", name);
568                 return lvds->output;
569         }
570
571         if (of_property_read_string(dev->of_node, "rockchip,data-mapping",
572                                     &name))
573                 /* default set it as format jeida */
574                 lvds->format = LVDS_FORMAT_JEIDA;
575         else
576                 lvds->format = lvds_name_to_format(name);
577
578         if (lvds->format < 0) {
579                 dev_err(dev, "invalid data-mapping format [%s]\n", name);
580                 return lvds->format;
581         }
582
583         if (of_property_read_u32(dev->of_node, "rockchip,data-width", &i)) {
584                 lvds->format |= LVDS_24BIT;
585         } else {
586                 if (i == 24) {
587                         lvds->format |= LVDS_24BIT;
588                 } else if (i == 18) {
589                         lvds->format |= LVDS_18BIT;
590                 } else {
591                         dev_err(&pdev->dev,
592                                 "rockchip-lvds unsupport data-width[%d]\n", i);
593                         return -EINVAL;
594                 }
595         }
596
597         output_node = of_parse_phandle(dev->of_node, "rockchip,panel", 0);
598         if (!output_node) {
599                 DRM_ERROR("failed to find rockchip,panel dt node\n");
600                 return -ENODEV;
601         }
602
603         lvds->panel = of_drm_find_panel(output_node);
604         of_node_put(output_node);
605         if (!lvds->panel) {
606                 DRM_ERROR("failed to find panel\n");
607                 return -EPROBE_DEFER;
608         }
609
610         ret = clk_prepare(lvds->pclk);
611         if (ret < 0) {
612                 dev_err(dev, "failed to prepare pclk_lvds\n");
613                 return ret;
614         }
615
616         ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
617         if (ret < 0)
618                 clk_unprepare(lvds->pclk);
619
620         return ret;
621 }
622
623 static int rockchip_lvds_remove(struct platform_device *pdev)
624 {
625         struct rockchip_lvds *lvds = dev_get_drvdata(&pdev->dev);
626
627         component_del(&pdev->dev, &rockchip_lvds_component_ops);
628         clk_unprepare(lvds->pclk);
629
630         return 0;
631 }
632
633 struct platform_driver rockchip_lvds_driver = {
634         .probe = rockchip_lvds_probe,
635         .remove = rockchip_lvds_remove,
636         .driver = {
637                    .name = "rockchip-lvds",
638                    .of_match_table = of_match_ptr(rockchip_lvds_dt_ids),
639         },
640 };
641 module_platform_driver(rockchip_lvds_driver);
642
643 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
644 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
645 MODULE_DESCRIPTION("ROCKCHIP LVDS Driver");
646 MODULE_LICENSE("GPL v2");