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