Annotation of sys/arch/zaurus/zaurus/zaurus_lcd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zaurus_lcd.c,v 1.21 2006/11/29 12:13:54 miod Exp $ */
2: /* $NetBSD: lubbock_lcd.c,v 1.1 2003/08/09 19:38:53 bsh Exp $ */
3:
4: /*
5: * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved.
6: * Written by Hiroyuki Bessho for Genetec Corporation.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. The name of Genetec Corporation may not be used to endorse or
17: * promote products derived from this software without specific prior
18: * written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
32:
33: /*
34: * LCD driver for Sharp Zaurus (based on the Intel Lubbock driver).
35: *
36: * Controlling LCD is almost completely done through PXA2X0's
37: * integrated LCD controller. Codes for it is arm/xscale/pxa2x0_lcd.c.
38: *
39: * Codes in this file provide platform specific things including:
40: * LCD on/off switch and backlight brightness
41: * LCD panel geometry
42: */
43:
44: #include <sys/param.h>
45: #include <sys/systm.h>
46: #include <sys/conf.h>
47: #include <sys/uio.h>
48: #include <sys/malloc.h>
49:
50: #include <dev/cons.h>
51: #include <dev/wscons/wsconsio.h>
52: #include <dev/wscons/wsdisplayvar.h>
53: #include <dev/wscons/wscons_callbacks.h>
54:
55: #include <machine/bus.h>
56: #include <arm/xscale/pxa2x0var.h>
57: #include <arm/xscale/pxa2x0reg.h>
58: #include <arm/xscale/pxa2x0_lcd.h>
59:
60: #include <zaurus/dev/zaurus_scoopvar.h>
61: #include <zaurus/dev/zaurus_sspvar.h>
62:
63: #include <dev/rasops/rasops.h>
64:
65: void lcd_attach(struct device *, struct device *, void *);
66: int lcd_match(struct device *, void *, void *);
67: int lcd_cnattach(void (*)(u_int, int));
68:
69: /*
70: * wsdisplay glue
71: */
72: struct pxa2x0_wsscreen_descr
73: lcd_bpp16_screen = {
74: {
75: "std"
76: },
77: 16, /* bits per pixel */
78: RI_ROTATE_CW /* quarter clockwise rotation */
79: };
80:
81: static const struct wsscreen_descr *lcd_scr_descr[] = {
82: &lcd_bpp16_screen.c
83: };
84:
85: const struct wsscreen_list lcd_screen_list = {
86: sizeof lcd_scr_descr / sizeof lcd_scr_descr[0], lcd_scr_descr
87: };
88:
89: int lcd_ioctl(void *, u_long, caddr_t, int, struct proc *);
90: void lcd_burner(void *, u_int, u_int);
91: int lcd_show_screen(void *, void *, int,
92: void (*)(void *, int, int), void *);
93:
94: int lcd_param(struct pxa2x0_lcd_softc *, u_long,
95: struct wsdisplay_param *);
96:
97: const struct wsdisplay_accessops lcd_accessops = {
98: lcd_ioctl,
99: pxa2x0_lcd_mmap,
100: pxa2x0_lcd_alloc_screen,
101: pxa2x0_lcd_free_screen,
102: lcd_show_screen,
103: NULL, /* load_font */
104: NULL, /* scrollback */
105: NULL, /* getchar */
106: lcd_burner
107: };
108:
109: struct cfattach lcd_pxaip_ca = {
110: sizeof (struct pxa2x0_lcd_softc), lcd_match, lcd_attach
111: };
112:
113: struct cfdriver lcd_cd = {
114: NULL, "lcd", DV_DULL
115: };
116:
117: #define CURRENT_DISPLAY &sharp_zaurus_C3000
118:
119: const struct lcd_panel_geometry sharp_zaurus_C3000 =
120: {
121: 480, /* Width */
122: 640, /* Height */
123: 0, /* No extra lines */
124:
125: LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP,
126: 1, /* clock divider */
127: 0, /* AC bias pin freq */
128:
129: 0x28, /* horizontal sync pulse width */
130: 0x2e, /* BLW */
131: 0x7d, /* ELW */
132:
133: 2, /* vertical sync pulse width */
134: 1, /* BFW */
135: 0, /* EFW */
136: };
137:
138: struct sharp_lcd_backlight {
139: int duty; /* LZ9JG18 DAC value */
140: int cont; /* BACKLIGHT_CONT signal */
141: int on; /* BACKLIGHT_ON signal */
142: };
143:
144: #define CURRENT_BACKLIGHT sharp_zaurus_C3000_bl
145:
146: const struct sharp_lcd_backlight sharp_zaurus_C3000_bl[] = {
147: { 0x00, 0, 0 }, /* 0: Off */
148: { 0x00, 0, 1 }, /* 1: 0% */
149: { 0x01, 0, 1 }, /* 2: 20% */
150: { 0x07, 0, 1 }, /* 3: 40% */
151: { 0x01, 1, 1 }, /* 4: 60% */
152: { 0x07, 1, 1 }, /* 5: 80% */
153: { 0x11, 1, 1 }, /* 6: 100% */
154: { -1, -1, -1 } /* 7: Invalid */
155: };
156:
157: int lcd_max_brightness(void);
158: int lcd_get_brightness(void);
159: void lcd_set_brightness(int);
160: void lcd_set_brightness_internal(int);
161: int lcd_get_backlight(void);
162: void lcd_set_backlight(int);
163: void lcd_blank(int);
164: void lcd_power(int, void *);
165:
166: int
167: lcd_match(struct device *parent, void *cf, void *aux)
168: {
169: return 1;
170: }
171:
172: void
173: lcd_attach(struct device *parent, struct device *self, void *aux)
174: {
175: struct pxa2x0_lcd_softc *sc = (struct pxa2x0_lcd_softc *)self;
176: struct wsemuldisplaydev_attach_args aa;
177: extern int glass_console;
178:
179: printf("\n");
180:
181: pxa2x0_lcd_attach_sub(sc, aux, &lcd_bpp16_screen, CURRENT_DISPLAY,
182: glass_console);
183:
184: aa.console = glass_console;
185: aa.scrdata = &lcd_screen_list;
186: aa.accessops = &lcd_accessops;
187: aa.accesscookie = sc;
188: aa.defaultscreens = 0;
189:
190: (void)config_found(self, &aa, wsemuldisplaydevprint);
191:
192: /* Start with approximately 40% of full brightness. */
193: lcd_set_brightness(3);
194:
195: (void)powerhook_establish(lcd_power, sc);
196: }
197:
198: int
199: lcd_cnattach(void (*clkman)(u_int, int))
200: {
201: return
202: (pxa2x0_lcd_cnattach(&lcd_bpp16_screen, CURRENT_DISPLAY, clkman));
203: }
204:
205: /*
206: * wsdisplay accessops overrides
207: */
208:
209: int
210: lcd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
211: {
212: struct pxa2x0_lcd_softc *sc = v;
213: int res = EINVAL;
214:
215: switch (cmd) {
216: case WSDISPLAYIO_GETPARAM:
217: case WSDISPLAYIO_SETPARAM:
218: res = lcd_param(sc, cmd, (struct wsdisplay_param *)data);
219: break;
220: }
221:
222: if (res == EINVAL)
223: res = pxa2x0_lcd_ioctl(v, cmd, data, flag, p);
224:
225: return res;
226: }
227:
228: void
229: lcd_burner(void *v, u_int on, u_int flags)
230: {
231:
232: lcd_set_brightness(on ? lcd_get_brightness() : 0);
233: }
234:
235: int
236: lcd_show_screen(void *v, void *cookie, int waitok,
237: void (*cb)(void *, int, int), void *cbarg)
238: {
239: int rc;
240:
241: if ((rc = pxa2x0_lcd_show_screen(v, cookie, waitok, cb, cbarg)) != 0)
242: return (rc);
243:
244: /* Turn on LCD */
245: lcd_burner(v, 1, 0);
246:
247: return (0);
248: }
249:
250: /*
251: * wsdisplay I/O controls
252: */
253:
254: int
255: lcd_param(struct pxa2x0_lcd_softc *sc, u_long cmd,
256: struct wsdisplay_param *dp)
257: {
258: int res = EINVAL;
259:
260: switch (dp->param) {
261: case WSDISPLAYIO_PARAM_BACKLIGHT:
262: if (cmd == WSDISPLAYIO_GETPARAM) {
263: dp->min = 0;
264: dp->max = 1;
265: dp->curval = lcd_get_backlight();
266: res = 0;
267: } else if (cmd == WSDISPLAYIO_SETPARAM) {
268: lcd_set_backlight(dp->curval);
269: res = 0;
270: }
271: break;
272:
273: case WSDISPLAYIO_PARAM_CONTRAST:
274: /* unsupported */
275: res = ENOTTY;
276: break;
277:
278: case WSDISPLAYIO_PARAM_BRIGHTNESS:
279: if (cmd == WSDISPLAYIO_GETPARAM) {
280: dp->min = 1;
281: dp->max = lcd_max_brightness();
282: dp->curval = lcd_get_brightness();
283: res = 0;
284: } else if (cmd == WSDISPLAYIO_SETPARAM) {
285: lcd_set_brightness(dp->curval);
286: res = 0;
287: }
288: break;
289: }
290:
291: return res;
292: }
293:
294: /*
295: * LCD backlight
296: */
297:
298: static int lcdbrightnesscurval = 1;
299: static int lcdislit = 1;
300: static int lcdisblank = 0;
301:
302: int
303: lcd_max_brightness(void)
304: {
305: int i;
306:
307: for (i = 0; CURRENT_BACKLIGHT[i].duty != -1; i++)
308: ;
309: return i - 1;
310: }
311:
312: int
313: lcd_get_brightness(void)
314: {
315:
316: return lcdbrightnesscurval;
317: }
318:
319: void
320: lcd_set_brightness(int newval)
321: {
322: int max;
323:
324: max = lcd_max_brightness();
325: if (newval < 0)
326: newval = 0;
327: else if (newval > max)
328: newval = max;
329:
330: if (lcd_get_backlight() && !lcdisblank)
331: lcd_set_brightness_internal(newval);
332:
333: if (newval > 0)
334: lcdbrightnesscurval = newval;
335: }
336:
337: void
338: lcd_set_brightness_internal(int newval)
339: {
340: static int curval = 1;
341: int i;
342:
343: /*
344: * It appears that the C3000 backlight can draw too much power if we
345: * switch it from a low to a high brightness. Increasing brightness
346: * in steps avoids this issue.
347: */
348: if (newval > curval) {
349: for (i = curval + 1; i <= newval; i++) {
350: (void)zssp_ic_send(ZSSP_IC_LZ9JG18,
351: CURRENT_BACKLIGHT[i].duty);
352: scoop_set_backlight(CURRENT_BACKLIGHT[i].on,
353: CURRENT_BACKLIGHT[i].cont);
354: delay(5000);
355: }
356: } else {
357: (void)zssp_ic_send(ZSSP_IC_LZ9JG18,
358: CURRENT_BACKLIGHT[newval].duty);
359: scoop_set_backlight(CURRENT_BACKLIGHT[newval].on,
360: CURRENT_BACKLIGHT[newval].cont);
361: }
362:
363: curval = newval;
364: }
365:
366: int
367: lcd_get_backlight(void)
368: {
369:
370: return lcdislit;
371: }
372:
373: void
374: lcd_set_backlight(int on)
375: {
376:
377: if (!on) {
378: lcd_set_brightness(0);
379: lcdislit = 0;
380: } else {
381: lcdislit = 1;
382: lcd_set_brightness(lcd_get_brightness());
383: }
384: }
385:
386: void
387: lcd_blank(int blank)
388: {
389:
390: if (blank) {
391: lcd_set_brightness(0);
392: lcdisblank = 1;
393: } else {
394: lcdisblank = 0;
395: lcd_set_brightness(lcd_get_brightness());
396: }
397: }
398:
399: void
400: lcd_power(int why, void *v)
401: {
402:
403: switch (why) {
404: case PWR_SUSPEND:
405: case PWR_STANDBY:
406: lcd_set_brightness(0);
407: pxa2x0_lcd_power(why, v);
408: break;
409:
410: case PWR_RESUME:
411: pxa2x0_lcd_power(why, v);
412: lcd_set_brightness(lcd_get_brightness());
413: break;
414: }
415: }
CVSweb