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