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