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