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 #include "opt_platform.h" 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/gpio.h> 34 #include <sys/kernel.h> 35 #include <sys/lock.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/mutex.h> 39 #include <sys/sysctl.h> 40 41 #include <dev/fdt/fdt_common.h> 42 #include <dev/ofw/ofw_bus.h> 43 44 #include <dev/gpio/gpiobusvar.h> 45 46 struct gpiobacklight_softc 47 { 48 gpio_pin_t sc_pin; 49 struct sysctl_oid *sc_oid; 50 bool sc_brightness; 51 }; 52 53 static int gpiobacklight_sysctl(SYSCTL_HANDLER_ARGS); 54 static void gpiobacklight_update_brightness(struct gpiobacklight_softc *); 55 static int gpiobacklight_probe(device_t); 56 static int gpiobacklight_attach(device_t); 57 static int gpiobacklight_detach(device_t); 58 59 static void 60 gpiobacklight_update_brightness(struct gpiobacklight_softc *sc) 61 { 62 63 if (sc->sc_pin) 64 gpio_pin_set_active(sc->sc_pin, sc->sc_brightness); 65 } 66 67 static int 68 gpiobacklight_sysctl(SYSCTL_HANDLER_ARGS) 69 { 70 struct gpiobacklight_softc *sc; 71 int error; 72 int brightness; 73 74 sc = (struct gpiobacklight_softc*)arg1; 75 76 brightness = sc->sc_brightness; 77 error = sysctl_handle_int(oidp, &brightness, 0, req); 78 79 if (error != 0 || req->newptr == NULL) 80 return (error); 81 82 sc->sc_brightness = (brightness > 0); 83 gpiobacklight_update_brightness(sc); 84 85 return (0); 86 } 87 88 static int 89 gpiobacklight_probe(device_t dev) 90 { 91 92 if (!ofw_bus_is_compatible(dev, "gpio-backlight")) 93 return (ENXIO); 94 95 device_set_desc(dev, "GPIO backlight"); 96 97 return (0); 98 } 99 100 static int 101 gpiobacklight_attach(device_t dev) 102 { 103 struct gpiobacklight_softc *sc; 104 struct sysctl_ctx_list *ctx; 105 struct sysctl_oid *tree; 106 phandle_t node; 107 108 sc = device_get_softc(dev); 109 110 if ((node = ofw_bus_get_node(dev)) == -1) 111 return (ENXIO); 112 113 if (OF_hasprop(node, "default-on")) 114 sc->sc_brightness = true; 115 else 116 sc->sc_brightness = false; 117 118 gpio_pin_get_by_ofw_idx(dev, node, 0, &sc->sc_pin); 119 if (sc->sc_pin == NULL) { 120 device_printf(dev, "failed to map GPIO pin\n"); 121 return (ENXIO); 122 } 123 124 gpio_pin_setflags(sc->sc_pin, GPIO_PIN_OUTPUT); 125 126 gpiobacklight_update_brightness(sc); 127 128 /* Init backlight interface */ 129 ctx = device_get_sysctl_ctx(dev); 130 tree = device_get_sysctl_tree(dev); 131 sc->sc_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 132 "brightness", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, 133 gpiobacklight_sysctl, "I", "backlight brightness"); 134 135 return (0); 136 } 137 138 static int 139 gpiobacklight_detach(device_t dev) 140 { 141 struct gpiobacklight_softc *sc; 142 143 sc = device_get_softc(dev); 144 145 if (sc->sc_pin) 146 gpio_pin_release(sc->sc_pin); 147 148 return (0); 149 } 150 151 static device_method_t gpiobacklight_methods[] = { 152 /* Device interface */ 153 DEVMETHOD(device_probe, gpiobacklight_probe), 154 DEVMETHOD(device_attach, gpiobacklight_attach), 155 DEVMETHOD(device_detach, gpiobacklight_detach), 156 157 DEVMETHOD_END 158 }; 159 160 static driver_t gpiobacklight_driver = { 161 "gpiobacklight", 162 gpiobacklight_methods, 163 sizeof(struct gpiobacklight_softc), 164 }; 165 166 DRIVER_MODULE(gpiobacklight, simplebus, gpiobacklight_driver, 0, 0); 167 MODULE_DEPEND(gpiobacklight, gpiobus, 1, 1, 1); 168