1 /* $NetBSD: vrc4172pwm.c,v 1.22 2012/10/27 17:17:55 chs 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.22 2012/10/27 17:17:55 chs 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(device_t, cfdata_t, void *); 63 static void vrc4172pwmattach(device_t, device_t, 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_NEW(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 { &platid_mask_MACH_NEC_MCR_730, &vrc4172pwm_mcr700_param}, 124 { &platid_mask_MACH_NEC_MCR_730A, &vrc4172pwm_mcr700_param}, 125 { NULL, NULL} 126 }; 127 128 struct vrc4172pwm_softc *this_pwm; 129 130 static inline void 131 vrc4172pwm_write(struct vrc4172pwm_softc *sc, int port, unsigned short val) 132 { 133 134 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val); 135 } 136 137 static inline unsigned short 138 vrc4172pwm_read(struct vrc4172pwm_softc *sc, int port) 139 { 140 141 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port)); 142 } 143 144 static int 145 vrc4172pwmprobe(device_t parent, cfdata_t cf, void *aux) 146 { 147 platid_mask_t mask; 148 struct vrip_attach_args *va = aux; 149 bus_space_handle_t ioh; 150 #ifdef VRC4172PWM_BROKEN_PROBE 151 int probe = 0; 152 #else /* VRC4172PWM_BROKEN_PROBE */ 153 int probe = 1; 154 #endif /* VRC4172PWM_BROKEN_PROBE */ 155 int data; 156 int data2; 157 struct vrc4172pwm_param *param; 158 int ret = 0; 159 160 if (va->va_addr == VRIPIFCF_ADDR_DEFAULT) 161 return (0); 162 163 if (cf->cf_loc[VRIPIFCF_PLATFORM] == 0) 164 return (0); 165 if (cf->cf_loc[VRIPIFCF_PLATFORM] != -1) { /* if specify */ 166 mask = PLATID_DEREF(cf->cf_loc[VRIPIFCF_PLATFORM]); 167 VPRINTF(("vrc4172pwmprobe: check platid\n")); 168 if (platid_match(&platid, &mask) == 0) 169 return (0); 170 param = vrc4172pwm_getparam(); 171 if (param != NULL && param->brokenprobe) 172 probe = 0; 173 } 174 if (probe) { 175 if (bus_space_map(va->va_iot, va->va_addr, va->va_size, 0, 176 &ioh)) { 177 return (0); 178 } 179 data = bus_space_read_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN); 180 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, 0xff); 181 if ((data2 = bus_space_read_2(va->va_iot, ioh, 182 VRC2_PWM_LCDDUTYEN)) == VRC2_PWM_LCDEN_MASK) { 183 VPRINTF(("vrc4172pwmprobe:" 184 " VRC2_PWM_LCDDUTYEN found\n")); 185 ret = 1; 186 } else { 187 VPRINTF(("vrc4172pwmprobe: VRC2_PWM_LCDDUTYEN" 188 " not found org=%x, data=%x!=%x\n", 189 data, data2, VRC2_PWM_LCDEN_MASK)); 190 } 191 bus_space_write_2(va->va_iot, ioh, VRC2_PWM_LCDDUTYEN, data); 192 bus_space_unmap(va->va_iot, ioh, va->va_size); 193 } else 194 ret = 1; 195 VPRINTF(("vrc4172pwmprobe: return %d\n", ret)); 196 197 return (ret); 198 } 199 200 static void 201 vrc4172pwmattach(device_t parent, device_t self, void *aux) 202 { 203 struct vrc4172pwm_softc *sc = device_private(self); 204 struct vrip_attach_args *va = aux; 205 206 bus_space_tag_t iot = va->va_iot; 207 bus_space_handle_t ioh; 208 209 if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) { 210 printf(": can't map bus space\n"); 211 return; 212 } 213 214 sc->sc_iot = iot; 215 sc->sc_ioh = ioh; 216 217 printf("\n"); 218 219 VDUMPREG(sc); 220 /* basic setup */ 221 sc->sc_pmhook = config_hook(CONFIG_HOOK_PMEVENT, 222 CONFIG_HOOK_PMEVENT_HARDPOWER, CONFIG_HOOK_SHARE, 223 vrc4172pwm_pmevent, sc); 224 sc->sc_lcdhook = config_hook(CONFIG_HOOK_POWERCONTROL, 225 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, CONFIG_HOOK_SHARE, 226 vrc4172pwm_event, sc); 227 sc->sc_getlcdhook = config_hook(CONFIG_HOOK_GET, 228 CONFIG_HOOK_POWER_LCDLIGHT, CONFIG_HOOK_SHARE, 229 vrc4172pwm_event, sc); 230 sc->sc_sethook = config_hook(CONFIG_HOOK_SET, 231 CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE, 232 vrc4172pwm_event, sc); 233 sc->sc_gethook = config_hook(CONFIG_HOOK_GET, 234 CONFIG_HOOK_BRIGHTNESS, CONFIG_HOOK_SHARE, 235 vrc4172pwm_event, sc); 236 sc->sc_getmaxhook = config_hook(CONFIG_HOOK_GET, 237 CONFIG_HOOK_BRIGHTNESS_MAX, CONFIG_HOOK_SHARE, 238 vrc4172pwm_event, sc); 239 240 vrc4172pwm_init_brightness(sc); 241 if (sc->sc_param == NULL) 242 printf("vrc4172pwm: NO parameter found. DISABLE pwm control\n"); 243 this_pwm = sc; 244 } 245 246 /* 247 * get platform related brightness paramerters 248 */ 249 struct vrc4172pwm_param * 250 vrc4172pwm_getparam(void) 251 { 252 struct platid_data *p; 253 254 if ((p = platid_search_data(&platid, vrc4172pwm_platid_param_table))) 255 return (p->data); 256 257 return (NULL); 258 } 259 260 /* 261 * 262 * Initialize PWM brightness parameters 263 * 264 */ 265 void 266 vrc4172pwm_init_brightness(struct vrc4172pwm_softc *sc) 267 { 268 sc->sc_param = vrc4172pwm_getparam(); 269 sc->sc_raw_freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ); 270 sc->sc_raw_duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY); 271 sc->sc_brightness = vrc4172pwm_rawduty2brightness(sc); 272 sc->sc_light = vrc4172pwm_get_light(sc); 273 DPRINTF(("vrc4172pwm_init_brightness: param=0x%x, freq=0x%x," 274 " duty=0x%x, blightness=%d light=%d\n", (int)sc->sc_param, 275 sc->sc_raw_freq, sc->sc_raw_duty, sc->sc_brightness, 276 sc->sc_light)); 277 } 278 /* 279 * backlight on/off 280 */ 281 void 282 vrc4172pwm_light(struct vrc4172pwm_softc *sc, int on) 283 { 284 int brightness; 285 286 DPRINTF(("vrc4172pwm_light: %s\n", on?"ON":"OFF")); 287 if (on) { 288 vrc4172pwm_set_brightness(sc, sc->sc_brightness); 289 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_EN); 290 } else { 291 brightness = sc->sc_brightness; /* save */ 292 vrc4172pwm_set_brightness(sc, 0); 293 /* need this, break sc->sc_brightness */ 294 sc->sc_brightness = brightness; /* resume */ 295 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTYEN, VRC2_PWM_LCD_DIS); 296 } 297 sc->sc_light = on; 298 } 299 300 /* 301 * get backlight on/off 302 */ 303 int 304 vrc4172pwm_get_light(struct vrc4172pwm_softc *sc) 305 { 306 307 return (VRC2_PWM_LCDEN_MASK&vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN)); 308 } 309 310 /* 311 * set brightness 312 */ 313 void 314 vrc4172pwm_set_brightness(struct vrc4172pwm_softc *sc, int val) 315 { 316 int raw; 317 318 if (sc->sc_param == NULL) 319 return; 320 if (val < 0) 321 val = 0; 322 if (val > VRC2_PWM_MAX_BRIGHTNESS) 323 val = VRC2_PWM_MAX_BRIGHTNESS; 324 if (val > sc->sc_param->n_brightness) 325 val = sc->sc_param->n_brightness; 326 sc->sc_brightness = val; 327 raw = vrc4172pwm_brightness2rawduty(sc); 328 vrc4172pwm_write(sc, VRC2_PWM_LCDDUTY, raw); 329 DPRINTF(("vrc4172pwm_set_brightness: val=%d raw=0x%x\n", val, raw)); 330 } 331 332 /* 333 * get brightness 334 */ 335 int 336 vrc4172pwm_get_brightness(struct vrc4172pwm_softc *sc) 337 { 338 339 if (sc->sc_param == NULL) 340 return (VRC2_PWM_MAX_BRIGHTNESS); 341 342 return (sc->sc_brightness); 343 } 344 345 /* 346 * PWM duty to brightness 347 */ 348 int 349 vrc4172pwm_rawduty2brightness(struct vrc4172pwm_softc *sc) 350 { 351 int i; 352 353 if (sc->sc_param == NULL) 354 return (VRC2_PWM_MAX_BRIGHTNESS); 355 for (i = 0; i < sc->sc_param->n_brightness; i++) { 356 if (sc->sc_raw_duty <= sc->sc_param->bvalues[i]) 357 break; 358 } 359 if (i >= sc->sc_param->n_brightness-1) 360 return (sc->sc_param->n_brightness-1); 361 else 362 return (i); 363 364 } 365 366 /* 367 * brightness to raw duty 368 */ 369 int 370 vrc4172pwm_brightness2rawduty(struct vrc4172pwm_softc *sc) 371 { 372 373 if (sc->sc_param == NULL) 374 return (VRC2_PWM_LCDDUTY_MASK); 375 376 return (sc->sc_param->bvalues[sc->sc_brightness]); 377 } 378 379 380 /* 381 * PWM config hook events 382 * 383 */ 384 int 385 vrc4172pwm_event(void *ctx, int type, long id, void *msg) 386 { 387 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx; 388 int why =(int)msg; 389 390 if (type == CONFIG_HOOK_POWERCONTROL 391 && id == CONFIG_HOOK_POWERCONTROL_LCDLIGHT) { 392 DPRINTF(("vrc4172pwm:POWERCONTROL_LCDLIGHT: %d\n", why)); 393 vrc4172pwm_light(sc, why); 394 } else if (type == CONFIG_HOOK_GET 395 && id == CONFIG_HOOK_POWER_LCDLIGHT) { 396 *(int *)msg = vrc4172pwm_get_light(sc); 397 DPRINTF(("vrc4172pwm:GET LCDLIGHT: %d\n", *(int *)msg)); 398 } else if (type == CONFIG_HOOK_GET 399 && id == CONFIG_HOOK_BRIGHTNESS) { 400 *(int *)msg = vrc4172pwm_get_brightness(sc); 401 DPRINTF(("vrc4172pwm:GET BRIGHTNESS: %d\n", *(int *)msg)); 402 } else if (type == CONFIG_HOOK_GET 403 && id == CONFIG_HOOK_BRIGHTNESS_MAX) { 404 if (sc->sc_param == NULL) 405 *(int *)msg = VRC2_PWM_MAX_BRIGHTNESS; 406 else 407 *(int *)msg = sc->sc_param->n_brightness-1; 408 DPRINTF(("vrc4172pwm:GET MAX BRIGHTNESS: %d\n", *(int *)msg)); 409 } else if (type == CONFIG_HOOK_SET 410 && id == CONFIG_HOOK_BRIGHTNESS) { 411 DPRINTF(("vrc4172pwm:SET BRIGHTNESS: %d\n", *(int *)msg)); 412 vrc4172pwm_set_brightness(sc, *(int *)msg); 413 } else { 414 DPRINTF(("vrc4172pwm:unknown event: type %d id %ld\n", 415 type, id)); 416 return (1); 417 } 418 419 return (0); 420 } 421 422 /* 423 * PWM config hook events 424 * 425 */ 426 int 427 vrc4172pwm_pmevent(void *ctx, int type, long id, void *msg) 428 { 429 struct vrc4172pwm_softc *sc = (struct vrc4172pwm_softc *)ctx; 430 int why =(int)msg; 431 432 if (type != CONFIG_HOOK_PMEVENT) 433 return (1); 434 435 switch (why) { 436 case PWR_STANDBY: 437 case PWR_SUSPEND: 438 sc->sc_light_save = sc->sc_light; 439 vrc4172pwm_light(sc, 0); 440 break; 441 case PWR_RESUME: 442 vrc4172pwm_light(sc, sc->sc_light_save); 443 break; 444 default: 445 return (1); 446 } 447 448 return (0); 449 } 450 451 /* 452 * dump pwm registers 453 */ 454 void 455 vrc4172pwm_dumpreg(struct vrc4172pwm_softc *sc) 456 { 457 int en, freq, duty; 458 459 en = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTYEN); 460 freq = vrc4172pwm_read(sc, VRC2_PWM_LCDFREQ); 461 duty = vrc4172pwm_read(sc, VRC2_PWM_LCDDUTY); 462 463 printf("vrc4172pwm: dumpreg: lightenable = %d," 464 " freq = 0x%x, duty = 0x%x\n", en, freq, duty); 465 } 466 467 /* end */ 468