1*05fd0bf3Spooka /* $NetBSD: obsled.c,v 1.10 2014/02/25 18:30:08 pooka 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*05fd0bf3Spooka __KERNEL_RCSID(0, "$NetBSD: obsled.c,v 1.10 2014/02/25 18:30:08 pooka 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 {
47534c8a68Smatt 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
54534c8a68Smatt static void obsled_attach(device_t, device_t, void *);
55534c8a68Smatt 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
59534c8a68Smatt CFATTACH_DECL_NEW(obsled, sizeof(struct obsled_softc),
603ad343e5Sshige obsled_match, obsled_attach, NULL, NULL);
613ad343e5Sshige
623ad343e5Sshige static int
obsled_match(device_t parent,cfdata_t cf,void * aux)63534c8a68Smatt 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
obsled_attach(device_t parent,device_t self,void * aux)79534c8a68Smatt obsled_attach(device_t parent, device_t self, void *aux)
803ad343e5Sshige {
81534c8a68Smatt 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];
86534c8a68Smatt /* int led = (1 << device_unit(sc->sc_dev)); */
873ad343e5Sshige
88044ec00fSshige snprintf(led_name, sizeof(led_name),
89534c8a68Smatt "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
93534c8a68Smatt 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)"),
1167c283e77Sdsl 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
obsled_sysctl_verify(SYSCTLFN_ARGS)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
obsled_set_state(struct obsled_softc * sc)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.
168044ec00fSshige * Argumnt `led' is 3-bit LED state (led=0-7/ON=1/OFF=0).
169044ec00fSshige */
1703ad343e5Sshige void
obs266_led_set(int led)171b55107dcSshige obs266_led_set(int led)
1723ad343e5Sshige {
173b504b9ffSdyoung device_t dv;
174b504b9ffSdyoung deviter_t di;
1753ad343e5Sshige
176044ec00fSshige /*
177044ec00fSshige * Sarching "obsled" devices from device tree.
178044ec00fSshige * Do you have something 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