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