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