Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31 568 lines 14 kB view raw
1/* 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 36/* Display specific information */ 37#define DPY_W 800 38#define DPY_H 600 39 40static struct fb_fix_screeninfo broadsheetfb_fix __devinitdata = { 41 .id = "broadsheetfb", 42 .type = FB_TYPE_PACKED_PIXELS, 43 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, 44 .xpanstep = 0, 45 .ypanstep = 0, 46 .ywrapstep = 0, 47 .line_length = DPY_W, 48 .accel = FB_ACCEL_NONE, 49}; 50 51static struct fb_var_screeninfo broadsheetfb_var __devinitdata = { 52 .xres = DPY_W, 53 .yres = DPY_H, 54 .xres_virtual = DPY_W, 55 .yres_virtual = DPY_H, 56 .bits_per_pixel = 8, 57 .grayscale = 1, 58 .red = { 0, 4, 0 }, 59 .green = { 0, 4, 0 }, 60 .blue = { 0, 4, 0 }, 61 .transp = { 0, 0, 0 }, 62}; 63 64/* main broadsheetfb functions */ 65static void broadsheet_issue_data(struct broadsheetfb_par *par, u16 data) 66{ 67 par->board->set_ctl(par, BS_WR, 0); 68 par->board->set_hdb(par, data); 69 par->board->set_ctl(par, BS_WR, 1); 70} 71 72static void broadsheet_issue_cmd(struct broadsheetfb_par *par, u16 data) 73{ 74 par->board->set_ctl(par, BS_DC, 0); 75 broadsheet_issue_data(par, data); 76} 77 78static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data) 79{ 80 par->board->wait_for_rdy(par); 81 82 par->board->set_ctl(par, BS_CS, 0); 83 broadsheet_issue_cmd(par, data); 84 par->board->set_ctl(par, BS_DC, 1); 85 par->board->set_ctl(par, BS_CS, 1); 86} 87 88static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd, 89 int argc, u16 *argv) 90{ 91 int i; 92 93 par->board->wait_for_rdy(par); 94 95 par->board->set_ctl(par, BS_CS, 0); 96 broadsheet_issue_cmd(par, cmd); 97 par->board->set_ctl(par, BS_DC, 1); 98 99 for (i = 0; i < argc; i++) 100 broadsheet_issue_data(par, argv[i]); 101 par->board->set_ctl(par, BS_CS, 1); 102} 103 104static void broadsheet_burst_write(struct broadsheetfb_par *par, int size, 105 u16 *data) 106{ 107 int i; 108 u16 tmp; 109 110 par->board->set_ctl(par, BS_CS, 0); 111 par->board->set_ctl(par, BS_DC, 1); 112 113 for (i = 0; i < size; i++) { 114 par->board->set_ctl(par, BS_WR, 0); 115 tmp = (data[i] & 0x0F) << 4; 116 tmp |= (data[i] & 0x0F00) << 4; 117 par->board->set_hdb(par, tmp); 118 par->board->set_ctl(par, BS_WR, 1); 119 } 120 121 par->board->set_ctl(par, BS_CS, 1); 122} 123 124static u16 broadsheet_get_data(struct broadsheetfb_par *par) 125{ 126 u16 res; 127 /* wait for ready to go hi. (lo is busy) */ 128 par->board->wait_for_rdy(par); 129 130 /* cs lo, dc lo for cmd, we lo for each data, db as usual */ 131 par->board->set_ctl(par, BS_DC, 1); 132 par->board->set_ctl(par, BS_CS, 0); 133 par->board->set_ctl(par, BS_WR, 0); 134 135 res = par->board->get_hdb(par); 136 137 /* strobe wr */ 138 par->board->set_ctl(par, BS_WR, 1); 139 par->board->set_ctl(par, BS_CS, 1); 140 141 return res; 142} 143 144static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg, 145 u16 data) 146{ 147 /* wait for ready to go hi. (lo is busy) */ 148 par->board->wait_for_rdy(par); 149 150 /* cs lo, dc lo for cmd, we lo for each data, db as usual */ 151 par->board->set_ctl(par, BS_CS, 0); 152 153 broadsheet_issue_cmd(par, BS_CMD_WR_REG); 154 155 par->board->set_ctl(par, BS_DC, 1); 156 157 broadsheet_issue_data(par, reg); 158 broadsheet_issue_data(par, data); 159 160 par->board->set_ctl(par, BS_CS, 1); 161} 162 163static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg) 164{ 165 broadsheet_send_command(par, reg); 166 msleep(100); 167 return broadsheet_get_data(par); 168} 169 170static void __devinit broadsheet_init_display(struct broadsheetfb_par *par) 171{ 172 u16 args[5]; 173 174 args[0] = DPY_W; 175 args[1] = DPY_H; 176 args[2] = (100 | (1 << 8) | (1 << 9)); /* sdcfg */ 177 args[3] = 2; /* gdrv cfg */ 178 args[4] = (4 | (1 << 7)); /* lut index format */ 179 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args); 180 181 /* did the controller really set it? */ 182 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args); 183 184 args[0] = 4; /* fsync len */ 185 args[1] = (10 << 8) | 4; /* fend/fbegin len */ 186 args[2] = 10; /* line sync len */ 187 args[3] = (100 << 8) | 4; /* line end/begin len */ 188 args[4] = 6; /* pixel clock cfg */ 189 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args); 190 191 /* setup waveform */ 192 args[0] = 0x886; 193 args[1] = 0; 194 broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args); 195 196 broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR); 197 198 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 199 200 broadsheet_write_reg(par, 0x330, 0x84); 201 202 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 203 204 args[0] = (0x3 << 4); 205 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); 206 207 args[0] = 0x154; 208 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 209 210 broadsheet_burst_write(par, DPY_W*DPY_H/2, 211 (u16 *) par->info->screen_base); 212 213 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 214 215 args[0] = 0x4300; 216 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 217 218 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 219 220 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 221 222 par->board->wait_for_rdy(par); 223} 224 225static void __devinit broadsheet_init(struct broadsheetfb_par *par) 226{ 227 broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN); 228 /* the controller needs a second */ 229 msleep(1000); 230 broadsheet_init_display(par); 231} 232 233static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par, 234 u16 y1, u16 y2) 235{ 236 u16 args[5]; 237 unsigned char *buf = (unsigned char *)par->info->screen_base; 238 239 /* y1 must be a multiple of 4 so drop the lower bits */ 240 y1 &= 0xFFFC; 241 /* y2 must be a multiple of 4 , but - 1 so up the lower bits */ 242 y2 |= 0x0003; 243 244 args[0] = 0x3 << 4; 245 args[1] = 0; 246 args[2] = y1; 247 args[3] = cpu_to_le16(par->info->var.xres); 248 args[4] = y2; 249 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args); 250 251 args[0] = 0x154; 252 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 253 254 buf += y1 * par->info->var.xres; 255 broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2, 256 (u16 *) buf); 257 258 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 259 260 args[0] = 0x4300; 261 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 262 263 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 264 265 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 266 267 par->board->wait_for_rdy(par); 268 269} 270 271static void broadsheetfb_dpy_update(struct broadsheetfb_par *par) 272{ 273 u16 args[5]; 274 275 args[0] = 0x3 << 4; 276 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); 277 278 args[0] = 0x154; 279 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 280 broadsheet_burst_write(par, DPY_W*DPY_H/2, 281 (u16 *) par->info->screen_base); 282 283 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 284 285 args[0] = 0x4300; 286 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 287 288 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 289 290 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 291 292 par->board->wait_for_rdy(par); 293 294} 295 296/* this is called back from the deferred io workqueue */ 297static void broadsheetfb_dpy_deferred_io(struct fb_info *info, 298 struct list_head *pagelist) 299{ 300 u16 y1 = 0, h = 0; 301 int prev_index = -1; 302 struct page *cur; 303 struct fb_deferred_io *fbdefio = info->fbdefio; 304 int h_inc; 305 u16 yres = info->var.yres; 306 u16 xres = info->var.xres; 307 308 /* height increment is fixed per page */ 309 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); 310 311 /* walk the written page list and swizzle the data */ 312 list_for_each_entry(cur, &fbdefio->pagelist, lru) { 313 if (prev_index < 0) { 314 /* just starting so assign first page */ 315 y1 = (cur->index << PAGE_SHIFT) / xres; 316 h = h_inc; 317 } else if ((prev_index + 1) == cur->index) { 318 /* this page is consecutive so increase our height */ 319 h += h_inc; 320 } else { 321 /* page not consecutive, issue previous update first */ 322 broadsheetfb_dpy_update_pages(info->par, y1, y1 + h); 323 /* start over with our non consecutive page */ 324 y1 = (cur->index << PAGE_SHIFT) / xres; 325 h = h_inc; 326 } 327 prev_index = cur->index; 328 } 329 330 /* if we still have any pages to update we do so now */ 331 if (h >= yres) { 332 /* its a full screen update, just do it */ 333 broadsheetfb_dpy_update(info->par); 334 } else { 335 broadsheetfb_dpy_update_pages(info->par, y1, 336 min((u16) (y1 + h), yres)); 337 } 338} 339 340static void broadsheetfb_fillrect(struct fb_info *info, 341 const struct fb_fillrect *rect) 342{ 343 struct broadsheetfb_par *par = info->par; 344 345 sys_fillrect(info, rect); 346 347 broadsheetfb_dpy_update(par); 348} 349 350static void broadsheetfb_copyarea(struct fb_info *info, 351 const struct fb_copyarea *area) 352{ 353 struct broadsheetfb_par *par = info->par; 354 355 sys_copyarea(info, area); 356 357 broadsheetfb_dpy_update(par); 358} 359 360static void broadsheetfb_imageblit(struct fb_info *info, 361 const struct fb_image *image) 362{ 363 struct broadsheetfb_par *par = info->par; 364 365 sys_imageblit(info, image); 366 367 broadsheetfb_dpy_update(par); 368} 369 370/* 371 * this is the slow path from userspace. they can seek and write to 372 * the fb. it's inefficient to do anything less than a full screen draw 373 */ 374static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf, 375 size_t count, loff_t *ppos) 376{ 377 struct broadsheetfb_par *par = info->par; 378 unsigned long p = *ppos; 379 void *dst; 380 int err = 0; 381 unsigned long total_size; 382 383 if (info->state != FBINFO_STATE_RUNNING) 384 return -EPERM; 385 386 total_size = info->fix.smem_len; 387 388 if (p > total_size) 389 return -EFBIG; 390 391 if (count > total_size) { 392 err = -EFBIG; 393 count = total_size; 394 } 395 396 if (count + p > total_size) { 397 if (!err) 398 err = -ENOSPC; 399 400 count = total_size - p; 401 } 402 403 dst = (void *)(info->screen_base + p); 404 405 if (copy_from_user(dst, buf, count)) 406 err = -EFAULT; 407 408 if (!err) 409 *ppos += count; 410 411 broadsheetfb_dpy_update(par); 412 413 return (err) ? err : count; 414} 415 416static struct fb_ops broadsheetfb_ops = { 417 .owner = THIS_MODULE, 418 .fb_read = fb_sys_read, 419 .fb_write = broadsheetfb_write, 420 .fb_fillrect = broadsheetfb_fillrect, 421 .fb_copyarea = broadsheetfb_copyarea, 422 .fb_imageblit = broadsheetfb_imageblit, 423}; 424 425static struct fb_deferred_io broadsheetfb_defio = { 426 .delay = HZ/4, 427 .deferred_io = broadsheetfb_dpy_deferred_io, 428}; 429 430static int __devinit broadsheetfb_probe(struct platform_device *dev) 431{ 432 struct fb_info *info; 433 struct broadsheet_board *board; 434 int retval = -ENOMEM; 435 int videomemorysize; 436 unsigned char *videomemory; 437 struct broadsheetfb_par *par; 438 int i; 439 440 /* pick up board specific routines */ 441 board = dev->dev.platform_data; 442 if (!board) 443 return -EINVAL; 444 445 /* try to count device specific driver, if can't, platform recalls */ 446 if (!try_module_get(board->owner)) 447 return -ENODEV; 448 449 info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev); 450 if (!info) 451 goto err; 452 453 videomemorysize = (DPY_W*DPY_H); 454 videomemory = vmalloc(videomemorysize); 455 if (!videomemory) 456 goto err_fb_rel; 457 458 memset(videomemory, 0, videomemorysize); 459 460 info->screen_base = (char *)videomemory; 461 info->fbops = &broadsheetfb_ops; 462 463 info->var = broadsheetfb_var; 464 info->fix = broadsheetfb_fix; 465 info->fix.smem_len = videomemorysize; 466 par = info->par; 467 par->info = info; 468 par->board = board; 469 par->write_reg = broadsheet_write_reg; 470 par->read_reg = broadsheet_read_reg; 471 init_waitqueue_head(&par->waitq); 472 473 info->flags = FBINFO_FLAG_DEFAULT; 474 475 info->fbdefio = &broadsheetfb_defio; 476 fb_deferred_io_init(info); 477 478 retval = fb_alloc_cmap(&info->cmap, 16, 0); 479 if (retval < 0) { 480 dev_err(&dev->dev, "Failed to allocate colormap\n"); 481 goto err_vfree; 482 } 483 484 /* set cmap */ 485 for (i = 0; i < 16; i++) 486 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32; 487 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16); 488 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16); 489 490 retval = par->board->setup_irq(info); 491 if (retval < 0) 492 goto err_cmap; 493 494 /* this inits the dpy */ 495 retval = board->init(par); 496 if (retval < 0) 497 goto err_free_irq; 498 499 broadsheet_init(par); 500 501 retval = register_framebuffer(info); 502 if (retval < 0) 503 goto err_free_irq; 504 platform_set_drvdata(dev, info); 505 506 printk(KERN_INFO 507 "fb%d: Broadsheet frame buffer, using %dK of video memory\n", 508 info->node, videomemorysize >> 10); 509 510 511 return 0; 512 513err_free_irq: 514 board->cleanup(par); 515err_cmap: 516 fb_dealloc_cmap(&info->cmap); 517err_vfree: 518 vfree(videomemory); 519err_fb_rel: 520 framebuffer_release(info); 521err: 522 module_put(board->owner); 523 return retval; 524 525} 526 527static int __devexit broadsheetfb_remove(struct platform_device *dev) 528{ 529 struct fb_info *info = platform_get_drvdata(dev); 530 531 if (info) { 532 struct broadsheetfb_par *par = info->par; 533 unregister_framebuffer(info); 534 fb_deferred_io_cleanup(info); 535 par->board->cleanup(par); 536 fb_dealloc_cmap(&info->cmap); 537 vfree((void *)info->screen_base); 538 module_put(par->board->owner); 539 framebuffer_release(info); 540 } 541 return 0; 542} 543 544static struct platform_driver broadsheetfb_driver = { 545 .probe = broadsheetfb_probe, 546 .remove = broadsheetfb_remove, 547 .driver = { 548 .owner = THIS_MODULE, 549 .name = "broadsheetfb", 550 }, 551}; 552 553static int __init broadsheetfb_init(void) 554{ 555 return platform_driver_register(&broadsheetfb_driver); 556} 557 558static void __exit broadsheetfb_exit(void) 559{ 560 platform_driver_unregister(&broadsheetfb_driver); 561} 562 563module_init(broadsheetfb_init); 564module_exit(broadsheetfb_exit); 565 566MODULE_DESCRIPTION("fbdev driver for Broadsheet controller"); 567MODULE_AUTHOR("Jaya Kumar"); 568MODULE_LICENSE("GPL");