zlcd.c revision 1.12 1 1.12 nonaka /* $NetBSD: zlcd.c,v 1.12 2011/06/19 16:20:09 nonaka Exp $ */
2 1.1 ober /* $OpenBSD: zaurus_lcd.c,v 1.20 2006/06/02 20:50:14 miod Exp $ */
3 1.1 ober /* NetBSD: lubbock_lcd.c,v 1.1 2003/08/09 19:38:53 bsh Exp */
4 1.1 ober
5 1.1 ober /*
6 1.1 ober * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved.
7 1.1 ober * Written by Hiroyuki Bessho for Genetec Corporation.
8 1.1 ober *
9 1.1 ober * Redistribution and use in source and binary forms, with or without
10 1.1 ober * modification, are permitted provided that the following conditions
11 1.1 ober * are met:
12 1.1 ober * 1. Redistributions of source code must retain the above copyright
13 1.1 ober * notice, this list of conditions and the following disclaimer.
14 1.1 ober * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 ober * notice, this list of conditions and the following disclaimer in the
16 1.1 ober * documentation and/or other materials provided with the distribution.
17 1.1 ober * 3. The name of Genetec Corporation may not be used to endorse or
18 1.1 ober * promote products derived from this software without specific prior
19 1.1 ober * written permission.
20 1.1 ober *
21 1.1 ober * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
22 1.1 ober * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.1 ober * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.1 ober * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
25 1.1 ober * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 1.1 ober * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 1.1 ober * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 1.1 ober * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.1 ober * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.1 ober * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1 ober * POSSIBILITY OF SUCH DAMAGE.
32 1.1 ober */
33 1.1 ober
34 1.1 ober /*
35 1.1 ober * LCD driver for Sharp Zaurus (based on the Intel Lubbock driver).
36 1.1 ober *
37 1.1 ober * Controlling LCD is almost completely done through PXA2X0's
38 1.1 ober * integrated LCD controller. Codes for it is arm/xscale/pxa2x0_lcd.c.
39 1.1 ober *
40 1.1 ober * Codes in this file provide platform specific things including:
41 1.1 ober * LCD on/off switch and backlight brightness
42 1.1 ober * LCD panel geometry
43 1.1 ober */
44 1.1 ober
45 1.1 ober #include <sys/cdefs.h>
46 1.12 nonaka __KERNEL_RCSID(0, "$NetBSD: zlcd.c,v 1.12 2011/06/19 16:20:09 nonaka Exp $");
47 1.1 ober
48 1.1 ober #include <sys/param.h>
49 1.1 ober #include <sys/systm.h>
50 1.1 ober #include <sys/conf.h>
51 1.1 ober #include <sys/uio.h>
52 1.1 ober #include <sys/malloc.h>
53 1.1 ober
54 1.1 ober #include <dev/cons.h>
55 1.1 ober #include <dev/wscons/wsconsio.h>
56 1.1 ober #include <dev/wscons/wsdisplayvar.h>
57 1.1 ober #include <dev/wscons/wscons_callbacks.h>
58 1.1 ober
59 1.6 nonaka #include <dev/hpc/hpcfbio.h>
60 1.6 nonaka
61 1.1 ober #include <machine/bus.h>
62 1.1 ober #include <arm/xscale/pxa2x0var.h>
63 1.1 ober #include <arm/xscale/pxa2x0reg.h>
64 1.1 ober #include <arm/xscale/pxa2x0_lcd.h>
65 1.1 ober
66 1.12 nonaka #include <zaurus/zaurus/zaurus_var.h>
67 1.12 nonaka #include <zaurus/dev/zlcdvar.h>
68 1.12 nonaka #include <zaurus/dev/zsspvar.h>
69 1.1 ober #include <zaurus/dev/scoopvar.h>
70 1.12 nonaka #include <zaurus/dev/ioexpvar.h>
71 1.1 ober
72 1.1 ober /*
73 1.1 ober * wsdisplay glue
74 1.1 ober */
75 1.2 peter static struct pxa2x0_wsscreen_descr lcd_std_screen = {
76 1.2 peter .c = {
77 1.2 peter .name = "std",
78 1.2 peter .textops = &pxa2x0_lcd_emulops,
79 1.2 peter .fontwidth = 8,
80 1.2 peter .fontheight = 16,
81 1.2 peter .capabilities = WSSCREEN_WSCOLORS,
82 1.1 ober },
83 1.2 peter .depth = 16, /* bits per pixel */
84 1.4 ober .flags = RI_ROTATE_CW, /* quarter clockwise rotation */
85 1.1 ober };
86 1.1 ober
87 1.1 ober static const struct wsscreen_descr *lcd_scr_descr[] = {
88 1.2 peter &lcd_std_screen.c
89 1.1 ober };
90 1.1 ober
91 1.2 peter static const struct wsscreen_list lcd_screen_list = {
92 1.2 peter .nscreens = __arraycount(lcd_scr_descr),
93 1.2 peter .screens = lcd_scr_descr,
94 1.1 ober };
95 1.1 ober
96 1.5 christos static int lcd_ioctl(void *, void *, u_long, void *, int, struct lwp *);
97 1.2 peter static int lcd_param(struct pxa2x0_lcd_softc *, u_long,
98 1.2 peter struct wsdisplay_param *);
99 1.2 peter static int lcd_show_screen(void *, void *, int,
100 1.2 peter void (*)(void *, int, int), void *);
101 1.1 ober
102 1.2 peter struct wsdisplay_accessops lcd_accessops = {
103 1.1 ober lcd_ioctl,
104 1.1 ober pxa2x0_lcd_mmap,
105 1.1 ober pxa2x0_lcd_alloc_screen,
106 1.1 ober pxa2x0_lcd_free_screen,
107 1.1 ober lcd_show_screen,
108 1.2 peter NULL,
109 1.2 peter NULL,
110 1.2 peter NULL,
111 1.1 ober };
112 1.1 ober
113 1.1 ober #define CURRENT_DISPLAY &sharp_zaurus_C3000
114 1.1 ober
115 1.1 ober const struct lcd_panel_geometry sharp_zaurus_C3000 =
116 1.1 ober {
117 1.1 ober 480, /* Width */
118 1.1 ober 640, /* Height */
119 1.1 ober 0, /* No extra lines */
120 1.1 ober
121 1.1 ober LCDPANEL_ACTIVE | LCDPANEL_VSP | LCDPANEL_HSP,
122 1.1 ober 1, /* clock divider */
123 1.1 ober 0, /* AC bias pin freq */
124 1.1 ober
125 1.1 ober 0x28, /* horizontal sync pulse width */
126 1.1 ober 0x2e, /* BLW */
127 1.1 ober 0x7d, /* ELW */
128 1.1 ober
129 1.1 ober 2, /* vertical sync pulse width */
130 1.1 ober 1, /* BFW */
131 1.1 ober 0, /* EFW */
132 1.1 ober };
133 1.1 ober
134 1.1 ober struct sharp_lcd_backlight {
135 1.1 ober int duty; /* LZ9JG18 DAC value */
136 1.1 ober int cont; /* BACKLIGHT_CONT signal */
137 1.1 ober int on; /* BACKLIGHT_ON signal */
138 1.1 ober };
139 1.1 ober
140 1.1 ober #define CURRENT_BACKLIGHT sharp_zaurus_C3000_bl
141 1.1 ober
142 1.1 ober const struct sharp_lcd_backlight sharp_zaurus_C3000_bl[] = {
143 1.2 peter { 0x00, 0, 0 }, /* 0: Off */
144 1.2 peter { 0x00, 0, 1 }, /* 1: 0% */
145 1.2 peter { 0x01, 0, 1 }, /* 2: 20% */
146 1.2 peter { 0x07, 0, 1 }, /* 3: 40% */
147 1.2 peter { 0x01, 1, 1 }, /* 4: 60% */
148 1.2 peter { 0x07, 1, 1 }, /* 5: 80% */
149 1.2 peter { 0x11, 1, 1 }, /* 6: 100% */
150 1.2 peter { -1, -1, -1 }, /* 7: Invalid */
151 1.1 ober };
152 1.1 ober
153 1.8 nonaka static int lcd_match(device_t, cfdata_t, void *);
154 1.8 nonaka static void lcd_attach(device_t, device_t, void *);
155 1.1 ober
156 1.8 nonaka CFATTACH_DECL_NEW(zlcd, sizeof(struct pxa2x0_lcd_softc),
157 1.1 ober lcd_match, lcd_attach, NULL, NULL);
158 1.1 ober
159 1.12 nonaka static bool lcd_suspend(device_t, const pmf_qual_t *);
160 1.12 nonaka static bool lcd_resume(device_t, const pmf_qual_t *);
161 1.12 nonaka static void lcd_brightness_up(device_t);
162 1.12 nonaka static void lcd_brightness_down(device_t);
163 1.12 nonaka static void lcd_display_on(device_t);
164 1.12 nonaka static void lcd_display_off(device_t);
165 1.12 nonaka
166 1.12 nonaka static int lcd_max_brightness(void);
167 1.12 nonaka static int lcd_get_brightness(void);
168 1.12 nonaka static void lcd_set_brightness(int);
169 1.12 nonaka static void lcd_set_brightness_internal(int);
170 1.12 nonaka static int lcd_get_backlight(void);
171 1.12 nonaka static void lcd_set_backlight(int);
172 1.1 ober
173 1.1 ober static int
174 1.8 nonaka lcd_match(device_t parent, cfdata_t cf, void *aux)
175 1.1 ober {
176 1.1 ober
177 1.12 nonaka if (ZAURUS_ISC1000 || ZAURUS_ISC3000)
178 1.12 nonaka return 1;
179 1.12 nonaka return 0;
180 1.1 ober }
181 1.1 ober
182 1.1 ober static void
183 1.8 nonaka lcd_attach(device_t parent, device_t self, void *aux)
184 1.1 ober {
185 1.8 nonaka struct pxa2x0_lcd_softc *sc = device_private(self);
186 1.1 ober struct wsemuldisplaydev_attach_args aa;
187 1.1 ober
188 1.8 nonaka sc->dev = self;
189 1.8 nonaka
190 1.3 nonaka pxa2x0_lcd_attach_sub(sc, aux, CURRENT_DISPLAY);
191 1.1 ober
192 1.1 ober aa.console = glass_console;
193 1.1 ober aa.scrdata = &lcd_screen_list;
194 1.1 ober aa.accessops = &lcd_accessops;
195 1.1 ober aa.accesscookie = sc;
196 1.1 ober
197 1.2 peter (void) config_found(self, &aa, wsemuldisplaydevprint);
198 1.1 ober
199 1.1 ober /* Start with approximately 40% of full brightness. */
200 1.1 ober lcd_set_brightness(3);
201 1.1 ober
202 1.12 nonaka if (!pmf_device_register(self, lcd_suspend, lcd_resume))
203 1.12 nonaka aprint_error_dev(self, "couldn't establish power handler\n");
204 1.12 nonaka if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP,
205 1.12 nonaka lcd_brightness_up, true))
206 1.12 nonaka aprint_error_dev(self, "couldn't register event handler\n");
207 1.12 nonaka if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN,
208 1.12 nonaka lcd_brightness_down, true))
209 1.12 nonaka aprint_error_dev(self, "couldn't register event handler\n");
210 1.12 nonaka if (!pmf_event_register(self, PMFE_DISPLAY_ON,
211 1.12 nonaka lcd_display_on, true))
212 1.12 nonaka aprint_error_dev(self, "couldn't register event handler\n");
213 1.12 nonaka if (!pmf_event_register(self, PMFE_DISPLAY_OFF,
214 1.12 nonaka lcd_display_off, true))
215 1.12 nonaka aprint_error_dev(self, "couldn't register event handler\n");
216 1.1 ober }
217 1.1 ober
218 1.3 nonaka void
219 1.3 nonaka lcd_cnattach(void)
220 1.3 nonaka {
221 1.3 nonaka
222 1.3 nonaka pxa2x0_lcd_cnattach(&lcd_std_screen, CURRENT_DISPLAY);
223 1.3 nonaka }
224 1.3 nonaka
225 1.1 ober /*
226 1.9 nonaka * power management
227 1.9 nonaka */
228 1.9 nonaka static bool
229 1.11 dyoung lcd_suspend(device_t dv, const pmf_qual_t *qual)
230 1.9 nonaka {
231 1.9 nonaka struct pxa2x0_lcd_softc *sc = device_private(dv);
232 1.9 nonaka
233 1.9 nonaka lcd_set_brightness(0);
234 1.9 nonaka pxa2x0_lcd_suspend(sc);
235 1.9 nonaka
236 1.9 nonaka return true;
237 1.9 nonaka }
238 1.9 nonaka
239 1.9 nonaka static bool
240 1.11 dyoung lcd_resume(device_t dv, const pmf_qual_t *qual)
241 1.9 nonaka {
242 1.9 nonaka struct pxa2x0_lcd_softc *sc = device_private(dv);
243 1.9 nonaka
244 1.9 nonaka pxa2x0_lcd_resume(sc);
245 1.9 nonaka lcd_set_brightness(lcd_get_brightness());
246 1.9 nonaka
247 1.9 nonaka return true;
248 1.9 nonaka }
249 1.9 nonaka
250 1.12 nonaka static void
251 1.12 nonaka lcd_brightness_up(device_t dv)
252 1.12 nonaka {
253 1.12 nonaka
254 1.12 nonaka lcd_set_brightness(lcd_get_brightness() + 1);
255 1.12 nonaka }
256 1.12 nonaka
257 1.12 nonaka static void
258 1.12 nonaka lcd_brightness_down(device_t dv)
259 1.12 nonaka {
260 1.12 nonaka
261 1.12 nonaka lcd_set_brightness(lcd_get_brightness() - 1);
262 1.12 nonaka }
263 1.12 nonaka
264 1.12 nonaka static void
265 1.12 nonaka lcd_display_on(device_t dv)
266 1.12 nonaka {
267 1.12 nonaka
268 1.12 nonaka lcd_blank(0);
269 1.12 nonaka lcd_set_backlight(1);
270 1.12 nonaka }
271 1.12 nonaka
272 1.12 nonaka static void
273 1.12 nonaka lcd_display_off(device_t dv)
274 1.12 nonaka {
275 1.12 nonaka
276 1.12 nonaka lcd_set_backlight(0);
277 1.12 nonaka lcd_blank(1);
278 1.12 nonaka }
279 1.12 nonaka
280 1.9 nonaka /*
281 1.1 ober * wsdisplay accessops overrides
282 1.1 ober */
283 1.2 peter static int
284 1.5 christos lcd_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
285 1.1 ober {
286 1.1 ober struct pxa2x0_lcd_softc *sc = (struct pxa2x0_lcd_softc *)v;
287 1.6 nonaka struct hpcfb_fbconf *fbconf;
288 1.6 nonaka struct hpcfb_dspconf *dspconf;
289 1.1 ober int res = EINVAL;
290 1.1 ober
291 1.1 ober switch (cmd) {
292 1.1 ober case WSDISPLAYIO_GETPARAM:
293 1.1 ober case WSDISPLAYIO_SETPARAM:
294 1.1 ober res = lcd_param(sc, cmd, (struct wsdisplay_param *)data);
295 1.1 ober break;
296 1.6 nonaka
297 1.6 nonaka case HPCFBIO_GCONF:
298 1.6 nonaka fbconf = (struct hpcfb_fbconf *)data;
299 1.6 nonaka if (fbconf->hf_conf_index != 0 &&
300 1.6 nonaka fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
301 1.6 nonaka break;
302 1.6 nonaka }
303 1.6 nonaka
304 1.6 nonaka fbconf->hf_conf_index = 0;
305 1.6 nonaka fbconf->hf_nconfs = 1;
306 1.6 nonaka fbconf->hf_class = HPCFB_CLASS_RGBCOLOR;
307 1.6 nonaka strlcpy(fbconf->hf_name, "Sharp Zaurus frame buffer",
308 1.6 nonaka sizeof(fbconf->hf_name));
309 1.6 nonaka strlcpy(fbconf->hf_conf_name, "default",
310 1.6 nonaka sizeof(fbconf->hf_conf_name));
311 1.6 nonaka fbconf->hf_width = sc->geometry->panel_width;
312 1.6 nonaka fbconf->hf_height = sc->geometry->panel_height;
313 1.6 nonaka fbconf->hf_baseaddr = (u_long)sc->active->buf_va;
314 1.6 nonaka fbconf->hf_offset = 0;
315 1.6 nonaka fbconf->hf_bytes_per_line = sc->geometry->panel_width *
316 1.6 nonaka sc->active->depth / 8;
317 1.6 nonaka fbconf->hf_nplanes = 1;
318 1.6 nonaka fbconf->hf_bytes_per_plane = sc->geometry->panel_width *
319 1.6 nonaka sc->geometry->panel_height * sc->active->depth / 8;
320 1.6 nonaka fbconf->hf_pack_width = sc->active->depth;
321 1.6 nonaka fbconf->hf_pixels_per_pack = 1;
322 1.6 nonaka fbconf->hf_pixel_width = sc->active->depth;
323 1.6 nonaka fbconf->hf_access_flags = (0
324 1.6 nonaka | HPCFB_ACCESS_BYTE
325 1.6 nonaka | HPCFB_ACCESS_WORD
326 1.6 nonaka | HPCFB_ACCESS_DWORD);
327 1.6 nonaka fbconf->hf_order_flags = 0;
328 1.6 nonaka fbconf->hf_reg_offset = 0;
329 1.6 nonaka
330 1.6 nonaka fbconf->hf_class_data_length = sizeof(struct hf_rgb_tag);
331 1.6 nonaka fbconf->hf_u.hf_rgb.hf_flags = 0;
332 1.6 nonaka fbconf->hf_u.hf_rgb.hf_red_width = 5;
333 1.6 nonaka fbconf->hf_u.hf_rgb.hf_red_shift = 11;
334 1.6 nonaka fbconf->hf_u.hf_rgb.hf_green_width = 6;
335 1.6 nonaka fbconf->hf_u.hf_rgb.hf_green_shift = 5;
336 1.6 nonaka fbconf->hf_u.hf_rgb.hf_blue_width = 5;
337 1.6 nonaka fbconf->hf_u.hf_rgb.hf_blue_shift = 0;
338 1.6 nonaka fbconf->hf_u.hf_rgb.hf_alpha_width = 0;
339 1.6 nonaka fbconf->hf_u.hf_rgb.hf_alpha_shift = 0;
340 1.6 nonaka
341 1.6 nonaka fbconf->hf_ext_size = 0;
342 1.6 nonaka fbconf->hf_ext_data = NULL;
343 1.6 nonaka
344 1.6 nonaka res = 0;
345 1.6 nonaka break;
346 1.6 nonaka
347 1.6 nonaka case HPCFBIO_SCONF:
348 1.6 nonaka fbconf = (struct hpcfb_fbconf *)data;
349 1.6 nonaka if (fbconf->hf_conf_index != 0 &&
350 1.6 nonaka fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
351 1.6 nonaka break;
352 1.6 nonaka }
353 1.6 nonaka /* nothing to do because we have only one configuration */
354 1.6 nonaka res = 0;
355 1.6 nonaka break;
356 1.6 nonaka
357 1.6 nonaka case HPCFBIO_GDSPCONF:
358 1.6 nonaka dspconf = (struct hpcfb_dspconf *)data;
359 1.6 nonaka if ((dspconf->hd_unit_index != 0 &&
360 1.6 nonaka dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
361 1.6 nonaka (dspconf->hd_conf_index != 0 &&
362 1.6 nonaka dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
363 1.6 nonaka break;
364 1.6 nonaka }
365 1.6 nonaka
366 1.6 nonaka dspconf->hd_unit_index = 0;
367 1.6 nonaka dspconf->hd_nunits = 1;
368 1.6 nonaka dspconf->hd_class = HPCFB_DSP_CLASS_COLORLCD;
369 1.6 nonaka strlcpy(dspconf->hd_name, "Sharp Zaurus LCD",
370 1.6 nonaka sizeof(dspconf->hd_name));
371 1.6 nonaka dspconf->hd_op_flags = 0;
372 1.6 nonaka dspconf->hd_conf_index = 0;
373 1.6 nonaka dspconf->hd_nconfs = 1;
374 1.6 nonaka strlcpy(dspconf->hd_conf_name, "default",
375 1.6 nonaka sizeof(dspconf->hd_conf_name));
376 1.6 nonaka dspconf->hd_width = sc->geometry->panel_width;
377 1.6 nonaka dspconf->hd_height = sc->geometry->panel_height;
378 1.6 nonaka dspconf->hd_xdpi = HPCFB_DSP_DPI_UNKNOWN;
379 1.6 nonaka dspconf->hd_ydpi = HPCFB_DSP_DPI_UNKNOWN;
380 1.6 nonaka
381 1.6 nonaka res = 0;
382 1.6 nonaka break;
383 1.6 nonaka
384 1.6 nonaka case HPCFBIO_SDSPCONF:
385 1.6 nonaka dspconf = (struct hpcfb_dspconf *)data;
386 1.6 nonaka if ((dspconf->hd_unit_index != 0 &&
387 1.6 nonaka dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
388 1.6 nonaka (dspconf->hd_conf_index != 0 &&
389 1.6 nonaka dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
390 1.6 nonaka break;
391 1.6 nonaka }
392 1.6 nonaka /*
393 1.6 nonaka * nothing to do
394 1.6 nonaka * because we have only one unit and one configuration
395 1.6 nonaka */
396 1.6 nonaka res = 0;
397 1.6 nonaka break;
398 1.6 nonaka
399 1.6 nonaka case HPCFBIO_GOP:
400 1.6 nonaka case HPCFBIO_SOP:
401 1.6 nonaka /* curently not implemented... */
402 1.6 nonaka break;
403 1.1 ober }
404 1.1 ober
405 1.1 ober if (res == EINVAL)
406 1.1 ober res = pxa2x0_lcd_ioctl(v, vs, cmd, data, flag, l);
407 1.1 ober return res;
408 1.1 ober }
409 1.1 ober
410 1.2 peter static int
411 1.1 ober lcd_show_screen(void *v, void *cookie, int waitok,
412 1.2 peter void (*cb_func)(void *, int, int), void *cb_arg)
413 1.1 ober {
414 1.1 ober int error;
415 1.1 ober
416 1.2 peter error = pxa2x0_lcd_show_screen(v, cookie, waitok, cb_func, cb_arg);
417 1.1 ober if (error)
418 1.1 ober return (error);
419 1.1 ober
420 1.1 ober /* Turn on LCD */
421 1.2 peter lcd_set_brightness(lcd_get_brightness());
422 1.1 ober
423 1.1 ober return 0;
424 1.1 ober }
425 1.1 ober
426 1.1 ober /*
427 1.1 ober * wsdisplay I/O controls
428 1.1 ober */
429 1.2 peter static int
430 1.6 nonaka lcd_param(struct pxa2x0_lcd_softc *sc, u_long cmd, struct wsdisplay_param *dp)
431 1.1 ober {
432 1.1 ober int res = EINVAL;
433 1.1 ober
434 1.1 ober switch (dp->param) {
435 1.1 ober case WSDISPLAYIO_PARAM_BACKLIGHT:
436 1.1 ober if (cmd == WSDISPLAYIO_GETPARAM) {
437 1.1 ober dp->min = 0;
438 1.1 ober dp->max = 1;
439 1.1 ober dp->curval = lcd_get_backlight();
440 1.1 ober res = 0;
441 1.1 ober } else if (cmd == WSDISPLAYIO_SETPARAM) {
442 1.1 ober lcd_set_backlight(dp->curval);
443 1.1 ober res = 0;
444 1.1 ober }
445 1.1 ober break;
446 1.1 ober
447 1.1 ober case WSDISPLAYIO_PARAM_CONTRAST:
448 1.1 ober /* unsupported */
449 1.1 ober res = ENOTTY;
450 1.1 ober break;
451 1.1 ober
452 1.1 ober case WSDISPLAYIO_PARAM_BRIGHTNESS:
453 1.1 ober if (cmd == WSDISPLAYIO_GETPARAM) {
454 1.1 ober dp->min = 1;
455 1.1 ober dp->max = lcd_max_brightness();
456 1.1 ober dp->curval = lcd_get_brightness();
457 1.1 ober res = 0;
458 1.1 ober } else if (cmd == WSDISPLAYIO_SETPARAM) {
459 1.1 ober lcd_set_brightness(dp->curval);
460 1.1 ober res = 0;
461 1.1 ober }
462 1.1 ober break;
463 1.1 ober }
464 1.1 ober
465 1.1 ober return res;
466 1.1 ober }
467 1.1 ober
468 1.1 ober /*
469 1.1 ober * LCD backlight
470 1.1 ober */
471 1.1 ober
472 1.1 ober static int lcdbrightnesscurval = 1;
473 1.1 ober static int lcdislit = 1;
474 1.1 ober static int lcdisblank = 0;
475 1.1 ober
476 1.12 nonaka static int
477 1.1 ober lcd_max_brightness(void)
478 1.1 ober {
479 1.1 ober int i;
480 1.1 ober
481 1.1 ober for (i = 0; CURRENT_BACKLIGHT[i].duty != -1; i++)
482 1.1 ober continue;
483 1.1 ober return i - 1;
484 1.1 ober }
485 1.1 ober
486 1.12 nonaka static int
487 1.1 ober lcd_get_brightness(void)
488 1.1 ober {
489 1.1 ober
490 1.1 ober return lcdbrightnesscurval;
491 1.1 ober }
492 1.1 ober
493 1.12 nonaka static void
494 1.1 ober lcd_set_brightness(int newval)
495 1.1 ober {
496 1.1 ober int maxval;
497 1.1 ober
498 1.1 ober maxval = lcd_max_brightness();
499 1.1 ober if (newval < 0)
500 1.1 ober newval = 0;
501 1.1 ober else if (newval > maxval)
502 1.1 ober newval = maxval;
503 1.1 ober
504 1.1 ober if (lcd_get_backlight() && !lcdisblank)
505 1.1 ober lcd_set_brightness_internal(newval);
506 1.1 ober
507 1.1 ober if (newval > 0)
508 1.1 ober lcdbrightnesscurval = newval;
509 1.1 ober }
510 1.1 ober
511 1.12 nonaka static void
512 1.1 ober lcd_set_brightness_internal(int newval)
513 1.1 ober {
514 1.1 ober static int curval = 1;
515 1.1 ober int i;
516 1.1 ober
517 1.1 ober /*
518 1.1 ober * It appears that the C3000 backlight can draw too much power if we
519 1.1 ober * switch it from a low to a high brightness. Increasing brightness
520 1.1 ober * in steps avoids this issue.
521 1.1 ober */
522 1.1 ober if (newval > curval) {
523 1.1 ober for (i = curval + 1; i <= newval; i++) {
524 1.1 ober (void)zssp_ic_send(ZSSP_IC_LZ9JG18,
525 1.1 ober CURRENT_BACKLIGHT[i].duty);
526 1.12 nonaka if (ZAURUS_ISC1000)
527 1.12 nonaka ioexp_set_backlight(CURRENT_BACKLIGHT[i].on,
528 1.12 nonaka CURRENT_BACKLIGHT[i].cont);
529 1.12 nonaka else
530 1.12 nonaka scoop_set_backlight(CURRENT_BACKLIGHT[i].on,
531 1.12 nonaka CURRENT_BACKLIGHT[i].cont);
532 1.1 ober delay(5000);
533 1.1 ober }
534 1.1 ober } else {
535 1.1 ober (void)zssp_ic_send(ZSSP_IC_LZ9JG18,
536 1.1 ober CURRENT_BACKLIGHT[newval].duty);
537 1.12 nonaka if (ZAURUS_ISC1000)
538 1.12 nonaka ioexp_set_backlight(CURRENT_BACKLIGHT[newval].on,
539 1.12 nonaka CURRENT_BACKLIGHT[newval].cont);
540 1.12 nonaka else
541 1.12 nonaka scoop_set_backlight(CURRENT_BACKLIGHT[newval].on,
542 1.12 nonaka CURRENT_BACKLIGHT[newval].cont);
543 1.1 ober }
544 1.1 ober
545 1.1 ober curval = newval;
546 1.1 ober }
547 1.1 ober
548 1.12 nonaka static int
549 1.1 ober lcd_get_backlight(void)
550 1.1 ober {
551 1.1 ober
552 1.1 ober return lcdislit;
553 1.1 ober }
554 1.1 ober
555 1.12 nonaka static void
556 1.2 peter lcd_set_backlight(int onoff)
557 1.1 ober {
558 1.1 ober
559 1.2 peter if (!onoff) {
560 1.1 ober lcd_set_brightness(0);
561 1.1 ober lcdislit = 0;
562 1.1 ober } else {
563 1.1 ober lcdislit = 1;
564 1.1 ober lcd_set_brightness(lcd_get_brightness());
565 1.1 ober }
566 1.1 ober }
567 1.1 ober
568 1.1 ober void
569 1.1 ober lcd_blank(int blank)
570 1.1 ober {
571 1.1 ober
572 1.1 ober if (blank) {
573 1.1 ober lcd_set_brightness(0);
574 1.1 ober lcdisblank = 1;
575 1.1 ober } else {
576 1.1 ober lcdisblank = 0;
577 1.1 ober lcd_set_brightness(lcd_get_brightness());
578 1.1 ober }
579 1.1 ober }
580