soekrisgpio.c revision 1.1
11.1Skardel/*	$OpenBSD$ */
21.1Skardel
31.1Skardel/*
41.1Skardel * Copyright (c) 2013 Matt Dainty <matt <at> bodgit-n-scarper.com>
51.1Skardel *
61.1Skardel * Permission to use, copy, modify, and distribute this software for any
71.1Skardel * purpose with or without fee is hereby granted, provided that the above
81.1Skardel * copyright notice and this permission notice appear in all copies.
91.1Skardel *
101.1Skardel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111.1Skardel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121.1Skardel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131.1Skardel * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141.1Skardel * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
151.1Skardel * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
161.1Skardel * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171.1Skardel */
181.1Skardel
191.1Skardel/*
201.1Skardel * Soekris net6501 GPIO and LEDs as implemented by the onboard Xilinx FPGA
211.1Skardel */
221.1Skardel
231.1Skardel#include <sys/param.h>
241.1Skardel#include <sys/systm.h>
251.1Skardel#include <sys/device.h>
261.1Skardel#include <sys/gpio.h>
271.1Skardel
281.1Skardel#include <machine/bus.h>
291.1Skardel#include <machine/intr.h>
301.1Skardel
311.1Skardel#include <dev/isa/isavar.h>
321.1Skardel
331.1Skardel#include <dev/gpio/gpiovar.h>
341.1Skardel
351.1Skardel#define	SOEKRIS_BASE		0x680	/* Base address of FPGA I/O */
361.1Skardel#define	SOEKRIS_IOSIZE		32	/* I/O region size */
371.1Skardel
381.1Skardel#define	SOEKRIS_NPINS		16	/* Number of Pins */
391.1Skardel#define	SOEKRIS_GPIO_INPUT	0x000	/* Current state of pins */
401.1Skardel#define	SOEKRIS_GPIO_OUTPUT	0x004	/* Set state of output pins */
411.1Skardel#define	SOEKRIS_GPIO_RESET	0x008	/* Reset output pins */
421.1Skardel#define	SOEKRIS_GPIO_SET	0x00c	/* Set output pins */
431.1Skardel#define	SOEKRIS_GPIO_DIR	0x010	/* Direction, set for output */
441.1Skardel
451.1Skardel#define	SOEKRIS_NLEDS		2	/* Number of LEDs */
461.1Skardel#define	SOEKRIS_LED_ERROR	0x01c	/* Offset to error LED */
471.1Skardel#define	SOEKRIS_LED_READY	0x01d	/* Offset to ready LED */
481.1Skardel
491.1Skardelconst u_int soekris_led_offset[SOEKRIS_NLEDS] = {
501.1Skardel	SOEKRIS_LED_ERROR, SOEKRIS_LED_READY
511.1Skardel};
521.1Skardel
531.1Skardelstruct soekris_softc {
541.1Skardel	struct device		 sc_dev;
551.1Skardel
561.1Skardel	bus_space_tag_t		 sc_iot;
571.1Skardel	bus_space_handle_t	 sc_ioh;
581.1Skardel
591.1Skardel	struct gpio_chipset_tag	 sc_gpio_gc;
601.1Skardel	gpio_pin_t		 sc_gpio_pins[SOEKRIS_NPINS];
611.1Skardel
621.1Skardel	/* Fake GPIO device for the LEDs */
631.1Skardel	struct gpio_chipset_tag	 sc_led_gc;
641.1Skardel	gpio_pin_t		 sc_led_pins[SOEKRIS_NLEDS];
651.1Skardel};
661.1Skardel
671.1Skardelint	 soekris_match(struct device *, void *, void *);
681.1Skardelvoid	 soekris_attach(struct device *, struct device *, void *);
691.1Skardelint	 soekris_gpio_read(void *, int);
701.1Skardelvoid	 soekris_gpio_write(void *, int, int);
711.1Skardelvoid	 soekris_gpio_ctl(void *, int, int);
721.1Skardelint	 soekris_led_read(void *, int);
731.1Skardelvoid	 soekris_led_write(void *, int, int);
741.1Skardelvoid	 soekris_led_ctl(void *, int, int);
751.1Skardel
761.1Skardelstruct cfattach soekris_ca = {
771.1Skardel	sizeof(struct soekris_softc), soekris_match, soekris_attach
781.1Skardel};
791.1Skardel
801.1Skardelstruct cfdriver soekris_cd = {
811.1Skardel	NULL, "soekris", DV_DULL
821.1Skardel};
831.1Skardel
841.1Skardelint
851.1Skardelsoekris_match(struct device *parent, void *match, void *aux)
861.1Skardel{
871.1Skardel	struct isa_attach_args *ia = aux;
881.1Skardel	bus_space_handle_t ioh;
891.1Skardel
901.1Skardel	/* Need some sort of heuristic to match the Soekris net6501 */
911.1Skardel
921.1Skardel	if (ia->ia_iobase != SOEKRIS_BASE || bus_space_map(ia->ia_iot,
931.1Skardel	    ia->ia_iobase, SOEKRIS_IOSIZE, 0, &ioh) != 0)
941.1Skardel		return (0);
951.1Skardel
961.1Skardel	bus_space_unmap(ia->ia_iot, ioh, SOEKRIS_IOSIZE);
971.1Skardel	ia->ia_iosize = SOEKRIS_IOSIZE;
981.1Skardel	ia->ipa_nio = 1;
991.1Skardel	ia->ipa_nmem = 0;
1001.1Skardel	ia->ipa_nirq = 0;
1011.1Skardel	ia->ipa_ndrq = 0;
1021.1Skardel
1031.1Skardel	return (1);
1041.1Skardel}
1051.1Skardel
1061.1Skardelvoid
1071.1Skardelsoekris_attach(struct device *parent, struct device *self, void *aux)
1081.1Skardel{
1091.1Skardel	struct soekris_softc *sc = (void *)self;
1101.1Skardel	struct isa_attach_args *ia = aux;
1111.1Skardel	struct gpiobus_attach_args gba1, gba2;
1121.1Skardel	u_int data;
1131.1Skardel	int i;
1141.1Skardel
1151.1Skardel	if (bus_space_map(ia->ia_iot, ia->ia_iobase, ia->ia_iosize, 0,
1161.1Skardel	    &sc->sc_ioh) != 0) {
1171.1Skardel		printf(": can't map i/o space\n");
1181.1Skardel		return;
1191.1Skardel	}
1201.1Skardel
1211.1Skardel	printf("\n");
1221.1Skardel
1231.1Skardel	sc->sc_iot = ia->ia_iot;
1241.1Skardel
1251.1Skardel	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR);
1261.1Skardel
1271.1Skardel	for (i = 0; i < SOEKRIS_NPINS; i++) {
1281.1Skardel		sc->sc_gpio_pins[i].pin_num = i;
1291.1Skardel		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
1301.1Skardel		    GPIO_PIN_OUTPUT;
1311.1Skardel		sc->sc_gpio_pins[i].pin_flags = (data & (1 << i)) ?
1321.1Skardel		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
1331.1Skardel		sc->sc_gpio_pins[i].pin_state = soekris_gpio_read(sc, i);
1341.1Skardel	}
1351.1Skardel
1361.1Skardel	sc->sc_gpio_gc.gp_cookie = sc;
1371.1Skardel	sc->sc_gpio_gc.gp_pin_read = soekris_gpio_read;
1381.1Skardel	sc->sc_gpio_gc.gp_pin_write = soekris_gpio_write;
1391.1Skardel	sc->sc_gpio_gc.gp_pin_ctl = soekris_gpio_ctl;
1401.1Skardel
1411.1Skardel	gba1.gba_name = "gpio";
1421.1Skardel	gba1.gba_gc = &sc->sc_gpio_gc;
1431.1Skardel	gba1.gba_pins = sc->sc_gpio_pins;
1441.1Skardel	gba1.gba_npins = SOEKRIS_NPINS;
1451.1Skardel
1461.1Skardel	(void)config_found(&sc->sc_dev, &gba1, gpiobus_print);
1471.1Skardel
1481.1Skardel	for (i = 0; i < SOEKRIS_NLEDS; i++) {
1491.1Skardel		sc->sc_led_pins[i].pin_num = i;
1501.1Skardel		sc->sc_led_pins[i].pin_caps = GPIO_PIN_OUTPUT;
1511.1Skardel		sc->sc_led_pins[i].pin_flags = GPIO_PIN_OUTPUT;
1521.1Skardel		sc->sc_led_pins[i].pin_state = soekris_led_read(sc, i);
1531.1Skardel	}
1541.1Skardel
1551.1Skardel	sc->sc_led_gc.gp_cookie = sc;
1561.1Skardel	sc->sc_led_gc.gp_pin_read = soekris_led_read;
1571.1Skardel	sc->sc_led_gc.gp_pin_write = soekris_led_write;
1581.1Skardel	sc->sc_led_gc.gp_pin_ctl = soekris_led_ctl;
1591.1Skardel
1601.1Skardel	gba2.gba_name = "gpio";
1611.1Skardel	gba2.gba_gc = &sc->sc_led_gc;
1621.1Skardel	gba2.gba_pins = sc->sc_led_pins;
1631.1Skardel	gba2.gba_npins = SOEKRIS_NLEDS;
1641.1Skardel
1651.1Skardel	(void)config_found(&sc->sc_dev, &gba2, gpiobus_print);
1661.1Skardel}
1671.1Skardel
1681.1Skardelint
1691.1Skardelsoekris_gpio_read(void *arg, int pin)
1701.1Skardel{
1711.1Skardel	struct soekris_softc *sc = arg;
1721.1Skardel	u_int16_t data;
1731.1Skardel
1741.1Skardel	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT);
1751.1Skardel
1761.1Skardel	return (data & (1 << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
1771.1Skardel}
1781.1Skardel
1791.1Skardelvoid
1801.1Skardelsoekris_gpio_write(void *arg, int pin, int value)
1811.1Skardel{
1821.1Skardel	struct soekris_softc *sc = arg;
1831.1Skardel	u_int16_t data;
1841.1Skardel
1851.1Skardel	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT);
1861.1Skardel
1871.1Skardel	if (value == GPIO_PIN_LOW)
1881.1Skardel		data &= ~(1 << pin);
1891.1Skardel	else if (value == GPIO_PIN_HIGH)
1901.1Skardel		data |= (1 << pin);
1911.1Skardel
1921.1Skardel	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_OUTPUT, data);
1931.1Skardel}
1941.1Skardel
1951.1Skardelvoid
1961.1Skardelsoekris_gpio_ctl(void *arg, int pin, int flags)
1971.1Skardel{
1981.1Skardel	struct soekris_softc *sc = arg;
1991.1Skardel	u_int16_t data;
2001.1Skardel
2011.1Skardel	data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR);
2021.1Skardel
2031.1Skardel	if (flags & GPIO_PIN_INPUT)
2041.1Skardel		data &= ~(1 << pin);
2051.1Skardel	if (flags & GPIO_PIN_OUTPUT)
2061.1Skardel		data |= (1 << pin);
2071.1Skardel
2081.1Skardel	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR, data);
2091.1Skardel}
2101.1Skardel
2111.1Skardelint
2121.1Skardelsoekris_led_read(void *arg, int pin)
2131.1Skardel{
2141.1Skardel	struct soekris_softc *sc = arg;
2151.1Skardel	u_int8_t value;
2161.1Skardel
2171.1Skardel	value = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
2181.1Skardel	    soekris_led_offset[pin]);
2191.1Skardel
2201.1Skardel	return (value & 0x1) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
2211.1Skardel}
2221.1Skardel
2231.1Skardelvoid
2241.1Skardelsoekris_led_write(void *arg, int pin, int value)
2251.1Skardel{
2261.1Skardel	struct soekris_softc *sc = arg;
2271.1Skardel
2281.1Skardel	bus_space_write_1(sc->sc_iot, sc->sc_ioh, soekris_led_offset[pin],
2291.1Skardel	    value);
2301.1Skardel}
2311.1Skardel
2321.1Skardelvoid
2331.1Skardelsoekris_led_ctl(void *arg, int pin, int flags)
2341.1Skardel{
2351.1Skardel}
236