gpiosim.c revision 1.2 1 /* $NetBSD: gpiosim.c,v 1.2 2009/07/26 13:45:20 mbalmer Exp $ */
2 /* $OpenBSD: gpiosim.c,v 1.1 2008/11/23 18:46:49 mbalmer Exp $ */
3
4 /*
5 * Copyright (c) 2007, 2008, 2009 Marc Balmer <marc (at) msys.ch>
6 * All rights reserved.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 /* 32 bit wide GPIO simulator */
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/device.h>
25 #include <sys/gpio.h>
26 #include <sys/malloc.h>
27 #include <sys/sysctl.h>
28 #include <sys/ioccom.h>
29
30 #include <dev/gpio/gpiovar.h>
31
32 #define GPIOSIM_NPINS 32
33
34 struct gpiosim_softc {
35 device_t sc_dev;
36 u_int32_t sc_state;
37 struct gpio_chipset_tag sc_gpio_gc;
38 gpio_pin_t sc_gpio_pins[GPIOSIM_NPINS];
39
40 const struct sysctlnode *sc_node;
41 };
42
43 int gpiosim_match(device_t, cfdata_t, void *);
44 void gpiosim_attach(device_t, device_t, void *);
45 int gpiosim_detach(device_t, int);
46 int gpiosim_activate(device_t, enum devact);
47 int gpiosim_sysctl(SYSCTLFN_PROTO);
48
49 int gpiosim_pin_read(void *, int);
50 void gpiosim_pin_write(void *, int, int);
51 void gpiosim_pin_ctl(void *, int, int);
52
53 CFATTACH_DECL_NEW(gpiosim, sizeof(struct gpiosim_softc), gpiosim_match,
54 gpiosim_attach, gpiosim_detach, gpiosim_activate);
55
56 extern struct cfdriver gpiosim_cd;
57
58 int
59 gpiosim_match(device_t parent, cfdata_t match, void *aux)
60 {
61 return 1;
62 }
63
64 void
65 gpiosim_attach(device_t parent, device_t self, void *aux)
66 {
67 struct gpiosim_softc *sc = device_private(self);
68 struct gpiobus_attach_args gba;
69 int i;
70
71 sc->sc_dev = self;
72
73 /* initialize pin array */
74 for (i = 0; i < GPIOSIM_NPINS; i++) {
75 sc->sc_gpio_pins[i].pin_num = i;
76 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
77 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
78 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN |
79 GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
80
81 /* read initial state */
82 sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_INPUT;
83 sc->sc_state = 0;
84
85 /* create controller tag */
86 sc->sc_gpio_gc.gp_cookie = sc;
87 sc->sc_gpio_gc.gp_pin_read = gpiosim_pin_read;
88 sc->sc_gpio_gc.gp_pin_write = gpiosim_pin_write;
89 sc->sc_gpio_gc.gp_pin_ctl = gpiosim_pin_ctl;
90
91 /* gba.gba_name = "gpio"; */
92 gba.gba_gc = &sc->sc_gpio_gc;
93 gba.gba_pins = sc->sc_gpio_pins;
94 gba.gba_npins = GPIOSIM_NPINS;
95 }
96
97 sysctl_createv(NULL, 0, NULL, NULL,
98 CTLFLAG_PERMANENT,
99 CTLTYPE_NODE, "hw", NULL,
100 NULL, 0, NULL, 0,
101 CTL_HW, CTL_EOL);
102 sysctl_createv(NULL, 0, NULL, &sc->sc_node,
103 0,
104 CTLTYPE_NODE, device_xname(sc->sc_dev),
105 SYSCTL_DESCR("GPIO simulator"),
106 NULL, 0, NULL, 0,
107 CTL_HW, CTL_CREATE, CTL_EOL);
108
109 if (sc->sc_node == NULL) {
110 printf(": can't create sysctl node\n");
111 return;
112 }
113
114 sysctl_createv(NULL, 0, &sc->sc_node, NULL,
115 CTLFLAG_READWRITE,
116 CTLTYPE_INT, "value",
117 SYSCTL_DESCR("Current GPIO simulator value"),
118 gpiosim_sysctl, 0, sc, 0,
119 CTL_CREATE, CTL_EOL);
120
121 printf("\n");
122 config_found_ia(self, "gpiobus", &gba, gpiobus_print);
123 }
124
125 int
126 gpiosim_detach(device_t self, int flags)
127 {
128 struct gpiosim_softc *sc = device_private(self);
129 struct sysctlnode node;
130
131 if (sc->sc_node != NULL) {
132 node = *sc->sc_node;
133 sysctl_destroyv(&node, CTL_EOL);
134 sc->sc_node = NULL;
135 }
136
137 return 0;
138 }
139
140 int
141 gpiosim_activate(device_t self, enum devact act)
142 {
143 switch (act) {
144 case DVACT_ACTIVATE:
145 return EOPNOTSUPP;
146 case DVACT_DEACTIVATE:
147 break;
148 }
149
150 return 0;
151 }
152
153 int
154 gpiosim_sysctl(SYSCTLFN_ARGS)
155 {
156 struct sysctlnode node;
157 struct gpiosim_softc *sc;
158 int val, error;
159
160 node = *rnode;
161 sc = node.sysctl_data;
162
163 node.sysctl_data = &val;
164
165 val = sc->sc_state;
166 error = sysctl_lookup(SYSCTLFN_CALL(&node));
167 if (error || newp == NULL)
168 return error;
169
170 sc->sc_state = val;
171 return 0;
172 }
173
174 int
175 gpiosim_pin_read(void *arg, int pin)
176 {
177 struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
178
179 if (sc->sc_state & (1 << pin))
180 return GPIO_PIN_HIGH;
181 else
182 return GPIO_PIN_LOW;
183 }
184
185 void
186 gpiosim_pin_write(void *arg, int pin, int value)
187 {
188 struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
189
190 if (value == 0)
191 sc->sc_state &= ~(1 << pin);
192 else
193 sc->sc_state |= (1 << pin);
194 }
195
196 void
197 gpiosim_pin_ctl(void *arg, int pin, int flags)
198 {
199 struct gpiosim_softc *sc = (struct gpiosim_softc *)arg;
200
201 sc->sc_gpio_pins[pin].pin_flags = flags;
202 }
203