amba-clcd-versatile.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. #include <linux/device.h>
  2. #include <linux/dma-mapping.h>
  3. #include <linux/amba/bus.h>
  4. #include <linux/amba/clcd.h>
  5. #include <linux/platform_data/video-clcd-versatile.h>
  6. #include <linux/of.h>
  7. #include <linux/of_graph.h>
  8. #include <linux/regmap.h>
  9. #include <linux/mfd/syscon.h>
  10. #include <linux/bitops.h>
  11. #include "amba-clcd-versatile.h"
  12. static struct clcd_panel vga = {
  13. .mode = {
  14. .name = "VGA",
  15. .refresh = 60,
  16. .xres = 640,
  17. .yres = 480,
  18. .pixclock = 39721,
  19. .left_margin = 40,
  20. .right_margin = 24,
  21. .upper_margin = 32,
  22. .lower_margin = 11,
  23. .hsync_len = 96,
  24. .vsync_len = 2,
  25. .sync = 0,
  26. .vmode = FB_VMODE_NONINTERLACED,
  27. },
  28. .width = -1,
  29. .height = -1,
  30. .tim2 = TIM2_BCD | TIM2_IPC,
  31. .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
  32. .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
  33. .bpp = 16,
  34. };
  35. static struct clcd_panel xvga = {
  36. .mode = {
  37. .name = "XVGA",
  38. .refresh = 60,
  39. .xres = 1024,
  40. .yres = 768,
  41. .pixclock = 15748,
  42. .left_margin = 152,
  43. .right_margin = 48,
  44. .upper_margin = 23,
  45. .lower_margin = 3,
  46. .hsync_len = 104,
  47. .vsync_len = 4,
  48. .sync = 0,
  49. .vmode = FB_VMODE_NONINTERLACED,
  50. },
  51. .width = -1,
  52. .height = -1,
  53. .tim2 = TIM2_BCD | TIM2_IPC,
  54. .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
  55. .caps = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
  56. .bpp = 16,
  57. };
  58. /* Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT */
  59. static struct clcd_panel sanyo_tm38qv67a02a = {
  60. .mode = {
  61. .name = "Sanyo TM38QV67A02A",
  62. .refresh = 116,
  63. .xres = 320,
  64. .yres = 240,
  65. .pixclock = 100000,
  66. .left_margin = 6,
  67. .right_margin = 6,
  68. .upper_margin = 5,
  69. .lower_margin = 5,
  70. .hsync_len = 6,
  71. .vsync_len = 6,
  72. .sync = 0,
  73. .vmode = FB_VMODE_NONINTERLACED,
  74. },
  75. .width = -1,
  76. .height = -1,
  77. .tim2 = TIM2_BCD,
  78. .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
  79. .caps = CLCD_CAP_5551,
  80. .bpp = 16,
  81. };
  82. static struct clcd_panel sanyo_2_5_in = {
  83. .mode = {
  84. .name = "Sanyo QVGA Portrait",
  85. .refresh = 116,
  86. .xres = 240,
  87. .yres = 320,
  88. .pixclock = 100000,
  89. .left_margin = 20,
  90. .right_margin = 10,
  91. .upper_margin = 2,
  92. .lower_margin = 2,
  93. .hsync_len = 10,
  94. .vsync_len = 2,
  95. .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  96. .vmode = FB_VMODE_NONINTERLACED,
  97. },
  98. .width = -1,
  99. .height = -1,
  100. .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC,
  101. .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
  102. .caps = CLCD_CAP_5551,
  103. .bpp = 16,
  104. };
  105. /* Epson L2F50113T00 - 2.2 inch 176x220 Color TFT */
  106. static struct clcd_panel epson_l2f50113t00 = {
  107. .mode = {
  108. .name = "Epson L2F50113T00",
  109. .refresh = 390,
  110. .xres = 176,
  111. .yres = 220,
  112. .pixclock = 62500,
  113. .left_margin = 3,
  114. .right_margin = 2,
  115. .upper_margin = 1,
  116. .lower_margin = 0,
  117. .hsync_len = 3,
  118. .vsync_len = 2,
  119. .sync = 0,
  120. .vmode = FB_VMODE_NONINTERLACED,
  121. },
  122. .width = -1,
  123. .height = -1,
  124. .tim2 = TIM2_BCD | TIM2_IPC,
  125. .cntl = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
  126. .caps = CLCD_CAP_5551,
  127. .bpp = 16,
  128. };
  129. static struct clcd_panel *panels[] = {
  130. &vga,
  131. &xvga,
  132. &sanyo_tm38qv67a02a,
  133. &sanyo_2_5_in,
  134. &epson_l2f50113t00,
  135. };
  136. struct clcd_panel *versatile_clcd_get_panel(const char *name)
  137. {
  138. int i;
  139. for (i = 0; i < ARRAY_SIZE(panels); i++)
  140. if (strcmp(panels[i]->mode.name, name) == 0)
  141. break;
  142. if (i < ARRAY_SIZE(panels))
  143. return panels[i];
  144. pr_err("CLCD: couldn't get parameters for panel %s\n", name);
  145. return NULL;
  146. }
  147. int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
  148. {
  149. dma_addr_t dma;
  150. fb->fb.screen_base = dma_alloc_wc(&fb->dev->dev, framesize, &dma,
  151. GFP_KERNEL);
  152. if (!fb->fb.screen_base) {
  153. pr_err("CLCD: unable to map framebuffer\n");
  154. return -ENOMEM;
  155. }
  156. fb->fb.fix.smem_start = dma;
  157. fb->fb.fix.smem_len = framesize;
  158. return 0;
  159. }
  160. int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
  161. {
  162. return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
  163. fb->fb.fix.smem_start, fb->fb.fix.smem_len);
  164. }
  165. void versatile_clcd_remove_dma(struct clcd_fb *fb)
  166. {
  167. dma_free_wc(&fb->dev->dev, fb->fb.fix.smem_len, fb->fb.screen_base,
  168. fb->fb.fix.smem_start);
  169. }
  170. #ifdef CONFIG_OF
  171. static struct regmap *versatile_syscon_map;
  172. static struct regmap *versatile_ib2_map;
  173. /*
  174. * We detect the different syscon types from the compatible strings.
  175. */
  176. enum versatile_clcd {
  177. INTEGRATOR_CLCD_CM,
  178. VERSATILE_CLCD,
  179. REALVIEW_CLCD_EB,
  180. REALVIEW_CLCD_PB1176,
  181. REALVIEW_CLCD_PB11MP,
  182. REALVIEW_CLCD_PBA8,
  183. REALVIEW_CLCD_PBX,
  184. };
  185. static const struct of_device_id versatile_clcd_of_match[] = {
  186. {
  187. .compatible = "arm,core-module-integrator",
  188. .data = (void *)INTEGRATOR_CLCD_CM,
  189. },
  190. {
  191. .compatible = "arm,versatile-sysreg",
  192. .data = (void *)VERSATILE_CLCD,
  193. },
  194. {
  195. .compatible = "arm,realview-eb-syscon",
  196. .data = (void *)REALVIEW_CLCD_EB,
  197. },
  198. {
  199. .compatible = "arm,realview-pb1176-syscon",
  200. .data = (void *)REALVIEW_CLCD_PB1176,
  201. },
  202. {
  203. .compatible = "arm,realview-pb11mp-syscon",
  204. .data = (void *)REALVIEW_CLCD_PB11MP,
  205. },
  206. {
  207. .compatible = "arm,realview-pba8-syscon",
  208. .data = (void *)REALVIEW_CLCD_PBA8,
  209. },
  210. {
  211. .compatible = "arm,realview-pbx-syscon",
  212. .data = (void *)REALVIEW_CLCD_PBX,
  213. },
  214. {},
  215. };
  216. /*
  217. * Core module CLCD control on the Integrator/CP, bits
  218. * 8 thru 19 of the CM_CONTROL register controls a bunch
  219. * of CLCD settings.
  220. */
  221. #define INTEGRATOR_HDR_CTRL_OFFSET 0x0C
  222. #define INTEGRATOR_CLCD_LCDBIASEN BIT(8)
  223. #define INTEGRATOR_CLCD_LCDBIASUP BIT(9)
  224. #define INTEGRATOR_CLCD_LCDBIASDN BIT(10)
  225. /* Bits 11,12,13 controls the LCD type */
  226. #define INTEGRATOR_CLCD_LCDMUX_MASK (BIT(11)|BIT(12)|BIT(13))
  227. #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11)
  228. #define INTEGRATOR_CLCD_LCDMUX_VGA565 BIT(12)
  229. #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12))
  230. #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13)
  231. #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13))
  232. #define INTEGRATOR_CLCD_LCD0_EN BIT(14)
  233. #define INTEGRATOR_CLCD_LCD1_EN BIT(15)
  234. /* R/L flip on Sharp */
  235. #define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16)
  236. /* U/D flip on Sharp */
  237. #define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17)
  238. /* No connection on Sharp */
  239. #define INTEGRATOR_CLCD_LCD_STATIC BIT(18)
  240. /* 0 = 24bit VGA, 1 = 18bit VGA */
  241. #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19)
  242. #define INTEGRATOR_CLCD_MASK (INTEGRATOR_CLCD_LCDBIASEN | \
  243. INTEGRATOR_CLCD_LCDBIASUP | \
  244. INTEGRATOR_CLCD_LCDBIASDN | \
  245. INTEGRATOR_CLCD_LCDMUX_MASK | \
  246. INTEGRATOR_CLCD_LCD0_EN | \
  247. INTEGRATOR_CLCD_LCD1_EN | \
  248. INTEGRATOR_CLCD_LCD_STATIC1 | \
  249. INTEGRATOR_CLCD_LCD_STATIC2 | \
  250. INTEGRATOR_CLCD_LCD_STATIC | \
  251. INTEGRATOR_CLCD_LCD_N24BITEN)
  252. static void integrator_clcd_enable(struct clcd_fb *fb)
  253. {
  254. struct fb_var_screeninfo *var = &fb->fb.var;
  255. u32 val;
  256. dev_info(&fb->dev->dev, "enable Integrator CLCD connectors\n");
  257. /* FIXME: really needed? */
  258. val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
  259. INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
  260. if (var->bits_per_pixel <= 8 ||
  261. (var->bits_per_pixel == 16 && var->green.length == 5))
  262. /* Pseudocolor, RGB555, BGR555 */
  263. val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
  264. else if (fb->fb.var.bits_per_pixel <= 16)
  265. /* truecolor RGB565 */
  266. val |= INTEGRATOR_CLCD_LCDMUX_VGA565;
  267. else
  268. val = 0; /* no idea for this, don't trust the docs */
  269. regmap_update_bits(versatile_syscon_map,
  270. INTEGRATOR_HDR_CTRL_OFFSET,
  271. INTEGRATOR_CLCD_MASK,
  272. val);
  273. }
  274. /*
  275. * This configuration register in the Versatile and RealView
  276. * family is uniformly present but appears more and more
  277. * unutilized starting with the RealView series.
  278. */
  279. #define SYS_CLCD 0x50
  280. #define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1))
  281. #define SYS_CLCD_MODE_888 0
  282. #define SYS_CLCD_MODE_5551 BIT(0)
  283. #define SYS_CLCD_MODE_565_R_LSB BIT(1)
  284. #define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1))
  285. #define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5))
  286. #define SYS_CLCD_NLCDIOON BIT(2)
  287. #define SYS_CLCD_VDDPOSSWITCH BIT(3)
  288. #define SYS_CLCD_PWR3V5SWITCH BIT(4)
  289. #define SYS_CLCD_VDDNEGSWITCH BIT(5)
  290. #define SYS_CLCD_TSNSS BIT(6) /* touchscreen enable */
  291. #define SYS_CLCD_SSPEXP BIT(7) /* SSP expansion enable */
  292. /* The Versatile can detect the connected panel type */
  293. #define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12))
  294. #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
  295. #define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8)
  296. #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
  297. #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
  298. #define SYS_CLCD_ID_VGA (0x1f << 8)
  299. #define SYS_CLCD_TSNDAV BIT(13) /* data ready from TS */
  300. /* IB2 control register for the Versatile daughterboard */
  301. #define IB2_CTRL 0x00
  302. #define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */
  303. #define IB2_CTRL_LCD_BL_ON BIT(0)
  304. #define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1))
  305. static void versatile_clcd_disable(struct clcd_fb *fb)
  306. {
  307. dev_info(&fb->dev->dev, "disable Versatile CLCD connectors\n");
  308. regmap_update_bits(versatile_syscon_map,
  309. SYS_CLCD,
  310. SYS_CLCD_CONNECTOR_MASK,
  311. 0);
  312. /* If we're on an IB2 daughterboard, turn off display */
  313. if (versatile_ib2_map) {
  314. dev_info(&fb->dev->dev, "disable IB2 display\n");
  315. regmap_update_bits(versatile_ib2_map,
  316. IB2_CTRL,
  317. IB2_CTRL_LCD_MASK,
  318. IB2_CTRL_LCD_SD);
  319. }
  320. }
  321. static void versatile_clcd_enable(struct clcd_fb *fb)
  322. {
  323. struct fb_var_screeninfo *var = &fb->fb.var;
  324. u32 val = 0;
  325. dev_info(&fb->dev->dev, "enable Versatile CLCD connectors\n");
  326. switch (var->green.length) {
  327. case 5:
  328. val |= SYS_CLCD_MODE_5551;
  329. break;
  330. case 6:
  331. if (var->red.offset == 0)
  332. val |= SYS_CLCD_MODE_565_R_LSB;
  333. else
  334. val |= SYS_CLCD_MODE_565_B_LSB;
  335. break;
  336. case 8:
  337. val |= SYS_CLCD_MODE_888;
  338. break;
  339. }
  340. /* Set up the MUX */
  341. regmap_update_bits(versatile_syscon_map,
  342. SYS_CLCD,
  343. SYS_CLCD_MODE_MASK,
  344. val);
  345. /* Then enable the display */
  346. regmap_update_bits(versatile_syscon_map,
  347. SYS_CLCD,
  348. SYS_CLCD_CONNECTOR_MASK,
  349. SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
  350. /* If we're on an IB2 daughterboard, turn on display */
  351. if (versatile_ib2_map) {
  352. dev_info(&fb->dev->dev, "enable IB2 display\n");
  353. regmap_update_bits(versatile_ib2_map,
  354. IB2_CTRL,
  355. IB2_CTRL_LCD_MASK,
  356. IB2_CTRL_LCD_BL_ON);
  357. }
  358. }
  359. static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
  360. {
  361. clcdfb_decode(fb, regs);
  362. /* Always clear BGR for RGB565: we do the routing externally */
  363. if (fb->fb.var.green.length == 6)
  364. regs->cntl &= ~CNTL_BGR;
  365. }
  366. static void realview_clcd_disable(struct clcd_fb *fb)
  367. {
  368. dev_info(&fb->dev->dev, "disable RealView CLCD connectors\n");
  369. regmap_update_bits(versatile_syscon_map,
  370. SYS_CLCD,
  371. SYS_CLCD_CONNECTOR_MASK,
  372. 0);
  373. }
  374. static void realview_clcd_enable(struct clcd_fb *fb)
  375. {
  376. dev_info(&fb->dev->dev, "enable RealView CLCD connectors\n");
  377. regmap_update_bits(versatile_syscon_map,
  378. SYS_CLCD,
  379. SYS_CLCD_CONNECTOR_MASK,
  380. SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
  381. }
  382. struct versatile_panel {
  383. u32 id;
  384. char *compatible;
  385. bool ib2;
  386. };
  387. static const struct versatile_panel versatile_panels[] = {
  388. {
  389. .id = SYS_CLCD_ID_VGA,
  390. .compatible = "VGA",
  391. },
  392. {
  393. .id = SYS_CLCD_ID_SANYO_3_8,
  394. .compatible = "sanyo,tm38qv67a02a",
  395. },
  396. {
  397. .id = SYS_CLCD_ID_SHARP_8_4,
  398. .compatible = "sharp,lq084v1dg21",
  399. },
  400. {
  401. .id = SYS_CLCD_ID_EPSON_2_2,
  402. .compatible = "epson,l2f50113t00",
  403. },
  404. {
  405. .id = SYS_CLCD_ID_SANYO_2_5,
  406. .compatible = "sanyo,alr252rgt",
  407. .ib2 = true,
  408. },
  409. };
  410. static void versatile_panel_probe(struct device *dev,
  411. struct device_node *endpoint)
  412. {
  413. struct versatile_panel const *vpanel = NULL;
  414. struct device_node *panel = NULL;
  415. u32 val;
  416. int ret;
  417. int i;
  418. /*
  419. * The Versatile CLCD has a panel auto-detection mechanism.
  420. * We use this and look for the compatible panel in the
  421. * device tree.
  422. */
  423. ret = regmap_read(versatile_syscon_map, SYS_CLCD, &val);
  424. if (ret) {
  425. dev_err(dev, "cannot read CLCD syscon register\n");
  426. return;
  427. }
  428. val &= SYS_CLCD_CLCDID_MASK;
  429. /* First find corresponding panel information */
  430. for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) {
  431. vpanel = &versatile_panels[i];
  432. if (val == vpanel->id) {
  433. dev_err(dev, "autodetected panel \"%s\"\n",
  434. vpanel->compatible);
  435. break;
  436. }
  437. }
  438. if (i == ARRAY_SIZE(versatile_panels)) {
  439. dev_err(dev, "could not auto-detect panel\n");
  440. return;
  441. }
  442. panel = of_graph_get_remote_port_parent(endpoint);
  443. if (!panel) {
  444. dev_err(dev, "could not locate panel in DT\n");
  445. return;
  446. }
  447. if (!of_device_is_compatible(panel, vpanel->compatible))
  448. dev_err(dev, "panel in DT is not compatible with the "
  449. "auto-detected panel, continuing anyway\n");
  450. /*
  451. * If we have a Sanyo 2.5" port
  452. * that we're running on an IB2 and proceed to look for the
  453. * IB2 syscon regmap.
  454. */
  455. if (!vpanel->ib2)
  456. return;
  457. versatile_ib2_map = syscon_regmap_lookup_by_compatible(
  458. "arm,versatile-ib2-syscon");
  459. if (IS_ERR(versatile_ib2_map)) {
  460. dev_err(dev, "could not locate IB2 control register\n");
  461. versatile_ib2_map = NULL;
  462. return;
  463. }
  464. }
  465. int versatile_clcd_init_panel(struct clcd_fb *fb,
  466. struct device_node *endpoint)
  467. {
  468. const struct of_device_id *clcd_id;
  469. enum versatile_clcd versatile_clcd_type;
  470. struct device_node *np;
  471. struct regmap *map;
  472. struct device *dev = &fb->dev->dev;
  473. np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
  474. &clcd_id);
  475. if (!np) {
  476. /* Vexpress does not have this */
  477. return 0;
  478. }
  479. versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
  480. map = syscon_node_to_regmap(np);
  481. if (IS_ERR(map)) {
  482. dev_err(dev, "no Versatile syscon regmap\n");
  483. return PTR_ERR(map);
  484. }
  485. switch (versatile_clcd_type) {
  486. case INTEGRATOR_CLCD_CM:
  487. versatile_syscon_map = map;
  488. fb->board->enable = integrator_clcd_enable;
  489. /* Override the caps, we have only these */
  490. fb->board->caps = CLCD_CAP_5551 | CLCD_CAP_RGB565 |
  491. CLCD_CAP_888;
  492. dev_info(dev, "set up callbacks for Integrator PL110\n");
  493. break;
  494. case VERSATILE_CLCD:
  495. versatile_syscon_map = map;
  496. fb->board->enable = versatile_clcd_enable;
  497. fb->board->disable = versatile_clcd_disable;
  498. fb->board->decode = versatile_clcd_decode;
  499. versatile_panel_probe(dev, endpoint);
  500. dev_info(dev, "set up callbacks for Versatile\n");
  501. break;
  502. case REALVIEW_CLCD_EB:
  503. case REALVIEW_CLCD_PB1176:
  504. case REALVIEW_CLCD_PB11MP:
  505. case REALVIEW_CLCD_PBA8:
  506. case REALVIEW_CLCD_PBX:
  507. versatile_syscon_map = map;
  508. fb->board->enable = realview_clcd_enable;
  509. fb->board->disable = realview_clcd_disable;
  510. dev_info(dev, "set up callbacks for RealView PL111\n");
  511. break;
  512. default:
  513. dev_info(dev, "unknown Versatile system controller\n");
  514. break;
  515. }
  516. return 0;
  517. }
  518. EXPORT_SYMBOL_GPL(versatile_clcd_init_panel);
  519. #endif