blob: 57dc1a0065c2d38948e87568f01f198ecf675fe1 [file] [log] [blame]
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +01001/*
2 * broadsheetfb.c -- FB driver for E-Ink Broadsheet controller
3 *
4 * Copyright (C) 2008, Jaya Kumar
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 *
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
11 *
12 * This driver is written to be used with the Broadsheet display controller.
13 *
14 * It is intended to be architecture independent. A board specific driver
15 * must be used to perform all the physical IO interactions.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/string.h>
23#include <linux/mm.h>
24#include <linux/slab.h>
25#include <linux/vmalloc.h>
26#include <linux/delay.h>
27#include <linux/interrupt.h>
28#include <linux/fb.h>
29#include <linux/init.h>
30#include <linux/platform_device.h>
31#include <linux/list.h>
32#include <linux/uaccess.h>
33
34#include <video/broadsheetfb.h>
35
Jaya Kumarc1c341a2010-03-10 15:21:24 -080036/* track panel specific parameters */
37struct panel_info {
38 int w;
39 int h;
40 u16 sdcfg;
41 u16 gdcfg;
42 u16 lutfmt;
43 u16 fsynclen;
44 u16 fendfbegin;
45 u16 lsynclen;
46 u16 lendlbegin;
47 u16 pixclk;
48};
49
50/* table of panel specific parameters to be indexed into by the board drivers */
51static struct panel_info panel_table[] = {
52 { /* standard 6" on TFT backplane */
53 .w = 800,
54 .h = 600,
55 .sdcfg = (100 | (1 << 8) | (1 << 9)),
56 .gdcfg = 2,
57 .lutfmt = (4 | (1 << 7)),
58 .fsynclen = 4,
59 .fendfbegin = (10 << 8) | 4,
60 .lsynclen = 10,
61 .lendlbegin = (100 << 8) | 4,
62 .pixclk = 6,
63 },
64 { /* custom 3.7" flexible on PET or steel */
65 .w = 320,
66 .h = 240,
67 .sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
68 .gdcfg = 3,
69 .lutfmt = (4 | (1 << 7)),
70 .fsynclen = 0,
71 .fendfbegin = (80 << 8) | 4,
72 .lsynclen = 10,
73 .lendlbegin = (80 << 8) | 20,
74 .pixclk = 14,
75 },
76 { /* standard 9.7" on TFT backplane */
77 .w = 1200,
78 .h = 825,
79 .sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
80 .gdcfg = 2,
81 .lutfmt = (4 | (1 << 7)),
82 .fsynclen = 0,
83 .fendfbegin = (4 << 8) | 4,
84 .lsynclen = 4,
85 .lendlbegin = (60 << 8) | 10,
86 .pixclk = 3,
87 },
88};
89
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +010090#define DPY_W 800
91#define DPY_H 600
92
93static struct fb_fix_screeninfo broadsheetfb_fix __devinitdata = {
94 .id = "broadsheetfb",
95 .type = FB_TYPE_PACKED_PIXELS,
96 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
97 .xpanstep = 0,
98 .ypanstep = 0,
99 .ywrapstep = 0,
100 .line_length = DPY_W,
101 .accel = FB_ACCEL_NONE,
102};
103
104static struct fb_var_screeninfo broadsheetfb_var __devinitdata = {
105 .xres = DPY_W,
106 .yres = DPY_H,
107 .xres_virtual = DPY_W,
108 .yres_virtual = DPY_H,
109 .bits_per_pixel = 8,
110 .grayscale = 1,
111 .red = { 0, 4, 0 },
112 .green = { 0, 4, 0 },
113 .blue = { 0, 4, 0 },
114 .transp = { 0, 0, 0 },
115};
116
117/* main broadsheetfb functions */
Jaya Kumar2afb1892010-03-10 15:21:41 -0800118static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100119{
120 par->board->set_ctl(par, BS_WR, 0);
121 par->board->set_hdb(par, data);
122 par->board->set_ctl(par, BS_WR, 1);
123}
124
Jaya Kumar2afb1892010-03-10 15:21:41 -0800125static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100126{
127 par->board->set_ctl(par, BS_DC, 0);
Jaya Kumar2afb1892010-03-10 15:21:41 -0800128 broadsheet_gpio_issue_data(par, data);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100129}
130
Jaya Kumar2afb1892010-03-10 15:21:41 -0800131static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100132{
133 par->board->wait_for_rdy(par);
134
135 par->board->set_ctl(par, BS_CS, 0);
Jaya Kumar2afb1892010-03-10 15:21:41 -0800136 broadsheet_gpio_issue_cmd(par, data);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100137 par->board->set_ctl(par, BS_DC, 1);
138 par->board->set_ctl(par, BS_CS, 1);
139}
140
Jaya Kumar2afb1892010-03-10 15:21:41 -0800141static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100142 int argc, u16 *argv)
143{
144 int i;
145
146 par->board->wait_for_rdy(par);
147
148 par->board->set_ctl(par, BS_CS, 0);
Jaya Kumar2afb1892010-03-10 15:21:41 -0800149 broadsheet_gpio_issue_cmd(par, cmd);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100150 par->board->set_ctl(par, BS_DC, 1);
151
152 for (i = 0; i < argc; i++)
Jaya Kumar2afb1892010-03-10 15:21:41 -0800153 broadsheet_gpio_issue_data(par, argv[i]);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100154 par->board->set_ctl(par, BS_CS, 1);
155}
156
Jaya Kumar2afb1892010-03-10 15:21:41 -0800157static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
158 int argc, u16 *argv)
159{
160 int i;
161
162 par->board->mmio_write(par, BS_MMIO_CMD, cmd);
163
164 for (i = 0; i < argc; i++)
165 par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
166}
167
168static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
169{
170 if (par->board->mmio_write)
171 par->board->mmio_write(par, BS_MMIO_CMD, data);
172 else
173 broadsheet_gpio_send_command(par, data);
174}
175
176static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
177 int argc, u16 *argv)
178{
179 if (par->board->mmio_write)
180 broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
181 else
182 broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
183}
184
185static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100186 u16 *data)
187{
188 int i;
189 u16 tmp;
190
191 par->board->set_ctl(par, BS_CS, 0);
192 par->board->set_ctl(par, BS_DC, 1);
193
194 for (i = 0; i < size; i++) {
195 par->board->set_ctl(par, BS_WR, 0);
196 tmp = (data[i] & 0x0F) << 4;
197 tmp |= (data[i] & 0x0F00) << 4;
198 par->board->set_hdb(par, tmp);
199 par->board->set_ctl(par, BS_WR, 1);
200 }
201
202 par->board->set_ctl(par, BS_CS, 1);
203}
204
Jaya Kumar2afb1892010-03-10 15:21:41 -0800205static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
206 u16 *data)
207{
208 int i;
209 u16 tmp;
210
211 for (i = 0; i < size; i++) {
212 tmp = (data[i] & 0x0F) << 4;
213 tmp |= (data[i] & 0x0F00) << 4;
214 par->board->mmio_write(par, BS_MMIO_DATA, tmp);
215 }
216
217}
218
219static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
220 u16 *data)
221{
222 if (par->board->mmio_write)
223 broadsheet_mmio_burst_write(par, size, data);
224 else
225 broadsheet_gpio_burst_write(par, size, data);
226}
227
228static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100229{
230 u16 res;
231 /* wait for ready to go hi. (lo is busy) */
232 par->board->wait_for_rdy(par);
233
234 /* cs lo, dc lo for cmd, we lo for each data, db as usual */
235 par->board->set_ctl(par, BS_DC, 1);
236 par->board->set_ctl(par, BS_CS, 0);
237 par->board->set_ctl(par, BS_WR, 0);
238
239 res = par->board->get_hdb(par);
240
241 /* strobe wr */
242 par->board->set_ctl(par, BS_WR, 1);
243 par->board->set_ctl(par, BS_CS, 1);
244
245 return res;
246}
247
Jaya Kumar2afb1892010-03-10 15:21:41 -0800248
249static u16 broadsheet_get_data(struct broadsheetfb_par *par)
250{
251 if (par->board->mmio_read)
252 return par->board->mmio_read(par);
253 else
254 return broadsheet_gpio_get_data(par);
255}
256
257static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100258 u16 data)
259{
260 /* wait for ready to go hi. (lo is busy) */
261 par->board->wait_for_rdy(par);
262
263 /* cs lo, dc lo for cmd, we lo for each data, db as usual */
264 par->board->set_ctl(par, BS_CS, 0);
265
Jaya Kumar2afb1892010-03-10 15:21:41 -0800266 broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100267
268 par->board->set_ctl(par, BS_DC, 1);
269
Jaya Kumar2afb1892010-03-10 15:21:41 -0800270 broadsheet_gpio_issue_data(par, reg);
271 broadsheet_gpio_issue_data(par, data);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100272
273 par->board->set_ctl(par, BS_CS, 1);
274}
275
Jaya Kumar2afb1892010-03-10 15:21:41 -0800276static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
277 u16 data)
278{
279 par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
280 par->board->mmio_write(par, BS_MMIO_DATA, reg);
281 par->board->mmio_write(par, BS_MMIO_DATA, data);
282
283}
284
285static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
286 u16 data)
287{
288 if (par->board->mmio_write)
289 broadsheet_mmio_write_reg(par, reg, data);
290 else
291 broadsheet_gpio_write_reg(par, reg, data);
292}
293
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800294static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
295 u32 data)
296{
297 broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
298 broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
299}
300
301
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100302static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
303{
Jaya Kumar2afb1892010-03-10 15:21:41 -0800304 broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);
305 par->board->wait_for_rdy(par);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100306 return broadsheet_get_data(par);
307}
308
309static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
310{
311 u16 args[5];
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800312 int xres = par->info->var.xres;
313 int yres = par->info->var.yres;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100314
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800315 args[0] = panel_table[par->panel_index].w;
316 args[1] = panel_table[par->panel_index].h;
317 args[2] = panel_table[par->panel_index].sdcfg;
318 args[3] = panel_table[par->panel_index].gdcfg;
319 args[4] = panel_table[par->panel_index].lutfmt;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100320 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
321
322 /* did the controller really set it? */
323 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
324
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800325 args[0] = panel_table[par->panel_index].fsynclen;
326 args[1] = panel_table[par->panel_index].fendfbegin;
327 args[2] = panel_table[par->panel_index].lsynclen;
328 args[3] = panel_table[par->panel_index].lendlbegin;
329 args[4] = panel_table[par->panel_index].pixclk;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100330 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
331
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800332 broadsheet_write_reg32(par, 0x310, xres*yres*2);
333
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100334 /* setup waveform */
335 args[0] = 0x886;
336 args[1] = 0;
337 broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args);
338
339 broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR);
340
341 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
342
343 broadsheet_write_reg(par, 0x330, 0x84);
344
345 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
346
347 args[0] = (0x3 << 4);
348 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
349
350 args[0] = 0x154;
351 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
352
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800353 broadsheet_burst_write(par, (panel_table[par->panel_index].w *
354 panel_table[par->panel_index].h)/2,
355 (u16 *) par->info->screen_base);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100356
357 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
358
359 args[0] = 0x4300;
360 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
361
362 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
363
364 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
365
366 par->board->wait_for_rdy(par);
367}
368
369static void __devinit broadsheet_init(struct broadsheetfb_par *par)
370{
371 broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
372 /* the controller needs a second */
373 msleep(1000);
374 broadsheet_init_display(par);
375}
376
377static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
378 u16 y1, u16 y2)
379{
380 u16 args[5];
381 unsigned char *buf = (unsigned char *)par->info->screen_base;
382
383 /* y1 must be a multiple of 4 so drop the lower bits */
384 y1 &= 0xFFFC;
385 /* y2 must be a multiple of 4 , but - 1 so up the lower bits */
386 y2 |= 0x0003;
387
388 args[0] = 0x3 << 4;
389 args[1] = 0;
390 args[2] = y1;
391 args[3] = cpu_to_le16(par->info->var.xres);
392 args[4] = y2;
393 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args);
394
395 args[0] = 0x154;
396 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
397
398 buf += y1 * par->info->var.xres;
399 broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2,
400 (u16 *) buf);
401
402 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
403
404 args[0] = 0x4300;
405 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
406
407 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
408
409 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
410
411 par->board->wait_for_rdy(par);
412
413}
414
415static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
416{
417 u16 args[5];
418
419 args[0] = 0x3 << 4;
420 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
421
422 args[0] = 0x154;
423 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800424 broadsheet_burst_write(par, (panel_table[par->panel_index].w *
425 panel_table[par->panel_index].h)/2,
426 (u16 *) par->info->screen_base);
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100427
428 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
429
430 args[0] = 0x4300;
431 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
432
433 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
434
435 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
436
437 par->board->wait_for_rdy(par);
438
439}
440
441/* this is called back from the deferred io workqueue */
442static void broadsheetfb_dpy_deferred_io(struct fb_info *info,
443 struct list_head *pagelist)
444{
445 u16 y1 = 0, h = 0;
446 int prev_index = -1;
447 struct page *cur;
448 struct fb_deferred_io *fbdefio = info->fbdefio;
449 int h_inc;
450 u16 yres = info->var.yres;
451 u16 xres = info->var.xres;
452
453 /* height increment is fixed per page */
454 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
455
456 /* walk the written page list and swizzle the data */
457 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
458 if (prev_index < 0) {
459 /* just starting so assign first page */
460 y1 = (cur->index << PAGE_SHIFT) / xres;
461 h = h_inc;
462 } else if ((prev_index + 1) == cur->index) {
463 /* this page is consecutive so increase our height */
464 h += h_inc;
465 } else {
466 /* page not consecutive, issue previous update first */
467 broadsheetfb_dpy_update_pages(info->par, y1, y1 + h);
468 /* start over with our non consecutive page */
469 y1 = (cur->index << PAGE_SHIFT) / xres;
470 h = h_inc;
471 }
472 prev_index = cur->index;
473 }
474
475 /* if we still have any pages to update we do so now */
476 if (h >= yres) {
477 /* its a full screen update, just do it */
478 broadsheetfb_dpy_update(info->par);
479 } else {
480 broadsheetfb_dpy_update_pages(info->par, y1,
481 min((u16) (y1 + h), yres));
482 }
483}
484
485static void broadsheetfb_fillrect(struct fb_info *info,
486 const struct fb_fillrect *rect)
487{
488 struct broadsheetfb_par *par = info->par;
489
490 sys_fillrect(info, rect);
491
492 broadsheetfb_dpy_update(par);
493}
494
495static void broadsheetfb_copyarea(struct fb_info *info,
496 const struct fb_copyarea *area)
497{
498 struct broadsheetfb_par *par = info->par;
499
500 sys_copyarea(info, area);
501
502 broadsheetfb_dpy_update(par);
503}
504
505static void broadsheetfb_imageblit(struct fb_info *info,
506 const struct fb_image *image)
507{
508 struct broadsheetfb_par *par = info->par;
509
510 sys_imageblit(info, image);
511
512 broadsheetfb_dpy_update(par);
513}
514
515/*
516 * this is the slow path from userspace. they can seek and write to
517 * the fb. it's inefficient to do anything less than a full screen draw
518 */
519static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf,
520 size_t count, loff_t *ppos)
521{
522 struct broadsheetfb_par *par = info->par;
523 unsigned long p = *ppos;
524 void *dst;
525 int err = 0;
526 unsigned long total_size;
527
528 if (info->state != FBINFO_STATE_RUNNING)
529 return -EPERM;
530
531 total_size = info->fix.smem_len;
532
533 if (p > total_size)
534 return -EFBIG;
535
536 if (count > total_size) {
537 err = -EFBIG;
538 count = total_size;
539 }
540
541 if (count + p > total_size) {
542 if (!err)
543 err = -ENOSPC;
544
545 count = total_size - p;
546 }
547
548 dst = (void *)(info->screen_base + p);
549
550 if (copy_from_user(dst, buf, count))
551 err = -EFAULT;
552
553 if (!err)
554 *ppos += count;
555
556 broadsheetfb_dpy_update(par);
557
558 return (err) ? err : count;
559}
560
561static struct fb_ops broadsheetfb_ops = {
562 .owner = THIS_MODULE,
563 .fb_read = fb_sys_read,
564 .fb_write = broadsheetfb_write,
565 .fb_fillrect = broadsheetfb_fillrect,
566 .fb_copyarea = broadsheetfb_copyarea,
567 .fb_imageblit = broadsheetfb_imageblit,
568};
569
570static struct fb_deferred_io broadsheetfb_defio = {
571 .delay = HZ/4,
572 .deferred_io = broadsheetfb_dpy_deferred_io,
573};
574
575static int __devinit broadsheetfb_probe(struct platform_device *dev)
576{
577 struct fb_info *info;
578 struct broadsheet_board *board;
579 int retval = -ENOMEM;
580 int videomemorysize;
581 unsigned char *videomemory;
582 struct broadsheetfb_par *par;
583 int i;
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800584 int dpyw, dpyh;
585 int panel_index;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100586
587 /* pick up board specific routines */
588 board = dev->dev.platform_data;
589 if (!board)
590 return -EINVAL;
591
592 /* try to count device specific driver, if can't, platform recalls */
593 if (!try_module_get(board->owner))
594 return -ENODEV;
595
596 info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev);
597 if (!info)
598 goto err;
599
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800600 switch (board->get_panel_type()) {
601 case 37:
602 panel_index = 1;
603 break;
604 case 97:
605 panel_index = 2;
606 break;
607 case 6:
608 default:
609 panel_index = 0;
610 break;
611 }
612
613 dpyw = panel_table[panel_index].w;
614 dpyh = panel_table[panel_index].h;
615
616 videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
617
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100618 videomemory = vmalloc(videomemorysize);
619 if (!videomemory)
620 goto err_fb_rel;
621
622 memset(videomemory, 0, videomemorysize);
623
624 info->screen_base = (char *)videomemory;
625 info->fbops = &broadsheetfb_ops;
626
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800627 broadsheetfb_var.xres = dpyw;
628 broadsheetfb_var.yres = dpyh;
629 broadsheetfb_var.xres_virtual = dpyw;
630 broadsheetfb_var.yres_virtual = dpyh;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100631 info->var = broadsheetfb_var;
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800632
633 broadsheetfb_fix.line_length = dpyw;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100634 info->fix = broadsheetfb_fix;
635 info->fix.smem_len = videomemorysize;
636 par = info->par;
Jaya Kumarc1c341a2010-03-10 15:21:24 -0800637 par->panel_index = panel_index;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100638 par->info = info;
639 par->board = board;
640 par->write_reg = broadsheet_write_reg;
641 par->read_reg = broadsheet_read_reg;
642 init_waitqueue_head(&par->waitq);
643
Konrad Rzeszutek Wilka9b5ff92009-12-03 10:31:58 -0500644 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
Jaya Kumar0d4ff4d2009-01-01 17:49:19 +0100645
646 info->fbdefio = &broadsheetfb_defio;
647 fb_deferred_io_init(info);
648
649 retval = fb_alloc_cmap(&info->cmap, 16, 0);
650 if (retval < 0) {
651 dev_err(&dev->dev, "Failed to allocate colormap\n");
652 goto err_vfree;
653 }
654
655 /* set cmap */
656 for (i = 0; i < 16; i++)
657 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32;
658 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16);
659 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16);
660
661 retval = par->board->setup_irq(info);
662 if (retval < 0)
663 goto err_cmap;
664
665 /* this inits the dpy */
666 retval = board->init(par);
667 if (retval < 0)
668 goto err_free_irq;
669
670 broadsheet_init(par);
671
672 retval = register_framebuffer(info);
673 if (retval < 0)
674 goto err_free_irq;
675 platform_set_drvdata(dev, info);
676
677 printk(KERN_INFO
678 "fb%d: Broadsheet frame buffer, using %dK of video memory\n",
679 info->node, videomemorysize >> 10);
680
681
682 return 0;
683
684err_free_irq:
685 board->cleanup(par);
686err_cmap:
687 fb_dealloc_cmap(&info->cmap);
688err_vfree:
689 vfree(videomemory);
690err_fb_rel:
691 framebuffer_release(info);
692err:
693 module_put(board->owner);
694 return retval;
695
696}
697
698static int __devexit broadsheetfb_remove(struct platform_device *dev)
699{
700 struct fb_info *info = platform_get_drvdata(dev);
701
702 if (info) {
703 struct broadsheetfb_par *par = info->par;
704 unregister_framebuffer(info);
705 fb_deferred_io_cleanup(info);
706 par->board->cleanup(par);
707 fb_dealloc_cmap(&info->cmap);
708 vfree((void *)info->screen_base);
709 module_put(par->board->owner);
710 framebuffer_release(info);
711 }
712 return 0;
713}
714
715static struct platform_driver broadsheetfb_driver = {
716 .probe = broadsheetfb_probe,
717 .remove = broadsheetfb_remove,
718 .driver = {
719 .owner = THIS_MODULE,
720 .name = "broadsheetfb",
721 },
722};
723
724static int __init broadsheetfb_init(void)
725{
726 return platform_driver_register(&broadsheetfb_driver);
727}
728
729static void __exit broadsheetfb_exit(void)
730{
731 platform_driver_unregister(&broadsheetfb_driver);
732}
733
734module_init(broadsheetfb_init);
735module_exit(broadsheetfb_exit);
736
737MODULE_DESCRIPTION("fbdev driver for Broadsheet controller");
738MODULE_AUTHOR("Jaya Kumar");
739MODULE_LICENSE("GPL");