Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / video / backlight / corgi_bl.c
1 /*
2  *  Backlight Driver for Sharp Corgi
3  *
4  *  Copyright (c) 2004-2005 Richard Purdie
5  *
6  *  Based on Sharp's 2.4 Backlight Driver
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  */
13
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/device.h>
18 #include <linux/spinlock.h>
19 #include <linux/fb.h>
20 #include <linux/backlight.h>
21
22 #include <asm/arch-pxa/corgi.h>
23 #include <asm/hardware/scoop.h>
24
25 #define CORGI_MAX_INTENSITY             0x3e
26 #define CORGI_DEFAULT_INTENSITY         0x1f
27 #define CORGI_LIMIT_MASK                        0x0b
28
29 static int corgibl_powermode = FB_BLANK_UNBLANK;
30 static int current_intensity = 0;
31 static int corgibl_limit = 0;
32 static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
33
34 static void corgibl_send_intensity(int intensity)
35 {
36         unsigned long flags;
37         void (*corgi_kick_batt)(void);
38
39         if (corgibl_powermode != FB_BLANK_UNBLANK) {
40                 intensity = 0;
41         } else {
42                 if (corgibl_limit)
43                         intensity &= CORGI_LIMIT_MASK;
44         }
45
46         /* Skip 0x20 as it will blank the display */
47         if (intensity >= 0x20)
48                 intensity++;
49
50         spin_lock_irqsave(&bl_lock, flags);
51         /* Bits 0-4 are accessed via the SSP interface */
52         corgi_ssp_blduty_set(intensity & 0x1f);
53         /* Bit 5 is via SCOOP */
54         if (intensity & 0x0020)
55                 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
56         else
57                 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
58         spin_unlock_irqrestore(&bl_lock, flags);
59 }
60
61 static void corgibl_blank(int blank)
62 {
63         switch(blank) {
64
65         case FB_BLANK_NORMAL:
66         case FB_BLANK_VSYNC_SUSPEND:
67         case FB_BLANK_HSYNC_SUSPEND:
68         case FB_BLANK_POWERDOWN:
69                 if (corgibl_powermode == FB_BLANK_UNBLANK) {
70                         corgibl_send_intensity(0);
71                         corgibl_powermode = blank;
72                 }
73                 break;
74         case FB_BLANK_UNBLANK:
75                 if (corgibl_powermode != FB_BLANK_UNBLANK) {
76                         corgibl_powermode = blank;
77                         corgibl_send_intensity(current_intensity);
78                 }
79                 break;
80         }
81 }
82
83 #ifdef CONFIG_PM
84 static int corgibl_suspend(struct device *dev, u32 state, u32 level)
85 {
86         if (level == SUSPEND_POWER_DOWN)
87                 corgibl_blank(FB_BLANK_POWERDOWN);
88         return 0;
89 }
90
91 static int corgibl_resume(struct device *dev, u32 level)
92 {
93         if (level == RESUME_POWER_ON)
94                 corgibl_blank(FB_BLANK_UNBLANK);
95         return 0;
96 }
97 #else
98 #define corgibl_suspend NULL
99 #define corgibl_resume  NULL
100 #endif
101
102
103 static int corgibl_set_power(struct backlight_device *bd, int state)
104 {
105         corgibl_blank(state);
106         return 0;
107 }
108
109 static int corgibl_get_power(struct backlight_device *bd)
110 {
111         return corgibl_powermode;
112 }
113
114 static int corgibl_set_intensity(struct backlight_device *bd, int intensity)
115 {
116         if (intensity > CORGI_MAX_INTENSITY)
117                 intensity = CORGI_MAX_INTENSITY;
118         corgibl_send_intensity(intensity);
119         current_intensity=intensity;
120         return 0;
121 }
122
123 static int corgibl_get_intensity(struct backlight_device *bd)
124 {
125         return current_intensity;
126 }
127
128 /*
129  * Called when the battery is low to limit the backlight intensity.
130  * If limit==0 clear any limit, otherwise limit the intensity
131  */
132 void corgibl_limit_intensity(int limit)
133 {
134         corgibl_limit = (limit ? 1 : 0);
135         corgibl_send_intensity(current_intensity);
136 }
137 EXPORT_SYMBOL(corgibl_limit_intensity);
138
139
140 static struct backlight_properties corgibl_data = {
141         .owner          = THIS_MODULE,
142         .get_power      = corgibl_get_power,
143         .set_power      = corgibl_set_power,
144         .max_brightness = CORGI_MAX_INTENSITY,
145         .get_brightness = corgibl_get_intensity,
146         .set_brightness = corgibl_set_intensity,
147 };
148
149 static struct backlight_device *corgi_backlight_device;
150
151 static int __init corgibl_probe(struct device *dev)
152 {
153         corgi_backlight_device = backlight_device_register ("corgi-bl",
154                 NULL, &corgibl_data);
155         if (IS_ERR (corgi_backlight_device))
156                 return PTR_ERR (corgi_backlight_device);
157
158         corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY);
159
160         printk("Corgi Backlight Driver Initialized.\n");
161         return 0;
162 }
163
164 static int corgibl_remove(struct device *dev)
165 {
166         backlight_device_unregister(corgi_backlight_device);
167
168         corgibl_set_intensity(NULL, 0);
169
170         printk("Corgi Backlight Driver Unloaded\n");
171         return 0;
172 }
173
174 static struct device_driver corgibl_driver = {
175         .name           = "corgi-bl",
176         .bus            = &platform_bus_type,
177         .probe          = corgibl_probe,
178         .remove         = corgibl_remove,
179         .suspend        = corgibl_suspend,
180         .resume         = corgibl_resume,
181 };
182
183 static int __init corgibl_init(void)
184 {
185         return driver_register(&corgibl_driver);
186 }
187
188 static void __exit corgibl_exit(void)
189 {
190         driver_unregister(&corgibl_driver);
191 }
192
193 module_init(corgibl_init);
194 module_exit(corgibl_exit);
195
196 MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
197 MODULE_DESCRIPTION("Corgi Backlight Driver");
198 MODULE_LICENSE("GPLv2");