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
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>
22 #include <linux/lcd.h>
23 #include <linux/backlight.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"
33 # define debug(s, args...) printk (KERN_INFO s, ##args)
35 # define debug(s, args...)
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
);
56 /* MediaQ GPIO 1 seems connected to flat-panel power */
57 mq_base
->set_GPIO (mq_base
, 1, MQ_GPIO_OUT1
);
59 /* Output '0' to MQ1132 GPIO 1 */
60 mq_base
->set_GPIO (mq_base
, 1, MQ_GPIO_OUT0
);
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
);
73 if (lcdfp_state
== 0) {
82 /* This routine is generic for any MediaQ 1100/1132 chips */
84 roverp5p_lcd_set_contrast (struct lcd_device
*ld
, int contrast
)
86 struct mediaq11xx_base
*mq_base
= class_get_devdata (&ld
->class_dev
);
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.
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);
114 roverp5p_lcd_get_contrast (struct lcd_device
*ld
)
116 struct mediaq11xx_base
*mq_base
= class_get_devdata (&ld
->class_dev
);
121 x
= (mq_base
->regs
->FP
.pin_output_select_1
& 0x7f);
122 for (c
= 7; x
; x
>>= 1, c
--)
127 /*---* Backlight *---*/
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 */
138 mq_base
->set_GPIO (mq_base
, 64, MQ_GPIO_IN
| MQ_GPIO_OUT1
);
139 if (PWM_PWDUTY0
& 0x3ff)
145 mq_base
->set_GPIO (mq_base
, 64, MQ_GPIO_IN
| MQ_GPIO_OUT0
);
151 roverp5p_backlight_get_power (struct backlight_device
*bd
)
153 struct mediaq11xx_base
*mq_base
= class_get_devdata (&bd
->class_dev
);
157 return mq_base
->get_GPIO (mq_base
, 64) ? 0 : 4;
161 roverp5p_backlight_set_brightness (struct backlight_device
*bd
, int brightness
)
163 debug_func ("brightness:%d\n", brightness
);
165 if (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 */
186 roverp5p_backlight_get_brightness (struct backlight_device
*bd
)
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
));
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
,
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
,
234 if (IS_ERR (mqfb_lcd_device
)) {
235 backlight_device_unregister (mqfb_backlight_device
);
236 return PTR_ERR (mqfb_lcd_device
);
242 static int roverp5p_fp_remove (struct device
*dev
)
246 backlight_device_unregister (mqfb_backlight_device
);
247 lcd_device_unregister (mqfb_lcd_device
);
252 static int roverp5p_fp_suspend (struct device
*dev
, u32 state
, u32 level
)
258 static int roverp5p_fp_resume (struct device
*dev
, u32 level
)
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
275 roverp5p_fp_init(void)
278 return driver_register (&roverp5p_fp_device_driver
);
282 roverp5p_fp_exit(void)
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");