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