1*8469df92Sandvar /* $NetBSD: obsled.c,v 1.12 2024/09/07 06:17:38 andvar Exp $ */ 23ad343e5Sshige 33ad343e5Sshige /* 43ad343e5Sshige * Copyright (c) 2004 Shigeyuki Fukushima. 53ad343e5Sshige * All rights reserved. 63ad343e5Sshige * 73ad343e5Sshige * Redistribution and use in source and binary forms, with or without 83ad343e5Sshige * modification, are permitted provided that the following conditions 93ad343e5Sshige * are met: 103ad343e5Sshige * 1. Redistributions of source code must retain the above copyright 113ad343e5Sshige * notice, this list of conditions and the following disclaimer. 123ad343e5Sshige * 2. Redistributions in binary form must reproduce the above 133ad343e5Sshige * copyright notice, this list of conditions and the following 143ad343e5Sshige * disclaimer in the documentation and/or other materials provided 153ad343e5Sshige * with the distribution. 163ad343e5Sshige * 3. The name of the author may not be used to endorse or promote 173ad343e5Sshige * products derived from this software without specific prior 183ad343e5Sshige * written permission. 193ad343e5Sshige * 203ad343e5Sshige * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 213ad343e5Sshige * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 223ad343e5Sshige * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 233ad343e5Sshige * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 243ad343e5Sshige * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 253ad343e5Sshige * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 263ad343e5Sshige * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 273ad343e5Sshige * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 283ad343e5Sshige * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 293ad343e5Sshige * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 303ad343e5Sshige * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 313ad343e5Sshige */ 323ad343e5Sshige 333ad343e5Sshige #include <sys/cdefs.h> 34*8469df92Sandvar __KERNEL_RCSID(0, "$NetBSD: obsled.c,v 1.12 2024/09/07 06:17:38 andvar Exp $"); 353ad343e5Sshige 363ad343e5Sshige #include <sys/param.h> 373ad343e5Sshige #include <sys/device.h> 383ad343e5Sshige #include <sys/queue.h> 39044ec00fSshige #include <sys/sysctl.h> 403ad343e5Sshige #include <sys/systm.h> 413ad343e5Sshige 42b55107dcSshige #include <machine/obs266.h> 433ad343e5Sshige 443ad343e5Sshige #include <powerpc/ibm4xx/dev/gpiovar.h> 453ad343e5Sshige 463ad343e5Sshige struct obsled_softc { 4751a2be50Smatt device_t sc_dev; 483ad343e5Sshige gpio_tag_t sc_tag; 493ad343e5Sshige int sc_addr; 50044ec00fSshige int sc_led_state; /* LED status (ON=1/OFF=0) */ 51044ec00fSshige int sc_led_state_mib; 523ad343e5Sshige }; 533ad343e5Sshige 5451a2be50Smatt static void obsled_attach(device_t, device_t, void *); 5551a2be50Smatt static int obsled_match(device_t, cfdata_t, void *); 56044ec00fSshige static int obsled_sysctl_verify(SYSCTLFN_PROTO); 57044ec00fSshige static void obsled_set_state(struct obsled_softc *); 583ad343e5Sshige 5951a2be50Smatt CFATTACH_DECL_NEW(obsled, sizeof(struct obsled_softc), 603ad343e5Sshige obsled_match, obsled_attach, NULL, NULL); 613ad343e5Sshige 623ad343e5Sshige static int 6351a2be50Smatt obsled_match(device_t parent, cfdata_t cf, void *aux) 643ad343e5Sshige { 653ad343e5Sshige struct gpio_attach_args *ga = aux; 663ad343e5Sshige 673ad343e5Sshige /* XXX: support only OpenBlockS266 LED */ 68b55107dcSshige if (ga->ga_addr == OBS266_GPIO_LED1) 693ad343e5Sshige return (1); 70b55107dcSshige else if (ga->ga_addr == OBS266_GPIO_LED2) 713ad343e5Sshige return (1); 72b55107dcSshige else if (ga->ga_addr == OBS266_GPIO_LED4) 733ad343e5Sshige return (1); 743ad343e5Sshige 753ad343e5Sshige return (0); 763ad343e5Sshige } 773ad343e5Sshige 783ad343e5Sshige static void 7951a2be50Smatt obsled_attach(device_t parent, device_t self, void *aux) 803ad343e5Sshige { 8151a2be50Smatt struct obsled_softc *sc = device_private(self); 823ad343e5Sshige struct gpio_attach_args *ga = aux; 83044ec00fSshige struct sysctlnode *node; 84044ec00fSshige int err, node_mib; 85044ec00fSshige char led_name[5]; 8651a2be50Smatt /* int led = (1 << device_unit(sc->sc_dev)); */ 873ad343e5Sshige 88044ec00fSshige snprintf(led_name, sizeof(led_name), 8951a2be50Smatt "led%d", (1 << device_unit(sc->sc_dev)) & 0x7); 90044ec00fSshige aprint_naive(": OpenBlockS %s\n", led_name); 91044ec00fSshige aprint_normal(": OpenBlockS %s\n", led_name); 923ad343e5Sshige 9351a2be50Smatt sc->sc_dev = self; 943ad343e5Sshige sc->sc_tag = ga->ga_tag; 953ad343e5Sshige sc->sc_addr = ga->ga_addr; 96044ec00fSshige sc->sc_led_state = 0; 973ad343e5Sshige 98b55107dcSshige obs266_led_set(OBS266_LED_OFF); 99044ec00fSshige 100044ec00fSshige /* add sysctl interface */ 101044ec00fSshige err = sysctl_createv(NULL, 0, 102044ec00fSshige NULL, (const struct sysctlnode **)&node, 103044ec00fSshige 0, CTLTYPE_NODE, 104044ec00fSshige "obsled", 105044ec00fSshige NULL, 106044ec00fSshige NULL, 0, NULL, 0, 107044ec00fSshige CTL_HW, CTL_CREATE, CTL_EOL); 108044ec00fSshige if (err != 0) 109044ec00fSshige return; 110044ec00fSshige node_mib = node->sysctl_num; 111044ec00fSshige err = sysctl_createv(NULL, 0, 112044ec00fSshige NULL, (const struct sysctlnode **)&node, 113044ec00fSshige CTLFLAG_READWRITE, CTLTYPE_INT, 114044ec00fSshige led_name, 115044ec00fSshige SYSCTL_DESCR("OpenBlockS LED state (0=off, 1=on)"), 116e21a34c2Sdsl obsled_sysctl_verify, 0, (void *)sc, 0, 117044ec00fSshige CTL_HW, node_mib, CTL_CREATE, CTL_EOL); 118044ec00fSshige if (err != 0) 119044ec00fSshige return; 120044ec00fSshige 121044ec00fSshige sc->sc_led_state_mib = node->sysctl_num; 1223ad343e5Sshige #if 0 1233ad343e5Sshige { 1243ad343e5Sshige gpio_tag_t tag = sc->sc_tag; 1253ad343e5Sshige (*(tag)->io_or_write)((tag)->cookie, sc->sc_addr, 0); 1263ad343e5Sshige } 1273ad343e5Sshige #endif 1283ad343e5Sshige } 1293ad343e5Sshige 130044ec00fSshige static int 131044ec00fSshige obsled_sysctl_verify(SYSCTLFN_ARGS) 132044ec00fSshige { 133044ec00fSshige struct obsled_softc *sc = rnode->sysctl_data; 134044ec00fSshige struct sysctlnode node; 135044ec00fSshige int err, state; 136044ec00fSshige 137044ec00fSshige node = *rnode; 138044ec00fSshige state = sc->sc_led_state; 139044ec00fSshige node.sysctl_data = &state; 140044ec00fSshige 141044ec00fSshige err = sysctl_lookup(SYSCTLFN_CALL(&node)); 142044ec00fSshige if (err != 0 || newp == NULL) 143044ec00fSshige return err; 144044ec00fSshige 145044ec00fSshige if (node.sysctl_num == sc->sc_led_state_mib) { 146044ec00fSshige if (state < 0 || state > 1) 147044ec00fSshige return EINVAL; 148044ec00fSshige sc->sc_led_state = state; 149044ec00fSshige obsled_set_state(sc); 150044ec00fSshige } 151044ec00fSshige 152044ec00fSshige return 0; 153044ec00fSshige } 154044ec00fSshige 155044ec00fSshige static void 156044ec00fSshige obsled_set_state(struct obsled_softc *sc) 157044ec00fSshige { 158044ec00fSshige gpio_tag_t tag = sc->sc_tag; 159044ec00fSshige 160044ec00fSshige (*(tag)->io_or_write)((tag)->cookie, 161044ec00fSshige sc->sc_addr, 162044ec00fSshige (~(sc->sc_led_state) & 1)); 163044ec00fSshige /* GPIO LED input ON=0/OFF=1 */ 164044ec00fSshige } 165044ec00fSshige 166044ec00fSshige /* 167044ec00fSshige * Setting LED interface for inside kernel. 168915340d5Sandvar * Argument `led' is 3-bit LED state (led=0-7/ON=1/OFF=0). 169044ec00fSshige */ 1703ad343e5Sshige void 171b55107dcSshige obs266_led_set(int led) 1723ad343e5Sshige { 173b504b9ffSdyoung device_t dv; 174b504b9ffSdyoung deviter_t di; 1753ad343e5Sshige 176044ec00fSshige /* 177*8469df92Sandvar * Searching "obsled" devices from device tree. 178*8469df92Sandvar * Do you have a better idea? 179044ec00fSshige */ 180b504b9ffSdyoung for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; 181b504b9ffSdyoung dv = deviter_next(&di)) { 182b504b9ffSdyoung if (device_is_a(dv, "obsles")) { 183b504b9ffSdyoung struct obsled_softc *sc = device_private(dv); 184044ec00fSshige sc->sc_led_state = 185b504b9ffSdyoung (led & (1 << device_unit(dv))) >> device_unit(dv); 186044ec00fSshige obsled_set_state(sc); 1873ad343e5Sshige } 1883ad343e5Sshige } 189b504b9ffSdyoung deviter_release(&di); 1903ad343e5Sshige } 191