Merge master.kernel.org:/home/rmk/linux-2.6-arm
[sfrench/cifs-2.6.git] / drivers / video / backlight / locomolcd.c
1 /*
2  * Backlight control code for Sharp Zaurus SL-5500
3  *
4  * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
5  * Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
6  * GPL v2
7  *
8  * This driver assumes single CPU. That's okay, because collie is
9  * slightly old hardware, and noone is going to retrofit second CPU to
10  * old PDA.
11  */
12
13 /* LCD power functions */
14 #include <linux/config.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/delay.h>
18 #include <linux/device.h>
19 #include <linux/interrupt.h>
20 #include <linux/fb.h>
21 #include <linux/backlight.h>
22
23 #include <asm/hardware/locomo.h>
24 #include <asm/irq.h>
25 #include <asm/mach/sharpsl_param.h>
26 #include <asm/mach-types.h>
27
28 #include "../../../arch/arm/mach-sa1100/generic.h"
29
30 static struct backlight_device *locomolcd_bl_device;
31 static struct locomo_dev *locomolcd_dev;
32 static unsigned long locomolcd_flags;
33 #define LOCOMOLCD_SUSPENDED     0x01
34
35 static void locomolcd_on(int comadj)
36 {
37         locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
38         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
39         mdelay(2);
40
41         locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
42         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
43         mdelay(2);
44
45         locomo_m62332_senddata(locomolcd_dev, comadj, 0);
46         mdelay(5);
47
48         locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
49         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
50         mdelay(10);
51
52         /* TFTCRST | CPSOUT=0 | CPSEN */
53         locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
54
55         /* Set CPSD */
56         locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
57
58         /* TFTCRST | CPSOUT=0 | CPSEN */
59         locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
60         mdelay(10);
61
62         locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
63         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
64 }
65
66 static void locomolcd_off(int comadj)
67 {
68         /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
69         locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
70         mdelay(1);
71
72         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
73         mdelay(110);
74
75         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
76         mdelay(700);
77
78         /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
79         locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
80         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
81         locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
82 }
83
84 void locomolcd_power(int on)
85 {
86         int comadj = sharpsl_param.comadj;
87         unsigned long flags;
88
89         local_irq_save(flags);
90
91         if (!locomolcd_dev) {
92                 local_irq_restore(flags);
93                 return;
94         }
95
96         /* read comadj */
97         if (comadj == -1 && machine_is_collie())
98                 comadj = 128;
99         if (comadj == -1 && machine_is_poodle())
100                 comadj = 118;
101
102         if (on)
103                 locomolcd_on(comadj);
104         else
105                 locomolcd_off(comadj);
106
107         local_irq_restore(flags);
108 }
109 EXPORT_SYMBOL(locomolcd_power);
110
111
112 static int current_intensity;
113
114 static int locomolcd_set_intensity(struct backlight_device *bd)
115 {
116         int intensity = bd->props->brightness;
117
118         if (bd->props->power != FB_BLANK_UNBLANK)
119                 intensity = 0;
120         if (bd->props->fb_blank != FB_BLANK_UNBLANK)
121                 intensity = 0;
122         if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
123                 intensity = 0;
124
125         switch (intensity) {
126         /* AC and non-AC are handled differently, but produce same results in sharp code? */
127         case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break;
128         case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break;
129         case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break;
130         case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break;
131         case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break;
132
133         default:
134                 return -ENODEV;
135         }
136         current_intensity = intensity;
137         return 0;
138 }
139
140 static int locomolcd_get_intensity(struct backlight_device *bd)
141 {
142         return current_intensity;
143 }
144
145 static struct backlight_properties locomobl_data = {
146         .owner          = THIS_MODULE,
147         .get_brightness = locomolcd_get_intensity,
148         .update_status  = locomolcd_set_intensity,
149         .max_brightness = 4,
150 };
151
152 #ifdef CONFIG_PM
153 static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state)
154 {
155         locomolcd_flags |= LOCOMOLCD_SUSPENDED;
156         locomolcd_set_intensity(locomolcd_bl_device);
157         return 0;
158 }
159
160 static int locomolcd_resume(struct locomo_dev *dev)
161 {
162         locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
163         locomolcd_set_intensity(locomolcd_bl_device);
164         return 0;
165 }
166 #else
167 #define locomolcd_suspend       NULL
168 #define locomolcd_resume        NULL
169 #endif
170
171 static int locomolcd_probe(struct locomo_dev *dev)
172 {
173         unsigned long flags;
174
175         local_irq_save(flags);
176         locomolcd_dev = dev;
177
178         locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0);
179
180         /* the poodle_lcd_power function is called for the first time
181          * from fs_initcall, which is before locomo is activated.
182          * We need to recall poodle_lcd_power here*/
183         if (machine_is_poodle())
184                 locomolcd_power(1);
185
186         local_irq_restore(flags);
187
188         locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data);
189
190         if (IS_ERR (locomolcd_bl_device))
191                 return PTR_ERR (locomolcd_bl_device);
192
193         /* Set up frontlight so that screen is readable */
194         locomobl_data.brightness = 2;
195         locomolcd_set_intensity(locomolcd_bl_device);
196
197         return 0;
198 }
199
200 static int locomolcd_remove(struct locomo_dev *dev)
201 {
202         unsigned long flags;
203
204         backlight_device_unregister(locomolcd_bl_device);
205         local_irq_save(flags);
206         locomolcd_dev = NULL;
207         local_irq_restore(flags);
208         return 0;
209 }
210
211 static struct locomo_driver poodle_lcd_driver = {
212         .drv = {
213                 .name = "locomo-backlight",
214         },
215         .devid  = LOCOMO_DEVID_BACKLIGHT,
216         .probe  = locomolcd_probe,
217         .remove = locomolcd_remove,
218         .suspend = locomolcd_suspend,
219         .resume = locomolcd_resume,
220 };
221
222
223 static int __init locomolcd_init(void)
224 {
225         int ret = locomo_driver_register(&poodle_lcd_driver);
226         if (ret)
227                 return ret;
228
229 #ifdef CONFIG_SA1100_COLLIE
230         sa1100fb_lcd_power = locomolcd_power;
231 #endif
232         return 0;
233 }
234
235 static void __exit locomolcd_exit(void)
236 {
237         locomo_driver_unregister(&poodle_lcd_driver);
238 }
239
240 module_init(locomolcd_init);
241 module_exit(locomolcd_exit);
242
243 MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>");
244 MODULE_DESCRIPTION("Collie LCD driver");
245 MODULE_LICENSE("GPL");