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_scheduled_work(); 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 = dev->props.brightness & 0x0F; 521 522 if (dev->props.power != FB_BLANK_UNBLANK) 523 level = 0; 524 525 if (level != dcon->bl_val) 526 dcon_set_backlight(dcon, level); 527 528 /* power down the DCON when the screen is blanked */ 529 if (!dcon->ignore_fb_events) 530 dcon_sleep(dcon, !!(dev->props.state & BL_CORE_FBBLANK)); 531 532 return 0; 533 } 534 535 static int dcon_bl_get(struct backlight_device *dev) 536 { 537 struct dcon_priv *dcon = bl_get_data(dev); 538 539 return dcon->bl_val; 540 } 541 542 static const struct backlight_ops dcon_bl_ops = { 543 .update_status = dcon_bl_update, 544 .get_brightness = dcon_bl_get, 545 }; 546 547 static struct backlight_properties dcon_bl_props = { 548 .max_brightness = 15, 549 .type = BACKLIGHT_RAW, 550 .power = FB_BLANK_UNBLANK, 551 }; 552 553 static int dcon_reboot_notify(struct notifier_block *nb, 554 unsigned long foo, void *bar) 555 { 556 struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb); 557 558 if (!dcon || !dcon->client) 559 return NOTIFY_DONE; 560 561 /* Turn off the DCON. Entirely. */ 562 dcon_write(dcon, DCON_REG_MODE, 0x39); 563 dcon_write(dcon, DCON_REG_MODE, 0x32); 564 return NOTIFY_DONE; 565 } 566 567 static int unfreeze_on_panic(struct notifier_block *nb, 568 unsigned long e, void *p) 569 { 570 pdata->set_dconload(1); 571 return NOTIFY_DONE; 572 } 573 574 static struct notifier_block dcon_panic_nb = { 575 .notifier_call = unfreeze_on_panic, 576 }; 577 578 static int dcon_detect(struct i2c_client *client, struct i2c_board_info *info) 579 { 580 strscpy(info->type, "olpc_dcon", I2C_NAME_SIZE); 581 582 return 0; 583 } 584 585 static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) 586 { 587 struct dcon_priv *dcon; 588 int rc, i, j; 589 590 if (!pdata) 591 return -ENXIO; 592 593 dcon = kzalloc(sizeof(*dcon), GFP_KERNEL); 594 if (!dcon) 595 return -ENOMEM; 596 597 dcon->client = client; 598 init_waitqueue_head(&dcon->waitq); 599 INIT_WORK(&dcon->switch_source, dcon_source_switch); 600 dcon->reboot_nb.notifier_call = dcon_reboot_notify; 601 dcon->reboot_nb.priority = -1; 602 603 i2c_set_clientdata(client, dcon); 604 605 if (num_registered_fb < 1) { 606 dev_err(&client->dev, "DCON driver requires a registered fb\n"); 607 rc = -EIO; 608 goto einit; 609 } 610 dcon->fbinfo = registered_fb[0]; 611 612 rc = dcon_hw_init(dcon, 1); 613 if (rc) 614 goto einit; 615 616 /* Add the DCON device */ 617 618 dcon_device = platform_device_alloc("dcon", -1); 619 620 if (!dcon_device) { 621 pr_err("Unable to create the DCON device\n"); 622 rc = -ENOMEM; 623 goto eirq; 624 } 625 rc = platform_device_add(dcon_device); 626 platform_set_drvdata(dcon_device, dcon); 627 628 if (rc) { 629 pr_err("Unable to add the DCON device\n"); 630 goto edev; 631 } 632 633 for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) { 634 rc = device_create_file(&dcon_device->dev, 635 &dcon_device_files[i]); 636 if (rc) { 637 dev_err(&dcon_device->dev, "Cannot create sysfs file\n"); 638 goto ecreate; 639 } 640 } 641 642 dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F; 643 644 /* Add the backlight device for the DCON */ 645 dcon_bl_props.brightness = dcon->bl_val; 646 dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev, 647 dcon, &dcon_bl_ops, 648 &dcon_bl_props); 649 if (IS_ERR(dcon->bl_dev)) { 650 dev_err(&client->dev, "cannot register backlight dev (%ld)\n", 651 PTR_ERR(dcon->bl_dev)); 652 dcon->bl_dev = NULL; 653 } 654 655 register_reboot_notifier(&dcon->reboot_nb); 656 atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb); 657 658 return 0; 659 660 ecreate: 661 for (j = 0; j < i; j++) 662 device_remove_file(&dcon_device->dev, &dcon_device_files[j]); 663 platform_device_del(dcon_device); 664 edev: 665 platform_device_put(dcon_device); 666 dcon_device = NULL; 667 eirq: 668 free_irq(DCON_IRQ, dcon); 669 einit: 670 kfree(dcon); 671 return rc; 672 } 673 674 static int dcon_remove(struct i2c_client *client) 675 { 676 struct dcon_priv *dcon = i2c_get_clientdata(client); 677 678 unregister_reboot_notifier(&dcon->reboot_nb); 679 atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb); 680 681 free_irq(DCON_IRQ, dcon); 682 683 backlight_device_unregister(dcon->bl_dev); 684 685 if (dcon_device) 686 platform_device_unregister(dcon_device); 687 cancel_work_sync(&dcon->switch_source); 688 689 kfree(dcon); 690 691 return 0; 692 } 693 694 #ifdef CONFIG_PM 695 static int dcon_suspend(struct device *dev) 696 { 697 struct i2c_client *client = to_i2c_client(dev); 698 struct dcon_priv *dcon = i2c_get_clientdata(client); 699 700 if (!dcon->asleep) { 701 /* Set up the DCON to have the source */ 702 dcon_set_source_sync(dcon, DCON_SOURCE_DCON); 703 } 704 705 return 0; 706 } 707 708 static int dcon_resume(struct device *dev) 709 { 710 struct i2c_client *client = to_i2c_client(dev); 711 struct dcon_priv *dcon = i2c_get_clientdata(client); 712 713 if (!dcon->asleep) { 714 dcon_bus_stabilize(dcon, 0); 715 dcon_set_source(dcon, DCON_SOURCE_CPU); 716 } 717 718 return 0; 719 } 720 721 #else 722 723 #define dcon_suspend NULL 724 #define dcon_resume NULL 725 726 #endif /* CONFIG_PM */ 727 728 irqreturn_t dcon_interrupt(int irq, void *id) 729 { 730 struct dcon_priv *dcon = id; 731 u8 status; 732 733 if (pdata->read_status(&status)) 734 return IRQ_NONE; 735 736 switch (status & 3) { 737 case 3: 738 pr_debug("DCONLOAD_MISSED interrupt\n"); 739 break; 740 741 case 2: /* switch to DCON mode */ 742 case 1: /* switch to CPU mode */ 743 dcon->switched = true; 744 dcon->irq_time = ktime_get(); 745 wake_up(&dcon->waitq); 746 break; 747 748 case 0: 749 /* workaround resume case: the DCON (on 1.5) doesn't 750 * ever assert status 0x01 when switching to CPU mode 751 * during resume. this is because DCONLOAD is de-asserted 752 * _immediately_ upon exiting S3, so the actual release 753 * of the DCON happened long before this point. 754 * see http://dev.laptop.org/ticket/9869 755 */ 756 if (dcon->curr_src != dcon->pending_src && !dcon->switched) { 757 dcon->switched = true; 758 dcon->irq_time = ktime_get(); 759 wake_up(&dcon->waitq); 760 pr_debug("switching w/ status 0/0\n"); 761 } else { 762 pr_debug("scanline interrupt w/CPU\n"); 763 } 764 } 765 766 return IRQ_HANDLED; 767 } 768 769 static const struct dev_pm_ops dcon_pm_ops = { 770 .suspend = dcon_suspend, 771 .resume = dcon_resume, 772 }; 773 774 static const struct i2c_device_id dcon_idtable[] = { 775 { "olpc_dcon", 0 }, 776 { } 777 }; 778 MODULE_DEVICE_TABLE(i2c, dcon_idtable); 779 780 static struct i2c_driver dcon_driver = { 781 .driver = { 782 .name = "olpc_dcon", 783 .pm = &dcon_pm_ops, 784 }, 785 .class = I2C_CLASS_DDC | I2C_CLASS_HWMON, 786 .id_table = dcon_idtable, 787 .probe = dcon_probe, 788 .remove = dcon_remove, 789 .detect = dcon_detect, 790 .address_list = normal_i2c, 791 }; 792 793 static int __init olpc_dcon_init(void) 794 { 795 /* XO-1.5 */ 796 if (olpc_board_at_least(olpc_board(0xd0))) 797 pdata = &dcon_pdata_xo_1_5; 798 else 799 pdata = &dcon_pdata_xo_1; 800 801 return i2c_add_driver(&dcon_driver); 802 } 803 804 static void __exit olpc_dcon_exit(void) 805 { 806 i2c_del_driver(&dcon_driver); 807 } 808 809 module_init(olpc_dcon_init); 810 module_exit(olpc_dcon_exit); 811 812 MODULE_LICENSE("GPL"); 813