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