1*2bd1432cShkenken /* $NetBSD: netwalker_backlight.c,v 1.3 2020/05/20 05:10:42 hkenken Exp $ */
2b9040788Shkenken
3b9040788Shkenken /*
4b9040788Shkenken * Copyright (c) 2014 Genetec Corporation. All rights reserved.
5b9040788Shkenken * Written by Hashimoto Kenichi for Genetec Corporation.
6b9040788Shkenken *
7b9040788Shkenken * Redistribution and use in source and binary forms, with or without
8b9040788Shkenken * modification, are permitted provided that the following conditions
9b9040788Shkenken * are met:
10b9040788Shkenken * 1. Redistributions of source code must retain the above copyright
11b9040788Shkenken * notice, this list of conditions and the following disclaimer.
12b9040788Shkenken * 2. Redistributions in binary form must reproduce the above copyright
13b9040788Shkenken * notice, this list of conditions and the following disclaimer in the
14b9040788Shkenken * documentation and/or other materials provided with the distribution.
15b9040788Shkenken *
16b9040788Shkenken * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
17b9040788Shkenken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18b9040788Shkenken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19b9040788Shkenken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
20b9040788Shkenken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21b9040788Shkenken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22b9040788Shkenken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23b9040788Shkenken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24b9040788Shkenken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25b9040788Shkenken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26b9040788Shkenken * POSSIBILITY OF SUCH DAMAGE.
27b9040788Shkenken */
28b9040788Shkenken
29b9040788Shkenken #include <sys/cdefs.h>
30*2bd1432cShkenken __KERNEL_RCSID(0, "$NetBSD: netwalker_backlight.c,v 1.3 2020/05/20 05:10:42 hkenken Exp $");
31b9040788Shkenken
32b9040788Shkenken #include <sys/param.h>
33b9040788Shkenken #include <sys/bus.h>
34b9040788Shkenken #include <sys/systm.h>
35b9040788Shkenken #include <sys/device.h>
36b9040788Shkenken #include <sys/pmf.h>
37b9040788Shkenken
38*2bd1432cShkenken #include <dev/pwm/pwmvar.h>
39*2bd1432cShkenken
40b9040788Shkenken #include <dev/wscons/wsconsio.h>
41b9040788Shkenken #include <dev/wscons/wsdisplayvar.h>
427bb55e03Shkenken #include <dev/wsfb/genfbvar.h>
43b9040788Shkenken
44b9040788Shkenken #include <dev/sysmon/sysmonvar.h>
45b9040788Shkenken #include <dev/sysmon/sysmon_taskq.h>
46b9040788Shkenken
47b9040788Shkenken #include <arm/imx/imx51reg.h>
48b9040788Shkenken #include <arm/imx/imx51var.h>
49b9040788Shkenken #include <arm/imx/imx51_ccmvar.h>
50b9040788Shkenken #include <arm/imx/imxpwmvar.h>
51b9040788Shkenken
52b9040788Shkenken #include <evbarm/netwalker/netwalker_backlightvar.h>
53b9040788Shkenken
547bb55e03Shkenken #define BRIGHTNESS_MAX 255
55b9040788Shkenken
56b9040788Shkenken struct netwalker_backlight_softc {
57b9040788Shkenken struct imxpwm_softc sc_imxpwm;
58b9040788Shkenken
59b9040788Shkenken int sc_brightness;
60b9040788Shkenken bool sc_islit;
61b9040788Shkenken };
62b9040788Shkenken
63b9040788Shkenken static struct netwalker_backlight_softc *netwalker_backlight_sc;
64b9040788Shkenken
657bb55e03Shkenken static struct genfb_parameter_callback gpc_backlight;
667bb55e03Shkenken static struct genfb_parameter_callback gpc_brightness;
677bb55e03Shkenken
68b9040788Shkenken static int netwalker_backlight_match(device_t, cfdata_t, void *);
69b9040788Shkenken static void netwalker_backlight_attach(device_t, device_t, void *);
70b9040788Shkenken static int netwalker_backlight_detach(device_t, int);
71b9040788Shkenken
72b9040788Shkenken CFATTACH_DECL_NEW(netwalker_backlight, sizeof(struct netwalker_backlight_softc),
73b9040788Shkenken netwalker_backlight_match, netwalker_backlight_attach, netwalker_backlight_detach, NULL);
74b9040788Shkenken
75b9040788Shkenken static bool netwalker_backlight_resume(device_t, const pmf_qual_t *);
76b9040788Shkenken static bool netwalker_backlight_suspend(device_t, const pmf_qual_t *);
77b9040788Shkenken static void netwalker_backlight_on(device_t);
78b9040788Shkenken static void netwalker_backlight_off(device_t);
79b9040788Shkenken static void netwalker_brightness_up(device_t);
80b9040788Shkenken static void netwalker_brightness_down(device_t);
81b9040788Shkenken static void netwalker_set_brightness(struct netwalker_backlight_softc *, int);
82b9040788Shkenken
83b9040788Shkenken static int
netwalker_backlight_match(device_t parent,cfdata_t cf,void * aux)84b9040788Shkenken netwalker_backlight_match(device_t parent, cfdata_t cf, void * aux)
85b9040788Shkenken {
86b9040788Shkenken return imxpwm_match(parent, cf, aux);
87b9040788Shkenken }
88b9040788Shkenken
89b9040788Shkenken static void
netwalker_backlight_attach(device_t parent,device_t self,void * aux)90b9040788Shkenken netwalker_backlight_attach(device_t parent, device_t self, void *aux)
91b9040788Shkenken {
92b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(self);
93b9040788Shkenken struct imxpwm_softc *imxpwm = &sc->sc_imxpwm;
94b9040788Shkenken
95b9040788Shkenken imxpwm->sc_dev = self;
96b9040788Shkenken imxpwm->sc_handler = NULL;
97b9040788Shkenken imxpwm->sc_cookie = sc;
98b9040788Shkenken imxpwm_attach(imxpwm, aux);
99b9040788Shkenken
100b9040788Shkenken aprint_normal(": LCD BackLight Control\n");
101b9040788Shkenken aprint_naive(": LCD BackLight Control\n");
102b9040788Shkenken
103b9040788Shkenken netwalker_backlight_sc = sc;
104b9040788Shkenken
105b9040788Shkenken /* BackLight 100% On */
106b9040788Shkenken sc->sc_islit = true;
107*2bd1432cShkenken netwalker_set_brightness(sc, BRIGHTNESS_MAX);
108b9040788Shkenken
109b9040788Shkenken if (!pmf_device_register(self, netwalker_backlight_suspend,
110b9040788Shkenken netwalker_backlight_resume))
111b9040788Shkenken aprint_error_dev(self,
112b9040788Shkenken "couldn't establish backlight handler\n");
113b9040788Shkenken
114b9040788Shkenken if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP,
115b9040788Shkenken netwalker_brightness_up, true))
116b9040788Shkenken aprint_error_dev(self,
117b9040788Shkenken "couldn't register BRIGHTNESS UP event handler\n");
118b9040788Shkenken if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN,
119b9040788Shkenken netwalker_brightness_down, true))
120b9040788Shkenken aprint_error_dev(self,
121b9040788Shkenken "couldn't register BRIGHTNESS DOWN event handler\n");
122b9040788Shkenken if (!pmf_event_register(self, PMFE_DISPLAY_ON,
123b9040788Shkenken netwalker_backlight_on, true))
124b9040788Shkenken aprint_error_dev(self,
125b9040788Shkenken "couldn't register DISPLAY ON event handler\n");
126b9040788Shkenken if (!pmf_event_register(self, PMFE_DISPLAY_OFF,
127b9040788Shkenken netwalker_backlight_off, true))
128b9040788Shkenken aprint_error_dev(self,
129b9040788Shkenken "couldn't register DISPLAY OFF event handler\n");
130b9040788Shkenken if (!pmf_event_register(self, PMFE_CHASSIS_LID_OPEN,
131b9040788Shkenken netwalker_backlight_on, true))
132b9040788Shkenken aprint_error_dev(self,
133b9040788Shkenken "couldn't register LID OPEN event handler\n");
134b9040788Shkenken if (!pmf_event_register(self, PMFE_CHASSIS_LID_CLOSE,
135b9040788Shkenken netwalker_backlight_off, true))
136b9040788Shkenken aprint_error_dev(self,
137b9040788Shkenken "couldn't register LID CLOSE event handler\n");
138b9040788Shkenken }
139b9040788Shkenken
140b9040788Shkenken static int
netwalker_backlight_detach(device_t self,int flags)141b9040788Shkenken netwalker_backlight_detach(device_t self, int flags)
142b9040788Shkenken {
143b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(self);
144b9040788Shkenken
145*2bd1432cShkenken netwalker_set_brightness(sc, 0);
146b9040788Shkenken pmf_device_deregister(self);
147b9040788Shkenken return 0;
148b9040788Shkenken }
149b9040788Shkenken
1507bb55e03Shkenken static int
netwalker_backlight_get_backlight(void * cookie,int * state)1517bb55e03Shkenken netwalker_backlight_get_backlight(void *cookie, int *state)
1527bb55e03Shkenken {
1537bb55e03Shkenken struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie;
1547bb55e03Shkenken *state = sc->sc_islit;
1557bb55e03Shkenken return 0;
1567bb55e03Shkenken }
1577bb55e03Shkenken
1587bb55e03Shkenken static int
netwalker_backlight_set_backlight(void * cookie,int state)1597bb55e03Shkenken netwalker_backlight_set_backlight(void *cookie, int state)
1607bb55e03Shkenken {
1617bb55e03Shkenken struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie;
1627bb55e03Shkenken
1637bb55e03Shkenken KASSERT(state >= 0 && state <= 1);
1647bb55e03Shkenken
1657bb55e03Shkenken sc->sc_islit = state;
1667bb55e03Shkenken netwalker_set_brightness(sc, sc->sc_brightness);
1677bb55e03Shkenken
1687bb55e03Shkenken return 0;
1697bb55e03Shkenken }
1707bb55e03Shkenken
1717bb55e03Shkenken static int
netwalker_backlight_get_brightness(void * cookie,int * level)1727bb55e03Shkenken netwalker_backlight_get_brightness(void *cookie, int *level)
1737bb55e03Shkenken {
1747bb55e03Shkenken struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie;
1757bb55e03Shkenken
1767bb55e03Shkenken if (sc->sc_brightness < 0)
1777bb55e03Shkenken return ENODEV;
1787bb55e03Shkenken
1797bb55e03Shkenken *level = sc->sc_brightness;
1807bb55e03Shkenken return 0;
1817bb55e03Shkenken }
1827bb55e03Shkenken
1837bb55e03Shkenken static int
netwalker_backlight_set_brightness(void * cookie,int level)1847bb55e03Shkenken netwalker_backlight_set_brightness(void *cookie, int level)
1857bb55e03Shkenken {
1867bb55e03Shkenken struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie;
1877bb55e03Shkenken
188*2bd1432cShkenken KASSERT(level >= 0 && level <= BRIGHTNESS_MAX);
1897bb55e03Shkenken
1907bb55e03Shkenken sc->sc_brightness = level;
1917bb55e03Shkenken netwalker_set_brightness(sc, sc->sc_brightness);
1927bb55e03Shkenken
1937bb55e03Shkenken return 0;
1947bb55e03Shkenken }
1957bb55e03Shkenken
1967bb55e03Shkenken static int
netwalker_backlight_upd_brightness(void * cookie,int delta)1977bb55e03Shkenken netwalker_backlight_upd_brightness(void *cookie, int delta)
1987bb55e03Shkenken {
1997bb55e03Shkenken struct netwalker_backlight_softc *sc = *(struct netwalker_backlight_softc **)cookie;
2007bb55e03Shkenken
2017bb55e03Shkenken if (sc->sc_brightness < 0)
2027bb55e03Shkenken return ENODEV;
2037bb55e03Shkenken
2047bb55e03Shkenken sc->sc_brightness += delta;
2057bb55e03Shkenken if (sc->sc_brightness < 0) sc->sc_brightness = 0;
206*2bd1432cShkenken if (sc->sc_brightness > BRIGHTNESS_MAX) sc->sc_brightness = BRIGHTNESS_MAX;
2077bb55e03Shkenken netwalker_set_brightness(sc, sc->sc_brightness);
2087bb55e03Shkenken
2097bb55e03Shkenken return 0;
2107bb55e03Shkenken }
2117bb55e03Shkenken
2127bb55e03Shkenken void
netwalker_backlight_genfb_parameter_set(prop_dictionary_t dict)2137bb55e03Shkenken netwalker_backlight_genfb_parameter_set(prop_dictionary_t dict)
2147bb55e03Shkenken {
2157bb55e03Shkenken gpc_backlight.gpc_cookie = (void *)&netwalker_backlight_sc;
2167bb55e03Shkenken gpc_backlight.gpc_set_parameter = netwalker_backlight_set_backlight;
2177bb55e03Shkenken gpc_backlight.gpc_get_parameter = netwalker_backlight_get_backlight;
2187bb55e03Shkenken gpc_backlight.gpc_upd_parameter = NULL;
2197bb55e03Shkenken prop_dictionary_set_uint64(dict, "backlight_callback",
2207bb55e03Shkenken (uint64_t)(uintptr_t)&gpc_backlight);
2217bb55e03Shkenken
2227bb55e03Shkenken gpc_brightness.gpc_cookie = (void *)&netwalker_backlight_sc;
2237bb55e03Shkenken gpc_brightness.gpc_set_parameter = netwalker_backlight_set_brightness;
2247bb55e03Shkenken gpc_brightness.gpc_get_parameter = netwalker_backlight_get_brightness;
2257bb55e03Shkenken gpc_brightness.gpc_upd_parameter = netwalker_backlight_upd_brightness;
2267bb55e03Shkenken prop_dictionary_set_uint64(dict, "brightness_callback",
2277bb55e03Shkenken (uint64_t)(uintptr_t)&gpc_brightness);
2287bb55e03Shkenken }
2297bb55e03Shkenken
230b9040788Shkenken /*
231b9040788Shkenken * Power management
232b9040788Shkenken */
233b9040788Shkenken static bool
netwalker_backlight_suspend(device_t dv,const pmf_qual_t * qual)234b9040788Shkenken netwalker_backlight_suspend(device_t dv, const pmf_qual_t *qual)
235b9040788Shkenken {
236b9040788Shkenken netwalker_backlight_off(dv);
237b9040788Shkenken return true;
238b9040788Shkenken }
239b9040788Shkenken
240b9040788Shkenken static bool
netwalker_backlight_resume(device_t dv,const pmf_qual_t * qual)241b9040788Shkenken netwalker_backlight_resume(device_t dv, const pmf_qual_t *qual)
242b9040788Shkenken {
243b9040788Shkenken netwalker_backlight_on(dv);
244b9040788Shkenken return true;
245b9040788Shkenken }
246b9040788Shkenken
247b9040788Shkenken static void
netwalker_backlight_on(device_t dv)248b9040788Shkenken netwalker_backlight_on(device_t dv)
249b9040788Shkenken {
250b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(dv);
251b9040788Shkenken sc->sc_islit = true;
252b9040788Shkenken netwalker_set_brightness(sc, sc->sc_brightness);
253b9040788Shkenken }
254b9040788Shkenken
255b9040788Shkenken static void
netwalker_backlight_off(device_t dv)256b9040788Shkenken netwalker_backlight_off(device_t dv)
257b9040788Shkenken {
258b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(dv);
259b9040788Shkenken sc->sc_islit = false;
260b9040788Shkenken netwalker_set_brightness(sc, sc->sc_brightness);
261b9040788Shkenken }
262b9040788Shkenken
263b9040788Shkenken static void
netwalker_brightness_up(device_t dv)264b9040788Shkenken netwalker_brightness_up(device_t dv)
265b9040788Shkenken {
266b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(dv);
267b9040788Shkenken netwalker_set_brightness(sc, sc->sc_brightness + 1);
268b9040788Shkenken }
269b9040788Shkenken
270b9040788Shkenken static void
netwalker_brightness_down(device_t dv)271b9040788Shkenken netwalker_brightness_down(device_t dv)
272b9040788Shkenken {
273b9040788Shkenken struct netwalker_backlight_softc *sc = device_private(dv);
274b9040788Shkenken netwalker_set_brightness(sc, sc->sc_brightness - 1);
275b9040788Shkenken }
276b9040788Shkenken
277b9040788Shkenken static void
netwalker_set_pwm(struct netwalker_backlight_softc * sc,int val)278*2bd1432cShkenken netwalker_set_pwm(struct netwalker_backlight_softc *sc, int val)
279*2bd1432cShkenken {
280*2bd1432cShkenken pwm_tag_t pwm = &sc->sc_imxpwm.sc_pwm;
281*2bd1432cShkenken struct pwm_config conf;
282*2bd1432cShkenken
283*2bd1432cShkenken pwm_disable(pwm);
284*2bd1432cShkenken pwm_get_config(pwm, &conf);
285*2bd1432cShkenken conf.duty_cycle = (conf.period * val) / BRIGHTNESS_MAX;
286*2bd1432cShkenken pwm_set_config(pwm, &conf);
287*2bd1432cShkenken pwm_enable(pwm);
288*2bd1432cShkenken }
289*2bd1432cShkenken
290*2bd1432cShkenken static void
netwalker_set_brightness(struct netwalker_backlight_softc * sc,int newval)291b9040788Shkenken netwalker_set_brightness(struct netwalker_backlight_softc *sc, int newval)
292b9040788Shkenken {
293b9040788Shkenken if (newval < 0)
294b9040788Shkenken newval = 0;
295b9040788Shkenken else if (newval > BRIGHTNESS_MAX)
296b9040788Shkenken newval = BRIGHTNESS_MAX;
297b9040788Shkenken sc->sc_brightness = newval;
298b9040788Shkenken
299b9040788Shkenken if (sc->sc_islit)
300*2bd1432cShkenken netwalker_set_pwm(sc, sc->sc_brightness);
301b9040788Shkenken else
302*2bd1432cShkenken netwalker_set_pwm(sc, 0);
303b9040788Shkenken }
304b9040788Shkenken
305b9040788Shkenken int
netwalker_lcd_param_ioctl(u_long cmd,struct wsdisplay_param * dp)306b9040788Shkenken netwalker_lcd_param_ioctl(u_long cmd, struct wsdisplay_param *dp)
307b9040788Shkenken {
308b9040788Shkenken struct netwalker_backlight_softc *sc = netwalker_backlight_sc;
309b9040788Shkenken int rv = EINVAL;
310b9040788Shkenken
311b9040788Shkenken switch (dp->param) {
312b9040788Shkenken case WSDISPLAYIO_PARAM_BACKLIGHT:
313b9040788Shkenken if (cmd == WSDISPLAYIO_GETPARAM) {
314b9040788Shkenken dp->min = 0;
315b9040788Shkenken dp->max = 1;
316b9040788Shkenken dp->curval = sc->sc_islit ? 1 : 0;
317b9040788Shkenken rv = 0;
318b9040788Shkenken } else if (cmd == WSDISPLAYIO_SETPARAM) {
319b9040788Shkenken if (dp->curval != 0)
320b9040788Shkenken netwalker_backlight_on(sc->sc_imxpwm.sc_dev);
321b9040788Shkenken else
322b9040788Shkenken netwalker_backlight_off(sc->sc_imxpwm.sc_dev);
323b9040788Shkenken rv = 0;
324b9040788Shkenken }
325b9040788Shkenken break;
326b9040788Shkenken
327b9040788Shkenken case WSDISPLAYIO_PARAM_CONTRAST:
328b9040788Shkenken /* unsupported */
329b9040788Shkenken rv = ENOTSUP;
330b9040788Shkenken break;
331b9040788Shkenken
332b9040788Shkenken case WSDISPLAYIO_PARAM_BRIGHTNESS:
333b9040788Shkenken if (cmd == WSDISPLAYIO_GETPARAM) {
334b9040788Shkenken dp->min = 0;
335b9040788Shkenken dp->max = BRIGHTNESS_MAX;
336b9040788Shkenken dp->curval = sc->sc_brightness;
337b9040788Shkenken rv = 0;
338b9040788Shkenken } else if (cmd == WSDISPLAYIO_SETPARAM) {
339b9040788Shkenken netwalker_set_brightness(sc, dp->curval);
340b9040788Shkenken rv = 0;
341b9040788Shkenken }
342b9040788Shkenken break;
343b9040788Shkenken }
344b9040788Shkenken
345b9040788Shkenken return rv;
346b9040788Shkenken }
347