sync hh.org
[hh.org.git] / arch / arm / mach-pxa / rover / roverp5p_lcd.c
blobd1a14d796537e00d1e8549812ebf3f1f71772650
1 /*
2 * LCD controls for roverp5p
4 * Copyright ? 2004 Andrew Zabolotny
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
11 * 2003 Andrew Zabolotny Original code for Axim X5
12 * 2004 Konstantine A. Beklemishev Copied from aximx5_lcd.c and adapted to Rover P5+
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <linux/tty.h>
19 #include <linux/sched.h>
20 #include <linux/delay.h>
21 #include <linux/pm.h>
22 #include <linux/lcd.h>
23 #include <linux/backlight.h>
24 #include <linux/fb.h>
25 #include <linux/device.h>
26 #include <linux/soc-old.h>
28 #include <asm/arch/pxa-regs.h>
29 #include <asm/arch/roverp5p-gpio.h>
30 #include "../drivers/soc/mq11xx.h"
32 #if 0
33 # define debug(s, args...) printk (KERN_INFO s, ##args)
34 #else
35 # define debug(s, args...)
36 #endif
37 #define debug_func(s, args...) debug ("%s: " s, __FUNCTION__, ##args)
39 static int roverp5p_lcd_set_power (struct lcd_device *ld, int state)
41 struct mediaq11xx_base *mq_base = class_get_devdata (&ld->class_dev);
42 int lcdfp_state = mq_base->get_power (mq_base, MEDIAQ_11XX_FP_DEVICE_ID) ? 1 : 0;
43 int fpctl_state = mq_base->get_power (mq_base, MEDIAQ_11XX_FB_DEVICE_ID) ? 1 : 0;
45 int new_lcdfp_state = (state < 1) ? 1 : 0;
46 int new_fpctl_state = (state < 4) ? 1 : 0;
48 debug_func ("state:%d\n", state);
50 if (new_lcdfp_state != lcdfp_state)
51 mq_base->set_power (mq_base, MEDIAQ_11XX_FP_DEVICE_ID, new_lcdfp_state);
52 if (new_fpctl_state != fpctl_state)
53 mq_base->set_power (mq_base, MEDIAQ_11XX_FB_DEVICE_ID, new_fpctl_state);
55 if (new_lcdfp_state)
56 /* MediaQ GPIO 1 seems connected to flat-panel power */
57 mq_base->set_GPIO (mq_base, 1, MQ_GPIO_OUT1);
58 else
59 /* Output '0' to MQ1132 GPIO 1 */
60 mq_base->set_GPIO (mq_base, 1, MQ_GPIO_OUT0);
62 return 0;
65 static int roverp5p_lcd_get_power (struct lcd_device *ld)
67 struct mediaq11xx_base *mq_base = class_get_devdata (&ld->class_dev);
68 int lcdfp_state = mq_base->get_power (mq_base, MEDIAQ_11XX_FP_DEVICE_ID);
69 int fpctl_state = mq_base->get_power (mq_base, MEDIAQ_11XX_FB_DEVICE_ID);
71 debug_func ("\n");
73 if (lcdfp_state == 0) {
74 if (fpctl_state == 0)
75 return 4;
76 else
77 return 2;
79 return 0;
82 /* This routine is generic for any MediaQ 1100/1132 chips */
83 static int
84 roverp5p_lcd_set_contrast (struct lcd_device *ld, int contrast)
86 struct mediaq11xx_base *mq_base = class_get_devdata (&ld->class_dev);
87 u32 x;
89 debug_func ("contrast:%d\n", contrast);
91 /* Well... this is kind of tricky but here's how it works:
92 * On 24-bit TFT panels the R,G,B channels are output via
93 * the FD0..FD23 MQ1132' outputs. There are separate enable
94 * bits for these pins in FP07R, which we will use.
95 * Basically we just mask out (setting them to '1')
96 * the lowest 1..8 bits of every color component thus
97 * effectively reducing the number of bits for them.
99 if (contrast > 7)
100 contrast = 7;
101 contrast = 7 ^ contrast;
103 x = (1 << contrast) - 1;
105 mq_base->regs->FP.pin_output_data |= 0x00ffffff;
106 mq_base->regs->FP.pin_output_select_1 =
107 (mq_base->regs->FP.pin_output_select_1 & 0xff000000) |
108 x | (x << 8) | (x << 16);
110 return 0;
113 static int
114 roverp5p_lcd_get_contrast (struct lcd_device *ld)
116 struct mediaq11xx_base *mq_base = class_get_devdata (&ld->class_dev);
117 u32 c, x;
119 debug_func ("\n");
121 x = (mq_base->regs->FP.pin_output_select_1 & 0x7f);
122 for (c = 7; x; x >>= 1, c--)
124 return c;
127 /*---* Backlight *---*/
129 static int
130 roverp5p_backlight_set_power (struct backlight_device *bd, int state)
132 struct mediaq11xx_base *mq_base = class_get_devdata (&bd->class_dev);
134 debug_func ("state:%d\n", state);
136 /* Turn off backlight power */
137 if (state == 0) {
138 mq_base->set_GPIO (mq_base, 64, MQ_GPIO_IN | MQ_GPIO_OUT1);
139 if (PWM_PWDUTY0 & 0x3ff)
140 CKEN |= CKEN0_PWM0;
141 else
142 CKEN &= ~CKEN0_PWM0;
143 } else {
144 CKEN &= ~CKEN0_PWM0;
145 mq_base->set_GPIO (mq_base, 64, MQ_GPIO_IN | MQ_GPIO_OUT0);
147 return 0;
150 static int
151 roverp5p_backlight_get_power (struct backlight_device *bd)
153 struct mediaq11xx_base *mq_base = class_get_devdata (&bd->class_dev);
155 debug_func ("\n");
157 return mq_base->get_GPIO (mq_base, 64) ? 0 : 4;
160 static int
161 roverp5p_backlight_set_brightness (struct backlight_device *bd, int brightness)
163 debug_func ("brightness:%d\n", brightness);
165 if (brightness > 0x3ff)
166 brightness = 0x3ff;
168 /* LCD brightness on Dell Axim is driven by PWM0.
169 * We'll set the pre-scaler to 8, and the period to 1024, this
170 * means the backlight refresh rate will be 3686400/(8*1024) =
171 * 450 Hz which is quite enough.
173 PWM_CTRL0 = 7; /* pre-scaler */
174 PWM_PWDUTY0 = brightness; /* duty cycle */
175 PWM_PERVAL0 = 0x3ff; /* period */
177 if (brightness)
178 CKEN |= CKEN0_PWM0;
179 else
180 CKEN &= ~CKEN0_PWM0;
182 return 0;
185 static int
186 roverp5p_backlight_get_brightness (struct backlight_device *bd)
188 u32 x, y;
190 debug_func ("\n");
192 x = PWM_PWDUTY0 & 0x3ff;
193 y = PWM_PERVAL0 & 0x3ff;
194 // To avoid division, we'll approximate y to nearest 2^n-1.
195 // PocketPC is using 0xfe as PERVAL0 and we're using 0x3ff.
196 x <<= (10 - fls (y));
197 return x;
200 /*-------------------// Flat panel driver for SoC device //------------------*/
202 static struct lcd_properties mq11xx_fb0_lcd = {
203 .owner = THIS_MODULE,
204 .get_power = roverp5p_lcd_get_power,
205 .set_power = roverp5p_lcd_set_power,
206 .max_contrast = 7,
207 .get_contrast = roverp5p_lcd_get_contrast,
208 .set_contrast = roverp5p_lcd_set_contrast,
211 static struct backlight_properties mq11xx_fb0_bl = {
212 .owner = THIS_MODULE,
213 .get_power = roverp5p_backlight_get_power,
214 .set_power = roverp5p_backlight_set_power,
215 .max_brightness = 0x3ff,
216 .get_brightness = roverp5p_backlight_get_brightness,
217 .set_brightness = roverp5p_backlight_set_brightness,
220 static struct lcd_device *mqfb_lcd_device;
221 static struct backlight_device *mqfb_backlight_device;
223 static int roverp5p_fp_probe (struct device *dev)
225 struct mediaq11xx_base *mq_base =
226 (struct mediaq11xx_base *)dev->platform_data;
228 mqfb_backlight_device = backlight_device_register ("mq11xx_fb0",
229 mq_base, &mq11xx_fb0_bl);
230 if (IS_ERR (mqfb_backlight_device))
231 return PTR_ERR (mqfb_backlight_device);
232 mqfb_lcd_device = lcd_device_register ("mq11xx_fb0", mq_base,
233 &mq11xx_fb0_lcd);
234 if (IS_ERR (mqfb_lcd_device)) {
235 backlight_device_unregister (mqfb_backlight_device);
236 return PTR_ERR (mqfb_lcd_device);
239 return 0;
242 static int roverp5p_fp_remove (struct device *dev)
244 debug_func ("\n");
246 backlight_device_unregister (mqfb_backlight_device);
247 lcd_device_unregister (mqfb_lcd_device);
249 return 0;
252 static int roverp5p_fp_suspend (struct device *dev, u32 state, u32 level)
254 debug_func ("\n");
255 return 0;
258 static int roverp5p_fp_resume (struct device *dev, u32 level)
260 debug_func ("\n");
261 return 0;
264 static platform_device_id roverp5p_fp_device_ids[] = { MEDIAQ_11XX_FP_DEVICE_ID, 0 };
266 struct device_driver roverp5p_fp_device_driver = {
267 .name = "mq11xx_lcd",
268 .probe = roverp5p_fp_probe,
269 .remove = roverp5p_fp_remove,
270 .suspend = roverp5p_fp_suspend,
271 .resume = roverp5p_fp_resume
274 static int __init
275 roverp5p_fp_init(void)
277 debug_func ("\n");
278 return driver_register (&roverp5p_fp_device_driver);
281 static void __exit
282 roverp5p_fp_exit(void)
284 debug_func ("\n");
285 driver_unregister (&roverp5p_fp_device_driver);
288 module_init(roverp5p_fp_init);
289 module_exit(roverp5p_fp_exit);
291 MODULE_AUTHOR("Konstantine A. Bekelmishev <konstantine@r66.ru>");
292 MODULE_DESCRIPTION("LCD driver for Rover P5+");
293 MODULE_LICENSE("GPL");