1 /* $NetBSD: netwalker_backlight.c,v 1.2 2015/12/21 04:26:29 hkenken Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Genetec Corporation. All rights reserved. 5 * Written by Hashimoto Kenichi for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netwalker_backlight.c,v 1.2 2015/12/21 04:26:29 hkenken Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/pmf.h> 37 38 #include <dev/wscons/wsconsio.h> 39 #include <dev/wscons/wsdisplayvar.h> 40 #include <dev/wsfb/genfbvar.h> 41 42 #include <dev/sysmon/sysmonvar.h> 43 #include <dev/sysmon/sysmon_taskq.h> 44 45 #include <arm/imx/imx51reg.h> 46 #include <arm/imx/imx51var.h> 47 #include <arm/imx/imx51_ccmvar.h> 48 #include <arm/imx/imxpwmvar.h> 49 50 #include <evbarm/netwalker/netwalker_backlightvar.h> 51 52 #define BRIGHTNESS_MAX 255 53 54 struct netwalker_backlight_softc { 55 struct imxpwm_softc sc_imxpwm; 56 57 int sc_brightness; 58 bool sc_islit; 59 }; 60 61 static struct netwalker_backlight_softc *netwalker_backlight_sc; 62 63 static struct genfb_parameter_callback gpc_backlight; 64 static struct genfb_parameter_callback gpc_brightness; 65 66 static int netwalker_backlight_match(device_t, cfdata_t, void *); 67 static void netwalker_backlight_attach(device_t, device_t, void *); 68 static int netwalker_backlight_detach(device_t, int); 69 70 CFATTACH_DECL_NEW(netwalker_backlight, sizeof(struct netwalker_backlight_softc), 71 netwalker_backlight_match, netwalker_backlight_attach, netwalker_backlight_detach, NULL); 72 73 static bool netwalker_backlight_resume(device_t, const pmf_qual_t *); 74 static bool netwalker_backlight_suspend(device_t, const pmf_qual_t *); 75 static void netwalker_backlight_on(device_t); 76 static void netwalker_backlight_off(device_t); 77 static void netwalker_brightness_up(device_t); 78 static void netwalker_brightness_down(device_t); 79 static void netwalker_set_brightness(struct netwalker_backlight_softc *, int); 80 81 static int 82 netwalker_backlight_match(device_t parent, cfdata_t cf, void * aux) 83 { 84 return imxpwm_match(parent, cf, aux); 85 } 86 87 static void 88 netwalker_backlight_attach(device_t parent, device_t self, void *aux) 89 { 90 struct netwalker_backlight_softc *sc = device_private(self); 91 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 92 93 imxpwm->sc_dev = self; 94 imxpwm->sc_hz = 1000; /* 1000 Hz */ 95 imxpwm->sc_handler = NULL; 96 imxpwm->sc_cookie = sc; 97 imxpwm_attach(imxpwm, aux); 98 99 aprint_normal(": LCD BackLight Control\n"); 100 aprint_naive(": LCD BackLight Control\n"); 101 102 netwalker_backlight_sc = sc; 103 104 /* BackLight 100% On */ 105 sc->sc_brightness = BRIGHTNESS_MAX; 106 sc->sc_islit = true; 107 imxpwm_set_pwm(imxpwm, 1000); 108 109 if (!pmf_device_register(self, netwalker_backlight_suspend, 110 netwalker_backlight_resume)) 111 aprint_error_dev(self, 112 "couldn't establish backlight handler\n"); 113 114 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 115 netwalker_brightness_up, true)) 116 aprint_error_dev(self, 117 "couldn't register BRIGHTNESS UP event handler\n"); 118 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 119 netwalker_brightness_down, true)) 120 aprint_error_dev(self, 121 "couldn't register BRIGHTNESS DOWN event handler\n"); 122 if (!pmf_event_register(self, PMFE_DISPLAY_ON, 123 netwalker_backlight_on, true)) 124 aprint_error_dev(self, 125 "couldn't register DISPLAY ON event handler\n"); 126 if (!pmf_event_register(self, PMFE_DISPLAY_OFF, 127 netwalker_backlight_off, true)) 128 aprint_error_dev(self, 129 "couldn't register DISPLAY OFF event handler\n"); 130 if (!pmf_event_register(self, PMFE_CHASSIS_LID_OPEN, 131 netwalker_backlight_on, true)) 132 aprint_error_dev(self, 133 "couldn't register LID OPEN event handler\n"); 134 if (!pmf_event_register(self, PMFE_CHASSIS_LID_CLOSE, 135 netwalker_backlight_off, true)) 136 aprint_error_dev(self, 137 "couldn't register LID CLOSE event handler\n"); 138 } 139 140 static int 141 netwalker_backlight_detach(device_t self, int flags) 142 { 143 struct netwalker_backlight_softc *sc = device_private(self); 144 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 145 146 imxpwm_set_pwm(imxpwm, 0); 147 pmf_device_deregister(self); 148 return 0; 149 } 150 151 static int 152 netwalker_backlight_get_backlight(void *cookie, int *state) 153 { 154 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 155 *state = sc->sc_islit; 156 return 0; 157 } 158 159 static int 160 netwalker_backlight_set_backlight(void *cookie, int state) 161 { 162 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 163 164 KASSERT(state >= 0 && state <= 1); 165 166 sc->sc_islit = state; 167 netwalker_set_brightness(sc, sc->sc_brightness); 168 169 return 0; 170 } 171 172 static int 173 netwalker_backlight_get_brightness(void *cookie, int *level) 174 { 175 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 176 177 if (sc->sc_brightness < 0) 178 return ENODEV; 179 180 *level = sc->sc_brightness; 181 return 0; 182 } 183 184 static int 185 netwalker_backlight_set_brightness(void *cookie, int level) 186 { 187 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 188 189 KASSERT(level >= 0 && level <= 255); 190 191 sc->sc_brightness = level; 192 netwalker_set_brightness(sc, sc->sc_brightness); 193 194 return 0; 195 } 196 197 static int 198 netwalker_backlight_upd_brightness(void *cookie, int delta) 199 { 200 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 201 202 if (sc->sc_brightness < 0) 203 return ENODEV; 204 205 sc->sc_brightness += delta; 206 if (sc->sc_brightness < 0) sc->sc_brightness = 0; 207 if (sc->sc_brightness > 255) sc->sc_brightness = 255; 208 netwalker_set_brightness(sc, sc->sc_brightness); 209 210 return 0; 211 } 212 213 void 214 netwalker_backlight_genfb_parameter_set(prop_dictionary_t dict) 215 { 216 gpc_backlight.gpc_cookie = (void *)&netwalker_backlight_sc; 217 gpc_backlight.gpc_set_parameter = netwalker_backlight_set_backlight; 218 gpc_backlight.gpc_get_parameter = netwalker_backlight_get_backlight; 219 gpc_backlight.gpc_upd_parameter = NULL; 220 prop_dictionary_set_uint64(dict, "backlight_callback", 221 (uint64_t)(uintptr_t)&gpc_backlight); 222 223 gpc_brightness.gpc_cookie = (void *)&netwalker_backlight_sc; 224 gpc_brightness.gpc_set_parameter = netwalker_backlight_set_brightness; 225 gpc_brightness.gpc_get_parameter = netwalker_backlight_get_brightness; 226 gpc_brightness.gpc_upd_parameter = netwalker_backlight_upd_brightness; 227 prop_dictionary_set_uint64(dict, "brightness_callback", 228 (uint64_t)(uintptr_t)&gpc_brightness); 229 } 230 231 /* 232 * Power management 233 */ 234 static bool 235 netwalker_backlight_suspend(device_t dv, const pmf_qual_t *qual) 236 { 237 netwalker_backlight_off(dv); 238 return true; 239 } 240 241 static bool 242 netwalker_backlight_resume(device_t dv, const pmf_qual_t *qual) 243 { 244 netwalker_backlight_on(dv); 245 return true; 246 } 247 248 static void 249 netwalker_backlight_on(device_t dv) 250 { 251 struct netwalker_backlight_softc *sc = device_private(dv); 252 sc->sc_islit = true; 253 netwalker_set_brightness(sc, sc->sc_brightness); 254 } 255 256 static void 257 netwalker_backlight_off(device_t dv) 258 { 259 struct netwalker_backlight_softc *sc = device_private(dv); 260 sc->sc_islit = false; 261 netwalker_set_brightness(sc, sc->sc_brightness); 262 } 263 264 static void 265 netwalker_brightness_up(device_t dv) 266 { 267 struct netwalker_backlight_softc *sc = device_private(dv); 268 netwalker_set_brightness(sc, sc->sc_brightness + 1); 269 } 270 271 static void 272 netwalker_brightness_down(device_t dv) 273 { 274 struct netwalker_backlight_softc *sc = device_private(dv); 275 netwalker_set_brightness(sc, sc->sc_brightness - 1); 276 } 277 278 static void 279 netwalker_set_brightness(struct netwalker_backlight_softc *sc, int newval) 280 { 281 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 282 283 if (newval < 0) 284 newval = 0; 285 else if (newval > BRIGHTNESS_MAX) 286 newval = BRIGHTNESS_MAX; 287 sc->sc_brightness = newval; 288 289 if (sc->sc_islit) 290 imxpwm_set_pwm(imxpwm, 1000 * sc->sc_brightness / BRIGHTNESS_MAX); 291 else 292 imxpwm_set_pwm(imxpwm, 0); 293 } 294 295 int 296 netwalker_lcd_param_ioctl(u_long cmd, struct wsdisplay_param *dp) 297 { 298 struct netwalker_backlight_softc *sc = netwalker_backlight_sc; 299 int rv = EINVAL; 300 301 switch (dp->param) { 302 case WSDISPLAYIO_PARAM_BACKLIGHT: 303 if (cmd == WSDISPLAYIO_GETPARAM) { 304 dp->min = 0; 305 dp->max = 1; 306 dp->curval = sc->sc_islit ? 1 : 0; 307 rv = 0; 308 } else if (cmd == WSDISPLAYIO_SETPARAM) { 309 if (dp->curval != 0) 310 netwalker_backlight_on(sc->sc_imxpwm.sc_dev); 311 else 312 netwalker_backlight_off(sc->sc_imxpwm.sc_dev); 313 rv = 0; 314 } 315 break; 316 317 case WSDISPLAYIO_PARAM_CONTRAST: 318 /* unsupported */ 319 rv = ENOTSUP; 320 break; 321 322 case WSDISPLAYIO_PARAM_BRIGHTNESS: 323 if (cmd == WSDISPLAYIO_GETPARAM) { 324 dp->min = 0; 325 dp->max = BRIGHTNESS_MAX; 326 dp->curval = sc->sc_brightness; 327 rv = 0; 328 } else if (cmd == WSDISPLAYIO_SETPARAM) { 329 netwalker_set_brightness(sc, dp->curval); 330 rv = 0; 331 } 332 break; 333 } 334 335 return rv; 336 } 337