vrc4172pwm.c revision 1.9 1 /* $Id: vrc4172pwm.c,v 1.9 2001/03/06 03:14:39 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 DPRINTF(("vrc4172pwm_init_brightness: param=0x%x, freq=0x%x, duty=0x%x, blightness=%d\n", (int)sc->sc_param, sc->sc_raw_freq, sc->sc_raw_duty, sc->sc_brightness));
274 }
275 /*
276 * backlight on/off
277 */
278 void
279 vrc4172pwm_light(sc, on)
280 struct vrc4172pwm_softc *sc;
281 int on;
282 {
283 int brightness;
284
285 DPRINTF(("vrc4172pwm_light: %s\n", on?"ON":"OFF"));
286 if (on) {
287 vrc4172pwm_set_brightness(sc, sc->sc_brightness);
288 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_EN);
289 } else {
290 brightness = sc->sc_brightness; /* save */
291 vrc4172pwm_set_brightness(sc, 0);
292 /* need this, break sc->sc_brightness */
293 sc->sc_brightness = brightness; /* resume */
294 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_DIS);
295 }
296 }
297
298 /*
299 * get backlight on/off
300 */
301 inline int
302 vrc4172pwm_get_light(sc)
303 struct vrc4172pwm_softc *sc;
304 {
305 return vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
306 }
307
308 /*
309 * set brightness
310 */
311 void
312 vrc4172pwm_set_brightness(sc, val)
313 struct vrc4172pwm_softc *sc;
314 int val;
315 {
316 int raw;
317
318 if (sc->sc_param == NULL)
319 return;
320 if (val < 0)
321 val = 0;
322 if (val > VRC2_PWM_MAX_BRIGHTNESS)
323 val = VRC2_PWM_MAX_BRIGHTNESS;
324 if (val > sc->sc_param->n_brightness)
325 val = sc->sc_param->n_brightness;
326 sc->sc_brightness = val;
327 raw = vrc4172pwm_brightness2rawduty(sc);
328 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTY, raw);
329 DPRINTF(("vrc4172pwm_set_brightness: val=%d raw=0x%x\n", val, raw));
330 }
331
332 /*
333 * get brightness
334 */
335 int
336 vrc4172pwm_get_brightness(sc)
337 struct vrc4172pwm_softc *sc;
338 {
339 if (sc->sc_param == NULL)
340 return VRC2_PWM_MAX_BRIGHTNESS;
341 return sc->sc_brightness;
342 }
343
344 /*
345 * PWM duty to brightness
346 */
347 int
348 vrc4172pwm_rawduty2brightness(sc)
349 struct vrc4172pwm_softc *sc;
350 {
351 int i;
352
353 if (sc->sc_param == NULL)
354 return VRC2_PWM_MAX_BRIGHTNESS;
355 for (i = 0; i < sc->sc_param->n_brightness; i++) {
356 if (sc->sc_raw_duty <= sc->sc_param->bvalues[i])
357 break;
358 }
359 if (i >= sc->sc_param->n_brightness-1)
360 return sc->sc_param->n_brightness-1;
361 else
362 return i;
363
364 }
365
366 /*
367 * brightness to raw duty
368 */
369 int
370 vrc4172pwm_brightness2rawduty(sc)
371 struct vrc4172pwm_softc *sc;
372 {
373 if (sc->sc_param == NULL)
374 return VRC2_PWM_LCDDUTY_MASK;
375 return sc->sc_param->bvalues[sc->sc_brightness];
376 }
377
378
379 /*
380 * PWM config hook events
381 *
382 */
383 int
384 vrc4172pwm_event(ctx, type, id, msg)
385 void *ctx;
386 int type;
387 long id;
388 void *msg;
389 {
390 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
391 int why =(int)msg;
392
393 if (type == CONFIG_HOOK_POWERCONTROL
394 && id == CONFIG_HOOK_POWERCONTROL_LCDLIGHT) {
395 DPRINTF(("vrc4172pwm:POWERCONTROL_LCDLIGHT: %d\n", why));
396 vrc4172pwm_light(sc, why);
397 } else if (type == CONFIG_HOOK_GET
398 && id == CONFIG_HOOK_POWER_LCDLIGHT) {
399 *(int *)msg = vrc4172pwm_get_light(sc);
400 DPRINTF(("vrc4172pwm:GET LCDLIGHT: %d\n", *(int *)msg));
401 } else if (type == CONFIG_HOOK_GET
402 && id == CONFIG_HOOK_BRIGHTNESS) {
403 *(int *)msg = vrc4172pwm_get_brightness(sc);
404 DPRINTF(("vrc4172pwm:GET BRIGHTNESS: %d\n", *(int *)msg));
405 } else if (type == CONFIG_HOOK_GET
406 && id == CONFIG_HOOK_BRIGHTNESS_MAX) {
407 if (sc->sc_param == NULL)
408 *(int *)msg = VRC2_PWM_MAX_BRIGHTNESS;
409 else
410 *(int *)msg = sc->sc_param->n_brightness-1;
411 DPRINTF(("vrc4172pwm:GET MAX BRIGHTNESS: %d\n", *(int *)msg));
412 } else if (type == CONFIG_HOOK_SET
413 && id == CONFIG_HOOK_BRIGHTNESS) {
414 DPRINTF(("vrc4172pwm:SET BRIGHTNESS: %d\n", *(int *)msg));
415 vrc4172pwm_set_brightness(sc, *(int *)msg);
416 } else {
417 DPRINTF(("vrc4172pwm:unknown event: type %d id %ld\n", type, id));
418 return 1;
419 }
420
421 return (0);
422 }
423
424
425 /*
426 * PWM config hook events
427 *
428 */
429 int
430 vrc4172pwm_pmevent(ctx, type, id, msg)
431 void *ctx;
432 int type;
433 long id;
434 void *msg;
435 {
436 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx;
437 int why =(int)msg;
438
439 if (type != CONFIG_HOOK_PMEVENT)
440 return 1;
441
442 switch (why) {
443 case PWR_STANDBY:
444 case PWR_SUSPEND:
445 vrc4172pwm_light(sc, 0);
446 break;
447 case PWR_RESUME:
448 vrc4172pwm_light(sc, 1);
449 break;
450 default:
451 return 1;
452 }
453
454 return (0);
455 }
456
457 /*
458 * dump pwm registers
459 */
460 void
461 vrc4172pwm_dumpreg(sc)
462 struct vrc4172pwm_softc *sc;
463 {
464 int en, freq, duty;
465
466 en = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN);
467 freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ);
468 duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY);
469
470 printf("vrc4172pwm: dumpreg: lightenable = %d, freq = 0x%x, duty = 0x%x\n",
471 en, freq, duty);
472 }
473
474 /* end */
475