1 /* $NetBSD: netwalker_backlight.c,v 1.1 2014/05/06 11:22:53 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.1 2014/05/06 11:22:53 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 41 #include <dev/sysmon/sysmonvar.h> 42 #include <dev/sysmon/sysmon_taskq.h> 43 44 #include <arm/imx/imx51reg.h> 45 #include <arm/imx/imx51var.h> 46 #include <arm/imx/imx51_ccmvar.h> 47 #include <arm/imx/imxpwmvar.h> 48 49 #include <evbarm/netwalker/netwalker_backlightvar.h> 50 51 #define BRIGHTNESS_MAX 16 52 53 struct netwalker_backlight_softc { 54 struct imxpwm_softc sc_imxpwm; 55 56 int sc_brightness; 57 bool sc_islit; 58 }; 59 60 static struct netwalker_backlight_softc *netwalker_backlight_sc; 61 62 static int netwalker_backlight_match(device_t, cfdata_t, void *); 63 static void netwalker_backlight_attach(device_t, device_t, void *); 64 static int netwalker_backlight_detach(device_t, int); 65 66 CFATTACH_DECL_NEW(netwalker_backlight, sizeof(struct netwalker_backlight_softc), 67 netwalker_backlight_match, netwalker_backlight_attach, netwalker_backlight_detach, NULL); 68 69 static bool netwalker_backlight_resume(device_t, const pmf_qual_t *); 70 static bool netwalker_backlight_suspend(device_t, const pmf_qual_t *); 71 static void netwalker_backlight_on(device_t); 72 static void netwalker_backlight_off(device_t); 73 static void netwalker_brightness_up(device_t); 74 static void netwalker_brightness_down(device_t); 75 static void netwalker_set_brightness(struct netwalker_backlight_softc *, int); 76 77 static int 78 netwalker_backlight_match(device_t parent, cfdata_t cf, void * aux) 79 { 80 return imxpwm_match(parent, cf, aux); 81 } 82 83 static void 84 netwalker_backlight_attach(device_t parent, device_t self, void *aux) 85 { 86 struct netwalker_backlight_softc *sc = device_private(self); 87 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 88 89 imxpwm->sc_dev = self; 90 imxpwm->sc_hz = 1000; /* 1000 Hz */ 91 imxpwm->sc_handler = NULL; 92 imxpwm->sc_cookie = sc; 93 imxpwm_attach(imxpwm, aux); 94 95 aprint_normal(": LCD BackLight Control\n"); 96 aprint_naive(": LCD BackLight Control\n"); 97 98 netwalker_backlight_sc = sc; 99 100 /* BackLight 100% On */ 101 sc->sc_brightness = BRIGHTNESS_MAX; 102 sc->sc_islit = true; 103 imxpwm_set_pwm(imxpwm, 1000); 104 105 if (!pmf_device_register(self, netwalker_backlight_suspend, 106 netwalker_backlight_resume)) 107 aprint_error_dev(self, 108 "couldn't establish backlight handler\n"); 109 110 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 111 netwalker_brightness_up, true)) 112 aprint_error_dev(self, 113 "couldn't register BRIGHTNESS UP event handler\n"); 114 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 115 netwalker_brightness_down, true)) 116 aprint_error_dev(self, 117 "couldn't register BRIGHTNESS DOWN event handler\n"); 118 if (!pmf_event_register(self, PMFE_DISPLAY_ON, 119 netwalker_backlight_on, true)) 120 aprint_error_dev(self, 121 "couldn't register DISPLAY ON event handler\n"); 122 if (!pmf_event_register(self, PMFE_DISPLAY_OFF, 123 netwalker_backlight_off, true)) 124 aprint_error_dev(self, 125 "couldn't register DISPLAY OFF event handler\n"); 126 if (!pmf_event_register(self, PMFE_CHASSIS_LID_OPEN, 127 netwalker_backlight_on, true)) 128 aprint_error_dev(self, 129 "couldn't register LID OPEN event handler\n"); 130 if (!pmf_event_register(self, PMFE_CHASSIS_LID_CLOSE, 131 netwalker_backlight_off, true)) 132 aprint_error_dev(self, 133 "couldn't register LID CLOSE event handler\n"); 134 } 135 136 static int 137 netwalker_backlight_detach(device_t self, int flags) 138 { 139 struct netwalker_backlight_softc *sc = device_private(self); 140 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 141 142 imxpwm_set_pwm(imxpwm, 0); 143 pmf_device_deregister(self); 144 return 0; 145 } 146 147 /* 148 * Power management 149 */ 150 static bool 151 netwalker_backlight_suspend(device_t dv, const pmf_qual_t *qual) 152 { 153 netwalker_backlight_off(dv); 154 return true; 155 } 156 157 static bool 158 netwalker_backlight_resume(device_t dv, const pmf_qual_t *qual) 159 { 160 netwalker_backlight_on(dv); 161 return true; 162 } 163 164 static void 165 netwalker_backlight_on(device_t dv) 166 { 167 struct netwalker_backlight_softc *sc = device_private(dv); 168 sc->sc_islit = true; 169 netwalker_set_brightness(sc, sc->sc_brightness); 170 } 171 172 static void 173 netwalker_backlight_off(device_t dv) 174 { 175 struct netwalker_backlight_softc *sc = device_private(dv); 176 sc->sc_islit = false; 177 netwalker_set_brightness(sc, sc->sc_brightness); 178 } 179 180 static void 181 netwalker_brightness_up(device_t dv) 182 { 183 struct netwalker_backlight_softc *sc = device_private(dv); 184 netwalker_set_brightness(sc, sc->sc_brightness + 1); 185 } 186 187 static void 188 netwalker_brightness_down(device_t dv) 189 { 190 struct netwalker_backlight_softc *sc = device_private(dv); 191 netwalker_set_brightness(sc, sc->sc_brightness - 1); 192 } 193 194 static void 195 netwalker_set_brightness(struct netwalker_backlight_softc *sc, int newval) 196 { 197 struct imxpwm_softc *imxpwm = &sc->sc_imxpwm; 198 199 if (newval < 0) 200 newval = 0; 201 else if (newval > BRIGHTNESS_MAX) 202 newval = BRIGHTNESS_MAX; 203 sc->sc_brightness = newval; 204 205 if (sc->sc_islit) 206 imxpwm_set_pwm(imxpwm, 1000 * sc->sc_brightness / BRIGHTNESS_MAX); 207 else 208 imxpwm_set_pwm(imxpwm, 0); 209 } 210 211 int 212 netwalker_lcd_param_ioctl(u_long cmd, struct wsdisplay_param *dp) 213 { 214 struct netwalker_backlight_softc *sc = netwalker_backlight_sc; 215 int rv = EINVAL; 216 217 switch (dp->param) { 218 case WSDISPLAYIO_PARAM_BACKLIGHT: 219 if (cmd == WSDISPLAYIO_GETPARAM) { 220 dp->min = 0; 221 dp->max = 1; 222 dp->curval = sc->sc_islit ? 1 : 0; 223 rv = 0; 224 } else if (cmd == WSDISPLAYIO_SETPARAM) { 225 if (dp->curval != 0) 226 netwalker_backlight_on(sc->sc_imxpwm.sc_dev); 227 else 228 netwalker_backlight_off(sc->sc_imxpwm.sc_dev); 229 rv = 0; 230 } 231 break; 232 233 case WSDISPLAYIO_PARAM_CONTRAST: 234 /* unsupported */ 235 rv = ENOTSUP; 236 break; 237 238 case WSDISPLAYIO_PARAM_BRIGHTNESS: 239 if (cmd == WSDISPLAYIO_GETPARAM) { 240 dp->min = 0; 241 dp->max = BRIGHTNESS_MAX; 242 dp->curval = sc->sc_brightness; 243 rv = 0; 244 } else if (cmd == WSDISPLAYIO_SETPARAM) { 245 netwalker_set_brightness(sc, dp->curval); 246 rv = 0; 247 } 248 break; 249 } 250 251 return rv; 252 } 253