soekrisgpio.c revision 1.1
1/*	$OpenBSD$ */
2
3/*
4 * Copyright (c) 2013 Matt Dainty <matt <at> bodgit-n-scarper.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
15 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * Soekris net6501 GPIO and LEDs as implemented by the onboard Xilinx FPGA
21 */
22
23#include <sys/param.h>
24#include <sys/systm.h>
25#include <sys/device.h>
26#include <sys/gpio.h>
27
28#include <machine/bus.h>
29#include <machine/intr.h>
30
31#include <dev/isa/isavar.h>
32
33#include <dev/gpio/gpiovar.h>
34
35#define	SOEKRIS_BASE		0x680	/* Base address of FPGA I/O */
36#define	SOEKRIS_IOSIZE		32	/* I/O region size */
37
38#define	SOEKRIS_NPINS		16	/* Number of Pins */
39#define	SOEKRIS_GPIO_INPUT	0x000	/* Current state of pins */
40#define	SOEKRIS_GPIO_OUTPUT	0x004	/* Set state of output pins */
41#define	SOEKRIS_GPIO_RESET	0x008	/* Reset output pins */
42#define	SOEKRIS_GPIO_SET	0x00c	/* Set output pins */
43#define	SOEKRIS_GPIO_DIR	0x010	/* Direction, set for output */
44
45#define	SOEKRIS_NLEDS		2	/* Number of LEDs */
46#define	SOEKRIS_LED_ERROR	0x01c	/* Offset to error LED */
47#define	SOEKRIS_LED_READY	0x01d	/* Offset to ready LED */
48
49const u_int soekris_led_offset[SOEKRIS_NLEDS] = {
50	SOEKRIS_LED_ERROR, SOEKRIS_LED_READY
51};
52
53struct soekris_softc {
54	struct device		 sc_dev;
55
56	bus_space_tag_t		 sc_iot;
57	bus_space_handle_t	 sc_ioh;
58
59	struct gpio_chipset_tag	 sc_gpio_gc;
60	gpio_pin_t		 sc_gpio_pins[SOEKRIS_NPINS];
61
62	/* Fake GPIO device for the LEDs */
63	struct gpio_chipset_tag	 sc_led_gc;
64	gpio_pin_t		 sc_led_pins[SOEKRIS_NLEDS];
65};
66
67int	 soekris_match(struct device *, void *, void *);
68void	 soekris_attach(struct device *, struct device *, void *);
69int	 soekris_gpio_read(void *, int);
70void	 soekris_gpio_write(void *, int, int);
71void	 soekris_gpio_ctl(void *, int, int);
72int	 soekris_led_read(void *, int);
73void	 soekris_led_write(void *, int, int);
74void	 soekris_led_ctl(void *, int, int);
75
76struct cfattach soekris_ca = {
77	sizeof(struct soekris_softc), soekris_match, soekris_attach
78};
79
80struct cfdriver soekris_cd = {
81	NULL, "soekris", DV_DULL
82};
83
84int
85soekris_match(struct device *parent, void *match, void *aux)
86{
87	struct isa_attach_args *ia = aux;
88	bus_space_handle_t ioh;
89
90	/* Need some sort of heuristic to match the Soekris net6501 */
91
92	if (ia->ia_iobase != SOEKRIS_BASE || bus_space_map(ia->ia_iot,
93	    ia->ia_iobase, SOEKRIS_IOSIZE, 0, &ioh) != 0)
94		return (0);
95
96	bus_space_unmap(ia->ia_iot, ioh, SOEKRIS_IOSIZE);
97	ia->ia_iosize = SOEKRIS_IOSIZE;
98	ia->ipa_nio = 1;
99	ia->ipa_nmem = 0;
100	ia->ipa_nirq = 0;
101	ia->ipa_ndrq = 0;
102
103	return (1);
104}
105
106void
107soekris_attach(struct device *parent, struct device *self, void *aux)
108{
109	struct soekris_softc *sc = (void *)self;
110	struct isa_attach_args *ia = aux;
111	struct gpiobus_attach_args gba1, gba2;
112	u_int data;
113	int i;
114
115	if (bus_space_map(ia->ia_iot, ia->ia_iobase, ia->ia_iosize, 0,
116	    &sc->sc_ioh) != 0) {
117		printf(": can't map i/o space\n");
118		return;
119	}
120
121	printf("\n");
122
123	sc->sc_iot = ia->ia_iot;
124
125	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR);
126
127	for (i = 0; i < SOEKRIS_NPINS; i++) {
128		sc->sc_gpio_pins[i].pin_num = i;
129		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
130		    GPIO_PIN_OUTPUT;
131		sc->sc_gpio_pins[i].pin_flags = (data & (1 << i)) ?
132		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
133		sc->sc_gpio_pins[i].pin_state = soekris_gpio_read(sc, i);
134	}
135
136	sc->sc_gpio_gc.gp_cookie = sc;
137	sc->sc_gpio_gc.gp_pin_read = soekris_gpio_read;
138	sc->sc_gpio_gc.gp_pin_write = soekris_gpio_write;
139	sc->sc_gpio_gc.gp_pin_ctl = soekris_gpio_ctl;
140
141	gba1.gba_name = "gpio";
142	gba1.gba_gc = &sc->sc_gpio_gc;
143	gba1.gba_pins = sc->sc_gpio_pins;
144	gba1.gba_npins = SOEKRIS_NPINS;
145
146	(void)config_found(&sc->sc_dev, &gba1, gpiobus_print);
147
148	for (i = 0; i < SOEKRIS_NLEDS; i++) {
149		sc->sc_led_pins[i].pin_num = i;
150		sc->sc_led_pins[i].pin_caps = GPIO_PIN_OUTPUT;
151		sc->sc_led_pins[i].pin_flags = GPIO_PIN_OUTPUT;
152		sc->sc_led_pins[i].pin_state = soekris_led_read(sc, i);
153	}
154
155	sc->sc_led_gc.gp_cookie = sc;
156	sc->sc_led_gc.gp_pin_read = soekris_led_read;
157	sc->sc_led_gc.gp_pin_write = soekris_led_write;
158	sc->sc_led_gc.gp_pin_ctl = soekris_led_ctl;
159
160	gba2.gba_name = "gpio";
161	gba2.gba_gc = &sc->sc_led_gc;
162	gba2.gba_pins = sc->sc_led_pins;
163	gba2.gba_npins = SOEKRIS_NLEDS;
164
165	(void)config_found(&sc->sc_dev, &gba2, gpiobus_print);
166}
167
168int
169soekris_gpio_read(void *arg, int pin)
170{
171	struct soekris_softc *sc = arg;
172	u_int16_t data;
173
174	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT);
175
176	return (data & (1 << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
177}
178
179void
180soekris_gpio_write(void *arg, int pin, int value)
181{
182	struct soekris_softc *sc = arg;
183	u_int16_t data;
184
185	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT);
186
187	if (value == GPIO_PIN_LOW)
188		data &= ~(1 << pin);
189	else if (value == GPIO_PIN_HIGH)
190		data |= (1 << pin);
191
192	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_OUTPUT, data);
193}
194
195void
196soekris_gpio_ctl(void *arg, int pin, int flags)
197{
198	struct soekris_softc *sc = arg;
199	u_int16_t data;
200
201	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR);
202
203	if (flags & GPIO_PIN_INPUT)
204		data &= ~(1 << pin);
205	if (flags & GPIO_PIN_OUTPUT)
206		data |= (1 << pin);
207
208	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR, data);
209}
210
211int
212soekris_led_read(void *arg, int pin)
213{
214	struct soekris_softc *sc = arg;
215	u_int8_t value;
216
217	value = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
218	    soekris_led_offset[pin]);
219
220	return (value & 0x1) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
221}
222
223void
224soekris_led_write(void *arg, int pin, int value)
225{
226	struct soekris_softc *sc = arg;
227
228	bus_space_write_1(sc->sc_iot, sc->sc_ioh, soekris_led_offset[pin],
229	    value);
230}
231
232void
233soekris_led_ctl(void *arg, int pin, int flags)
234{
235}
236