blob: aa210f1edf8daf526932aa8b1bd098df40a58a88 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/time.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/semaphore.h>
24#include <linux/uaccess.h>
25#include <linux/clk.h>
26#include <linux/platform_device.h>
27#include <asm/system.h>
28#include <asm/mach-types.h>
29#include <mach/hardware.h>
30#include <mach/gpio.h>
31#include <mach/clk.h>
32
33#include "msm_fb.h"
34#include "mipi_dsi.h"
35#include "mdp.h"
36#include "mdp4.h"
37
38u32 dsi_irq;
39
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +053040static boolean tlmm_settings = FALSE;
41
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042static int mipi_dsi_probe(struct platform_device *pdev);
43static int mipi_dsi_remove(struct platform_device *pdev);
44
45static int mipi_dsi_off(struct platform_device *pdev);
46static int mipi_dsi_on(struct platform_device *pdev);
47
48static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
49static int pdev_list_cnt;
50static struct mipi_dsi_platform_data *mipi_dsi_pdata;
51
52static int vsync_gpio = -1;
53
54static struct platform_driver mipi_dsi_driver = {
55 .probe = mipi_dsi_probe,
56 .remove = mipi_dsi_remove,
57 .shutdown = NULL,
58 .driver = {
59 .name = "mipi_dsi",
60 },
61};
62
63struct device dsi_dev;
64
65static int mipi_dsi_off(struct platform_device *pdev)
66{
67 int ret = 0;
68 struct msm_fb_data_type *mfd;
69 struct msm_panel_info *pinfo;
70
71 mfd = platform_get_drvdata(pdev);
72 pinfo = &mfd->panel_info;
73
74 if (mdp_rev >= MDP_REV_41)
75 mutex_lock(&mfd->dma->ov_mutex);
76 else
77 down(&mfd->dma->mutex);
78
79 mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND);
80
81 /*
82 * Description: dsi clock is need to perform shutdown.
83 * mdp4_dsi_cmd_dma_busy_wait() will enable dsi clock if disabled.
84 * also, wait until dma (overlay and dmap) finish.
85 */
86 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
87 if (mdp_rev >= MDP_REV_41) {
88 mdp4_dsi_cmd_dma_busy_wait(mfd);
89 mdp4_dsi_blt_dmap_busy_wait(mfd);
kuogee hsieh8717a172011-09-05 09:57:58 -070090 mipi_dsi_mdp_busy_wait(mfd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 } else {
92 mdp3_dsi_cmd_dma_busy_wait(mfd);
93 }
94 }
95
96 /*
97 * Desctiption: change to DSI_CMD_MODE since it needed to
98 * tx DCS dsiplay off comamnd to panel
99 */
100 mipi_dsi_op_mode_config(DSI_CMD_MODE);
101
102 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
103 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700104 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530105 if (MDP_REV_303 != mdp_rev)
106 gpio_free(vsync_gpio);
107 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108 mipi_dsi_set_tear_off(mfd);
109 }
110 }
111
112 ret = panel_next_off(pdev);
113
114#ifdef CONFIG_MSM_BUS_SCALING
115 mdp_bus_scale_update_request(0);
116#endif
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700117
118 local_bh_disable();
119 mipi_dsi_clk_disable();
120 local_bh_enable();
121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 /* disbale dsi engine */
123 MIPI_OUTP(MIPI_DSI_BASE + 0x0000, 0);
124
125 mipi_dsi_phy_ctrl(0);
126
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 local_bh_disable();
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700129 mipi_dsi_ahb_ctrl(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 local_bh_enable();
131
132 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
133 mipi_dsi_pdata->dsi_power_save(0);
134
135 if (mdp_rev >= MDP_REV_41)
136 mutex_unlock(&mfd->dma->ov_mutex);
137 else
138 up(&mfd->dma->mutex);
139
kuogee hsieh4b1bde42011-11-08 15:26:26 -0800140 pr_debug("%s-:\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141
142 return ret;
143}
144
145static int mipi_dsi_on(struct platform_device *pdev)
146{
147 int ret = 0;
148 u32 clk_rate;
149 struct msm_fb_data_type *mfd;
150 struct fb_info *fbi;
151 struct fb_var_screeninfo *var;
152 struct msm_panel_info *pinfo;
153 struct mipi_panel_info *mipi;
154 u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
155 u32 ystride, bpp, data;
156 u32 dummy_xres, dummy_yres;
157 int target_type = 0;
158
159 mfd = platform_get_drvdata(pdev);
160 fbi = mfd->fbi;
161 var = &fbi->var;
162 pinfo = &mfd->panel_info;
163
164 if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
165 mipi_dsi_pdata->dsi_power_save(1);
166
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700167 local_bh_disable();
168 mipi_dsi_ahb_ctrl(1);
169 local_bh_enable();
170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 clk_rate = mfd->fbi->var.pixclock;
172 clk_rate = min(clk_rate, mfd->panel_info.clk_max);
173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
175 MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
176
177 hbp = var->left_margin;
178 hfp = var->right_margin;
179 vbp = var->upper_margin;
180 vfp = var->lower_margin;
181 hspw = var->hsync_len;
182 vspw = var->vsync_len;
183 width = mfd->panel_info.xres;
184 height = mfd->panel_info.yres;
185
186 mipi_dsi_phy_ctrl(1);
187
188 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
189 target_type = mipi_dsi_pdata->target_type;
190
191 mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
192
Nagamalleswararao Ganji2ca30352011-06-24 18:16:23 -0700193 local_bh_disable();
194 mipi_dsi_clk_enable();
195 local_bh_enable();
196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 mipi = &mfd->panel_info.mipi;
198 if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
199 dummy_xres = mfd->panel_info.mipi.xres_pad;
200 dummy_yres = mfd->panel_info.mipi.yres_pad;
201
202 if (mdp_rev >= MDP_REV_41) {
203 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
204 ((hspw + hbp + width + dummy_xres) << 16 |
205 (hspw + hbp)));
206 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
207 ((vspw + vbp + height + dummy_yres) << 16 |
208 (vspw + vbp)));
209 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
210 (vspw + vbp + height + dummy_yres +
211 vfp - 1) << 16 | (hspw + hbp +
212 width + dummy_xres + hfp - 1));
213 } else {
214 /* DSI_LAN_SWAP_CTRL */
215 MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap);
216
217 MIPI_OUTP(MIPI_DSI_BASE + 0x20,
218 ((hbp + width + dummy_xres) << 16 | (hbp)));
219 MIPI_OUTP(MIPI_DSI_BASE + 0x24,
220 ((vbp + height + dummy_yres) << 16 | (vbp)));
221 MIPI_OUTP(MIPI_DSI_BASE + 0x28,
222 (vbp + height + dummy_yres + vfp) << 16 |
223 (hbp + width + dummy_xres + hfp));
224 }
225
226 MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16));
227 MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0);
228 MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16));
229
230 } else { /* command mode */
231 if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
232 bpp = 3;
233 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
234 bpp = 3;
235 else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
236 bpp = 2;
237 else
238 bpp = 3; /* Default format set to RGB888 */
239
240 ystride = width * bpp + 1;
241
242 /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
243 data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
244 MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data);
245 MIPI_OUTP(MIPI_DSI_BASE + 0x54, data);
246
247 /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
248 data = height << 16 | width;
249 MIPI_OUTP(MIPI_DSI_BASE + 0x60, data);
250 MIPI_OUTP(MIPI_DSI_BASE + 0x58, data);
251 }
252
253 mipi_dsi_host_init(mipi);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254
Amir Samuelovb84120b2011-09-03 17:49:43 +0300255 if (mipi->force_clk_lane_hs) {
256 u32 tmp;
257
258 tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8);
259 tmp |= (1<<28);
260 MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp);
261 wmb();
262 }
263
kuogee hsieh4b1bde42011-11-08 15:26:26 -0800264 if (mdp_rev >= MDP_REV_41)
265 mutex_lock(&mfd->dma->ov_mutex);
266 else
267 down(&mfd->dma->mutex);
268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 ret = panel_next_on(pdev);
270
271 mipi_dsi_op_mode_config(mipi->mode);
272
273 if (mfd->panel_info.type == MIPI_CMD_PANEL) {
274 if (pinfo->lcd.vsync_enable) {
Ravishangar Kalyanam48551552011-08-08 15:33:42 -0700275 if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
Jeevan Shriram9d28c3e2011-07-08 17:59:18 +0530276 if (mdp_rev >= MDP_REV_41) {
277 if (gpio_request(vsync_gpio,
278 "MDP_VSYNC") == 0)
279 gpio_direction_input(
280 vsync_gpio);
281 else
282 pr_err("%s: unable to \
283 request gpio=%d\n",
284 __func__, vsync_gpio);
285 } else if (mdp_rev == MDP_REV_303) {
286 if (!tlmm_settings && gpio_request(
287 vsync_gpio, "MDP_VSYNC") == 0) {
288 ret = gpio_tlmm_config(
289 GPIO_CFG(
290 vsync_gpio, 1,
291 GPIO_CFG_INPUT,
292 GPIO_CFG_PULL_DOWN,
293 GPIO_CFG_2MA),
294 GPIO_CFG_ENABLE);
295
296 if (ret) {
297 pr_err(
298 "%s: unable to config \
299 tlmm = %d\n",
300 __func__, vsync_gpio);
301 }
302 tlmm_settings = TRUE;
303
304 gpio_direction_input(
305 vsync_gpio);
306 } else {
307 if (!tlmm_settings) {
308 pr_err(
309 "%s: unable to request \
310 gpio=%d\n",
311 __func__, vsync_gpio);
312 }
313 }
314 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 }
316 mipi_dsi_set_tear_on(mfd);
317 }
318 }
319
320#ifdef CONFIG_MSM_BUS_SCALING
321 mdp_bus_scale_update_request(2);
322#endif
kuogee hsieh4b1bde42011-11-08 15:26:26 -0800323
324 mdp4_overlay_dsi_state_set(ST_DSI_RESUME);
325
326 if (mdp_rev >= MDP_REV_41)
327 mutex_unlock(&mfd->dma->ov_mutex);
328 else
329 up(&mfd->dma->mutex);
330
331 pr_debug("%s-:\n", __func__);
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 return ret;
334}
335
336
337static int mipi_dsi_resource_initialized;
338
339static int mipi_dsi_probe(struct platform_device *pdev)
340{
341 struct msm_fb_data_type *mfd;
342 struct fb_info *fbi;
343 struct msm_panel_info *pinfo;
344 struct mipi_panel_info *mipi;
345 struct platform_device *mdp_dev = NULL;
346 struct msm_fb_panel_data *pdata = NULL;
347 int rc;
348 uint8 lanes = 0, bpp;
349 uint32 h_period, v_period, dsi_pclk_rate;
350
351 resource_size_t size ;
352
353 if ((pdev->id == 1) && (pdev->num_resources >= 0)) {
354 mipi_dsi_pdata = pdev->dev.platform_data;
355
356 size = resource_size(&pdev->resource[0]);
357 mipi_dsi_base = ioremap(pdev->resource[0].start, size);
358
359 MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n",
360 pdev->resource[0].start, (int) mipi_dsi_base);
361
362 if (!mipi_dsi_base)
363 return -ENOMEM;
364
365 if (mdp_rev >= MDP_REV_41) {
366 mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100);
367 MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x,"
368 "virt = 0x%x\n", MMSS_SFPB_BASE_PHY,
369 (int) mmss_sfpb_base);
370
371 if (!mmss_sfpb_base)
372 return -ENOMEM;
373 }
374
375 dsi_irq = platform_get_irq(pdev, 0);
376 if (dsi_irq < 0) {
377 pr_err("mipi_dsi: can not get mdp irq\n");
378 return -ENOMEM;
379 }
380
381 rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED,
382 "MIPI_DSI", 0);
383 if (rc) {
384 pr_err("mipi_dsi_host request_irq() failed!\n");
385 return rc;
386 }
387
388 disable_irq(dsi_irq);
389
390 if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata &&
391 mipi_dsi_pdata->target_type == 1) {
392 /* Target type is 1 for device with (De)serializer
393 * 0x4f00000 is the base for TV Encoder.
394 * Unused Offset 0x1000 is used for
395 * (de)serializer on emulation platform
396 */
397 periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100);
398
399 if (periph_base) {
400 pr_debug("periph_base %p\n", periph_base);
401 writel(0x4, periph_base + 0x28);
402 writel(0xc, periph_base + 0x28);
403 } else {
404 pr_err("periph_base is NULL\n");
405 free_irq(dsi_irq, 0);
406 return -ENOMEM;
407 }
408 }
409
410 if (mipi_dsi_pdata) {
411 vsync_gpio = mipi_dsi_pdata->vsync_gpio;
412 pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio);
413
414 if (mdp_rev == MDP_REV_303 &&
415 mipi_dsi_pdata->dsi_client_reset) {
416 if (mipi_dsi_pdata->dsi_client_reset())
417 pr_err("%s: DSI Client Reset failed!\n",
418 __func__);
419 else
420 pr_debug("%s: DSI Client Reset success\n",
421 __func__);
422 }
423 }
424
425 mipi_dsi_resource_initialized = 1;
426
427 return 0;
428 }
429
430 mipi_dsi_clk_init(&pdev->dev);
431
432 if (!mipi_dsi_resource_initialized)
433 return -EPERM;
434
435 mfd = platform_get_drvdata(pdev);
436
437 if (!mfd)
438 return -ENODEV;
439
440 if (mfd->key != MFD_KEY)
441 return -EINVAL;
442
443 if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
444 return -ENOMEM;
445
446
447 mdp_dev = platform_device_alloc("mdp", pdev->id);
448 if (!mdp_dev)
449 return -ENOMEM;
450
451 /*
452 * link to the latest pdev
453 */
454 mfd->pdev = mdp_dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455
456 /*
457 * alloc panel device data
458 */
459 if (platform_device_add_data
460 (mdp_dev, pdev->dev.platform_data,
461 sizeof(struct msm_fb_panel_data))) {
462 pr_err("mipi_dsi_probe: platform_device_add_data failed!\n");
463 platform_device_put(mdp_dev);
464 return -ENOMEM;
465 }
466 /*
467 * data chain
468 */
469 pdata = mdp_dev->dev.platform_data;
470 pdata->on = mipi_dsi_on;
471 pdata->off = mipi_dsi_off;
472 pdata->next = pdev;
473
474 /*
475 * get/set panel specific fb info
476 */
477 mfd->panel_info = pdata->panel_info;
478 pinfo = &mfd->panel_info;
479
Ravishangar Kalyanam7a7e46f2011-09-12 12:45:29 -0700480 if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
481 mfd->dest = DISPLAY_LCDC;
482 else
483 mfd->dest = DISPLAY_LCD;
484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 if (mdp_rev == MDP_REV_303 &&
486 mipi_dsi_pdata->get_lane_config) {
487 if (mipi_dsi_pdata->get_lane_config() != 2) {
488 pr_info("Changing to DSI Single Mode Configuration\n");
489#ifdef CONFIG_FB_MSM_MDP303
490 update_lane_config(pinfo);
491#endif
492 }
493 }
494
495 if (mfd->index == 0)
496 mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
497 else
498 mfd->fb_imgType = MDP_RGB_565;
499
500 fbi = mfd->fbi;
501 fbi->var.pixclock = mfd->panel_info.clk_rate;
502 fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
503 fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
504 fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
505 fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
506 fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
507 fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
508
509 h_period = ((mfd->panel_info.lcdc.h_pulse_width)
510 + (mfd->panel_info.lcdc.h_back_porch)
511 + (mfd->panel_info.xres)
512 + (mfd->panel_info.lcdc.h_front_porch));
513
514 v_period = ((mfd->panel_info.lcdc.v_pulse_width)
515 + (mfd->panel_info.lcdc.v_back_porch)
516 + (mfd->panel_info.yres)
517 + (mfd->panel_info.lcdc.v_front_porch));
518
519 mipi = &mfd->panel_info.mipi;
520
521 if (mipi->data_lane3)
522 lanes += 1;
523 if (mipi->data_lane2)
524 lanes += 1;
525 if (mipi->data_lane1)
526 lanes += 1;
527 if (mipi->data_lane0)
528 lanes += 1;
529
530 if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
531 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
532 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
533 bpp = 3;
534 else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
535 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
536 bpp = 2;
537 else
538 bpp = 3; /* Default format set to RGB888 */
539
540 if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
541 !mfd->panel_info.clk_rate) {
542 h_period += mfd->panel_info.mipi.xres_pad;
543 v_period += mfd->panel_info.mipi.yres_pad;
544
545 if (lanes > 0) {
546 mfd->panel_info.clk_rate =
547 ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
548 / lanes);
549 } else {
550 pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__);
551 mfd->panel_info.clk_rate =
552 (h_period * v_period
553 * (mipi->frame_rate) * bpp * 8);
554 }
555 }
556 pll_divider_config.clk_rate = mfd->panel_info.clk_rate;
557
558 rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
559 if (rc)
560 goto mipi_dsi_probe_err;
561
562 if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000))
563 dsi_pclk_rate = 35000000;
564 mipi->dsi_pclk_rate = dsi_pclk_rate;
565
566 /*
567 * set driver data
568 */
569 platform_set_drvdata(mdp_dev, mfd);
570
571 /*
572 * register in mdp driver
573 */
574 rc = platform_device_add(mdp_dev);
575 if (rc)
576 goto mipi_dsi_probe_err;
577
578 pdev_list[pdev_list_cnt++] = pdev;
579
580return 0;
581
582mipi_dsi_probe_err:
583 platform_device_put(mdp_dev);
584 return rc;
585}
586
587static int mipi_dsi_remove(struct platform_device *pdev)
588{
589 struct msm_fb_data_type *mfd;
590
591 mfd = platform_get_drvdata(pdev);
592 iounmap(mipi_dsi_base);
593 return 0;
594}
595
596static int mipi_dsi_register_driver(void)
597{
598 return platform_driver_register(&mipi_dsi_driver);
599}
600
601static int __init mipi_dsi_driver_init(void)
602{
603 int ret;
604
605 mipi_dsi_init();
606
607 ret = mipi_dsi_register_driver();
608
609 device_initialize(&dsi_dev);
610
611 if (ret) {
612 pr_err("mipi_dsi_register_driver() failed!\n");
613 return ret;
614 }
615
616 return ret;
617}
618
619module_init(mipi_dsi_driver_init);