1 /*- 2 * Copyright (c) 2015-2016 Oleksandr Tymoshenko <gonzo@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_platform.h" 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/gpio.h> 36 #include <sys/kernel.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/module.h> 40 #include <sys/mutex.h> 41 #include <sys/sysctl.h> 42 43 #include <dev/fdt/fdt_common.h> 44 #include <dev/ofw/ofw_bus.h> 45 46 #include <dev/gpio/gpiobusvar.h> 47 48 struct gpiobacklight_softc 49 { 50 gpio_pin_t sc_pin; 51 struct sysctl_oid *sc_oid; 52 bool sc_brightness; 53 }; 54 55 static int gpiobacklight_sysctl(SYSCTL_HANDLER_ARGS); 56 static void gpiobacklight_update_brightness(struct gpiobacklight_softc *); 57 static int gpiobacklight_probe(device_t); 58 static int gpiobacklight_attach(device_t); 59 static int gpiobacklight_detach(device_t); 60 61 static void 62 gpiobacklight_update_brightness(struct gpiobacklight_softc *sc) 63 { 64 65 if (sc->sc_pin) 66 gpio_pin_set_active(sc->sc_pin, sc->sc_brightness); 67 } 68 69 static int 70 gpiobacklight_sysctl(SYSCTL_HANDLER_ARGS) 71 { 72 struct gpiobacklight_softc *sc; 73 int error; 74 int brightness; 75 76 sc = (struct gpiobacklight_softc*)arg1; 77 78 brightness = sc->sc_brightness; 79 error = sysctl_handle_int(oidp, &brightness, 0, req); 80 81 if (error != 0 || req->newptr == NULL) 82 return (error); 83 84 sc->sc_brightness = (brightness > 0); 85 gpiobacklight_update_brightness(sc); 86 87 return (0); 88 } 89 90 static int 91 gpiobacklight_probe(device_t dev) 92 { 93 94 if (!ofw_bus_is_compatible(dev, "gpio-backlight")) 95 return (ENXIO); 96 97 device_set_desc(dev, "GPIO backlight"); 98 99 return (0); 100 } 101 102 static int 103 gpiobacklight_attach(device_t dev) 104 { 105 struct gpiobacklight_softc *sc; 106 struct sysctl_ctx_list *ctx; 107 struct sysctl_oid *tree; 108 phandle_t node; 109 110 sc = device_get_softc(dev); 111 112 if ((node = ofw_bus_get_node(dev)) == -1) 113 return (ENXIO); 114 115 if (OF_hasprop(node, "default-on")) 116 sc->sc_brightness = true; 117 else 118 sc->sc_brightness = false; 119 120 gpio_pin_get_by_ofw_idx(dev, node, 0, &sc->sc_pin); 121 if (sc->sc_pin == NULL) { 122 device_printf(dev, "failed to map GPIO pin\n"); 123 return (ENXIO); 124 } 125 126 gpio_pin_setflags(sc->sc_pin, GPIO_PIN_OUTPUT); 127 128 gpiobacklight_update_brightness(sc); 129 130 /* Init backlight interface */ 131 ctx = device_get_sysctl_ctx(dev); 132 tree = device_get_sysctl_tree(dev); 133 sc->sc_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 134 "brightness", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 135 gpiobacklight_sysctl, "I", "backlight brightness"); 136 137 return (0); 138 } 139 140 static int 141 gpiobacklight_detach(device_t dev) 142 { 143 struct gpiobacklight_softc *sc; 144 145 sc = device_get_softc(dev); 146 147 if (sc->sc_pin) 148 gpio_pin_release(sc->sc_pin); 149 150 return (0); 151 } 152 153 static devclass_t gpiobacklight_devclass; 154 155 static device_method_t gpiobacklight_methods[] = { 156 /* Device interface */ 157 DEVMETHOD(device_probe, gpiobacklight_probe), 158 DEVMETHOD(device_attach, gpiobacklight_attach), 159 DEVMETHOD(device_detach, gpiobacklight_detach), 160 161 DEVMETHOD_END 162 }; 163 164 static driver_t gpiobacklight_driver = { 165 "gpiobacklight", 166 gpiobacklight_methods, 167 sizeof(struct gpiobacklight_softc), 168 }; 169 170 DRIVER_MODULE(gpiobacklight, simplebus, gpiobacklight_driver, 171 gpiobacklight_devclass, 0, 0); 172 MODULE_DEPEND(gpiobacklight, gpiobus, 1, 1, 1); 173