018-Add-SSD1289-TFT-LCD-framebuffer-driver-on-TWR-MCF544.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. From c1de95e3a608c48b5576e32181480930d9106ac4 Mon Sep 17 00:00:00 2001
  2. From: Alison Wang <[email protected]>
  3. Date: Thu, 4 Aug 2011 09:59:44 +0800
  4. Subject: [PATCH 18/52] Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X
  5. Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X. Flexbus and spi
  6. interfaces are both supported.
  7. Signed-off-by: Alison Wang <[email protected]>
  8. ---
  9. arch/m68k/coldfire/m5441x/config.c | 1 +
  10. arch/m68k/coldfire/m5441x/devices.c | 1 +
  11. arch/m68k/include/asm/fsl-ssd1289-fb.h | 93 ++++
  12. drivers/video/Kconfig | 24 +
  13. drivers/video/Makefile | 1 +
  14. drivers/video/fsl-ssd1289-fb.c | 791 ++++++++++++++++++++++++++++++++
  15. 6 files changed, 911 insertions(+), 0 deletions(-)
  16. create mode 100644 arch/m68k/include/asm/fsl-ssd1289-fb.h
  17. create mode 100644 drivers/video/fsl-ssd1289-fb.c
  18. --- a/arch/m68k/coldfire/m5441x/config.c
  19. +++ b/arch/m68k/coldfire/m5441x/config.c
  20. @@ -45,6 +45,7 @@
  21. #include <asm/mcf5441x_fbcs.h>
  22. #include <asm/mcf5441x_dtim.h>
  23. #include <asm/mcf5441x_xbs.h>
  24. +#include <asm/fsl-ssd1289-fb.h>
  25. extern int get_irq_list(struct seq_file *p, void *v);
  26. extern char _text, _end;
  27. --- a/arch/m68k/coldfire/m5441x/devices.c
  28. +++ b/arch/m68k/coldfire/m5441x/devices.c
  29. @@ -33,6 +33,7 @@
  30. #include <asm/mcfqspi.h>
  31. #include <asm/mcfdspi.h>
  32. #include <asm/cf_io.h>
  33. +#include <asm/fsl-ssd1289-fb.h>
  34. /*
  35. * I2C: only support i2c0 module on m5441x platform
  36. --- /dev/null
  37. +++ b/arch/m68k/include/asm/fsl-ssd1289-fb.h
  38. @@ -0,0 +1,93 @@
  39. +/*
  40. + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
  41. + *
  42. + * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
  43. + *
  44. + * This program is free software; you can redistribute it and/or modify it
  45. + * under the terms of the GNU General Public License as published by the
  46. + * Free Software Foundation; either version 2 of the License, or (at your
  47. + * option) any later version.
  48. + */
  49. +
  50. +#ifndef __FSL_SSD1289_FB_H__
  51. +#define __FSL_SSD1289_FB_H__
  52. +
  53. +#define SSD1289_REG_OSCILLATION 0x00
  54. +#define SSD1289_REG_DRIVER_OUT_CTRL 0x01
  55. +#define SSD1289_REG_LCD_DRIVE_AC 0x02
  56. +#define SSD1289_REG_POWER_CTRL_1 0x03
  57. +#define SSD1289_REG_COMPARE_1 0x05
  58. +#define SSD1289_REG_COMPARE_2 0x06
  59. +#define SSD1289_REG_DISPLAY_CTRL 0x07
  60. +#define SSD1289_REG_FRAME_CYCLE 0x0b
  61. +#define SSD1289_REG_POWER_CTRL_2 0x0c
  62. +#define SSD1289_REG_POWER_CTRL_3 0x0d
  63. +#define SSD1289_REG_POWER_CTRL_4 0x0e
  64. +#define SSD1289_REG_GATE_SCAN_START 0x0f
  65. +#define SSD1289_REG_SLEEP_MODE 0x10
  66. +#define SSD1289_REG_ENTRY_MODE 0x11
  67. +#define SSD1289_REG_OPT_SPEED_3 0x12
  68. +#define SSD1289_REG_H_PORCH 0x16
  69. +#define SSD1289_REG_V_PORCH 0x17
  70. +#define SSD1289_REG_POWER_CTRL_5 0x1e
  71. +#define SSD1289_REG_GDDRAM_DATA 0x22
  72. +#define SSD1289_REG_WR_DATA_MASK_1 0x23
  73. +#define SSD1289_REG_WR_DATA_MASK_2 0x24
  74. +#define SSD1289_REG_FRAME_FREQUENCY 0x25
  75. +#define SSD1289_REG_OPT_SPEED_1 0x28
  76. +#define SSD1289_REG_OPT_SPEED_2 0x2f
  77. +#define SSD1289_REG_GAMMA_CTRL_1 0x30
  78. +#define SSD1289_REG_GAMMA_CTRL_2 0x31
  79. +#define SSD1289_REG_GAMMA_CTRL_3 0x32
  80. +#define SSD1289_REG_GAMMA_CTRL_4 0x33
  81. +#define SSD1289_REG_GAMMA_CTRL_5 0x34
  82. +#define SSD1289_REG_GAMMA_CTRL_6 0x35
  83. +#define SSD1289_REG_GAMMA_CTRL_7 0x36
  84. +#define SSD1289_REG_GAMMA_CTRL_8 0x37
  85. +#define SSD1289_REG_GAMMA_CTRL_9 0x3a
  86. +#define SSD1289_REG_GAMMA_CTRL_10 0x3b
  87. +#define SSD1289_REG_V_SCROLL_CTRL_1 0x41
  88. +#define SSD1289_REG_V_SCROLL_CTRL_2 0x42
  89. +#define SSD1289_REG_H_RAM_ADR_POS 0x44
  90. +#define SSD1289_REG_V_RAM_ADR_START 0x45
  91. +#define SSD1289_REG_V_RAM_ADR_END 0x46
  92. +#define SSD1289_REG_FIRST_WIN_START 0x48
  93. +#define SSD1289_REG_FIRST_WIN_END 0x49
  94. +#define SSD1289_REG_SECND_WIN_START 0x4a
  95. +#define SSD1289_REG_SECND_WIN_END 0x4b
  96. +#define SSD1289_REG_GDDRAM_X_ADDR 0x4e
  97. +#define SSD1289_REG_GDDRAM_Y_ADDR 0x4f
  98. +
  99. +struct ssd1289 {
  100. + void __iomem *cmd;
  101. + void __iomem *data;
  102. +} __packed;
  103. +
  104. +struct fsl_ssd1289_fb_info {
  105. + struct device *dev;
  106. + struct ssd1289 ssd1289_reg;
  107. + int openflag;
  108. + struct spi_device *spidev;
  109. +
  110. + struct task_struct *task;
  111. + unsigned long pseudo_palette[16];
  112. +};
  113. +
  114. +/* LCD description */
  115. +struct fsl_ssd1289_fb_display {
  116. + /* Screen size */
  117. + unsigned short width;
  118. + unsigned short height;
  119. +
  120. + /* Screen info */
  121. + unsigned short xres;
  122. + unsigned short yres;
  123. + unsigned short bpp;
  124. +};
  125. +
  126. +#define FLEXBUS_LCD_CMD_ADDRESS 0xc0000000
  127. +#define FLEXBUS_LCD_DATA_ADDRESS 0xc0010000
  128. +
  129. +#define SPI_LCD_BLOCK_SIZE 4096
  130. +#define SPI_LCD_BLOCK_HALF_SIZE 2048
  131. +#endif
  132. --- a/drivers/video/Kconfig
  133. +++ b/drivers/video/Kconfig
  134. @@ -1980,6 +1980,30 @@ config FB_FSL_DIU
  135. ---help---
  136. Framebuffer driver for the Freescale SoC DIU
  137. +config FB_FSL_SSD1289
  138. + tristate "SSD1289 TFT LCD (Freescale MCF54418)"
  139. + depends on FB && M5441X
  140. + select FB_CFB_FILLRECT
  141. + select FB_CFB_COPYAREA
  142. + select FB_CFB_IMAGEBLIT
  143. + select FB_SYS_FOPS
  144. + ---help---
  145. + This is the framebuffer device driver for a Solomon Systech 240RGBx320
  146. + TFT LCD SSD1289.
  147. +
  148. +choice
  149. + prompt "SSD1289 LCD Controller Interface mode"
  150. + depends on FB_FSL_SSD1289
  151. +
  152. +config SSD1289_FLEXBUS_MODE
  153. + bool "SSD1289 LCD Controller Flexbus Interface mode"
  154. +
  155. +config SSD1289_SPI_MODE
  156. + bool "SSD1289 LCD Controller SPI Interface mode"
  157. + depends on SPI_DSPI && DSPI0
  158. +
  159. +endchoice
  160. +
  161. config FB_W100
  162. tristate "W100 frame buffer support"
  163. depends on FB && ARCH_PXA
  164. --- a/drivers/video/Makefile
  165. +++ b/drivers/video/Makefile
  166. @@ -120,6 +120,7 @@ obj-$(CONFIG_FB_IMX) += imx
  167. obj-$(CONFIG_FB_S3C) += s3c-fb.o
  168. obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
  169. obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
  170. +obj-$(CONFIG_FB_FSL_SSD1289) += fsl-ssd1289-fb.o
  171. obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
  172. obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
  173. obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
  174. --- /dev/null
  175. +++ b/drivers/video/fsl-ssd1289-fb.c
  176. @@ -0,0 +1,791 @@
  177. +/*
  178. + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
  179. + *
  180. + * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
  181. + *
  182. + * Author: Alison Wang <[email protected]>
  183. + * Jason Jin <[email protected]>
  184. + *
  185. + * This program is free software; you can redistribute it and/or modify it
  186. + * under the terms of the GNU General Public License as published by the
  187. + * Free Software Foundation; either version 2 of the License, or (at your
  188. + * option) any later version.
  189. + */
  190. +
  191. +#include <linux/module.h>
  192. +#include <linux/kernel.h>
  193. +#include <linux/errno.h>
  194. +#include <linux/string.h>
  195. +#include <linux/mm.h>
  196. +#include <linux/slab.h>
  197. +#include <linux/delay.h>
  198. +#include <linux/fb.h>
  199. +#include <linux/init.h>
  200. +#include <linux/interrupt.h>
  201. +#include <linux/platform_device.h>
  202. +#include <linux/dma-mapping.h>
  203. +#include <linux/clk.h>
  204. +#include <linux/uaccess.h>
  205. +#include <linux/timer.h>
  206. +#include <linux/kthread.h>
  207. +#include <linux/spi/spi.h>
  208. +
  209. +#include <asm/mcf5441x_fbcs.h>
  210. +#include <asm/mcf5441x_dspi.h>
  211. +#include <asm/fsl-ssd1289-fb.h>
  212. +#include <asm/mcf5441x_gpio.h>
  213. +#include <asm/mcf5441x_ccm.h>
  214. +#include <asm/mcf_edma.h>
  215. +
  216. +#ifdef CONFIG_PM
  217. +#include <linux/pm.h>
  218. +#endif
  219. +
  220. +#if defined(CONFIG_SSD1289_SPI_MODE)
  221. +unsigned char spi_block_buffer[SPI_LCD_BLOCK_SIZE];
  222. +
  223. +static int ssd1289_spi_writeblock(struct fb_info *info,
  224. + unsigned char *daddr, int flag)
  225. +{
  226. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  227. + struct spi_device *devtmp;
  228. + int i;
  229. +
  230. + for (i = 0; i < SPI_LCD_BLOCK_SIZE; i++) {
  231. + if (i % 2 == 0)
  232. + spi_block_buffer[i] = 0x01;
  233. + else if (flag == 1)
  234. + spi_block_buffer[i] = *(daddr + (i >> 1));
  235. + else if (flag == 0)
  236. + spi_block_buffer[i] = 0;
  237. + }
  238. +
  239. + devtmp = fbinfo->spidev;
  240. + spi_write(devtmp, (const unsigned char *)spi_block_buffer,
  241. + SPI_LCD_BLOCK_SIZE);
  242. + return 0;
  243. +}
  244. +
  245. +static int ssd1289_spi_write(struct fb_info *info,
  246. + unsigned short value, unsigned int flag)
  247. +{
  248. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  249. + struct spi_device *devtmp;
  250. + unsigned short tmpl;
  251. + unsigned short tmph;
  252. +
  253. + devtmp = fbinfo->spidev;
  254. + if (flag == 1) {
  255. + /* D/C = 1 */
  256. + tmph = ((value >> 8) & 0xff) + 0x0100;
  257. + tmpl = (value & 0xff) + 0x0100;
  258. + spi_write(devtmp, (const u8 *)&tmph, sizeof(tmph));
  259. + spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
  260. + } else {
  261. + /* D/C = 0 */
  262. + tmpl = (value & 0xff);
  263. + spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
  264. + }
  265. + return 0;
  266. +}
  267. +#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
  268. +static int ssd1289_flexbus_write(struct fb_info *info, unsigned short value,
  269. + unsigned int flag)
  270. +{
  271. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  272. + void __iomem *cmd_addr, *data_addr;
  273. +
  274. + cmd_addr = fbinfo->ssd1289_reg.cmd;
  275. + data_addr = fbinfo->ssd1289_reg.data;
  276. +
  277. + if (flag == 0)
  278. + out_be16(cmd_addr, value);
  279. + else
  280. + out_be16(data_addr, value);
  281. +
  282. + return 0;
  283. +}
  284. +#endif
  285. +
  286. +static int ssd1289_write(struct fb_info *info, unsigned short value,
  287. + unsigned int flag)
  288. +{
  289. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  290. + ssd1289_flexbus_write(info, value, flag);
  291. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  292. + ssd1289_spi_write(info, value, flag);
  293. +#endif
  294. + return 0;
  295. +}
  296. +
  297. +static void fsl_ssd1289_enable_lcd(struct fb_info *info)
  298. +{
  299. + int i;
  300. +
  301. +#if defined(CONFIG_SSD1289_SPI_MODE)
  302. + int count;
  303. +#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
  304. + /* GPIO configuration */
  305. + MCF_GPIO_PAR_BE = MCF_GPIO_PAR_BE_BE3_FB_A1 | MCF_GPIO_PAR_BE_BE2_FB_A0
  306. + | MCF_GPIO_PAR_BE_BE1_BE1 | MCF_GPIO_PAR_BE_BE0_BE0;
  307. + MCF_GPIO_PAR_CS |= MCF_GPIO_PAR_CS_CS0_CS0;
  308. +#endif
  309. +
  310. + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
  311. + ssd1289_write(info, 0x0200, 1);
  312. +
  313. + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
  314. + ssd1289_write(info, 0x0000, 1);
  315. +
  316. + mdelay(100);
  317. +
  318. + /* turn on the oscillator */
  319. + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
  320. + ssd1289_write(info, 0x0001, 1);
  321. +
  322. + mdelay(100);
  323. + /* power control 1 */
  324. + ssd1289_write(info, SSD1289_REG_POWER_CTRL_1, 0);
  325. + ssd1289_write(info, 0xaeac, 1);
  326. +
  327. + /* power control 2 */
  328. + ssd1289_write(info, SSD1289_REG_POWER_CTRL_2, 0);
  329. + ssd1289_write(info, 0x0007, 1);
  330. +
  331. + /* power control 3 */
  332. + ssd1289_write(info, SSD1289_REG_POWER_CTRL_3, 0);
  333. + ssd1289_write(info, 0x000f, 1);
  334. +
  335. + /* power control 4 */
  336. + ssd1289_write(info, SSD1289_REG_POWER_CTRL_4, 0);
  337. + ssd1289_write(info, 0x2900, 1);
  338. +
  339. + /* power control 5 */
  340. + ssd1289_write(info, SSD1289_REG_POWER_CTRL_5, 0);
  341. + ssd1289_write(info, 0x00b3, 1);
  342. +
  343. + mdelay(15);
  344. + /* driver output control */
  345. + ssd1289_write(info, SSD1289_REG_DRIVER_OUT_CTRL, 0);
  346. + ssd1289_write(info, 0x2b3f, 1);
  347. +
  348. + /* lcd-driving-waveform control */
  349. + ssd1289_write(info, SSD1289_REG_LCD_DRIVE_AC, 0);
  350. + ssd1289_write(info, 0x0600, 1);
  351. +
  352. + /* sleep mode */
  353. + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
  354. + ssd1289_write(info, 0x0000, 1);
  355. +
  356. + /* entry mode */
  357. + ssd1289_write(info, SSD1289_REG_ENTRY_MODE, 0);
  358. + ssd1289_write(info, 0x60a8, 1);
  359. +
  360. + mdelay(15);
  361. + /* compare register */
  362. + ssd1289_write(info, SSD1289_REG_COMPARE_1, 0);
  363. + ssd1289_write(info, 0x0000, 1);
  364. +
  365. + ssd1289_write(info, SSD1289_REG_COMPARE_2, 0);
  366. + ssd1289_write(info, 0x0000, 1);
  367. +
  368. + /* horizontal porch */
  369. + ssd1289_write(info, SSD1289_REG_H_PORCH, 0);
  370. + ssd1289_write(info, 0xef1c, 1);
  371. +
  372. + /* vertical porch */
  373. + ssd1289_write(info, SSD1289_REG_V_PORCH, 0);
  374. + ssd1289_write(info, 0x0003, 1);
  375. +
  376. + /* display control */
  377. + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
  378. + ssd1289_write(info, 0x0233, 1);
  379. +
  380. + /* frame cycle control */
  381. + ssd1289_write(info, SSD1289_REG_FRAME_CYCLE, 0);
  382. + ssd1289_write(info, 0x5312, 1);
  383. +
  384. + /* gate scan position */
  385. + ssd1289_write(info, SSD1289_REG_GATE_SCAN_START, 0);
  386. + ssd1289_write(info, 0x0000, 1);
  387. +
  388. + mdelay(20);
  389. + /* vertical scroll control */
  390. + ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_1, 0);
  391. + ssd1289_write(info, 0x0000, 1);
  392. +
  393. + ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_2, 0);
  394. + ssd1289_write(info, 0x0000, 1);
  395. +
  396. + /* 1st screen driving position */
  397. + ssd1289_write(info, SSD1289_REG_FIRST_WIN_START, 0);
  398. + ssd1289_write(info, 0x0000, 1);
  399. +
  400. + ssd1289_write(info, SSD1289_REG_FIRST_WIN_END, 0);
  401. + ssd1289_write(info, 0x013F, 1);
  402. +
  403. + /* 2nd screen driving position */
  404. + ssd1289_write(info, SSD1289_REG_SECND_WIN_START, 0);
  405. + ssd1289_write(info, 0x0000, 1);
  406. +
  407. + ssd1289_write(info, SSD1289_REG_SECND_WIN_END, 0);
  408. + ssd1289_write(info, 0x0000, 1);
  409. +
  410. + mdelay(20);
  411. + /* gamma control */
  412. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_1, 0);
  413. + ssd1289_write(info, 0x0707, 1);
  414. +
  415. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_2, 0);
  416. + ssd1289_write(info, 0x0704, 1);
  417. +
  418. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_3, 0);
  419. + ssd1289_write(info, 0x0204, 1);
  420. +
  421. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_4, 0);
  422. + ssd1289_write(info, 0x0201, 1);
  423. +
  424. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_5, 0);
  425. + ssd1289_write(info, 0x0203, 1);
  426. +
  427. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_6, 0);
  428. + ssd1289_write(info, 0x0204, 1);
  429. +
  430. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_7, 0);
  431. + ssd1289_write(info, 0x0204, 1);
  432. +
  433. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_8, 0);
  434. + ssd1289_write(info, 0x0502, 1);
  435. +
  436. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_9, 0);
  437. + ssd1289_write(info, 0x0302, 1);
  438. +
  439. + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_10, 0);
  440. + ssd1289_write(info, 0x0500, 1);
  441. +
  442. + /* ram write data mask */
  443. + ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_1, 0);
  444. + ssd1289_write(info, 0x0000, 1);
  445. +
  446. + ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_2, 0);
  447. + ssd1289_write(info, 0x0000, 1);
  448. +
  449. + /* frame frequency control */
  450. + ssd1289_write(info, SSD1289_REG_FRAME_FREQUENCY, 0);
  451. + ssd1289_write(info, 0xe000, 1);
  452. +
  453. + /* optimize data access speed */
  454. + ssd1289_write(info, SSD1289_REG_OPT_SPEED_1, 0);
  455. + ssd1289_write(info, 0x0006, 1);
  456. +
  457. + ssd1289_write(info, SSD1289_REG_OPT_SPEED_2, 0);
  458. + ssd1289_write(info, 0x12ae, 1);
  459. +
  460. + ssd1289_write(info, SSD1289_REG_OPT_SPEED_3, 0);
  461. + ssd1289_write(info, 0x6ceb, 1);
  462. +
  463. + /* horizontal ram address position */
  464. + ssd1289_write(info, SSD1289_REG_H_RAM_ADR_POS, 0);
  465. + ssd1289_write(info, 0xef00, 1);
  466. +
  467. + /* vertical ram address position */
  468. + ssd1289_write(info, SSD1289_REG_V_RAM_ADR_START, 0);
  469. + ssd1289_write(info, 0x0000, 1);
  470. +
  471. + ssd1289_write(info, SSD1289_REG_V_RAM_ADR_END, 0);
  472. + ssd1289_write(info, 0x013f, 1);
  473. +
  474. + mdelay(20);
  475. +
  476. + /* set start address counter */
  477. + ssd1289_write(info, SSD1289_REG_GDDRAM_X_ADDR, 0);
  478. + ssd1289_write(info, 0x00ef, 1);
  479. +
  480. + ssd1289_write(info, SSD1289_REG_GDDRAM_Y_ADDR, 0);
  481. + ssd1289_write(info, 0x0000, 1);
  482. +
  483. + ssd1289_write(info, SSD1289_REG_GDDRAM_DATA, 0);
  484. +
  485. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  486. + for (i = 0; i < info->screen_size; i += 2)
  487. + ssd1289_write(info, 0, 1);
  488. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  489. + count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
  490. + for (i = 0; i < count; i++)
  491. + ssd1289_spi_writeblock(info, NULL, 0);
  492. +#endif
  493. +}
  494. +
  495. +static void fsl_ssd1289_disable_lcd(struct fb_info *info)
  496. +{
  497. + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
  498. + ssd1289_write(info, 0x0200, 1);
  499. +
  500. + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
  501. + ssd1289_write(info, 0x0000, 1);
  502. +}
  503. +
  504. +static int ssd1289fbd(void *arg)
  505. +{
  506. + struct fb_info *info = arg;
  507. + int i;
  508. + unsigned short *buf_p;
  509. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  510. +#if defined(CONFIG_SSD1289_SPI_MODE)
  511. + unsigned char *bufspi_p;
  512. + int count;
  513. +#endif
  514. +
  515. + while (!kthread_should_stop()) {
  516. + set_current_state(TASK_INTERRUPTIBLE);
  517. +
  518. + if (fbinfo->openflag == 1) {
  519. + buf_p = (unsigned short *)(info->screen_base);
  520. +
  521. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  522. + for (i = 0; i < info->screen_size; i += 2) {
  523. + ssd1289_write(info, *buf_p, 1);
  524. + buf_p++;
  525. + }
  526. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  527. + bufspi_p = (unsigned char *)buf_p;
  528. + count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
  529. + for (i = 0; i < count; i++)
  530. + ssd1289_spi_writeblock(info, (bufspi_p +
  531. + SPI_LCD_BLOCK_HALF_SIZE * i), 1);
  532. +#endif
  533. + }
  534. + schedule_timeout(HZ/25);
  535. + }
  536. +
  537. + return 0;
  538. +}
  539. +
  540. +static int fsl_ssd1289_check_var(struct fb_var_screeninfo *var,
  541. + struct fb_info *info)
  542. +{
  543. + if (var->xres_virtual < var->xres)
  544. + var->xres_virtual = var->xres;
  545. + if (var->yres_virtual < var->yres)
  546. + var->yres_virtual = var->yres;
  547. +
  548. + if (var->xoffset < 0)
  549. + var->xoffset = 0;
  550. +
  551. + if (var->yoffset < 0)
  552. + var->yoffset = 0;
  553. +
  554. + if (var->xoffset + info->var.xres > info->var.xres_virtual)
  555. + var->xoffset = info->var.xres_virtual - info->var.xres;
  556. +
  557. + if (var->yoffset + info->var.yres > info->var.yres_virtual)
  558. + var->yoffset = info->var.yres_virtual - info->var.yres;
  559. +
  560. + switch (var->bits_per_pixel) {
  561. + case 8:
  562. + /* 8 bpp, 332 format */
  563. + var->red.length = 3;
  564. + var->red.offset = 5;
  565. + var->red.msb_right = 0;
  566. +
  567. + var->green.length = 3;
  568. + var->green.offset = 2;
  569. + var->green.msb_right = 0;
  570. +
  571. + var->blue.length = 2;
  572. + var->blue.offset = 0;
  573. + var->blue.msb_right = 0;
  574. +
  575. + var->transp.length = 0;
  576. + var->transp.offset = 0;
  577. + var->transp.msb_right = 0;
  578. + break;
  579. + case 16:
  580. + /* 16 bpp, 565 format */
  581. + var->red.length = 5;
  582. + var->red.offset = 11;
  583. + var->red.msb_right = 0;
  584. +
  585. + var->green.length = 6;
  586. + var->green.offset = 5;
  587. + var->green.msb_right = 0;
  588. +
  589. + var->blue.length = 5;
  590. + var->blue.offset = 0;
  591. + var->blue.msb_right = 0;
  592. +
  593. + var->transp.length = 0;
  594. + var->transp.offset = 0;
  595. + var->transp.msb_right = 0;
  596. + break;
  597. + default:
  598. + printk(KERN_ERR "Depth not supported: %u BPP\n",
  599. + var->bits_per_pixel);
  600. + return -EINVAL;
  601. + }
  602. + return 0;
  603. +}
  604. +
  605. +static int fsl_ssd1289_set_par(struct fb_info *info)
  606. +{
  607. + struct fb_var_screeninfo *var = &info->var;
  608. +
  609. + switch (var->bits_per_pixel) {
  610. + case 16:
  611. + info->fix.visual = FB_VISUAL_TRUECOLOR;
  612. + break;
  613. + case 8:
  614. + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  615. + break;
  616. + default:
  617. + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  618. + break;
  619. + }
  620. +
  621. + return 0;
  622. +}
  623. +
  624. +static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
  625. +{
  626. + return ((val<<width) + 0x7FFF - val)>>16;
  627. +}
  628. +
  629. +static int fsl_ssd1289_setcolreg(unsigned regno,
  630. + unsigned red, unsigned green, unsigned blue,
  631. + unsigned transp, struct fb_info *info)
  632. +{
  633. + int ret = 1;
  634. +
  635. + /*
  636. + * If greyscale is true, then we convert the RGB value
  637. + * to greyscale no matter what visual we are using.
  638. + */
  639. + if (info->var.grayscale)
  640. + red = green = blue = (19595 * red + 38470 * green +
  641. + 7471 * blue) >> 16;
  642. + switch (info->fix.visual) {
  643. + case FB_VISUAL_TRUECOLOR:
  644. + if (regno < 16) {
  645. + u32 *pal = info->pseudo_palette;
  646. + u32 value;
  647. +
  648. + red = CNVT_TOHW(red, info->var.red.length);
  649. + green = CNVT_TOHW(green, info->var.green.length);
  650. + blue = CNVT_TOHW(blue, info->var.blue.length);
  651. + transp = CNVT_TOHW(transp, info->var.transp.length);
  652. +
  653. + value = (red << info->var.red.offset) |
  654. + (green << info->var.green.offset) |
  655. + (blue << info->var.blue.offset) |
  656. + (transp << info->var.transp.offset);
  657. +
  658. + pal[regno] = value;
  659. + ret = 0;
  660. + }
  661. + break;
  662. + case FB_VISUAL_STATIC_PSEUDOCOLOR:
  663. + case FB_VISUAL_PSEUDOCOLOR:
  664. + break;
  665. + }
  666. + return ret;
  667. +}
  668. +
  669. +static int fsl_ssd1289_blank(int blank_mode, struct fb_info *info)
  670. +{
  671. + if (blank_mode == FB_BLANK_POWERDOWN)
  672. + fsl_ssd1289_disable_lcd(info);
  673. + else
  674. + fsl_ssd1289_enable_lcd(info);
  675. +
  676. + return 0;
  677. +}
  678. +
  679. +static int fsl_ssd1289_open(struct fb_info *info, int user)
  680. +{
  681. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  682. + struct task_struct *task;
  683. + int ret;
  684. +
  685. + if (fbinfo->openflag == 0) {
  686. + memset(info->screen_base, 0, info->screen_size);
  687. + fsl_ssd1289_enable_lcd(info);
  688. +
  689. + task = kthread_run(ssd1289fbd, info, "SSD1289 LCD");
  690. + if (IS_ERR(task)) {
  691. + ret = PTR_ERR(task);
  692. + return ret;
  693. + }
  694. + fbinfo->task = task;
  695. + }
  696. +
  697. + fbinfo->openflag = 1;
  698. + return 0;
  699. +}
  700. +
  701. +static int fsl_ssd1289_release(struct fb_info *info, int user)
  702. +{
  703. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  704. +
  705. + fbinfo->openflag = 0;
  706. + if (fbinfo->task) {
  707. + struct task_struct *task = fbinfo->task;
  708. + fbinfo->task = NULL;
  709. + kthread_stop(task);
  710. + }
  711. +
  712. + memset(info->screen_base, 0, info->screen_size);
  713. + fsl_ssd1289_disable_lcd(info);
  714. + return 0;
  715. +}
  716. +
  717. +static struct fb_ops fsl_ssd1289_ops = {
  718. + .owner = THIS_MODULE,
  719. + .fb_check_var = fsl_ssd1289_check_var,
  720. + .fb_set_par = fsl_ssd1289_set_par,
  721. + .fb_setcolreg = fsl_ssd1289_setcolreg,
  722. + .fb_blank = fsl_ssd1289_blank,
  723. + .fb_open = fsl_ssd1289_open,
  724. + .fb_release = fsl_ssd1289_release,
  725. + .fb_copyarea = cfb_copyarea,
  726. + .fb_fillrect = cfb_fillrect,
  727. + .fb_imageblit = cfb_imageblit,
  728. +};
  729. +
  730. +static int fsl_ssd1289_map_video_memory(struct fb_info *info)
  731. +{
  732. + unsigned int map_size = info->fix.smem_len;
  733. +
  734. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  735. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  736. +
  737. + fbinfo->ssd1289_reg.cmd =
  738. + ioremap_nocache(FLEXBUS_LCD_CMD_ADDRESS, 2);
  739. + fbinfo->ssd1289_reg.data =
  740. + ioremap_nocache(FLEXBUS_LCD_DATA_ADDRESS, 2);
  741. +#endif
  742. +
  743. + info->screen_base = kmalloc(map_size, GFP_KERNEL);
  744. + info->fix.smem_start = virt_to_phys(info->screen_base);
  745. + info->screen_size = info->fix.smem_len;
  746. +
  747. + if (info->screen_base)
  748. + memset(info->screen_base, 0, map_size);
  749. +
  750. + return info->screen_base ? 0 : -ENOMEM;
  751. +}
  752. +
  753. +static inline void fsl_ssd1289_unmap_video_memory(struct fb_info *info)
  754. +{
  755. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  756. + struct fsl_ssd1289_fb_info *fbinfo = info->par;
  757. +
  758. + iounmap(fbinfo->ssd1289_reg.cmd);
  759. + iounmap(fbinfo->ssd1289_reg.data);
  760. +#endif
  761. + kfree(info->screen_base);
  762. +}
  763. +
  764. +
  765. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  766. +static int fsl_ssd1289_probe(struct platform_device *pdev)
  767. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  768. +static int fsl_ssd1289_probe(struct spi_device *spi)
  769. +#endif
  770. +{
  771. + struct fsl_ssd1289_fb_info *fbinfo;
  772. + struct fb_info *info;
  773. + struct fsl_ssd1289_fb_display *display;
  774. + int ret;
  775. + unsigned long smem_len;
  776. +
  777. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  778. + info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
  779. + &pdev->dev);
  780. + if (!info)
  781. + return -ENOMEM;
  782. +
  783. + platform_set_drvdata(pdev, info);
  784. +
  785. + fbinfo = info->par;
  786. + fbinfo->dev = &pdev->dev;
  787. + display = pdev->dev.platform_data;
  788. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  789. + info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
  790. + &spi->dev);
  791. + if (!info)
  792. + return -ENOMEM;
  793. +
  794. + dev_set_drvdata(&spi->dev, info);
  795. +
  796. + fbinfo = info->par;
  797. + fbinfo->dev = &spi->dev;
  798. + fbinfo->spidev = spi;
  799. + display = spi->dev.platform_data;
  800. +#endif
  801. +
  802. + fbinfo->openflag = 0;
  803. + info->fix.type = FB_TYPE_PACKED_PIXELS;
  804. + info->fix.type_aux = 0;
  805. + info->fix.xpanstep = 0;
  806. + info->fix.ypanstep = 0;
  807. + info->fix.ywrapstep = 0;
  808. + info->fix.accel = FB_ACCEL_NONE;
  809. +
  810. + info->var.nonstd = 0;
  811. + info->var.activate = FB_ACTIVATE_NOW;
  812. + info->var.accel_flags = 0;
  813. + info->var.vmode = FB_VMODE_NONINTERLACED;
  814. +
  815. + info->fbops = &fsl_ssd1289_ops;
  816. + info->flags = FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT
  817. + | FBINFO_HWACCEL_COPYAREA;
  818. + info->pseudo_palette = &fbinfo->pseudo_palette;
  819. +
  820. + /* find maximum required memory size for display */
  821. + smem_len = display->xres;
  822. + smem_len *= display->yres;
  823. + smem_len *= display->bpp;
  824. + smem_len >>= 3;
  825. + if (info->fix.smem_len < smem_len)
  826. + info->fix.smem_len = smem_len;
  827. +
  828. + /* Intialize video memory */
  829. + ret = fsl_ssd1289_map_video_memory(info);
  830. + if (ret) {
  831. + printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
  832. + ret = -ENOMEM;
  833. + goto dealloc_fb;
  834. + }
  835. +
  836. + info->var.xres = display->xres;
  837. + info->var.yres = display->yres;
  838. + info->var.bits_per_pixel = display->bpp;
  839. + info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8;
  840. +
  841. + fsl_ssd1289_check_var(&info->var, info);
  842. +
  843. + ret = register_framebuffer(info);
  844. + if (ret < 0) {
  845. + printk(KERN_ERR "Failed to register framebuffer device: %d\n",
  846. + ret);
  847. + goto free_video_memory;
  848. + }
  849. +
  850. + printk(KERN_INFO "fb: SSD1289 TFT LCD Framebuffer Driver\n");
  851. + return 0;
  852. +
  853. +free_video_memory:
  854. + fsl_ssd1289_unmap_video_memory(info);
  855. +dealloc_fb:
  856. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  857. + platform_set_drvdata(pdev, NULL);
  858. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  859. + dev_set_drvdata(&spi->dev, NULL);
  860. +#endif
  861. + framebuffer_release(info);
  862. + return ret;
  863. +}
  864. +
  865. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  866. +static int fsl_ssd1289_remove(struct platform_device *pdev)
  867. +{
  868. + struct fb_info *info = platform_get_drvdata(pdev);
  869. +
  870. + platform_set_drvdata(pdev, NULL);
  871. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  872. +static int fsl_ssd1289_remove(struct spi_device *spi)
  873. +{
  874. + struct fb_info *info = dev_get_drvdata(&spi->dev);
  875. +
  876. + dev_set_drvdata(&spi->dev, NULL);
  877. +#endif
  878. + unregister_framebuffer(info);
  879. + fsl_ssd1289_unmap_video_memory(info);
  880. + framebuffer_release(info);
  881. + return 0;
  882. +}
  883. +
  884. +#ifdef CONFIG_PM
  885. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  886. +static int fsl_ssd1289_suspend(struct platform_device *dev, pm_message_t state)
  887. +{
  888. + struct fb_info *info = platform_get_drvdata(dev);
  889. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  890. +static int fsl_ssd1289_suspend(struct spi_device *spi, pm_message_t state)
  891. +{
  892. + struct fb_info *info = dev_get_drvdata(&spi->dev);
  893. +#endif
  894. + /* enter into sleep mode */
  895. + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
  896. + ssd1289_write(info, 0x0001, 1);
  897. + return 0;
  898. +}
  899. +
  900. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  901. +static int fsl_ssd1289_resume(struct platform_device *dev)
  902. +{
  903. + struct fb_info *info = platform_get_drvdata(dev);
  904. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  905. +static int fsl_ssd1289_resume(struct spi_device *spi)
  906. +{
  907. + struct fb_info *info = dev_get_drvdata(&spi->dev);
  908. +#endif
  909. + /* leave sleep mode */
  910. + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
  911. + ssd1289_write(info, 0x0000, 1);
  912. + return 0;
  913. +}
  914. +#else
  915. +#define fsl_ssd1289_suspend NULL
  916. +#define fsl_ssd1289_resume NULL
  917. +#endif
  918. +
  919. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  920. +static struct platform_driver fsl_ssd1289_driver = {
  921. + .probe = fsl_ssd1289_probe,
  922. + .remove = fsl_ssd1289_remove,
  923. + .suspend = fsl_ssd1289_suspend,
  924. + .resume = fsl_ssd1289_resume,
  925. + .driver = {
  926. + .name = "fsl-ssd1289",
  927. + .owner = THIS_MODULE,
  928. + },
  929. +};
  930. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  931. +static struct spi_driver spi_ssd1289_driver = {
  932. + .driver = {
  933. + .name = "spi-ssd1289",
  934. + .bus = &spi_bus_type,
  935. + .owner = THIS_MODULE,
  936. + },
  937. + .probe = fsl_ssd1289_probe,
  938. + .remove = fsl_ssd1289_remove,
  939. + .suspend = fsl_ssd1289_suspend,
  940. + .resume = fsl_ssd1289_resume,
  941. +};
  942. +#endif
  943. +
  944. +static int __devinit fsl_ssd1289_init(void)
  945. +{
  946. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  947. + return platform_driver_register(&fsl_ssd1289_driver);
  948. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  949. + return spi_register_driver(&spi_ssd1289_driver);
  950. +#endif
  951. +}
  952. +
  953. +static void __exit fsl_ssd1289_exit(void)
  954. +{
  955. +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
  956. + return platform_driver_unregister(&fsl_ssd1289_driver);
  957. +#elif defined(CONFIG_SSD1289_SPI_MODE)
  958. + return spi_unregister_driver(&spi_ssd1289_driver);
  959. +#endif
  960. +}
  961. +
  962. +module_init(fsl_ssd1289_init);
  963. +module_exit(fsl_ssd1289_exit);
  964. +
  965. +MODULE_AUTHOR("Alison Wang <[email protected]>");
  966. +MODULE_DESCRIPTION("Freescale MCF54418 SSD1289 TFT LCD Framebuffer Driver");
  967. +MODULE_LICENSE("GPL");