1 /* $NetBSD: netwalker_backlight.c,v 1.3 2020/05/20 05:10:42 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.3 2020/05/20 05:10:42 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/pwm/pwmvar.h> 39 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wscons/wsdisplayvar.h> 42 #include <dev/wsfb/genfbvar.h> 43 44 #include <dev/sysmon/sysmonvar.h> 45 #include <dev/sysmon/sysmon_taskq.h> 46 47 #include <arm/imx/imx51reg.h> 48 #include <arm/imx/imx51var.h> 49 #include <arm/imx/imx51_ccmvar.h> 50 #include <arm/imx/imxpwmvar.h> 51 52 #include <evbarm/netwalker/netwalker_backlightvar.h> 53 54 #define BRIGHTNESS_MAX 255 55 56 struct netwalker_backlight_softc { 57 struct imxpwm_softc sc_imxpwm; 58 59 int sc_brightness; 60 bool sc_islit; 61 }; 62 63 static struct netwalker_backlight_softc *netwalker_backlight_sc; 64 65 static struct genfb_parameter_callback gpc_backlight; 66 static struct genfb_parameter_callback gpc_brightness; 67 68 static int netwalker_backlight_match(device_t, cfdata_t, void *); 69 static void netwalker_backlight_attach(device_t, device_t, void *); 70 static int netwalker_backlight_detach(device_t, int); 71 72 CFATTACH_DECL_NEW(netwalker_backlight, sizeof(struct netwalker_backlight_softc), 73 netwalker_backlight_match, netwalker_backlight_attach, netwalker_backlight_detach, NULL); 74 75 static bool netwalker_backlight_resume(device_t, const pmf_qual_t *); 76 static bool netwalker_backlight_suspend(device_t, const pmf_qual_t *); 77 static void netwalker_backlight_on(device_t); 78 static void netwalker_backlight_off(device_t); 79 static void netwalker_brightness_up(device_t); 80 static void netwalker_brightness_down(device_t); 81 static void netwalker_set_brightness(struct netwalker_backlight_softc *, int); 82 83 static int 84 netwalker_backlight_match(device_t parent, cfdata_t cf, void * aux) 85 { 86 return imxpwm_match(parent, cf, aux); 87 } 88 89 static void 90 netwalker_backlight_attach(device_t parent, device_t self, void *aux) 91 { 92 struct netwalker_backlight_softc *sc = device_private(self); 93 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 94 95 imxpwm->sc_dev = self; 96 imxpwm->sc_handler = NULL; 97 imxpwm->sc_cookie = sc; 98 imxpwm_attach(imxpwm, aux); 99 100 aprint_normal(": LCD BackLight Control\n"); 101 aprint_naive(": LCD BackLight Control\n"); 102 103 netwalker_backlight_sc = sc; 104 105 /* BackLight 100% On */ 106 sc->sc_islit = true; 107 netwalker_set_brightness(sc, BRIGHTNESS_MAX); 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 145 netwalker_set_brightness(sc, 0); 146 pmf_device_deregister(self); 147 return 0; 148 } 149 150 static int 151 netwalker_backlight_get_backlight(void *cookie, int *state) 152 { 153 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 154 *state = sc->sc_islit; 155 return 0; 156 } 157 158 static int 159 netwalker_backlight_set_backlight(void *cookie, int state) 160 { 161 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 162 163 KASSERT(state >= 0 && state <= 1); 164 165 sc->sc_islit = state; 166 netwalker_set_brightness(sc, sc->sc_brightness); 167 168 return 0; 169 } 170 171 static int 172 netwalker_backlight_get_brightness(void *cookie, int *level) 173 { 174 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 175 176 if (sc->sc_brightness < 0) 177 return ENODEV; 178 179 *level = sc->sc_brightness; 180 return 0; 181 } 182 183 static int 184 netwalker_backlight_set_brightness(void *cookie, int level) 185 { 186 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 187 188 KASSERT(level >= 0 && level <= BRIGHTNESS_MAX); 189 190 sc->sc_brightness = level; 191 netwalker_set_brightness(sc, sc->sc_brightness); 192 193 return 0; 194 } 195 196 static int 197 netwalker_backlight_upd_brightness(void *cookie, int delta) 198 { 199 struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie; 200 201 if (sc->sc_brightness < 0) 202 return ENODEV; 203 204 sc->sc_brightness += delta; 205 if (sc->sc_brightness < 0) sc->sc_brightness = 0; 206 if (sc->sc_brightness > BRIGHTNESS_MAX) sc->sc_brightness = BRIGHTNESS_MAX; 207 netwalker_set_brightness(sc, sc->sc_brightness); 208 209 return 0; 210 } 211 212 void 213 netwalker_backlight_genfb_parameter_set(prop_dictionary_t dict) 214 { 215 gpc_backlight.gpc_cookie = (void *)&netwalker_backlight_sc; 216 gpc_backlight.gpc_set_parameter = netwalker_backlight_set_backlight; 217 gpc_backlight.gpc_get_parameter = netwalker_backlight_get_backlight; 218 gpc_backlight.gpc_upd_parameter = NULL; 219 prop_dictionary_set_uint64(dict, "backlight_callback", 220 (uint64_t)(uintptr_t)&gpc_backlight); 221 222 gpc_brightness.gpc_cookie = (void *)&netwalker_backlight_sc; 223 gpc_brightness.gpc_set_parameter = netwalker_backlight_set_brightness; 224 gpc_brightness.gpc_get_parameter = netwalker_backlight_get_brightness; 225 gpc_brightness.gpc_upd_parameter = netwalker_backlight_upd_brightness; 226 prop_dictionary_set_uint64(dict, "brightness_callback", 227 (uint64_t)(uintptr_t)&gpc_brightness); 228 } 229 230 /* 231 * Power management 232 */ 233 static bool 234 netwalker_backlight_suspend(device_t dv, const pmf_qual_t *qual) 235 { 236 netwalker_backlight_off(dv); 237 return true; 238 } 239 240 static bool 241 netwalker_backlight_resume(device_t dv, const pmf_qual_t *qual) 242 { 243 netwalker_backlight_on(dv); 244 return true; 245 } 246 247 static void 248 netwalker_backlight_on(device_t dv) 249 { 250 struct netwalker_backlight_softc *sc = device_private(dv); 251 sc->sc_islit = true; 252 netwalker_set_brightness(sc, sc->sc_brightness); 253 } 254 255 static void 256 netwalker_backlight_off(device_t dv) 257 { 258 struct netwalker_backlight_softc *sc = device_private(dv); 259 sc->sc_islit = false; 260 netwalker_set_brightness(sc, sc->sc_brightness); 261 } 262 263 static void 264 netwalker_brightness_up(device_t dv) 265 { 266 struct netwalker_backlight_softc *sc = device_private(dv); 267 netwalker_set_brightness(sc, sc->sc_brightness + 1); 268 } 269 270 static void 271 netwalker_brightness_down(device_t dv) 272 { 273 struct netwalker_backlight_softc *sc = device_private(dv); 274 netwalker_set_brightness(sc, sc->sc_brightness - 1); 275 } 276 277 static void 278 netwalker_set_pwm(struct netwalker_backlight_softc *sc, int val) 279 { 280 pwm_tag_t pwm = &sc->sc_imxpwm.sc_pwm; 281 struct pwm_config conf; 282 283 pwm_disable(pwm); 284 pwm_get_config(pwm, &conf); 285 conf.duty_cycle = (conf.period * val) / BRIGHTNESS_MAX; 286 pwm_set_config(pwm, &conf); 287 pwm_enable(pwm); 288 } 289 290 static void 291 netwalker_set_brightness(struct netwalker_backlight_softc *sc, int newval) 292 { 293 if (newval < 0) 294 newval = 0; 295 else if (newval > BRIGHTNESS_MAX) 296 newval = BRIGHTNESS_MAX; 297 sc->sc_brightness = newval; 298 299 if (sc->sc_islit) 300 netwalker_set_pwm(sc, sc->sc_brightness); 301 else 302 netwalker_set_pwm(sc, 0); 303 } 304 305 int 306 netwalker_lcd_param_ioctl(u_long cmd, struct wsdisplay_param *dp) 307 { 308 struct netwalker_backlight_softc *sc = netwalker_backlight_sc; 309 int rv = EINVAL; 310 311 switch (dp->param) { 312 case WSDISPLAYIO_PARAM_BACKLIGHT: 313 if (cmd == WSDISPLAYIO_GETPARAM) { 314 dp->min = 0; 315 dp->max = 1; 316 dp->curval = sc->sc_islit ? 1 : 0; 317 rv = 0; 318 } else if (cmd == WSDISPLAYIO_SETPARAM) { 319 if (dp->curval != 0) 320 netwalker_backlight_on(sc->sc_imxpwm.sc_dev); 321 else 322 netwalker_backlight_off(sc->sc_imxpwm.sc_dev); 323 rv = 0; 324 } 325 break; 326 327 case WSDISPLAYIO_PARAM_CONTRAST: 328 /* unsupported */ 329 rv = ENOTSUP; 330 break; 331 332 case WSDISPLAYIO_PARAM_BRIGHTNESS: 333 if (cmd == WSDISPLAYIO_GETPARAM) { 334 dp->min = 0; 335 dp->max = BRIGHTNESS_MAX; 336 dp->curval = sc->sc_brightness; 337 rv = 0; 338 } else if (cmd == WSDISPLAYIO_SETPARAM) { 339 netwalker_set_brightness(sc, dp->curval); 340 rv = 0; 341 } 342 break; 343 } 344 345 return rv; 346 } 347