root/drivers/staging/olpc_dcon/olpc_dcon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dcon_write
  2. dcon_read
  3. dcon_hw_init
  4. dcon_bus_stabilize
  5. dcon_set_backlight
  6. dcon_set_mono_mode
  7. dcon_sleep
  8. dcon_load_holdoff
  9. dcon_blank_fb
  10. dcon_source_switch
  11. dcon_set_source
  12. dcon_set_source_sync
  13. dcon_mode_show
  14. dcon_sleep_show
  15. dcon_freeze_show
  16. dcon_mono_show
  17. dcon_resumeline_show
  18. dcon_mono_store
  19. dcon_freeze_store
  20. dcon_resumeline_store
  21. dcon_sleep_store
  22. dcon_bl_update
  23. dcon_bl_get
  24. dcon_reboot_notify
  25. unfreeze_on_panic
  26. dcon_detect
  27. dcon_probe
  28. dcon_remove
  29. dcon_suspend
  30. dcon_resume
  31. dcon_interrupt
  32. olpc_dcon_init
  33. olpc_dcon_exit

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

/* [<][>][^][v][top][bottom][index][help] */