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