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("%s to CPU\n", __func__); 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("%s to DCON\n", __func__); 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, 397 char *buf) 398 { 399 struct dcon_priv *dcon = dev_get_drvdata(dev); 400 401 return sprintf(buf, "%4.4X\n", dcon->disp_mode); 402 } 403 404 static ssize_t dcon_sleep_show(struct device *dev, 405 struct device_attribute *attr, 406 char *buf) 407 { 408 struct dcon_priv *dcon = dev_get_drvdata(dev); 409 410 return sprintf(buf, "%d\n", dcon->asleep); 411 } 412 413 static ssize_t dcon_freeze_show(struct device *dev, 414 struct device_attribute *attr, 415 char *buf) 416 { 417 struct dcon_priv *dcon = dev_get_drvdata(dev); 418 419 return sprintf(buf, "%d\n", dcon->curr_src == DCON_SOURCE_DCON ? 1 : 0); 420 } 421 422 static ssize_t dcon_mono_show(struct device *dev, 423 struct device_attribute *attr, 424 char *buf) 425 { 426 struct dcon_priv *dcon = dev_get_drvdata(dev); 427 428 return sprintf(buf, "%d\n", dcon->mono); 429 } 430 431 static ssize_t dcon_resumeline_show(struct device *dev, 432 struct device_attribute *attr, 433 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, 440 const char *buf, size_t count) 441 { 442 unsigned long enable_mono; 443 int rc; 444 445 rc = kstrtoul(buf, 10, &enable_mono); 446 if (rc) 447 return rc; 448 449 dcon_set_mono_mode(dev_get_drvdata(dev), enable_mono ? true : false); 450 451 return count; 452 } 453 454 static ssize_t dcon_freeze_store(struct device *dev, 455 struct device_attribute *attr, 456 const char *buf, size_t count) 457 { 458 struct dcon_priv *dcon = dev_get_drvdata(dev); 459 unsigned long output; 460 int ret; 461 462 ret = kstrtoul(buf, 10, &output); 463 if (ret) 464 return ret; 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, 485 const char *buf, size_t count) 486 { 487 unsigned short rl; 488 int rc; 489 490 rc = kstrtou16(buf, 10, &rl); 491 if (rc) 492 return rc; 493 494 resumeline = rl; 495 dcon_write(dev_get_drvdata(dev), DCON_REG_SCAN_INT, resumeline); 496 497 return count; 498 } 499 500 static ssize_t dcon_sleep_store(struct device *dev, 501 struct device_attribute *attr, 502 const char *buf, size_t count) 503 { 504 unsigned long output; 505 int ret; 506 507 ret = kstrtoul(buf, 10, &output); 508 if (ret) 509 return ret; 510 511 dcon_sleep(dev_get_drvdata(dev), output ? true : false); 512 return count; 513 } 514 515 static struct device_attribute dcon_device_files[] = { 516 __ATTR(mode, 0444, dcon_mode_show, NULL), 517 __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store), 518 __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store), 519 __ATTR(monochrome, 0644, dcon_mono_show, dcon_mono_store), 520 __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), 521 }; 522 523 static int dcon_bl_update(struct backlight_device *dev) 524 { 525 struct dcon_priv *dcon = bl_get_data(dev); 526 u8 level = dev->props.brightness & 0x0F; 527 528 if (dev->props.power != FB_BLANK_UNBLANK) 529 level = 0; 530 531 if (level != dcon->bl_val) 532 dcon_set_backlight(dcon, level); 533 534 /* power down the DCON when the screen is blanked */ 535 if (!dcon->ignore_fb_events) 536 dcon_sleep(dcon, !!(dev->props.state & BL_CORE_FBBLANK)); 537 538 return 0; 539 } 540 541 static int dcon_bl_get(struct backlight_device *dev) 542 { 543 struct dcon_priv *dcon = bl_get_data(dev); 544 545 return dcon->bl_val; 546 } 547 548 static const struct backlight_ops dcon_bl_ops = { 549 .update_status = dcon_bl_update, 550 .get_brightness = dcon_bl_get, 551 }; 552 553 static struct backlight_properties dcon_bl_props = { 554 .max_brightness = 15, 555 .type = BACKLIGHT_RAW, 556 .power = FB_BLANK_UNBLANK, 557 }; 558 559 static int dcon_reboot_notify(struct notifier_block *nb, 560 unsigned long foo, void *bar) 561 { 562 struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb); 563 564 if (!dcon || !dcon->client) 565 return NOTIFY_DONE; 566 567 /* Turn off the DCON. Entirely. */ 568 dcon_write(dcon, DCON_REG_MODE, 0x39); 569 dcon_write(dcon, DCON_REG_MODE, 0x32); 570 return NOTIFY_DONE; 571 } 572 573 static int unfreeze_on_panic(struct notifier_block *nb, 574 unsigned long e, void *p) 575 { 576 pdata->set_dconload(1); 577 return NOTIFY_DONE; 578 } 579 580 static struct notifier_block dcon_panic_nb = { 581 .notifier_call = unfreeze_on_panic, 582 }; 583 584 static int dcon_detect(struct i2c_client *client, struct i2c_board_info *info) 585 { 586 strlcpy(info->type, "olpc_dcon", I2C_NAME_SIZE); 587 588 return 0; 589 } 590 591 static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) 592 { 593 struct dcon_priv *dcon; 594 int rc, i, j; 595 596 if (!pdata) 597 return -ENXIO; 598 599 dcon = kzalloc(sizeof(*dcon), GFP_KERNEL); 600 if (!dcon) 601 return -ENOMEM; 602 603 dcon->client = client; 604 init_waitqueue_head(&dcon->waitq); 605 INIT_WORK(&dcon->switch_source, dcon_source_switch); 606 dcon->reboot_nb.notifier_call = dcon_reboot_notify; 607 dcon->reboot_nb.priority = -1; 608 609 i2c_set_clientdata(client, dcon); 610 611 if (num_registered_fb < 1) { 612 dev_err(&client->dev, "DCON driver requires a registered fb\n"); 613 rc = -EIO; 614 goto einit; 615 } 616 dcon->fbinfo = registered_fb[0]; 617 618 rc = dcon_hw_init(dcon, 1); 619 if (rc) 620 goto einit; 621 622 /* Add the DCON device */ 623 624 dcon_device = platform_device_alloc("dcon", -1); 625 626 if (!dcon_device) { 627 pr_err("Unable to create the DCON device\n"); 628 rc = -ENOMEM; 629 goto eirq; 630 } 631 rc = platform_device_add(dcon_device); 632 platform_set_drvdata(dcon_device, dcon); 633 634 if (rc) { 635 pr_err("Unable to add the DCON device\n"); 636 goto edev; 637 } 638 639 for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) { 640 rc = device_create_file(&dcon_device->dev, 641 &dcon_device_files[i]); 642 if (rc) { 643 dev_err(&dcon_device->dev, "Cannot create sysfs file\n"); 644 goto ecreate; 645 } 646 } 647 648 dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F; 649 650 /* Add the backlight device for the DCON */ 651 dcon_bl_props.brightness = dcon->bl_val; 652 dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev, 653 dcon, &dcon_bl_ops, 654 &dcon_bl_props); 655 if (IS_ERR(dcon->bl_dev)) { 656 dev_err(&client->dev, "cannot register backlight dev (%ld)\n", 657 PTR_ERR(dcon->bl_dev)); 658 dcon->bl_dev = NULL; 659 } 660 661 register_reboot_notifier(&dcon->reboot_nb); 662 atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb); 663 664 return 0; 665 666 ecreate: 667 for (j = 0; j < i; j++) 668 device_remove_file(&dcon_device->dev, &dcon_device_files[j]); 669 edev: 670 platform_device_unregister(dcon_device); 671 dcon_device = NULL; 672 eirq: 673 free_irq(DCON_IRQ, dcon); 674 einit: 675 kfree(dcon); 676 return rc; 677 } 678 679 static int dcon_remove(struct i2c_client *client) 680 { 681 struct dcon_priv *dcon = i2c_get_clientdata(client); 682 683 unregister_reboot_notifier(&dcon->reboot_nb); 684 atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb); 685 686 free_irq(DCON_IRQ, dcon); 687 688 backlight_device_unregister(dcon->bl_dev); 689 690 if (dcon_device) 691 platform_device_unregister(dcon_device); 692 cancel_work_sync(&dcon->switch_source); 693 694 kfree(dcon); 695 696 return 0; 697 } 698 699 #ifdef CONFIG_PM 700 static int dcon_suspend(struct device *dev) 701 { 702 struct i2c_client *client = to_i2c_client(dev); 703 struct dcon_priv *dcon = i2c_get_clientdata(client); 704 705 if (!dcon->asleep) { 706 /* Set up the DCON to have the source */ 707 dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 708 } 709 710 return 0; 711 } 712 713 static int dcon_resume(struct device *dev) 714 { 715 struct i2c_client *client = to_i2c_client(dev); 716 struct dcon_priv *dcon = i2c_get_clientdata(client); 717 718 if (!dcon->asleep) { 719 dcon_bus_stabilize(dcon, 0); 720 dcon_set_source(dcon, DCON_SOURCE_CPU); 721 } 722 723 return 0; 724 } 725 726 #else 727 728 #define dcon_suspend NULL 729 #define dcon_resume NULL 730 731 #endif /* CONFIG_PM */ 732 733 irqreturn_t dcon_interrupt(int irq, void *id) 734 { 735 struct dcon_priv *dcon = id; 736 u8 status; 737 738 if (pdata->read_status(&status)) 739 return IRQ_NONE; 740 741 switch (status & 3) { 742 case 3: 743 pr_debug("DCONLOAD_MISSED interrupt\n"); 744 break; 745 746 case 2: /* switch to DCON mode */ 747 case 1: /* switch to CPU mode */ 748 dcon->switched = true; 749 dcon->irq_time = ktime_get(); 750 wake_up(&dcon->waitq); 751 break; 752 753 case 0: 754 /* workaround resume case: the DCON (on 1.5) doesn't 755 * ever assert status 0x01 when switching to CPU mode 756 * during resume. this is because DCONLOAD is de-asserted 757 * _immediately_ upon exiting S3, so the actual release 758 * of the DCON happened long before this point. 759 * see http://dev.laptop.org/ticket/9869 760 */ 761 if (dcon->curr_src != dcon->pending_src && !dcon->switched) { 762 dcon->switched = true; 763 dcon->irq_time = ktime_get(); 764 wake_up(&dcon->waitq); 765 pr_debug("switching w/ status 0/0\n"); 766 } else { 767 pr_debug("scanline interrupt w/CPU\n"); 768 } 769 } 770 771 return IRQ_HANDLED; 772 } 773 774 static const struct dev_pm_ops dcon_pm_ops = { 775 .suspend = dcon_suspend, 776 .resume = dcon_resume, 777 }; 778 779 static const struct i2c_device_id dcon_idtable[] = { 780 { "olpc_dcon", 0 }, 781 { } 782 }; 783 MODULE_DEVICE_TABLE(i2c, dcon_idtable); 784 785 static struct i2c_driver dcon_driver = { 786 .driver = { 787 .name = "olpc_dcon", 788 .pm = &dcon_pm_ops, 789 }, 790 .class = I2C_CLASS_DDC | I2C_CLASS_HWMON, 791 .id_table = dcon_idtable, 792 .probe = dcon_probe, 793 .remove = dcon_remove, 794 .detect = dcon_detect, 795 .address_list = normal_i2c, 796 }; 797 798 static int __init olpc_dcon_init(void) 799 { 800 #ifdef CONFIG_FB_OLPC_DCON_1_5 801 /* XO-1.5 */ 802 if (olpc_board_at_least(olpc_board(0xd0))) 803 pdata = &dcon_pdata_xo_1_5; 804 #endif 805 #ifdef CONFIG_FB_OLPC_DCON_1 806 if (!pdata) 807 pdata = &dcon_pdata_xo_1; 808 #endif 809 810 return i2c_add_driver(&dcon_driver); 811 } 812 813 static void __exit olpc_dcon_exit(void) 814 { 815 i2c_del_driver(&dcon_driver); 816 } 817 818 module_init(olpc_dcon_init); 819 module_exit(olpc_dcon_exit); 820 821 MODULE_LICENSE("GPL"); 822