bfin-lq035q1-fb.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. /*
  2. * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02
  3. *
  4. * Copyright 2008-2009 Analog Devices Inc.
  5. * Licensed under the GPL-2 or later.
  6. */
  7. #define DRIVER_NAME "bfin-lq035q1"
  8. #define pr_fmt(fmt) DRIVER_NAME ": " fmt
  9. #include <linux/module.h>
  10. #include <linux/kernel.h>
  11. #include <linux/errno.h>
  12. #include <linux/string.h>
  13. #include <linux/fb.h>
  14. #include <linux/gpio.h>
  15. #include <linux/slab.h>
  16. #include <linux/init.h>
  17. #include <linux/types.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/device.h>
  20. #include <linux/backlight.h>
  21. #include <linux/lcd.h>
  22. #include <linux/dma-mapping.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/spi/spi.h>
  25. #include <asm/blackfin.h>
  26. #include <asm/irq.h>
  27. #include <asm/dma.h>
  28. #include <asm/portmux.h>
  29. #include <asm/gptimers.h>
  30. #include <asm/bfin-lq035q1.h>
  31. #if defined(BF533_FAMILY) || defined(BF538_FAMILY)
  32. #define TIMER_HSYNC_id TIMER1_id
  33. #define TIMER_HSYNCbit TIMER1bit
  34. #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
  35. #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
  36. #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
  37. #define TIMER_VSYNC_id TIMER2_id
  38. #define TIMER_VSYNCbit TIMER2bit
  39. #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2
  40. #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2
  41. #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2
  42. #else
  43. #define TIMER_HSYNC_id TIMER0_id
  44. #define TIMER_HSYNCbit TIMER0bit
  45. #define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0
  46. #define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0
  47. #define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0
  48. #define TIMER_VSYNC_id TIMER1_id
  49. #define TIMER_VSYNCbit TIMER1bit
  50. #define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
  51. #define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
  52. #define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
  53. #endif
  54. #define LCD_X_RES 320 /* Horizontal Resolution */
  55. #define LCD_Y_RES 240 /* Vertical Resolution */
  56. #define DMA_BUS_SIZE 16
  57. #define U_LINE 4 /* Blanking Lines */
  58. /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
  59. * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
  60. */
  61. #define BFIN_LCD_NBR_PALETTE_ENTRIES 256
  62. #define PPI_TX_MODE 0x2
  63. #define PPI_XFER_TYPE_11 0xC
  64. #define PPI_PORT_CFG_01 0x10
  65. #define PPI_POLS_1 0x8000
  66. #define LQ035_INDEX 0x74
  67. #define LQ035_DATA 0x76
  68. #define LQ035_DRIVER_OUTPUT_CTL 0x1
  69. #define LQ035_SHUT_CTL 0x11
  70. #define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
  71. #define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
  72. #define LQ035_SHUT (1 << 0) /* Shutdown */
  73. #define LQ035_ON (0 << 0) /* Shutdown */
  74. struct bfin_lq035q1fb_info {
  75. struct fb_info *fb;
  76. struct device *dev;
  77. struct spi_driver spidrv;
  78. struct bfin_lq035q1fb_disp_info *disp_info;
  79. unsigned char *fb_buffer; /* RGB Buffer */
  80. dma_addr_t dma_handle;
  81. int lq035_open_cnt;
  82. int irq;
  83. spinlock_t lock; /* lock */
  84. u32 pseudo_pal[16];
  85. u32 lcd_bpp;
  86. u32 h_actpix;
  87. u32 h_period;
  88. u32 h_pulse;
  89. u32 h_start;
  90. u32 v_lines;
  91. u32 v_pulse;
  92. u32 v_period;
  93. };
  94. static int nocursor;
  95. module_param(nocursor, int, 0644);
  96. MODULE_PARM_DESC(nocursor, "cursor enable/disable");
  97. struct spi_control {
  98. unsigned short mode;
  99. };
  100. static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value)
  101. {
  102. int ret;
  103. u8 regs[3] = { LQ035_INDEX, 0, 0 };
  104. u8 dat[3] = { LQ035_DATA, 0, 0 };
  105. if (!spi)
  106. return -ENODEV;
  107. regs[2] = reg;
  108. dat[1] = value >> 8;
  109. dat[2] = value & 0xFF;
  110. ret = spi_write(spi, regs, ARRAY_SIZE(regs));
  111. ret |= spi_write(spi, dat, ARRAY_SIZE(dat));
  112. return ret;
  113. }
  114. static int __devinit lq035q1_spidev_probe(struct spi_device *spi)
  115. {
  116. int ret;
  117. struct spi_control *ctl;
  118. struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver,
  119. struct bfin_lq035q1fb_info,
  120. spidrv.driver);
  121. ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
  122. if (!ctl)
  123. return -ENOMEM;
  124. ctl->mode = (info->disp_info->mode &
  125. LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT;
  126. ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
  127. ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
  128. if (ret) {
  129. kfree(ctl);
  130. return ret;
  131. }
  132. spi_set_drvdata(spi, ctl);
  133. return 0;
  134. }
  135. static int lq035q1_spidev_remove(struct spi_device *spi)
  136. {
  137. return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
  138. }
  139. #ifdef CONFIG_PM
  140. static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state)
  141. {
  142. return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
  143. }
  144. static int lq035q1_spidev_resume(struct spi_device *spi)
  145. {
  146. int ret;
  147. struct spi_control *ctl = spi_get_drvdata(spi);
  148. ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
  149. if (ret)
  150. return ret;
  151. return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
  152. }
  153. #else
  154. # define lq035q1_spidev_suspend NULL
  155. # define lq035q1_spidev_resume NULL
  156. #endif
  157. /* Power down all displays on reboot, poweroff or halt */
  158. static void lq035q1_spidev_shutdown(struct spi_device *spi)
  159. {
  160. lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
  161. }
  162. static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
  163. {
  164. if (info->disp_info->use_bl)
  165. gpio_set_value(info->disp_info->gpio_bl, arg);
  166. return 0;
  167. }
  168. static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi)
  169. {
  170. unsigned long clocks_per_pix, cpld_pipeline_delay_cor;
  171. /*
  172. * Interface 16/18-bit TFT over an 8-bit wide PPI using a small
  173. * Programmable Logic Device (CPLD)
  174. * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
  175. */
  176. switch (fbi->disp_info->ppi_mode) {
  177. case USE_RGB565_16_BIT_PPI:
  178. fbi->lcd_bpp = 16;
  179. clocks_per_pix = 1;
  180. cpld_pipeline_delay_cor = 0;
  181. break;
  182. case USE_RGB565_8_BIT_PPI:
  183. fbi->lcd_bpp = 16;
  184. clocks_per_pix = 2;
  185. cpld_pipeline_delay_cor = 3;
  186. break;
  187. case USE_RGB888_8_BIT_PPI:
  188. fbi->lcd_bpp = 24;
  189. clocks_per_pix = 3;
  190. cpld_pipeline_delay_cor = 5;
  191. break;
  192. default:
  193. return -EINVAL;
  194. }
  195. /*
  196. * HS and VS timing parameters (all in number of PPI clk ticks)
  197. */
  198. fbi->h_actpix = (LCD_X_RES * clocks_per_pix); /* active horizontal pixel */
  199. fbi->h_period = (336 * clocks_per_pix); /* HS period */
  200. fbi->h_pulse = (2 * clocks_per_pix); /* HS pulse width */
  201. fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor); /* first valid pixel */
  202. fbi->v_lines = (LCD_Y_RES + U_LINE); /* total vertical lines */
  203. fbi->v_pulse = (2 * clocks_per_pix); /* VS pulse width (1-5 H_PERIODs) */
  204. fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */
  205. return 0;
  206. }
  207. static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
  208. {
  209. unsigned ppi_pmode;
  210. if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI)
  211. ppi_pmode = DLEN_16;
  212. else
  213. ppi_pmode = (DLEN_8 | PACK_EN);
  214. bfin_write_PPI_DELAY(fbi->h_start);
  215. bfin_write_PPI_COUNT(fbi->h_actpix - 1);
  216. bfin_write_PPI_FRAME(fbi->v_lines);
  217. bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */
  218. PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
  219. PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */
  220. ppi_pmode | /* 8/16 bit data length / PACK_EN? */
  221. PPI_POLS_1); /* faling edge syncs POLS */
  222. }
  223. static inline void bfin_lq035q1_disable_ppi(void)
  224. {
  225. bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);
  226. }
  227. static inline void bfin_lq035q1_enable_ppi(void)
  228. {
  229. bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
  230. }
  231. static void bfin_lq035q1_start_timers(void)
  232. {
  233. enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit);
  234. }
  235. static void bfin_lq035q1_stop_timers(void)
  236. {
  237. disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit);
  238. set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN |
  239. TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL |
  240. TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF);
  241. }
  242. static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi)
  243. {
  244. bfin_lq035q1_stop_timers();
  245. set_gptimer_period(TIMER_HSYNC_id, fbi->h_period);
  246. set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse);
  247. set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
  248. TIMER_TIN_SEL | TIMER_CLK_SEL|
  249. TIMER_EMU_RUN);
  250. set_gptimer_period(TIMER_VSYNC_id, fbi->v_period);
  251. set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse);
  252. set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
  253. TIMER_TIN_SEL | TIMER_CLK_SEL |
  254. TIMER_EMU_RUN);
  255. }
  256. static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
  257. {
  258. set_dma_config(CH_PPI,
  259. set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
  260. INTR_DISABLE, DIMENSION_2D,
  261. DATA_SIZE_16,
  262. DMA_NOSYNC_KEEP_DMA_BUF));
  263. set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE);
  264. set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
  265. set_dma_y_count(CH_PPI, fbi->v_lines);
  266. set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
  267. set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
  268. }
  269. static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
  270. P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
  271. P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
  272. P_PPI0_D6, P_PPI0_D7, P_PPI0_D8,
  273. P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
  274. P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
  275. P_PPI0_D15, 0};
  276. static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
  277. P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
  278. P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
  279. P_PPI0_D6, P_PPI0_D7, 0};
  280. static inline void bfin_lq035q1_free_ports(unsigned ppi16)
  281. {
  282. if (ppi16)
  283. peripheral_free_list(ppi0_req_16);
  284. else
  285. peripheral_free_list(ppi0_req_8);
  286. if (ANOMALY_05000400)
  287. gpio_free(P_IDENT(P_PPI0_FS3));
  288. }
  289. static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev,
  290. unsigned ppi16)
  291. {
  292. int ret;
  293. /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
  294. * Drive PPI_FS3 Low
  295. */
  296. if (ANOMALY_05000400) {
  297. int ret = gpio_request_one(P_IDENT(P_PPI0_FS3),
  298. GPIOF_OUT_INIT_LOW, "PPI_FS3");
  299. if (ret)
  300. return ret;
  301. }
  302. if (ppi16)
  303. ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME);
  304. else
  305. ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME);
  306. if (ret) {
  307. dev_err(&pdev->dev, "requesting peripherals failed\n");
  308. return -EFAULT;
  309. }
  310. return 0;
  311. }
  312. static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
  313. {
  314. struct bfin_lq035q1fb_info *fbi = info->par;
  315. spin_lock(&fbi->lock);
  316. fbi->lq035_open_cnt++;
  317. if (fbi->lq035_open_cnt <= 1) {
  318. bfin_lq035q1_disable_ppi();
  319. SSYNC();
  320. bfin_lq035q1_config_dma(fbi);
  321. bfin_lq035q1_config_ppi(fbi);
  322. bfin_lq035q1_init_timers(fbi);
  323. /* start dma */
  324. enable_dma(CH_PPI);
  325. bfin_lq035q1_enable_ppi();
  326. bfin_lq035q1_start_timers();
  327. lq035q1_backlight(fbi, 1);
  328. }
  329. spin_unlock(&fbi->lock);
  330. return 0;
  331. }
  332. static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
  333. {
  334. struct bfin_lq035q1fb_info *fbi = info->par;
  335. spin_lock(&fbi->lock);
  336. fbi->lq035_open_cnt--;
  337. if (fbi->lq035_open_cnt <= 0) {
  338. lq035q1_backlight(fbi, 0);
  339. bfin_lq035q1_disable_ppi();
  340. SSYNC();
  341. disable_dma(CH_PPI);
  342. bfin_lq035q1_stop_timers();
  343. }
  344. spin_unlock(&fbi->lock);
  345. return 0;
  346. }
  347. static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
  348. struct fb_info *info)
  349. {
  350. struct bfin_lq035q1fb_info *fbi = info->par;
  351. if (var->bits_per_pixel == fbi->lcd_bpp) {
  352. var->red.offset = info->var.red.offset;
  353. var->green.offset = info->var.green.offset;
  354. var->blue.offset = info->var.blue.offset;
  355. var->red.length = info->var.red.length;
  356. var->green.length = info->var.green.length;
  357. var->blue.length = info->var.blue.length;
  358. var->transp.offset = 0;
  359. var->transp.length = 0;
  360. var->transp.msb_right = 0;
  361. var->red.msb_right = 0;
  362. var->green.msb_right = 0;
  363. var->blue.msb_right = 0;
  364. } else {
  365. pr_debug("%s: depth not supported: %u BPP\n", __func__,
  366. var->bits_per_pixel);
  367. return -EINVAL;
  368. }
  369. if (info->var.xres != var->xres || info->var.yres != var->yres ||
  370. info->var.xres_virtual != var->xres_virtual ||
  371. info->var.yres_virtual != var->yres_virtual) {
  372. pr_debug("%s: Resolution not supported: X%u x Y%u \n",
  373. __func__, var->xres, var->yres);
  374. return -EINVAL;
  375. }
  376. /*
  377. * Memory limit
  378. */
  379. if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
  380. pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
  381. __func__, var->yres_virtual);
  382. return -ENOMEM;
  383. }
  384. return 0;
  385. }
  386. int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  387. {
  388. if (nocursor)
  389. return 0;
  390. else
  391. return -EINVAL; /* just to force soft_cursor() call */
  392. }
  393. static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green,
  394. u_int blue, u_int transp,
  395. struct fb_info *info)
  396. {
  397. if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
  398. return -EINVAL;
  399. if (info->var.grayscale) {
  400. /* grayscale = 0.30*R + 0.59*G + 0.11*B */
  401. red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
  402. }
  403. if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
  404. u32 value;
  405. /* Place color in the pseudopalette */
  406. if (regno > 16)
  407. return -EINVAL;
  408. red >>= (16 - info->var.red.length);
  409. green >>= (16 - info->var.green.length);
  410. blue >>= (16 - info->var.blue.length);
  411. value = (red << info->var.red.offset) |
  412. (green << info->var.green.offset) |
  413. (blue << info->var.blue.offset);
  414. value &= 0xFFFFFF;
  415. ((u32 *) (info->pseudo_palette))[regno] = value;
  416. }
  417. return 0;
  418. }
  419. static struct fb_ops bfin_lq035q1_fb_ops = {
  420. .owner = THIS_MODULE,
  421. .fb_open = bfin_lq035q1_fb_open,
  422. .fb_release = bfin_lq035q1_fb_release,
  423. .fb_check_var = bfin_lq035q1_fb_check_var,
  424. .fb_fillrect = cfb_fillrect,
  425. .fb_copyarea = cfb_copyarea,
  426. .fb_imageblit = cfb_imageblit,
  427. .fb_cursor = bfin_lq035q1_fb_cursor,
  428. .fb_setcolreg = bfin_lq035q1_fb_setcolreg,
  429. };
  430. static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id)
  431. {
  432. /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/
  433. u16 status = bfin_read_PPI_STATUS();
  434. bfin_write_PPI_STATUS(-1);
  435. if (status) {
  436. bfin_lq035q1_disable_ppi();
  437. disable_dma(CH_PPI);
  438. /* start dma */
  439. enable_dma(CH_PPI);
  440. bfin_lq035q1_enable_ppi();
  441. bfin_write_PPI_STATUS(-1);
  442. }
  443. return IRQ_HANDLED;
  444. }
  445. static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
  446. {
  447. struct bfin_lq035q1fb_info *info;
  448. struct fb_info *fbinfo;
  449. u32 active_video_mem_offset;
  450. int ret;
  451. ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
  452. if (ret < 0) {
  453. dev_err(&pdev->dev, "PPI DMA unavailable\n");
  454. goto out1;
  455. }
  456. fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev);
  457. if (!fbinfo) {
  458. ret = -ENOMEM;
  459. goto out2;
  460. }
  461. info = fbinfo->par;
  462. info->fb = fbinfo;
  463. info->dev = &pdev->dev;
  464. info->disp_info = pdev->dev.platform_data;
  465. platform_set_drvdata(pdev, fbinfo);
  466. ret = bfin_lq035q1_calc_timing(info);
  467. if (ret < 0) {
  468. dev_err(&pdev->dev, "Failed PPI Mode\n");
  469. goto out3;
  470. }
  471. strcpy(fbinfo->fix.id, DRIVER_NAME);
  472. fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
  473. fbinfo->fix.type_aux = 0;
  474. fbinfo->fix.xpanstep = 0;
  475. fbinfo->fix.ypanstep = 0;
  476. fbinfo->fix.ywrapstep = 0;
  477. fbinfo->fix.accel = FB_ACCEL_NONE;
  478. fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
  479. fbinfo->var.nonstd = 0;
  480. fbinfo->var.activate = FB_ACTIVATE_NOW;
  481. fbinfo->var.height = -1;
  482. fbinfo->var.width = -1;
  483. fbinfo->var.accel_flags = 0;
  484. fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
  485. fbinfo->var.xres = LCD_X_RES;
  486. fbinfo->var.xres_virtual = LCD_X_RES;
  487. fbinfo->var.yres = LCD_Y_RES;
  488. fbinfo->var.yres_virtual = LCD_Y_RES;
  489. fbinfo->var.bits_per_pixel = info->lcd_bpp;
  490. if (info->disp_info->mode & LQ035_BGR) {
  491. if (info->lcd_bpp == 24) {
  492. fbinfo->var.red.offset = 0;
  493. fbinfo->var.green.offset = 8;
  494. fbinfo->var.blue.offset = 16;
  495. } else {
  496. fbinfo->var.red.offset = 0;
  497. fbinfo->var.green.offset = 5;
  498. fbinfo->var.blue.offset = 11;
  499. }
  500. } else {
  501. if (info->lcd_bpp == 24) {
  502. fbinfo->var.red.offset = 16;
  503. fbinfo->var.green.offset = 8;
  504. fbinfo->var.blue.offset = 0;
  505. } else {
  506. fbinfo->var.red.offset = 11;
  507. fbinfo->var.green.offset = 5;
  508. fbinfo->var.blue.offset = 0;
  509. }
  510. }
  511. fbinfo->var.transp.offset = 0;
  512. if (info->lcd_bpp == 24) {
  513. fbinfo->var.red.length = 8;
  514. fbinfo->var.green.length = 8;
  515. fbinfo->var.blue.length = 8;
  516. } else {
  517. fbinfo->var.red.length = 5;
  518. fbinfo->var.green.length = 6;
  519. fbinfo->var.blue.length = 5;
  520. }
  521. fbinfo->var.transp.length = 0;
  522. active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8));
  523. fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8
  524. + active_video_mem_offset;
  525. fbinfo->fix.line_length = fbinfo->var.xres_virtual *
  526. fbinfo->var.bits_per_pixel / 8;
  527. fbinfo->fbops = &bfin_lq035q1_fb_ops;
  528. fbinfo->flags = FBINFO_FLAG_DEFAULT;
  529. info->fb_buffer =
  530. dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
  531. GFP_KERNEL);
  532. if (NULL == info->fb_buffer) {
  533. dev_err(&pdev->dev, "couldn't allocate dma buffer\n");
  534. ret = -ENOMEM;
  535. goto out3;
  536. }
  537. fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset;
  538. fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset;
  539. fbinfo->fbops = &bfin_lq035q1_fb_ops;
  540. fbinfo->pseudo_palette = &info->pseudo_pal;
  541. ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0);
  542. if (ret < 0) {
  543. dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n",
  544. BFIN_LCD_NBR_PALETTE_ENTRIES);
  545. goto out4;
  546. }
  547. ret = bfin_lq035q1_request_ports(pdev,
  548. info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI);
  549. if (ret) {
  550. dev_err(&pdev->dev, "couldn't request gpio port\n");
  551. goto out6;
  552. }
  553. info->irq = platform_get_irq(pdev, 0);
  554. if (info->irq < 0) {
  555. ret = -EINVAL;
  556. goto out7;
  557. }
  558. ret = request_irq(info->irq, bfin_lq035q1_irq_error, 0,
  559. DRIVER_NAME" PPI ERROR", info);
  560. if (ret < 0) {
  561. dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
  562. goto out7;
  563. }
  564. info->spidrv.driver.name = DRIVER_NAME"-spi";
  565. info->spidrv.probe = lq035q1_spidev_probe;
  566. info->spidrv.remove = __devexit_p(lq035q1_spidev_remove);
  567. info->spidrv.shutdown = lq035q1_spidev_shutdown;
  568. info->spidrv.suspend = lq035q1_spidev_suspend;
  569. info->spidrv.resume = lq035q1_spidev_resume;
  570. ret = spi_register_driver(&info->spidrv);
  571. if (ret < 0) {
  572. dev_err(&pdev->dev, "couldn't register SPI Interface\n");
  573. goto out8;
  574. }
  575. if (info->disp_info->use_bl) {
  576. ret = gpio_request_one(info->disp_info->gpio_bl,
  577. GPIOF_OUT_INIT_LOW, "LQ035 Backlight");
  578. if (ret) {
  579. dev_err(&pdev->dev, "failed to request GPIO %d\n",
  580. info->disp_info->gpio_bl);
  581. goto out9;
  582. }
  583. }
  584. ret = register_framebuffer(fbinfo);
  585. if (ret < 0) {
  586. dev_err(&pdev->dev, "unable to register framebuffer\n");
  587. goto out10;
  588. }
  589. dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
  590. LCD_X_RES, LCD_Y_RES, info->lcd_bpp);
  591. return 0;
  592. out10:
  593. if (info->disp_info->use_bl)
  594. gpio_free(info->disp_info->gpio_bl);
  595. out9:
  596. spi_unregister_driver(&info->spidrv);
  597. out8:
  598. free_irq(info->irq, info);
  599. out7:
  600. bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
  601. USE_RGB565_16_BIT_PPI);
  602. out6:
  603. fb_dealloc_cmap(&fbinfo->cmap);
  604. out4:
  605. dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
  606. info->dma_handle);
  607. out3:
  608. framebuffer_release(fbinfo);
  609. out2:
  610. free_dma(CH_PPI);
  611. out1:
  612. platform_set_drvdata(pdev, NULL);
  613. return ret;
  614. }
  615. static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
  616. {
  617. struct fb_info *fbinfo = platform_get_drvdata(pdev);
  618. struct bfin_lq035q1fb_info *info = fbinfo->par;
  619. if (info->disp_info->use_bl)
  620. gpio_free(info->disp_info->gpio_bl);
  621. spi_unregister_driver(&info->spidrv);
  622. unregister_framebuffer(fbinfo);
  623. free_dma(CH_PPI);
  624. free_irq(info->irq, info);
  625. if (info->fb_buffer != NULL)
  626. dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
  627. info->dma_handle);
  628. fb_dealloc_cmap(&fbinfo->cmap);
  629. bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
  630. USE_RGB565_16_BIT_PPI);
  631. platform_set_drvdata(pdev, NULL);
  632. framebuffer_release(fbinfo);
  633. dev_info(&pdev->dev, "unregistered LCD driver\n");
  634. return 0;
  635. }
  636. #ifdef CONFIG_PM
  637. static int bfin_lq035q1_suspend(struct device *dev)
  638. {
  639. struct fb_info *fbinfo = dev_get_drvdata(dev);
  640. struct bfin_lq035q1fb_info *info = fbinfo->par;
  641. if (info->lq035_open_cnt) {
  642. lq035q1_backlight(info, 0);
  643. bfin_lq035q1_disable_ppi();
  644. SSYNC();
  645. disable_dma(CH_PPI);
  646. bfin_lq035q1_stop_timers();
  647. bfin_write_PPI_STATUS(-1);
  648. }
  649. return 0;
  650. }
  651. static int bfin_lq035q1_resume(struct device *dev)
  652. {
  653. struct fb_info *fbinfo = dev_get_drvdata(dev);
  654. struct bfin_lq035q1fb_info *info = fbinfo->par;
  655. if (info->lq035_open_cnt) {
  656. bfin_lq035q1_disable_ppi();
  657. SSYNC();
  658. bfin_lq035q1_config_dma(info);
  659. bfin_lq035q1_config_ppi(info);
  660. bfin_lq035q1_init_timers(info);
  661. /* start dma */
  662. enable_dma(CH_PPI);
  663. bfin_lq035q1_enable_ppi();
  664. bfin_lq035q1_start_timers();
  665. lq035q1_backlight(info, 1);
  666. }
  667. return 0;
  668. }
  669. static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = {
  670. .suspend = bfin_lq035q1_suspend,
  671. .resume = bfin_lq035q1_resume,
  672. };
  673. #endif
  674. static struct platform_driver bfin_lq035q1_driver = {
  675. .probe = bfin_lq035q1_probe,
  676. .remove = __devexit_p(bfin_lq035q1_remove),
  677. .driver = {
  678. .name = DRIVER_NAME,
  679. #ifdef CONFIG_PM
  680. .pm = &bfin_lq035q1_dev_pm_ops,
  681. #endif
  682. },
  683. };
  684. static int __init bfin_lq035q1_driver_init(void)
  685. {
  686. return platform_driver_register(&bfin_lq035q1_driver);
  687. }
  688. module_init(bfin_lq035q1_driver_init);
  689. static void __exit bfin_lq035q1_driver_cleanup(void)
  690. {
  691. platform_driver_unregister(&bfin_lq035q1_driver);
  692. }
  693. module_exit(bfin_lq035q1_driver_cleanup);
  694. MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
  695. MODULE_LICENSE("GPL");