vrc4172pwm.c revision 1.10 1 /* $Id: vrc4172pwm.c,v 1.10 2001/03/12 08:46:27 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_mcr530_param = {
87 0,
88 8,
89 { 0x16, 0x1b, 0x20, 0x25, 0x2a, 0x30, 0x37, 0x3f }
90 };
91
92 struct vrc4172pwm_param vrc4172pwm_mcr700_param = {
93 1, /* probe broken */
94 8,
95 { 0x12, 0x15, 0x18, 0x1d, 0x24, 0x2d, 0x38, 0x3f }
96 };
97
98 struct vrc4172pwm_param vrc4172pwm_sigmarion_param = {
99 0,
100 8,
101 { 0xe, 0x13, 0x18, 0x1c, 0x23, 0x29, 0x32, 0x3f }
102 };
103
104
105 struct platid_data vrc4172pwm_platid_param_table[] = {
106 { &platid_mask_MACH_NEC_MCR_430,
107 &vrc4172pwm_mcr530_param},
108 { &platid_mask_MACH_NEC_MCR_530,
109 &vrc4172pwm_mcr530_param},
110 { &platid_mask_MACH_NEC_MCR_530A,
111 &vrc4172pwm_mcr530_param},
112 { &platid_mask_MACH_NEC_MCR_SIGMARION,
113 &vrc4172pwm_sigmarion_param},
114 { &platid_mask_MACH_NEC_MCR_700,
115 &vrc4172pwm_mcr700_param},
116 { &platid_mask_MACH_NEC_MCR_700A,
117 &vrc4172pwm_mcr700_param},
118 { NULL, NULL}
119 };
120
121 struct vrc4172pwm_softc *this_pwm;
122
123 static inline void
124 vrc4172pwm_write(sc, port, val)
125 struct vrc4172pwm_softc *sc;
126 int port;
127 unsigned short val;
128 {
129 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
130 }
131
132 static inline unsigned short
133 vrc4172pwm_read(sc, port)
134 struct vrc4172pwm_softc *sc;
135 int port;
136 {
137 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
138 }
139
140 static int
141 vrc4172pwmprobe(parent, cf, aux)
142 struct device *parent;
143 struct cfdata *cf;
144 void *aux;
145 {
146 platid_mask_t mask;
147 struct vrip_attach_args *va = aux;
148 bus_space_handle_t ioh;
149 #ifdef VRC4172PWM_BROKEN_PROBE
150 int probe = 0;
151 #else /* VRC4172PWM_BROKEN_PROBE */
152 int probe = 1;
153 #endif /* VRC4172PWM_BROKEN_PROBE */
154 int data;
155 int data2;
156 struct vrc4172pwm_param *param;
157 int ret = 0;
158
159 if (va->va_addr == VRIPCF_ADDR_DEFAULT)
160 return 0;
161
162 if (cf->cf_loc[VRIPCF_PLATFORM] == 0)
163 return 0;
164 if (cf->cf_loc[VRIPCF_PLATFORM] != -1) { /* if specify */
165 mask = PLATID_DEREF(cf->cf_loc[VRIPCF_PLATFORM]);
166 VPRINTF(("vrc4172pwmprobe: check platid\n"));
167 if (platid_match(&platid, &mask) == 0)
168 return 0;
169 param = vrc4172pwm_getparam();
170 if (param != NULL && param->brokenprobe)
171 probe = 0;
172 }
173 if (probe) {
174 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, &ioh)) {
175 return 0;
176 }
177 data = bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN);
178 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, 0xff);
179 if ((data2 = bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN))
180 == VRC2_PWM_LCDEN_MASK) {
181 VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN found\n"));
182 ret = 1;
183 } else {
184 VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN not found org=%x, data=%x!=%x\n", data, data2, VRC2_PWM_LCDEN_MASK));
185 }
186 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, data);
187 bus_space_unmap(va->va_iot, ioh, va->va_size);
188 } else
189 ret = 1;
190 VPRINTF(("vrc4172pwmprobe: return %d\n", ret));
191 return ret;
192 }
193
194 static void
195 vrc4172pwmattach(parent, self, aux)
196 struct device *parent;
197 struct device *self;
198 void *aux;
199 {
200 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)self;
201 struct vrip_attach_args *va = aux;
202
203 bus_space_tag_t iot = va->va_iot;
204 bus_space_handle_t ioh;
205
206 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
207 printf(": can't map bus space\n");
208 return;
209 }
210
211 sc->sc_iot = iot;
212 sc->sc_ioh = ioh;
213
214 printf("\n");
215
216 VDUMPREG(sc);
217 /* basic setup */
218 sc->sc_pmhook = config_hook(CONFIG_HOOK_PMEVENT,
219 CONFIG_HOOK_PMEVENT_HARDPOWER,
220 CONFIG_HOOK_SHARE,
221 vrc4172pwm_pmevent, sc);
222 sc->sc_lcdhook = config_hook(CONFIG_HOOK_POWERCONTROL,
223 CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
224 CONFIG_HOOK_SHARE,
225 vrc4172pwm_event, sc);
226 sc->sc_getlcdhook = config_hook(CONFIG_HOOK_GET,
227 CONFIG_HOOK_POWER_LCDLIGHT,
228 CONFIG_HOOK_SHARE,
229 vrc4172pwm_event, sc);
230 sc->sc_sethook = config_hook(CONFIG_HOOK_SET,
231 CONFIG_HOOK_BRIGHTNESS,
232 CONFIG_HOOK_SHARE,
233 vrc4172pwm_event, sc);
234 sc->sc_gethook = config_hook(CONFIG_HOOK_GET,
235 CONFIG_HOOK_BRIGHTNESS,
236 CONFIG_HOOK_SHARE,
237 vrc4172pwm_event, sc);
238 sc->sc_getmaxhook = config_hook(CONFIG_HOOK_GET,
239 CONFIG_HOOK_BRIGHTNESS_MAX,
240 CONFIG_HOOK_SHARE,
241 vrc4172pwm_event, sc);
242
243 vrc4172pwm_init_brightness(sc);
244 this_pwm = sc;
245 }
246
247 /*
248 * get platform related brightness paramerters
249 */
250 struct vrc4172pwm_param *
251 vrc4172pwm_getparam()
252 {
253 struct platid_data *p;
254
255 if ((p = platid_search(&platid, vrc4172pwm_platid_param_table)))
256 return p->data;
257 return NULL;
258 }
259
260 /*
261 *
262 * Initialize PWM brightness parameters
263 *
264 */
265 void
266 vrc4172pwm_init_brightness(sc)
267 struct vrc4172pwm_softc *sc;
268 {
269 sc->sc_param = vrc4172pwm_getparam();
270 sc->sc_raw_freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
271 sc->sc_raw_duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
272 sc->sc_brightness = vrc4172pwm_rawduty2brightness(sc);
273 sc->sc_light = vrc4172pwm_get_light(sc);
274 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));
275 }
276 /*
277 * backlight on/off
278 */
279 void
280 vrc4172pwm_light(sc, on)
281 struct vrc4172pwm_softc *sc;
282 int on;
283 {
284 int brightness;
285
286 DPRINTF(("vrc4172pwm_light: %s\n", on?"ON":"OFF"));
287 if (on) {
288 vrc4172pwm_set_brightness(sc, sc->sc_brightness);
289 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_EN);
290 } else {
291 brightness = sc->sc_brightness; /* save */
292 vrc4172pwm_set_brightness(sc, 0);
293 /* need this, break sc->sc_brightness */
294 sc->sc_brightness = brightness; /* resume */
295 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_DIS);
296 }
297 sc->sc_light = on;
298 }
299
300 /*
301 * get backlight on/off
302 */
303 int
304 vrc4172pwm_get_light(sc)
305 struct vrc4172pwm_softc *sc;
306 {
307 return VRC2_PWM_LCDEN_MASK&vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
308 }
309
310 /*
311 * set brightness
312 */
313 void
314 vrc4172pwm_set_brightness(sc, val)
315 struct vrc4172pwm_softc *sc;
316 int val;
317 {
318 int raw;
319
320 if (sc->sc_param == NULL)
321 return;
322 if (val < 0)
323 val = 0;
324 if (val > VRC2_PWM_MAX_BRIGHTNESS)
325 val = VRC2_PWM_MAX_BRIGHTNESS;
326 if (val > sc->sc_param->n_brightness)
327 val = sc->sc_param->n_brightness;
328 sc->sc_brightness = val;
329 raw = vrc4172pwm_brightness2rawduty(sc);
330 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTY, raw);
331 DPRINTF(("vrc4172pwm_set_brightness: val=%d raw=0x%x\n", val, raw));
332 }
333
334 /*
335 * get brightness
336 */
337 int
338 vrc4172pwm_get_brightness(sc)
339 struct vrc4172pwm_softc *sc;
340 {
341 if (sc->sc_param == NULL)
342 return VRC2_PWM_MAX_BRIGHTNESS;
343 return sc->sc_brightness;
344 }
345
346 /*
347 * PWM duty to brightness
348 */
349 int
350 vrc4172pwm_rawduty2brightness(sc)
351 struct vrc4172pwm_softc *sc;
352 {
353 int i;
354
355 if (sc->sc_param == NULL)
356 return VRC2_PWM_MAX_BRIGHTNESS;
357 for (i = 0; i < sc->sc_param->n_brightness; i++) {
358 if (sc->sc_raw_duty <= sc->sc_param->bvalues[i])
359 break;
360 }
361 if (i >= sc->sc_param->n_brightness-1)
362 return sc->sc_param->n_brightness-1;
363 else
364 return i;
365
366 }
367
368 /*
369 * brightness to raw duty
370 */
371 int
372 vrc4172pwm_brightness2rawduty(sc)
373 struct vrc4172pwm_softc *sc;
374 {
375 if (sc->sc_param == NULL)
376 return VRC2_PWM_LCDDUTY_MASK;
377 return sc->sc_param->bvalues[sc->sc_brightness];
378 }
379
380
381 /*
382 * PWM config hook events
383 *
384 */
385 int
386 vrc4172pwm_event(ctx, type, id, msg)
387 void *ctx;
388 int type;
389 long id;
390 void *msg;
391 {
392 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
393 int why =(int)msg;
394
395 if (type == CONFIG_HOOK_POWERCONTROL
396 && id == CONFIG_HOOK_POWERCONTROL_LCDLIGHT) {
397 DPRINTF(("vrc4172pwm:POWERCONTROL_LCDLIGHT: %d\n", why));
398 vrc4172pwm_light(sc, why);
399 } else if (type == CONFIG_HOOK_GET
400 && id == CONFIG_HOOK_POWER_LCDLIGHT) {
401 *(int *)msg = vrc4172pwm_get_light(sc);
402 DPRINTF(("vrc4172pwm:GET LCDLIGHT: %d\n", *(int *)msg));
403 } else if (type == CONFIG_HOOK_GET
404 && id == CONFIG_HOOK_BRIGHTNESS) {
405 *(int *)msg = vrc4172pwm_get_brightness(sc);
406 DPRINTF(("vrc4172pwm:GET BRIGHTNESS: %d\n", *(int *)msg));
407 } else if (type == CONFIG_HOOK_GET
408 && id == CONFIG_HOOK_BRIGHTNESS_MAX) {
409 if (sc->sc_param == NULL)
410 *(int *)msg = VRC2_PWM_MAX_BRIGHTNESS;
411 else
412 *(int *)msg = sc->sc_param->n_brightness-1;
413 DPRINTF(("vrc4172pwm:GET MAX BRIGHTNESS: %d\n", *(int *)msg));
414 } else if (type == CONFIG_HOOK_SET
415 && id == CONFIG_HOOK_BRIGHTNESS) {
416 DPRINTF(("vrc4172pwm:SET BRIGHTNESS: %d\n", *(int *)msg));
417 vrc4172pwm_set_brightness(sc, *(int *)msg);
418 } else {
419 DPRINTF(("vrc4172pwm:unknown event: type %d id %ld\n", type, id));
420 return 1;
421 }
422
423 return (0);
424 }
425
426
427 /*
428 * PWM config hook events
429 *
430 */
431 int
432 vrc4172pwm_pmevent(ctx, type, id, msg)
433 void *ctx;
434 int type;
435 long id;
436 void *msg;
437 {
438 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
439 int why =(int)msg;
440
441 if (type != CONFIG_HOOK_PMEVENT)
442 return 1;
443
444 switch (why) {
445 case PWR_STANDBY:
446 case PWR_SUSPEND:
447 sc->sc_light_save = sc->sc_light;
448 vrc4172pwm_light(sc, 0);
449 break;
450 case PWR_RESUME:
451 vrc4172pwm_light(sc, sc->sc_light_save);
452 break;
453 default:
454 return 1;
455 }
456
457 return (0);
458 }
459
460 /*
461 * dump pwm registers
462 */
463 void
464 vrc4172pwm_dumpreg(sc)
465 struct vrc4172pwm_softc *sc;
466 {
467 int en, freq, duty;
468
469 en = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
470 freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
471 duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
472
473 printf("vrc4172pwm: dumpreg: lightenable = %d, freq = 0x%x, duty = 0x%x\n",
474 en, freq, duty);
475 }
476
477 /* end */
478