Linux-2.6.12-rc2
[GitHub/mt8127/android_kernel_alcatel_ttab.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");