Annotation of sys/arch/zaurus/zaurus/zaurus_lcd.c, Revision 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