1 /* $NetBSD: vrc4172pwm.c,v 1.15 2002/01/27 14:18:12 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/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 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 == VRIPIFCF_ADDR_DEFAULT) 157 return (0); 158 159 if (cf->cf_loc[VRIPIFCF_PLATFORM] == 0) 160 return (0); 161 if (cf->cf_loc[VRIPIFCF_PLATFORM] != -1) { /* if specify */ 162 mask = PLATID_DEREF(cf->cf_loc[VRIPIFCF_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