1 /* 2 * Mainly by David Woodhouse, somewhat modified by Jordan Crouse 3 * 4 * Copyright © 2006-2007 Red Hat, Inc. 5 * Copyright © 2006-2007 Advanced Micro Devices, Inc. 6 * Copyright © 2009 VIA Technology, Inc. 7 * Copyright (c) 2010-2011 Andres Salomon <dilinger@queued.net> 8 * 9 * This program is free software. You can redistribute it and/or 10 * modify it under the terms of version 2 of the GNU General Public 11 * License as published by the Free Software Foundation. 12 */ 13 14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16 #include <linux/kernel.h> 17 #include <linux/fb.h> 18 #include <linux/console.h> 19 #include <linux/i2c.h> 20 #include <linux/platform_device.h> 21 #include <linux/pci.h> 22 #include <linux/pci_ids.h> 23 #include <linux/interrupt.h> 24 #include <linux/delay.h> 25 #include <linux/module.h> 26 #include <linux/backlight.h> 27 #include <linux/device.h> 28 #include <linux/uaccess.h> 29 #include <linux/ctype.h> 30 #include <linux/reboot.h> 31 #include <linux/olpc-ec.h> 32 #include <asm/tsc.h> 33 #include <asm/olpc.h> 34 35 #include "olpc_dcon.h" 36 37 /* Module definitions */ 38 39 static ushort resumeline = 898; 40 module_param(resumeline, ushort, 0444); 41 42 static struct dcon_platform_data *pdata; 43 44 /* I2C structures */ 45 46 /* Platform devices */ 47 static struct platform_device *dcon_device; 48 49 static unsigned short normal_i2c[] = { 0x0d, I2C_CLIENT_END }; 50 51 static s32 dcon_write(struct dcon_priv *dcon, u8 reg, u16 val) 52 { 53 return i2c_smbus_write_word_data(dcon->client, reg, val); 54 } 55 56 static s32 dcon_read(struct dcon_priv *dcon, u8 reg) 57 { 58 return i2c_smbus_read_word_data(dcon->client, reg); 59 } 60 61 /* ===== API functions - these are called by a variety of users ==== */ 62 63 static int dcon_hw_init(struct dcon_priv *dcon, int is_init) 64 { 65 uint16_t ver; 66 int rc = 0; 67 68 ver = dcon_read(dcon, DCON_REG_ID); 69 if ((ver >> 8) != 0xDC) { 70 pr_err("DCON ID not 0xDCxx: 0x%04x instead.\n", ver); 71 rc = -ENXIO; 72 goto err; 73 } 74 75 if (is_init) { 76 pr_info("Discovered DCON version %x\n", ver & 0xFF); 77 rc = pdata->init(dcon); 78 if (rc != 0) { 79 pr_err("Unable to init.\n"); 80 goto err; 81 } 82 } 83 84 if (ver < 0xdc02) { 85 dev_err(&dcon->client->dev, 86 "DCON v1 is unsupported, giving up..\n"); 87 rc = -ENODEV; 88 goto err; 89 } 90 91 /* SDRAM setup/hold time */ 92 dcon_write(dcon, 0x3a, 0xc040); 93 dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000); /* clear option bits */ 94 dcon_write(dcon, DCON_REG_MEM_OPT_A, 95 MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN); 96 dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET); 97 98 /* Colour swizzle, AA, no passthrough, backlight */ 99 if (is_init) { 100 dcon->disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | 101 MODE_CSWIZZLE | MODE_COL_AA; 102 } 103 dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 104 105 106 /* Set the scanline to interrupt on during resume */ 107 dcon_write(dcon, DCON_REG_SCAN_INT, resumeline); 108 109 err: 110 return rc; 111 } 112 113 /* 114 * The smbus doesn't always come back due to what is believed to be 115 * hardware (power rail) bugs. For older models where this is known to 116 * occur, our solution is to attempt to wait for the bus to stabilize; 117 * if it doesn't happen, cut power to the dcon, repower it, and wait 118 * for the bus to stabilize. Rinse, repeat until we have a working 119 * smbus. For newer models, we simply BUG(); we want to know if this 120 * still happens despite the power fixes that have been made! 121 */ 122 static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down) 123 { 124 unsigned long timeout; 125 u8 pm; 126 int x; 127 128 power_up: 129 if (is_powered_down) { 130 pm = 1; 131 x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 132 if (x) { 133 pr_warn("unable to force dcon to power up: %d!\n", x); 134 return x; 135 } 136 usleep_range(10000, 11000); /* we'll be conservative */ 137 } 138 139 pdata->bus_stabilize_wiggle(); 140 141 for (x = -1, timeout = 50; timeout && x < 0; timeout--) { 142 usleep_range(1000, 1100); 143 x = dcon_read(dcon, DCON_REG_ID); 144 } 145 if (x < 0) { 146 pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n"); 147 BUG_ON(olpc_board_at_least(olpc_board(0xc2))); 148 pm = 0; 149 olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 150 msleep(100); 151 is_powered_down = 1; 152 goto power_up; /* argh, stupid hardware.. */ 153 } 154 155 if (is_powered_down) 156 return dcon_hw_init(dcon, 0); 157 return 0; 158 } 159 160 static void dcon_set_backlight(struct dcon_priv *dcon, u8 level) 161 { 162 dcon->bl_val = level; 163 dcon_write(dcon, DCON_REG_BRIGHT, dcon->bl_val); 164 165 /* Purposely turn off the backlight when we go to level 0 */ 166 if (dcon->bl_val == 0) { 167 dcon->disp_mode &= ~MODE_BL_ENABLE; 168 dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 169 } else if (!(dcon->disp_mode & MODE_BL_ENABLE)) { 170 dcon->disp_mode |= MODE_BL_ENABLE; 171 dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 172 } 173 } 174 175 /* Set the output type to either color or mono */ 176 static int dcon_set_mono_mode(struct dcon_priv *dcon, bool enable_mono) 177 { 178 if (dcon->mono == enable_mono) 179 return 0; 180 181 dcon->mono = enable_mono; 182 183 if (enable_mono) { 184 dcon->disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA); 185 dcon->disp_mode |= MODE_MONO_LUMA; 186 } else { 187 dcon->disp_mode &= ~(MODE_MONO_LUMA); 188 dcon->disp_mode |= MODE_CSWIZZLE | MODE_COL_AA; 189 } 190 191 dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); 192 return 0; 193 } 194 195 /* For now, this will be really stupid - we need to address how 196 * DCONLOAD works in a sleep and account for it accordingly 197 */ 198 199 static void dcon_sleep(struct dcon_priv *dcon, bool sleep) 200 { 201 int x; 202 203 /* Turn off the backlight and put the DCON to sleep */ 204 205 if (dcon->asleep == sleep) 206 return; 207 208 if (!olpc_board_at_least(olpc_board(0xc2))) 209 return; 210 211 if (sleep) { 212 u8 pm = 0; 213 214 x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); 215 if (x) 216 pr_warn("unable to force dcon to power down: %d!\n", x); 217 else 218 dcon->asleep = sleep; 219 } else { 220 /* Only re-enable the backlight if the backlight value is set */ 221 if (dcon->bl_val != 0) 222 dcon->disp_mode |= MODE_BL_ENABLE; 223 x = dcon_bus_stabilize(dcon, 1); 224 if (x) 225 pr_warn("unable to reinit dcon hardware: %d!\n", x); 226 else 227 dcon->asleep = sleep; 228 229 /* Restore backlight */ 230 dcon_set_backlight(dcon, dcon->bl_val); 231 } 232 233 /* We should turn off some stuff in the framebuffer - but what? */ 234 } 235 236 /* the DCON seems to get confused if we change DCONLOAD too 237 * frequently -- i.e., approximately faster than frame time. 238 * normally we don't change it this fast, so in general we won't 239 * delay here. 240 */ 241 static void dcon_load_holdoff(struct dcon_priv *dcon) 242 { 243 struct timespec delta_t, now; 244 245 while (1) { 246 getnstimeofday(&now); 247 delta_t = timespec_sub(now, dcon->load_time); 248 if (delta_t.tv_sec != 0 || 249 delta_t.tv_nsec > NSEC_PER_MSEC * 20) { 250 break; 251 } 252 mdelay(4); 253 } 254 } 255 256 static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank) 257 { 258 int err; 259 260 console_lock(); 261 if (!lock_fb_info(dcon->fbinfo)) { 262 console_unlock(); 263 dev_err(&dcon->client->dev, "unable to lock framebuffer\n"); 264 return false; 265 } 266 267 dcon->ignore_fb_events = true; 268 err = fb_blank(dcon->fbinfo, 269 blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); 270 dcon->ignore_fb_events = false; 271 unlock_fb_info(dcon->fbinfo); 272 console_unlock(); 273 274 if (err) { 275 dev_err(&dcon->client->dev, "couldn't %sblank framebuffer\n", 276 blank ? "" : "un"); 277 return false; 278 } 279 return true; 280 } 281 282 /* Set the source of the display (CPU or DCON) */ 283 static void dcon_source_switch(struct work_struct *work) 284 { 285 struct dcon_priv *dcon = container_of(work, struct dcon_priv, 286 switch_source); 287 int source = dcon->pending_src; 288 289 if (dcon->curr_src == source) 290 return; 291 292 dcon_load_holdoff(dcon); 293 294 dcon->switched = false; 295 296 switch (source) { 297 case DCON_SOURCE_CPU: 298 pr_info("dcon_source_switch to CPU\n"); 299 /* Enable the scanline interrupt bit */ 300 if (dcon_write(dcon, DCON_REG_MODE, 301 dcon->disp_mode | MODE_SCAN_INT)) 302 pr_err("couldn't enable scanline interrupt!\n"); 303 else 304 /* Wait up to one second for the scanline interrupt */ 305 wait_event_timeout(dcon->waitq, dcon->switched, HZ); 306 307 if (!dcon->switched) 308 pr_err("Timeout entering CPU mode; expect a screen glitch.\n"); 309 310 /* Turn off the scanline interrupt */ 311 if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode)) 312 pr_err("couldn't disable scanline interrupt!\n"); 313 314 /* 315 * Ideally we'd like to disable interrupts here so that the 316 * fb unblanking and DCON turn on happen at a known time value; 317 * however, we can't do that right now with fb_blank 318 * messing with semaphores. 319 * 320 * For now, we just hope.. 321 */ 322 if (!dcon_blank_fb(dcon, false)) { 323 pr_err("Failed to enter CPU mode\n"); 324 dcon->pending_src = DCON_SOURCE_DCON; 325 return; 326 } 327 328 /* And turn off the DCON */ 329 pdata->set_dconload(1); 330 getnstimeofday(&dcon->load_time); 331 332 pr_info("The CPU has control\n"); 333 break; 334 case DCON_SOURCE_DCON: 335 { 336 struct timespec delta_t; 337 338 pr_info("dcon_source_switch to DCON\n"); 339 340 /* Clear DCONLOAD - this implies that the DCON is in control */ 341 pdata->set_dconload(0); 342 getnstimeofday(&dcon->load_time); 343 344 wait_event_timeout(dcon->waitq, dcon->switched, HZ/2); 345 346 if (!dcon->switched) { 347 pr_err("Timeout entering DCON mode; expect a screen glitch.\n"); 348 } else { 349 /* sometimes the DCON doesn't follow its own rules, 350 * and doesn't wait for two vsync pulses before 351 * ack'ing the frame load with an IRQ. the result 352 * is that the display shows the *previously* 353 * loaded frame. we can detect this by looking at 354 * the time between asserting DCONLOAD and the IRQ -- 355 * if it's less than 20msec, then the DCON couldn't 356 * have seen two VSYNC pulses. in that case we 357 * deassert and reassert, and hope for the best. 358 * see http://dev.laptop.org/ticket/9664 359 */ 360 delta_t = timespec_sub(dcon->irq_time, dcon->load_time); 361 if (dcon->switched && delta_t.tv_sec == 0 && 362 delta_t.tv_nsec < NSEC_PER_MSEC * 20) { 363 pr_err("missed loading, retrying\n"); 364 pdata->set_dconload(1); 365 mdelay(41); 366 pdata->set_dconload(0); 367 getnstimeofday(&dcon->load_time); 368 mdelay(41); 369 } 370 } 371 372 dcon_blank_fb(dcon, true); 373 pr_info("The DCON has control\n"); 374 break; 375 } 376 default: 377 BUG(); 378 } 379 380 dcon->curr_src = source; 381 } 382 383 static void dcon_set_source(struct dcon_priv *dcon, int arg) 384 { 385 if (dcon->pending_src == arg) 386 return; 387 388 dcon->pending_src = arg; 389 390 if (dcon->curr_src != arg) 391 schedule_work(&dcon->switch_source); 392 } 393 394 static void dcon_set_source_sync(struct dcon_priv *dcon, int arg) 395 { 396 dcon_set_source(dcon, arg); 397 flush_scheduled_work(); 398 } 399 400 static ssize_t dcon_mode_show(struct device *dev, 401 struct device_attribute *attr, char *buf) 402 { 403 struct dcon_priv *dcon = dev_get_drvdata(dev); 404 405 return sprintf(buf, "%4.4X\n", dcon->disp_mode); 406 } 407 408 static ssize_t dcon_sleep_show(struct device *dev, 409 struct device_attribute *attr, char *buf) 410 { 411 struct dcon_priv *dcon = dev_get_drvdata(dev); 412 413 return sprintf(buf, "%d\n", dcon->asleep); 414 } 415 416 static ssize_t dcon_freeze_show(struct device *dev, 417 struct device_attribute *attr, char *buf) 418 { 419 struct dcon_priv *dcon = dev_get_drvdata(dev); 420 421 return sprintf(buf, "%d\n", dcon->curr_src == DCON_SOURCE_DCON ? 1 : 0); 422 } 423 424 static ssize_t dcon_mono_show(struct device *dev, 425 struct device_attribute *attr, char *buf) 426 { 427 struct dcon_priv *dcon = dev_get_drvdata(dev); 428 429 return sprintf(buf, "%d\n", dcon->mono); 430 } 431 432 static ssize_t dcon_resumeline_show(struct device *dev, 433 struct device_attribute *attr, char *buf) 434 { 435 return sprintf(buf, "%d\n", resumeline); 436 } 437 438 static ssize_t dcon_mono_store(struct device *dev, 439 struct device_attribute *attr, const char *buf, size_t count) 440 { 441 unsigned long enable_mono; 442 int rc; 443 444 rc = kstrtoul(buf, 10, &enable_mono); 445 if (rc) 446 return rc; 447 448 dcon_set_mono_mode(dev_get_drvdata(dev), enable_mono ? true : false); 449 450 return count; 451 } 452 453 static ssize_t dcon_freeze_store(struct device *dev, 454 struct device_attribute *attr, const char *buf, size_t count) 455 { 456 struct dcon_priv *dcon = dev_get_drvdata(dev); 457 unsigned long output; 458 int ret; 459 460 ret = kstrtoul(buf, 10, &output); 461 if (ret) 462 return ret; 463 464 pr_info("dcon_freeze_store: %lu\n", output); 465 466 switch (output) { 467 case 0: 468 dcon_set_source(dcon, DCON_SOURCE_CPU); 469 break; 470 case 1: 471 dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 472 break; 473 case 2: /* normally unused */ 474 dcon_set_source(dcon, DCON_SOURCE_DCON); 475 break; 476 default: 477 return -EINVAL; 478 } 479 480 return count; 481 } 482 483 static ssize_t dcon_resumeline_store(struct device *dev, 484 struct device_attribute *attr, const char *buf, size_t count) 485 { 486 unsigned short rl; 487 int rc; 488 489 rc = kstrtou16(buf, 10, &rl); 490 if (rc) 491 return rc; 492 493 resumeline = rl; 494 dcon_write(dev_get_drvdata(dev), DCON_REG_SCAN_INT, resumeline); 495 496 return count; 497 } 498 499 static ssize_t dcon_sleep_store(struct device *dev, 500 struct device_attribute *attr, const char *buf, size_t count) 501 { 502 unsigned long output; 503 int ret; 504 505 ret = kstrtoul(buf, 10, &output); 506 if (ret) 507 return ret; 508 509 dcon_sleep(dev_get_drvdata(dev), output ? true : false); 510 return count; 511 } 512 513 static struct device_attribute dcon_device_files[] = { 514 __ATTR(mode, 0444, dcon_mode_show, NULL), 515 __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store), 516 __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store), 517 __ATTR(monochrome, 0644, dcon_mono_show, dcon_mono_store), 518 __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), 519 }; 520 521 static int dcon_bl_update(struct backlight_device *dev) 522 { 523 struct dcon_priv *dcon = bl_get_data(dev); 524 u8 level = dev->props.brightness & 0x0F; 525 526 if (dev->props.power != FB_BLANK_UNBLANK) 527 level = 0; 528 529 if (level != dcon->bl_val) 530 dcon_set_backlight(dcon, level); 531 532 /* power down the DCON when the screen is blanked */ 533 if (!dcon->ignore_fb_events) 534 dcon_sleep(dcon, !!(dev->props.state & BL_CORE_FBBLANK)); 535 536 return 0; 537 } 538 539 static int dcon_bl_get(struct backlight_device *dev) 540 { 541 struct dcon_priv *dcon = bl_get_data(dev); 542 543 return dcon->bl_val; 544 } 545 546 static const struct backlight_ops dcon_bl_ops = { 547 .update_status = dcon_bl_update, 548 .get_brightness = dcon_bl_get, 549 }; 550 551 static struct backlight_properties dcon_bl_props = { 552 .max_brightness = 15, 553 .type = BACKLIGHT_RAW, 554 .power = FB_BLANK_UNBLANK, 555 }; 556 557 static int dcon_reboot_notify(struct notifier_block *nb, 558 unsigned long foo, void *bar) 559 { 560 struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb); 561 562 if (!dcon || !dcon->client) 563 return NOTIFY_DONE; 564 565 /* Turn off the DCON. Entirely. */ 566 dcon_write(dcon, DCON_REG_MODE, 0x39); 567 dcon_write(dcon, DCON_REG_MODE, 0x32); 568 return NOTIFY_DONE; 569 } 570 571 static int unfreeze_on_panic(struct notifier_block *nb, 572 unsigned long e, void *p) 573 { 574 pdata->set_dconload(1); 575 return NOTIFY_DONE; 576 } 577 578 static struct notifier_block dcon_panic_nb = { 579 .notifier_call = unfreeze_on_panic, 580 }; 581 582 static int dcon_detect(struct i2c_client *client, struct i2c_board_info *info) 583 { 584 strlcpy(info->type, "olpc_dcon", I2C_NAME_SIZE); 585 586 return 0; 587 } 588 589 static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) 590 { 591 struct dcon_priv *dcon; 592 int rc, i, j; 593 594 if (!pdata) 595 return -ENXIO; 596 597 dcon = kzalloc(sizeof(*dcon), GFP_KERNEL); 598 if (!dcon) 599 return -ENOMEM; 600 601 dcon->client = client; 602 init_waitqueue_head(&dcon->waitq); 603 INIT_WORK(&dcon->switch_source, dcon_source_switch); 604 dcon->reboot_nb.notifier_call = dcon_reboot_notify; 605 dcon->reboot_nb.priority = -1; 606 607 i2c_set_clientdata(client, dcon); 608 609 if (num_registered_fb < 1) { 610 dev_err(&client->dev, "DCON driver requires a registered fb\n"); 611 rc = -EIO; 612 goto einit; 613 } 614 dcon->fbinfo = registered_fb[0]; 615 616 rc = dcon_hw_init(dcon, 1); 617 if (rc) 618 goto einit; 619 620 /* Add the DCON device */ 621 622 dcon_device = platform_device_alloc("dcon", -1); 623 624 if (dcon_device == NULL) { 625 pr_err("Unable to create the DCON device\n"); 626 rc = -ENOMEM; 627 goto eirq; 628 } 629 rc = platform_device_add(dcon_device); 630 platform_set_drvdata(dcon_device, dcon); 631 632 if (rc) { 633 pr_err("Unable to add the DCON device\n"); 634 goto edev; 635 } 636 637 for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) { 638 rc = device_create_file(&dcon_device->dev, 639 &dcon_device_files[i]); 640 if (rc) { 641 dev_err(&dcon_device->dev, "Cannot create sysfs file\n"); 642 goto ecreate; 643 } 644 } 645 646 dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F; 647 648 /* Add the backlight device for the DCON */ 649 dcon_bl_props.brightness = dcon->bl_val; 650 dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev, 651 dcon, &dcon_bl_ops, &dcon_bl_props); 652 if (IS_ERR(dcon->bl_dev)) { 653 dev_err(&client->dev, "cannot register backlight dev (%ld)\n", 654 PTR_ERR(dcon->bl_dev)); 655 dcon->bl_dev = NULL; 656 } 657 658 register_reboot_notifier(&dcon->reboot_nb); 659 atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb); 660 661 return 0; 662 663 ecreate: 664 for (j = 0; j < i; j++) 665 device_remove_file(&dcon_device->dev, &dcon_device_files[j]); 666 edev: 667 platform_device_unregister(dcon_device); 668 dcon_device = NULL; 669 eirq: 670 free_irq(DCON_IRQ, dcon); 671 einit: 672 kfree(dcon); 673 return rc; 674 } 675 676 static int dcon_remove(struct i2c_client *client) 677 { 678 struct dcon_priv *dcon = i2c_get_clientdata(client); 679 680 unregister_reboot_notifier(&dcon->reboot_nb); 681 atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb); 682 683 free_irq(DCON_IRQ, dcon); 684 685 if (dcon->bl_dev) 686 backlight_device_unregister(dcon->bl_dev); 687 688 if (dcon_device != NULL) 689 platform_device_unregister(dcon_device); 690 cancel_work_sync(&dcon->switch_source); 691 692 kfree(dcon); 693 694 return 0; 695 } 696 697 #ifdef CONFIG_PM 698 static int dcon_suspend(struct device *dev) 699 { 700 struct i2c_client *client = to_i2c_client(dev); 701 struct dcon_priv *dcon = i2c_get_clientdata(client); 702 703 if (!dcon->asleep) { 704 /* Set up the DCON to have the source */ 705 dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 706 } 707 708 return 0; 709 } 710 711 static int dcon_resume(struct device *dev) 712 { 713 struct i2c_client *client = to_i2c_client(dev); 714 struct dcon_priv *dcon = i2c_get_clientdata(client); 715 716 if (!dcon->asleep) { 717 dcon_bus_stabilize(dcon, 0); 718 dcon_set_source(dcon, DCON_SOURCE_CPU); 719 } 720 721 return 0; 722 } 723 724 #else 725 726 #define dcon_suspend NULL 727 #define dcon_resume NULL 728 729 #endif /* CONFIG_PM */ 730 731 732 irqreturn_t dcon_interrupt(int irq, void *id) 733 { 734 struct dcon_priv *dcon = id; 735 u8 status; 736 737 if (pdata->read_status(&status)) 738 return IRQ_NONE; 739 740 switch (status & 3) { 741 case 3: 742 pr_debug("DCONLOAD_MISSED interrupt\n"); 743 break; 744 745 case 2: /* switch to DCON mode */ 746 case 1: /* switch to CPU mode */ 747 dcon->switched = true; 748 getnstimeofday(&dcon->irq_time); 749 wake_up(&dcon->waitq); 750 break; 751 752 case 0: 753 /* workaround resume case: the DCON (on 1.5) doesn't 754 * ever assert status 0x01 when switching to CPU mode 755 * during resume. this is because DCONLOAD is de-asserted 756 * _immediately_ upon exiting S3, so the actual release 757 * of the DCON happened long before this point. 758 * see http://dev.laptop.org/ticket/9869 759 */ 760 if (dcon->curr_src != dcon->pending_src && !dcon->switched) { 761 dcon->switched = true; 762 getnstimeofday(&dcon->irq_time); 763 wake_up(&dcon->waitq); 764 pr_debug("switching w/ status 0/0\n"); 765 } else { 766 pr_debug("scanline interrupt w/CPU\n"); 767 } 768 } 769 770 return IRQ_HANDLED; 771 } 772 773 static const struct dev_pm_ops dcon_pm_ops = { 774 .suspend = dcon_suspend, 775 .resume = dcon_resume, 776 }; 777 778 static const struct i2c_device_id dcon_idtable[] = { 779 { "olpc_dcon", 0 }, 780 { } 781 }; 782 MODULE_DEVICE_TABLE(i2c, dcon_idtable); 783 784 struct i2c_driver dcon_driver = { 785 .driver = { 786 .name = "olpc_dcon", 787 .pm = &dcon_pm_ops, 788 }, 789 .class = I2C_CLASS_DDC | I2C_CLASS_HWMON, 790 .id_table = dcon_idtable, 791 .probe = dcon_probe, 792 .remove = dcon_remove, 793 .detect = dcon_detect, 794 .address_list = normal_i2c, 795 }; 796 797 static int __init olpc_dcon_init(void) 798 { 799 #ifdef CONFIG_FB_OLPC_DCON_1_5 800 /* XO-1.5 */ 801 if (olpc_board_at_least(olpc_board(0xd0))) 802 pdata = &dcon_pdata_xo_1_5; 803 #endif 804 #ifdef CONFIG_FB_OLPC_DCON_1 805 if (!pdata) 806 pdata = &dcon_pdata_xo_1; 807 #endif 808 809 return i2c_add_driver(&dcon_driver); 810 } 811 812 static void __exit olpc_dcon_exit(void) 813 { 814 i2c_del_driver(&dcon_driver); 815 } 816 817 module_init(olpc_dcon_init); 818 module_exit(olpc_dcon_exit); 819 820 MODULE_LICENSE("GPL"); 821