mipi_dsi.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /* Copyright (c) 2008-2013, The Linux Foundation. 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. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/time.h>
  17. #include <linux/init.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/delay.h>
  21. #include <linux/io.h>
  22. #include <linux/semaphore.h>
  23. #include <linux/uaccess.h>
  24. #include <linux/clk.h>
  25. #include <linux/platform_device.h>
  26. #include <asm/system.h>
  27. #include <asm/mach-types.h>
  28. #include <mach/hardware.h>
  29. #include <mach/gpio.h>
  30. #include <mach/clk.h>
  31. #include "msm_fb.h"
  32. #include "mipi_dsi.h"
  33. #include "mdp.h"
  34. #include "mdp4.h"
  35. u32 dsi_irq;
  36. u32 esc_byte_ratio;
  37. static boolean tlmm_settings = FALSE;
  38. static int mipi_dsi_probe(struct platform_device *pdev);
  39. static int mipi_dsi_remove(struct platform_device *pdev);
  40. static int mipi_dsi_off(struct platform_device *pdev);
  41. static int mipi_dsi_on(struct platform_device *pdev);
  42. static int mipi_dsi_fps_level_change(struct platform_device *pdev,
  43. u32 fps_level);
  44. static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
  45. static int pdev_list_cnt;
  46. static struct mipi_dsi_platform_data *mipi_dsi_pdata;
  47. static int vsync_gpio = -1;
  48. static struct platform_driver mipi_dsi_driver = {
  49. .probe = mipi_dsi_probe,
  50. .remove = mipi_dsi_remove,
  51. .shutdown = NULL,
  52. .driver = {
  53. .name = "mipi_dsi",
  54. },
  55. };
  56. struct device dsi_dev;
  57. static int mipi_dsi_fps_level_change(struct platform_device *pdev,
  58. u32 fps_level)
  59. {
  60. mipi_dsi_wait4video_done();
  61. mipi_dsi_configure_fb_divider(fps_level);
  62. return 0;
  63. }
  64. static int mipi_dsi_off(struct platform_device *pdev)
  65. {
  66. int ret = 0;
  67. struct msm_fb_data_type *mfd;
  68. struct msm_panel_info *pinfo;
  69. pr_debug("%s+:\n", __func__);
  70. mfd = platform_get_drvdata(pdev);
  71. pinfo = &mfd->panel_info;
  72. if (mdp_rev >= MDP_REV_41)
  73. mutex_lock(&mfd->dma->ov_mutex);
  74. else
  75. down(&mfd->dma->mutex);
  76. if (mfd->panel_info.type == MIPI_CMD_PANEL) {
  77. mipi_dsi_prepare_clocks();
  78. mipi_dsi_ahb_ctrl(1);
  79. mipi_dsi_clk_enable();
  80. /* make sure dsi_cmd_mdp is idle */
  81. mipi_dsi_cmd_mdp_busy();
  82. }
  83. /*
  84. * Desctiption: change to DSI_CMD_MODE since it needed to
  85. * tx DCS dsiplay off comamnd to panel
  86. */
  87. mipi_dsi_op_mode_config(DSI_CMD_MODE);
  88. if (mfd->panel_info.type == MIPI_CMD_PANEL) {
  89. if (pinfo->lcd.vsync_enable) {
  90. if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
  91. if (MDP_REV_303 != mdp_rev)
  92. gpio_free(vsync_gpio);
  93. }
  94. mipi_dsi_set_tear_off(mfd);
  95. }
  96. }
  97. ret = panel_next_off(pdev);
  98. mipi_dsi_clk_disable();
  99. /* disbale dsi engine */
  100. MIPI_OUTP(MIPI_DSI_BASE + 0x0000, 0);
  101. mipi_dsi_phy_ctrl(0);
  102. mipi_dsi_ahb_ctrl(0);
  103. mipi_dsi_unprepare_clocks();
  104. if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
  105. mipi_dsi_pdata->dsi_power_save(0);
  106. if (mdp_rev >= MDP_REV_41)
  107. mutex_unlock(&mfd->dma->ov_mutex);
  108. else
  109. up(&mfd->dma->mutex);
  110. pr_debug("%s-:\n", __func__);
  111. return ret;
  112. }
  113. static int mipi_dsi_on(struct platform_device *pdev)
  114. {
  115. int ret = 0;
  116. u32 clk_rate;
  117. struct msm_fb_data_type *mfd;
  118. struct fb_info *fbi;
  119. struct fb_var_screeninfo *var;
  120. struct msm_panel_info *pinfo;
  121. struct mipi_panel_info *mipi;
  122. u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
  123. u32 ystride, bpp, data;
  124. u32 dummy_xres, dummy_yres;
  125. int target_type = 0;
  126. int old_nice;
  127. pr_debug("%s+:\n", __func__);
  128. mfd = platform_get_drvdata(pdev);
  129. fbi = mfd->fbi;
  130. var = &fbi->var;
  131. pinfo = &mfd->panel_info;
  132. esc_byte_ratio = pinfo->mipi.esc_byte_ratio;
  133. /*
  134. * Now first priority is to turn on LCD quickly for better
  135. * user experience. We set current task to higher priority
  136. * and restore it after panel is on.
  137. */
  138. old_nice = task_nice(current);
  139. if (old_nice > -20)
  140. set_user_nice(current, -20);
  141. if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
  142. mipi_dsi_pdata->dsi_power_save(1);
  143. cont_splash_clk_ctrl(0);
  144. mipi_dsi_prepare_clocks();
  145. mipi_dsi_ahb_ctrl(1);
  146. clk_rate = mfd->fbi->var.pixclock;
  147. clk_rate = min(clk_rate, mfd->panel_info.clk_max);
  148. mipi_dsi_phy_ctrl(1);
  149. if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
  150. target_type = mipi_dsi_pdata->target_type;
  151. mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
  152. mipi_dsi_clk_enable();
  153. MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
  154. MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
  155. hbp = var->left_margin;
  156. hfp = var->right_margin;
  157. vbp = var->upper_margin;
  158. vfp = var->lower_margin;
  159. hspw = var->hsync_len;
  160. vspw = var->vsync_len;
  161. width = mfd->panel_info.xres;
  162. height = mfd->panel_info.yres;
  163. mipi = &mfd->panel_info.mipi;
  164. if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
  165. dummy_xres = mfd->panel_info.lcdc.xres_pad;
  166. dummy_yres = mfd->panel_info.lcdc.yres_pad;
  167. if (mdp_rev >= MDP_REV_41) {
  168. MIPI_OUTP(MIPI_DSI_BASE + 0x20,
  169. ((hspw + hbp + width + dummy_xres) << 16 |
  170. (hspw + hbp)));
  171. MIPI_OUTP(MIPI_DSI_BASE + 0x24,
  172. ((vspw + vbp + height + dummy_yres) << 16 |
  173. (vspw + vbp)));
  174. MIPI_OUTP(MIPI_DSI_BASE + 0x28,
  175. (vspw + vbp + height + dummy_yres +
  176. vfp - 1) << 16 | (hspw + hbp +
  177. width + dummy_xres + hfp - 1));
  178. } else {
  179. /* DSI_LAN_SWAP_CTRL */
  180. MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap);
  181. MIPI_OUTP(MIPI_DSI_BASE + 0x20,
  182. ((hbp + width + dummy_xres) << 16 | (hbp)));
  183. MIPI_OUTP(MIPI_DSI_BASE + 0x24,
  184. ((vbp + height + dummy_yres) << 16 | (vbp)));
  185. MIPI_OUTP(MIPI_DSI_BASE + 0x28,
  186. (vbp + height + dummy_yres + vfp) << 16 |
  187. (hbp + width + dummy_xres + hfp));
  188. }
  189. MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16));
  190. MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0);
  191. MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16));
  192. } else { /* command mode */
  193. if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
  194. bpp = 3;
  195. else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666)
  196. bpp = 3;
  197. else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
  198. bpp = 2;
  199. else
  200. bpp = 3; /* Default format set to RGB888 */
  201. ystride = width * bpp + 1;
  202. /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
  203. data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE;
  204. MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data);
  205. MIPI_OUTP(MIPI_DSI_BASE + 0x54, data);
  206. /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
  207. data = height << 16 | width;
  208. MIPI_OUTP(MIPI_DSI_BASE + 0x60, data);
  209. MIPI_OUTP(MIPI_DSI_BASE + 0x58, data);
  210. }
  211. mipi_dsi_host_init(mipi);
  212. if (mipi->force_clk_lane_hs) {
  213. u32 tmp;
  214. tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8);
  215. tmp |= (1<<28);
  216. MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp);
  217. wmb();
  218. }
  219. if (mdp_rev >= MDP_REV_41)
  220. mutex_lock(&mfd->dma->ov_mutex);
  221. else
  222. down(&mfd->dma->mutex);
  223. ret = panel_next_on(pdev);
  224. mipi_dsi_op_mode_config(mipi->mode);
  225. if (mfd->panel_info.type == MIPI_CMD_PANEL) {
  226. if (pinfo->lcd.vsync_enable) {
  227. if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) {
  228. if (mdp_rev >= MDP_REV_41) {
  229. if (gpio_request(vsync_gpio,
  230. "MDP_VSYNC") == 0)
  231. gpio_direction_input(
  232. vsync_gpio);
  233. else
  234. pr_err("%s: unable to \
  235. request gpio=%d\n",
  236. __func__, vsync_gpio);
  237. } else if (mdp_rev == MDP_REV_303) {
  238. if (!tlmm_settings && gpio_request(
  239. vsync_gpio, "MDP_VSYNC") == 0) {
  240. ret = gpio_tlmm_config(
  241. GPIO_CFG(
  242. vsync_gpio, 1,
  243. GPIO_CFG_INPUT,
  244. GPIO_CFG_PULL_DOWN,
  245. GPIO_CFG_2MA),
  246. GPIO_CFG_ENABLE);
  247. if (ret) {
  248. pr_err(
  249. "%s: unable to config \
  250. tlmm = %d\n",
  251. __func__, vsync_gpio);
  252. }
  253. tlmm_settings = TRUE;
  254. gpio_direction_input(
  255. vsync_gpio);
  256. } else {
  257. if (!tlmm_settings) {
  258. pr_err(
  259. "%s: unable to request \
  260. gpio=%d\n",
  261. __func__, vsync_gpio);
  262. }
  263. }
  264. }
  265. }
  266. mipi_dsi_set_tear_on(mfd);
  267. }
  268. mipi_dsi_clk_disable();
  269. mipi_dsi_ahb_ctrl(0);
  270. mipi_dsi_unprepare_clocks();
  271. }
  272. if (mdp_rev >= MDP_REV_41)
  273. mutex_unlock(&mfd->dma->ov_mutex);
  274. else
  275. up(&mfd->dma->mutex);
  276. /* Restore current priority */
  277. if (old_nice > -20)
  278. set_user_nice(current, old_nice);
  279. pr_debug("%s-:\n", __func__);
  280. return ret;
  281. }
  282. static int mipi_dsi_late_init(struct platform_device *pdev)
  283. {
  284. return panel_next_late_init(pdev);
  285. }
  286. static int mipi_dsi_resource_initialized;
  287. static int mipi_dsi_probe(struct platform_device *pdev)
  288. {
  289. struct msm_fb_data_type *mfd;
  290. struct fb_info *fbi;
  291. struct msm_panel_info *pinfo;
  292. struct mipi_panel_info *mipi;
  293. struct platform_device *mdp_dev = NULL;
  294. struct msm_fb_panel_data *pdata = NULL;
  295. int rc;
  296. uint8 lanes = 0, bpp;
  297. uint32 h_period, v_period, dsi_pclk_rate;
  298. resource_size_t size ;
  299. if ((pdev->id == 1) && (pdev->num_resources >= 0)) {
  300. mipi_dsi_pdata = pdev->dev.platform_data;
  301. size = resource_size(&pdev->resource[0]);
  302. mipi_dsi_base = ioremap(pdev->resource[0].start, size);
  303. MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n",
  304. pdev->resource[0].start, (int) mipi_dsi_base);
  305. if (!mipi_dsi_base)
  306. return -ENOMEM;
  307. if (mdp_rev >= MDP_REV_41) {
  308. mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100);
  309. MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x,"
  310. "virt = 0x%x\n", MMSS_SFPB_BASE_PHY,
  311. (int) mmss_sfpb_base);
  312. if (!mmss_sfpb_base)
  313. return -ENOMEM;
  314. }
  315. dsi_irq = platform_get_irq(pdev, 0);
  316. if (dsi_irq < 0) {
  317. pr_err("mipi_dsi: can not get mdp irq\n");
  318. return -ENOMEM;
  319. }
  320. rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED,
  321. "MIPI_DSI", 0);
  322. if (rc) {
  323. pr_err("mipi_dsi_host request_irq() failed!\n");
  324. return rc;
  325. }
  326. disable_irq(dsi_irq);
  327. if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata &&
  328. mipi_dsi_pdata->target_type == 1) {
  329. /* Target type is 1 for device with (De)serializer
  330. * 0x4f00000 is the base for TV Encoder.
  331. * Unused Offset 0x1000 is used for
  332. * (de)serializer on emulation platform
  333. */
  334. periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100);
  335. if (periph_base) {
  336. pr_debug("periph_base %pK\n", periph_base);
  337. writel(0x4, periph_base + 0x28);
  338. writel(0xc, periph_base + 0x28);
  339. } else {
  340. pr_err("periph_base is NULL\n");
  341. free_irq(dsi_irq, 0);
  342. return -ENOMEM;
  343. }
  344. }
  345. if (mipi_dsi_pdata) {
  346. vsync_gpio = mipi_dsi_pdata->vsync_gpio;
  347. pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio);
  348. if (mdp_rev == MDP_REV_303 &&
  349. mipi_dsi_pdata->dsi_client_reset) {
  350. if (mipi_dsi_pdata->dsi_client_reset())
  351. pr_err("%s: DSI Client Reset failed!\n",
  352. __func__);
  353. else
  354. pr_debug("%s: DSI Client Reset success\n",
  355. __func__);
  356. }
  357. }
  358. if (mipi_dsi_clk_init(pdev))
  359. return -EPERM;
  360. if (mipi_dsi_pdata->splash_is_enabled &&
  361. !mipi_dsi_pdata->splash_is_enabled()) {
  362. mipi_dsi_ahb_ctrl(1);
  363. MIPI_OUTP(MIPI_DSI_BASE + 0x118, 0);
  364. MIPI_OUTP(MIPI_DSI_BASE + 0x0, 0);
  365. MIPI_OUTP(MIPI_DSI_BASE + 0x200, 0);
  366. mipi_dsi_ahb_ctrl(0);
  367. }
  368. mipi_dsi_resource_initialized = 1;
  369. return 0;
  370. }
  371. if (!mipi_dsi_resource_initialized)
  372. return -EPERM;
  373. mfd = platform_get_drvdata(pdev);
  374. if (!mfd)
  375. return -ENODEV;
  376. if (mfd->key != MFD_KEY)
  377. return -EINVAL;
  378. if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
  379. return -ENOMEM;
  380. mdp_dev = platform_device_alloc("mdp", pdev->id);
  381. if (!mdp_dev)
  382. return -ENOMEM;
  383. /*
  384. * link to the latest pdev
  385. */
  386. mfd->pdev = mdp_dev;
  387. /*
  388. * alloc panel device data
  389. */
  390. if (platform_device_add_data
  391. (mdp_dev, pdev->dev.platform_data,
  392. sizeof(struct msm_fb_panel_data))) {
  393. pr_err("mipi_dsi_probe: platform_device_add_data failed!\n");
  394. platform_device_put(mdp_dev);
  395. return -ENOMEM;
  396. }
  397. /*
  398. * data chain
  399. */
  400. pdata = mdp_dev->dev.platform_data;
  401. pdata->on = mipi_dsi_on;
  402. pdata->off = mipi_dsi_off;
  403. pdata->fps_level_change = mipi_dsi_fps_level_change;
  404. pdata->late_init = mipi_dsi_late_init;
  405. pdata->next = pdev;
  406. /*
  407. * get/set panel specific fb info
  408. */
  409. mfd->panel_info = pdata->panel_info;
  410. pinfo = &mfd->panel_info;
  411. if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
  412. mfd->dest = DISPLAY_LCDC;
  413. else
  414. mfd->dest = DISPLAY_LCD;
  415. if (mdp_rev == MDP_REV_303 &&
  416. mipi_dsi_pdata->get_lane_config) {
  417. if (mipi_dsi_pdata->get_lane_config() != 2) {
  418. pr_info("Changing to DSI Single Mode Configuration\n");
  419. #ifdef CONFIG_FB_MSM_MDP303
  420. update_lane_config(pinfo);
  421. #endif
  422. }
  423. }
  424. if (mfd->index == 0)
  425. mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
  426. else
  427. mfd->fb_imgType = MDP_RGB_565;
  428. fbi = mfd->fbi;
  429. fbi->var.pixclock = mfd->panel_info.clk_rate;
  430. fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
  431. fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
  432. fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
  433. fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
  434. fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
  435. fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
  436. h_period = ((mfd->panel_info.lcdc.h_pulse_width)
  437. + (mfd->panel_info.lcdc.h_back_porch)
  438. + (mfd->panel_info.xres)
  439. + (mfd->panel_info.lcdc.h_front_porch));
  440. v_period = ((mfd->panel_info.lcdc.v_pulse_width)
  441. + (mfd->panel_info.lcdc.v_back_porch)
  442. + (mfd->panel_info.yres)
  443. + (mfd->panel_info.lcdc.v_front_porch));
  444. mipi = &mfd->panel_info.mipi;
  445. if (mipi->data_lane3)
  446. lanes += 1;
  447. if (mipi->data_lane2)
  448. lanes += 1;
  449. if (mipi->data_lane1)
  450. lanes += 1;
  451. if (mipi->data_lane0)
  452. lanes += 1;
  453. if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
  454. || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
  455. || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
  456. bpp = 3;
  457. else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
  458. || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
  459. bpp = 2;
  460. else
  461. bpp = 3; /* Default format set to RGB888 */
  462. if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
  463. !mfd->panel_info.clk_rate) {
  464. h_period += mfd->panel_info.lcdc.xres_pad;
  465. v_period += mfd->panel_info.lcdc.yres_pad;
  466. if (lanes > 0) {
  467. mfd->panel_info.clk_rate =
  468. ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
  469. / lanes);
  470. } else {
  471. pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__);
  472. mfd->panel_info.clk_rate =
  473. (h_period * v_period
  474. * (mipi->frame_rate) * bpp * 8);
  475. }
  476. }
  477. pll_divider_config.clk_rate = mfd->panel_info.clk_rate;
  478. rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
  479. if (rc)
  480. goto mipi_dsi_probe_err;
  481. if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 223000000)) {
  482. pr_err("%s: Pixel clock not supported\n", __func__);
  483. dsi_pclk_rate = 35000000;
  484. }
  485. mipi->dsi_pclk_rate = dsi_pclk_rate;
  486. /*
  487. * set driver data
  488. */
  489. platform_set_drvdata(mdp_dev, mfd);
  490. /*
  491. * register in mdp driver
  492. */
  493. rc = platform_device_add(mdp_dev);
  494. if (rc)
  495. goto mipi_dsi_probe_err;
  496. pdev_list[pdev_list_cnt++] = pdev;
  497. if (!mfd->cont_splash_done)
  498. cont_splash_clk_ctrl(1);
  499. return 0;
  500. mipi_dsi_probe_err:
  501. platform_device_put(mdp_dev);
  502. return rc;
  503. }
  504. static int mipi_dsi_remove(struct platform_device *pdev)
  505. {
  506. struct msm_fb_data_type *mfd;
  507. mfd = platform_get_drvdata(pdev);
  508. iounmap(mipi_dsi_base);
  509. return 0;
  510. }
  511. static int mipi_dsi_register_driver(void)
  512. {
  513. return platform_driver_register(&mipi_dsi_driver);
  514. }
  515. static int __init mipi_dsi_driver_init(void)
  516. {
  517. int ret;
  518. mipi_dsi_init();
  519. ret = mipi_dsi_register_driver();
  520. device_initialize(&dsi_dev);
  521. if (ret) {
  522. pr_err("mipi_dsi_register_driver() failed!\n");
  523. return ret;
  524. }
  525. return ret;
  526. }
  527. module_init(mipi_dsi_driver_init);