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