vrc4172pwm.c revision 1.11 1 /* $Id: vrc4172pwm.c,v 1.11 2001/03/24 15:53:37 sato Exp $ */
2
3 /*
4 * Copyright (c) 2000,2001 SATO Kazumi. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/device.h>
31 #include <sys/reboot.h>
32
33 #include <machine/bus.h>
34 #include <machine/config_hook.h>
35 #include <machine/platid.h>
36 #include <machine/platid_mask.h>
37
38 #include <hpcmips/vr/vr.h>
39 #include <hpcmips/vr/vripvar.h>
40 #include <hpcmips/vr/vrc4172pwmvar.h>
41 #include <hpcmips/vr/vrc4172pwmreg.h>
42
43 #include "locators.h"
44
45 #ifdef VRC2PWMDEBUG
46 #ifndef VRC2PWMDEBUG_CONF
47 #define VRC2PWMDEBUG_CONF 0
48 #endif /* VRC2PWMDEBUG_CONF */
49 int vrc4172pwmdebug = VRC2PWMDEBUG_CONF;
50 #define DPRINTF(arg) if (vrc4172pwmdebug) printf arg;
51 #define VPRINTF(arg) if (bootverbose||vrc4172pwmdebug) printf arg;
52 #define VDUMPREG(arg) if (bootverbose||vrc4172pwmdebug) vrc4172pwm_dumpreg(arg);
53 #else /* VRC2PWMDEBUG */
54 #define DPRINTF(arg)
55 #define VPRINTF(arg) if (bootverbose) printf arg;
56 #define VDUMPREG(arg) if (bootverbose) vrc4172pwm_dumpreg(arg);
57 #endif /* VRC2PWMDEBUG */
58
59 static int vrc4172pwmprobe __P((struct device *, struct cfdata *, void *));
60 static void vrc4172pwmattach __P((struct device *, struct device *, void *));
61
62 static void vrc4172pwm_write __P((struct vrc4172pwm_softc *, int, unsigned short));
63 static unsigned short vrc4172pwm_read __P((struct vrc4172pwm_softc *, int));
64
65 static int vrc4172pwm_event __P((void *, int, long, void *));
66 static int vrc4172pwm_pmevent __P((void *, int, long, void *));
67
68 static void vrc4172pwm_dumpreg __P((struct vrc4172pwm_softc *));
69 static void vrc4172pwm_init_brightness __P((struct vrc4172pwm_softc *));
70 void vrc4172pwm_light __P((struct vrc4172pwm_softc *, int));
71 int vrc4172pwm_get_light __P((struct vrc4172pwm_softc *));
72 int vrc4172pwm_get_brightness __P((struct vrc4172pwm_softc *));
73 void vrc4172pwm_set_brightness __P((struct vrc4172pwm_softc *, int));
74 int vrc4172pwm_rawduty2brightness __P((struct vrc4172pwm_softc *));
75 int vrc4172pwm_brightness2rawduty __P((struct vrc4172pwm_softc *));
76 struct vrc4172pwm_param * vrc4172pwm_getparam __P((void));
77 void vrc4172pwm_dumpreg __P((struct vrc4172pwm_softc *));
78
79 struct cfattach vrc4172pwm_ca = {
80 sizeof(struct vrc4172pwm_softc), vrc4172pwmprobe, vrc4172pwmattach
81 };
82
83 /*
84 * platform related parameters
85 */
86 struct vrc4172pwm_param vrc4172pwm_mcr520_param = {
87 1, /* probe broken */
88 8, /* levels */
89 { 0x16, 0x1f, 0x24, 0x2a, 0x2f, 0x34, 0x3a, 0x3f }
90 };
91
92 struct vrc4172pwm_param vrc4172pwm_mcr530_param = {
93 0,
94 8, /* levels */
95 { 0x16, 0x1b, 0x20, 0x25, 0x2a, 0x30, 0x37, 0x3f }
96 };
97
98 struct vrc4172pwm_param vrc4172pwm_mcr700_param = {
99 1, /* probe broken */
100 8, /* levels */
101 { 0x12, 0x15, 0x18, 0x1d, 0x24, 0x2d, 0x38, 0x3f }
102 };
103
104 struct vrc4172pwm_param vrc4172pwm_sigmarion_param = {
105 0,
106 8, /* levels */
107 { 0xe, 0x13, 0x18, 0x1c, 0x23, 0x29, 0x32, 0x3f }
108 };
109
110
111 struct platid_data vrc4172pwm_platid_param_table[] = {
112 { &platid_mask_MACH_NEC_MCR_430,
113 &vrc4172pwm_mcr530_param},
114 { &platid_mask_MACH_NEC_MCR_510,
115 &vrc4172pwm_mcr520_param},
116 { &platid_mask_MACH_NEC_MCR_520,
117 &vrc4172pwm_mcr520_param},
118 { &platid_mask_MACH_NEC_MCR_520A,
119 &vrc4172pwm_mcr520_param},
120 { &platid_mask_MACH_NEC_MCR_530,
121 &vrc4172pwm_mcr530_param},
122 { &platid_mask_MACH_NEC_MCR_530A,
123 &vrc4172pwm_mcr530_param},
124 { &platid_mask_MACH_NEC_MCR_SIGMARION,
125 &vrc4172pwm_sigmarion_param},
126 { &platid_mask_MACH_NEC_MCR_700,
127 &vrc4172pwm_mcr700_param},
128 { &platid_mask_MACH_NEC_MCR_700A,
129 &vrc4172pwm_mcr700_param},
130 { NULL, NULL}
131 };
132
133 struct vrc4172pwm_softc *this_pwm;
134
135 static inline void
136 vrc4172pwm_write(sc, port, val)
137 struct vrc4172pwm_softc *sc;
138 int port;
139 unsigned short val;
140 {
141 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
142 }
143
144 static inline unsigned short
145 vrc4172pwm_read(sc, port)
146 struct vrc4172pwm_softc *sc;
147 int port;
148 {
149 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
150 }
151
152 static int
153 vrc4172pwmprobe(parent, cf, aux)
154 struct device *parent;
155 struct cfdata *cf;
156 void *aux;
157 {
158 platid_mask_t mask;
159 struct vrip_attach_args *va = aux;
160 bus_space_handle_t ioh;
161 #ifdef VRC4172PWM_BROKEN_PROBE
162 int probe = 0;
163 #else /* VRC4172PWM_BROKEN_PROBE */
164 int probe = 1;
165 #endif /* VRC4172PWM_BROKEN_PROBE */
166 int data;
167 int data2;
168 struct vrc4172pwm_param *param;
169 int ret = 0;
170
171 if (va->va_addr == VRIPCF_ADDR_DEFAULT)
172 return 0;
173
174 if (cf->cf_loc[VRIPCF_PLATFORM] == 0)
175 return 0;
176 if (cf->cf_loc[VRIPCF_PLATFORM] != -1) { /* if specify */
177 mask = PLATID_DEREF(cf->cf_loc[VRIPCF_PLATFORM]);
178 VPRINTF(("vrc4172pwmprobe: check platid\n"));
179 if (platid_match(&platid, &mask) == 0)
180 return 0;
181 param = vrc4172pwm_getparam();
182 if (param != NULL && param->brokenprobe)
183 probe = 0;
184 }
185 if (probe) {
186 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh)) {
187 return 0;
188 }
189 data = bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN);
190 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, 0xff);
191 if ((data2 = bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN))
192 == VRC2_PWM_LCDEN_MASK) {
193 VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN found\n"));
194 ret = 1;
195 } else {
196 VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN not found org=%x, data=%x!=%x\n", data, data2, VRC2_PWM_LCDEN_MASK));
197 }
198 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, data);
199 bus_space_unmap(va->va_iot, ioh, va->va_size);
200 } else
201 ret = 1;
202 VPRINTF(("vrc4172pwmprobe: return %d\n", ret));
203 return ret;
204 }
205
206 static void
207 vrc4172pwmattach(parent, self, aux)
208 struct device *parent;
209 struct device *self;
210 void *aux;
211 {
212 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)self;
213 struct vrip_attach_args *va = aux;
214
215 bus_space_tag_t iot = va->va_iot;
216 bus_space_handle_t ioh;
217
218 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
219 printf(": can't map bus space\n");
220 return;
221 }
222
223 sc->sc_iot = iot;
224 sc->sc_ioh = ioh;
225
226 printf("\n");
227
228 VDUMPREG(sc);
229 /* basic setup */
230 sc->sc_pmhook = config_hook(CONFIG_HOOK_PMEVENT,
231 CONFIG_HOOK_PMEVENT_HARDPOWER,
232 CONFIG_HOOK_SHARE,
233 vrc4172pwm_pmevent, sc);
234 sc->sc_lcdhook = config_hook(CONFIG_HOOK_POWERCONTROL,
235 CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
236 CONFIG_HOOK_SHARE,
237 vrc4172pwm_event, sc);
238 sc->sc_getlcdhook = config_hook(CONFIG_HOOK_GET,
239 CONFIG_HOOK_POWER_LCDLIGHT,
240 CONFIG_HOOK_SHARE,
241 vrc4172pwm_event, sc);
242 sc->sc_sethook = config_hook(CONFIG_HOOK_SET,
243 CONFIG_HOOK_BRIGHTNESS,
244 CONFIG_HOOK_SHARE,
245 vrc4172pwm_event, sc);
246 sc->sc_gethook = config_hook(CONFIG_HOOK_GET,
247 CONFIG_HOOK_BRIGHTNESS,
248 CONFIG_HOOK_SHARE,
249 vrc4172pwm_event, sc);
250 sc->sc_getmaxhook = config_hook(CONFIG_HOOK_GET,
251 CONFIG_HOOK_BRIGHTNESS_MAX,
252 CONFIG_HOOK_SHARE,
253 vrc4172pwm_event, sc);
254
255 vrc4172pwm_init_brightness(sc);
256 if (sc->sc_param == NULL)
257 printf("vrc4172pwm: NO parameter found. DISABLE pwm control\n");;
258 this_pwm = sc;
259 }
260
261 /*
262 * get platform related brightness paramerters
263 */
264 struct vrc4172pwm_param *
265 vrc4172pwm_getparam()
266 {
267 struct platid_data *p;
268
269 if ((p = platid_search(&platid, vrc4172pwm_platid_param_table)))
270 return p->data;
271 return NULL;
272 }
273
274 /*
275 *
276 * Initialize PWM brightness parameters
277 *
278 */
279 void
280 vrc4172pwm_init_brightness(sc)
281 struct vrc4172pwm_softc *sc;
282 {
283 sc->sc_param = vrc4172pwm_getparam();
284 sc->sc_raw_freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
285 sc->sc_raw_duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
286 sc->sc_brightness = vrc4172pwm_rawduty2brightness(sc);
287 sc->sc_light = vrc4172pwm_get_light(sc);
288 DPRINTF(("vrc4172pwm_init_brightness: param=0x%x, freq=0x%x, duty=0x%x, blightness=%d light=%d\n", (int)sc->sc_param, sc->sc_raw_freq, sc->sc_raw_duty, sc->sc_brightness, sc->sc_light));
289 }
290 /*
291 * backlight on/off
292 */
293 void
294 vrc4172pwm_light(sc, on)
295 struct vrc4172pwm_softc *sc;
296 int on;
297 {
298 int brightness;
299
300 DPRINTF(("vrc4172pwm_light: %s\n", on?"ON":"OFF"));
301 if (on) {
302 vrc4172pwm_set_brightness(sc, sc->sc_brightness);
303 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_EN);
304 } else {
305 brightness = sc->sc_brightness; /* save */
306 vrc4172pwm_set_brightness(sc, 0);
307 /* need this, break sc->sc_brightness */
308 sc->sc_brightness = brightness; /* resume */
309 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_DIS);
310 }
311 sc->sc_light = on;
312 }
313
314 /*
315 * get backlight on/off
316 */
317 int
318 vrc4172pwm_get_light(sc)
319 struct vrc4172pwm_softc *sc;
320 {
321 return VRC2_PWM_LCDEN_MASK&vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
322 }
323
324 /*
325 * set brightness
326 */
327 void
328 vrc4172pwm_set_brightness(sc, val)
329 struct vrc4172pwm_softc *sc;
330 int val;
331 {
332 int raw;
333
334 if (sc->sc_param == NULL)
335 return;
336 if (val < 0)
337 val = 0;
338 if (val > VRC2_PWM_MAX_BRIGHTNESS)
339 val = VRC2_PWM_MAX_BRIGHTNESS;
340 if (val > sc->sc_param->n_brightness)
341 val = sc->sc_param->n_brightness;
342 sc->sc_brightness = val;
343 raw = vrc4172pwm_brightness2rawduty(sc);
344 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTY, raw);
345 DPRINTF(("vrc4172pwm_set_brightness: val=%d raw=0x%x\n", val, raw));
346 }
347
348 /*
349 * get brightness
350 */
351 int
352 vrc4172pwm_get_brightness(sc)
353 struct vrc4172pwm_softc *sc;
354 {
355 if (sc->sc_param == NULL)
356 return VRC2_PWM_MAX_BRIGHTNESS;
357 return sc->sc_brightness;
358 }
359
360 /*
361 * PWM duty to brightness
362 */
363 int
364 vrc4172pwm_rawduty2brightness(sc)
365 struct vrc4172pwm_softc *sc;
366 {
367 int i;
368
369 if (sc->sc_param == NULL)
370 return VRC2_PWM_MAX_BRIGHTNESS;
371 for (i = 0; i < sc->sc_param->n_brightness; i++) {
372 if (sc->sc_raw_duty <= sc->sc_param->bvalues[i])
373 break;
374 }
375 if (i >= sc->sc_param->n_brightness-1)
376 return sc->sc_param->n_brightness-1;
377 else
378 return i;
379
380 }
381
382 /*
383 * brightness to raw duty
384 */
385 int
386 vrc4172pwm_brightness2rawduty(sc)
387 struct vrc4172pwm_softc *sc;
388 {
389 if (sc->sc_param == NULL)
390 return VRC2_PWM_LCDDUTY_MASK;
391 return sc->sc_param->bvalues[sc->sc_brightness];
392 }
393
394
395 /*
396 * PWM config hook events
397 *
398 */
399 int
400 vrc4172pwm_event(ctx, type, id, msg)
401 void *ctx;
402 int type;
403 long id;
404 void *msg;
405 {
406 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
407 int why =(int)msg;
408
409 if (type == CONFIG_HOOK_POWERCONTROL
410 && id == CONFIG_HOOK_POWERCONTROL_LCDLIGHT) {
411 DPRINTF(("vrc4172pwm:POWERCONTROL_LCDLIGHT: %d\n", why));
412 vrc4172pwm_light(sc, why);
413 } else if (type == CONFIG_HOOK_GET
414 && id == CONFIG_HOOK_POWER_LCDLIGHT) {
415 *(int *)msg = vrc4172pwm_get_light(sc);
416 DPRINTF(("vrc4172pwm:GET LCDLIGHT: %d\n", *(int *)msg));
417 } else if (type == CONFIG_HOOK_GET
418 && id == CONFIG_HOOK_BRIGHTNESS) {
419 *(int *)msg = vrc4172pwm_get_brightness(sc);
420 DPRINTF(("vrc4172pwm:GET BRIGHTNESS: %d\n", *(int *)msg));
421 } else if (type == CONFIG_HOOK_GET
422 && id == CONFIG_HOOK_BRIGHTNESS_MAX) {
423 if (sc->sc_param == NULL)
424 *(int *)msg = VRC2_PWM_MAX_BRIGHTNESS;
425 else
426 *(int *)msg = sc->sc_param->n_brightness-1;
427 DPRINTF(("vrc4172pwm:GET MAX BRIGHTNESS: %d\n", *(int *)msg));
428 } else if (type == CONFIG_HOOK_SET
429 && id == CONFIG_HOOK_BRIGHTNESS) {
430 DPRINTF(("vrc4172pwm:SET BRIGHTNESS: %d\n", *(int *)msg));
431 vrc4172pwm_set_brightness(sc, *(int *)msg);
432 } else {
433 DPRINTF(("vrc4172pwm:unknown event: type %d id %ld\n", type, id));
434 return 1;
435 }
436
437 return (0);
438 }
439
440
441 /*
442 * PWM config hook events
443 *
444 */
445 int
446 vrc4172pwm_pmevent(ctx, type, id, msg)
447 void *ctx;
448 int type;
449 long id;
450 void *msg;
451 {
452 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
453 int why =(int)msg;
454
455 if (type != CONFIG_HOOK_PMEVENT)
456 return 1;
457
458 switch (why) {
459 case PWR_STANDBY:
460 case PWR_SUSPEND:
461 sc->sc_light_save = sc->sc_light;
462 vrc4172pwm_light(sc, 0);
463 break;
464 case PWR_RESUME:
465 vrc4172pwm_light(sc, sc->sc_light_save);
466 break;
467 default:
468 return 1;
469 }
470
471 return (0);
472 }
473
474 /*
475 * dump pwm registers
476 */
477 void
478 vrc4172pwm_dumpreg(sc)
479 struct vrc4172pwm_softc *sc;
480 {
481 int en, freq, duty;
482
483 en = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
484 freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
485 duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
486
487 printf("vrc4172pwm: dumpreg: lightenable = %d, freq = 0x%x, duty = 0x%x\n",
488 en, freq, duty);
489 }
490
491 /* end */
492