11.2Skardel/* from $OpenBSD$ */ 21.1Skardel 31.1Skardel/* 41.2Skardel * ported to NetBSD by Frank Kardel 51.2Skardel * (http://permalink.gmane.org/gmane.os.openbsd.tech/31317) 61.2Skardel * 71.1Skardel * Copyright (c) 2013 Matt Dainty <matt <at> bodgit-n-scarper.com> 81.1Skardel * 91.1Skardel * Permission to use, copy, modify, and distribute this software for any 101.1Skardel * purpose with or without fee is hereby granted, provided that the above 111.1Skardel * copyright notice and this permission notice appear in all copies. 121.1Skardel * 131.1Skardel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 141.1Skardel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 151.1Skardel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 161.1Skardel * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 171.1Skardel * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 181.1Skardel * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 191.1Skardel * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 201.1Skardel */ 211.1Skardel 221.1Skardel/* 231.3Smsaitoh * Soekris net6501 GPIO and LEDs as implemented by the onboard Xilinx FPGA 241.1Skardel */ 251.1Skardel 261.2Skardel#include <sys/cdefs.h> 271.5Sthorpej__KERNEL_RCSID(0, "$NetBSD: soekrisgpio.c,v 1.5 2021/08/07 16:19:12 thorpej Exp $"); 281.2Skardel 291.1Skardel#include <sys/param.h> 301.1Skardel#include <sys/systm.h> 311.2Skardel#include <sys/types.h> 321.1Skardel#include <sys/device.h> 331.1Skardel 341.2Skardel#include <sys/bus.h> 351.2Skardel#include <machine/autoconf.h> 361.1Skardel 371.1Skardel#include <dev/isa/isavar.h> 381.1Skardel 391.2Skardel#include <sys/gpio.h> 401.1Skardel#include <dev/gpio/gpiovar.h> 411.1Skardel 421.2Skardel#include "gpio.h" 431.2Skardel 441.1Skardel#define SOEKRIS_BASE 0x680 /* Base address of FPGA I/O */ 451.1Skardel#define SOEKRIS_IOSIZE 32 /* I/O region size */ 461.1Skardel 471.1Skardel#define SOEKRIS_NPINS 16 /* Number of Pins */ 481.1Skardel#define SOEKRIS_GPIO_INPUT 0x000 /* Current state of pins */ 491.1Skardel#define SOEKRIS_GPIO_OUTPUT 0x004 /* Set state of output pins */ 501.1Skardel#define SOEKRIS_GPIO_RESET 0x008 /* Reset output pins */ 511.1Skardel#define SOEKRIS_GPIO_SET 0x00c /* Set output pins */ 521.1Skardel#define SOEKRIS_GPIO_DIR 0x010 /* Direction, set for output */ 531.1Skardel 541.1Skardel#define SOEKRIS_NLEDS 2 /* Number of LEDs */ 551.1Skardel#define SOEKRIS_LED_ERROR 0x01c /* Offset to error LED */ 561.1Skardel#define SOEKRIS_LED_READY 0x01d /* Offset to ready LED */ 571.1Skardel 581.1Skardelconst u_int soekris_led_offset[SOEKRIS_NLEDS] = { 591.1Skardel SOEKRIS_LED_ERROR, SOEKRIS_LED_READY 601.1Skardel}; 611.1Skardel 621.1Skardelstruct soekris_softc { 631.2Skardel device_t sc_dev; 641.1Skardel 651.1Skardel bus_space_tag_t sc_iot; 661.1Skardel bus_space_handle_t sc_ioh; 671.1Skardel 681.1Skardel struct gpio_chipset_tag sc_gpio_gc; 691.1Skardel gpio_pin_t sc_gpio_pins[SOEKRIS_NPINS]; 701.1Skardel 711.1Skardel /* Fake GPIO device for the LEDs */ 721.1Skardel struct gpio_chipset_tag sc_led_gc; 731.1Skardel gpio_pin_t sc_led_pins[SOEKRIS_NLEDS]; 741.1Skardel}; 751.1Skardel 761.2Skardelstatic int soekris_match(device_t, cfdata_t , void *); 771.2Skardelstatic void soekris_attach(device_t, device_t, void *); 781.2Skardelstatic int soekris_detach(device_t, int); 791.2Skardelstatic int soekris_gpio_read(void *, int); 801.2Skardelstatic void soekris_gpio_write(void *, int, int); 811.2Skardelstatic void soekris_gpio_ctl(void *, int, int); 821.2Skardelstatic int soekris_led_read(void *, int); 831.2Skardelstatic void soekris_led_write(void *, int, int); 841.2Skardelstatic void soekris_led_ctl(void *, int, int); 851.2Skardel 861.2SkardelCFATTACH_DECL_NEW(soekrisgpio, 871.2Skardel sizeof(struct soekris_softc), 881.2Skardel soekris_match, 891.2Skardel soekris_attach, 901.2Skardel soekris_detach, 911.2Skardel NULL); 921.1Skardel 931.2Skardelstatic int 941.2Skardelsoekris_match(device_t parent, cfdata_t match, void *aux) 951.1Skardel{ 961.1Skardel struct isa_attach_args *ia = aux; 971.1Skardel bus_space_handle_t ioh; 981.2Skardel int iobase; 991.2Skardel 1001.2Skardel if (ia->ia_nio < 1) 1011.2Skardel return (0); 1021.2Skardel 1031.2Skardel /* Disallow wildcarded i/o address. */ 1041.2Skardel if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 1051.2Skardel return (0); 1061.2Skardel 1071.2Skardel iobase = ia->ia_io[0].ir_addr; 1081.1Skardel 1091.1Skardel /* Need some sort of heuristic to match the Soekris net6501 */ 1101.1Skardel 1111.2Skardel if (iobase != SOEKRIS_BASE || bus_space_map(ia->ia_iot, 1121.2Skardel iobase, SOEKRIS_IOSIZE, 0, &ioh) != 0) 1131.1Skardel return (0); 1141.1Skardel 1151.1Skardel bus_space_unmap(ia->ia_iot, ioh, SOEKRIS_IOSIZE); 1161.2Skardel 1171.2Skardel ia->ia_io[0].ir_size = SOEKRIS_IOSIZE; 1181.1Skardel 1191.1Skardel return (1); 1201.1Skardel} 1211.1Skardel 1221.2Skardelstatic void 1231.2Skardelsoekris_attach(device_t parent, device_t self, void *aux) 1241.1Skardel{ 1251.2Skardel struct soekris_softc *sc = device_private(self); 1261.1Skardel struct isa_attach_args *ia = aux; 1271.1Skardel struct gpiobus_attach_args gba1, gba2; 1281.1Skardel u_int data; 1291.1Skardel int i; 1301.1Skardel 1311.3Smsaitoh if (bus_space_map(ia->ia_iot, ia->ia_io[0].ir_addr, 1321.3Smsaitoh ia->ia_io[0].ir_size, 0, &sc->sc_ioh) != 0) { 1331.2Skardel aprint_normal(": can't map i/o space\n"); 1341.1Skardel return; 1351.1Skardel } 1361.1Skardel 1371.2Skardel aprint_normal("\n"); 1381.1Skardel 1391.2Skardel sc->sc_dev = self; 1401.1Skardel sc->sc_iot = ia->ia_iot; 1411.1Skardel 1421.1Skardel data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR); 1431.1Skardel 1441.1Skardel for (i = 0; i < SOEKRIS_NPINS; i++) { 1451.1Skardel sc->sc_gpio_pins[i].pin_num = i; 1461.1Skardel sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 1471.1Skardel GPIO_PIN_OUTPUT; 1481.1Skardel sc->sc_gpio_pins[i].pin_flags = (data & (1 << i)) ? 1491.1Skardel GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; 1501.1Skardel sc->sc_gpio_pins[i].pin_state = soekris_gpio_read(sc, i); 1511.1Skardel } 1521.1Skardel 1531.1Skardel sc->sc_gpio_gc.gp_cookie = sc; 1541.1Skardel sc->sc_gpio_gc.gp_pin_read = soekris_gpio_read; 1551.1Skardel sc->sc_gpio_gc.gp_pin_write = soekris_gpio_write; 1561.1Skardel sc->sc_gpio_gc.gp_pin_ctl = soekris_gpio_ctl; 1571.1Skardel 1581.1Skardel gba1.gba_gc = &sc->sc_gpio_gc; 1591.1Skardel gba1.gba_pins = sc->sc_gpio_pins; 1601.1Skardel gba1.gba_npins = SOEKRIS_NPINS; 1611.1Skardel 1621.1Skardel for (i = 0; i < SOEKRIS_NLEDS; i++) { 1631.1Skardel sc->sc_led_pins[i].pin_num = i; 1641.1Skardel sc->sc_led_pins[i].pin_caps = GPIO_PIN_OUTPUT; 1651.1Skardel sc->sc_led_pins[i].pin_flags = GPIO_PIN_OUTPUT; 1661.1Skardel sc->sc_led_pins[i].pin_state = soekris_led_read(sc, i); 1671.1Skardel } 1681.1Skardel 1691.1Skardel sc->sc_led_gc.gp_cookie = sc; 1701.1Skardel sc->sc_led_gc.gp_pin_read = soekris_led_read; 1711.1Skardel sc->sc_led_gc.gp_pin_write = soekris_led_write; 1721.1Skardel sc->sc_led_gc.gp_pin_ctl = soekris_led_ctl; 1731.1Skardel 1741.1Skardel gba2.gba_gc = &sc->sc_led_gc; 1751.1Skardel gba2.gba_pins = sc->sc_led_pins; 1761.1Skardel gba2.gba_npins = SOEKRIS_NLEDS; 1771.1Skardel 1781.2Skardel#if NGPIO > 0 1791.5Sthorpej (void)config_found(sc->sc_dev, &gba1, gpiobus_print, CFARGS_NONE); 1801.5Sthorpej (void)config_found(sc->sc_dev, &gba2, gpiobus_print, CFARGS_NONE); 1811.2Skardel#endif 1821.2Skardel} 1831.2Skardel 1841.2Skardelstatic int 1851.2Skardelsoekris_detach(device_t self, int flags) 1861.2Skardel{ 1871.2Skardel struct soekris_softc *sc = device_private(self); 1881.2Skardel 1891.2Skardel bus_space_unmap(sc->sc_iot, sc->sc_ioh, SOEKRIS_IOSIZE); 1901.2Skardel return 0; 1911.1Skardel} 1921.1Skardel 1931.2Skardelstatic int 1941.1Skardelsoekris_gpio_read(void *arg, int pin) 1951.1Skardel{ 1961.1Skardel struct soekris_softc *sc = arg; 1971.1Skardel u_int16_t data; 1981.1Skardel 1991.1Skardel data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT); 2001.1Skardel 2011.1Skardel return (data & (1 << pin)) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 2021.1Skardel} 2031.1Skardel 2041.2Skardelstatic void 2051.1Skardelsoekris_gpio_write(void *arg, int pin, int value) 2061.1Skardel{ 2071.1Skardel struct soekris_softc *sc = arg; 2081.1Skardel u_int16_t data; 2091.1Skardel 2101.1Skardel data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_INPUT); 2111.1Skardel 2121.1Skardel if (value == GPIO_PIN_LOW) 2131.1Skardel data &= ~(1 << pin); 2141.1Skardel else if (value == GPIO_PIN_HIGH) 2151.1Skardel data |= (1 << pin); 2161.1Skardel 2171.1Skardel bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_OUTPUT, data); 2181.1Skardel} 2191.1Skardel 2201.2Skardelstatic void 2211.1Skardelsoekris_gpio_ctl(void *arg, int pin, int flags) 2221.1Skardel{ 2231.1Skardel struct soekris_softc *sc = arg; 2241.1Skardel u_int16_t data; 2251.1Skardel 2261.1Skardel data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR); 2271.1Skardel 2281.1Skardel if (flags & GPIO_PIN_INPUT) 2291.1Skardel data &= ~(1 << pin); 2301.1Skardel if (flags & GPIO_PIN_OUTPUT) 2311.1Skardel data |= (1 << pin); 2321.1Skardel 2331.1Skardel bus_space_write_2(sc->sc_iot, sc->sc_ioh, SOEKRIS_GPIO_DIR, data); 2341.1Skardel} 2351.1Skardel 2361.2Skardelstatic int 2371.1Skardelsoekris_led_read(void *arg, int pin) 2381.1Skardel{ 2391.1Skardel struct soekris_softc *sc = arg; 2401.1Skardel u_int8_t value; 2411.1Skardel 2421.1Skardel value = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 2431.1Skardel soekris_led_offset[pin]); 2441.1Skardel 2451.1Skardel return (value & 0x1) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 2461.1Skardel} 2471.1Skardel 2481.2Skardelstatic void 2491.1Skardelsoekris_led_write(void *arg, int pin, int value) 2501.1Skardel{ 2511.1Skardel struct soekris_softc *sc = arg; 2521.1Skardel 2531.1Skardel bus_space_write_1(sc->sc_iot, sc->sc_ioh, soekris_led_offset[pin], 2541.1Skardel value); 2551.1Skardel} 2561.1Skardel 2571.2Skardelstatic void 2581.1Skardelsoekris_led_ctl(void *arg, int pin, int flags) 2591.1Skardel{ 2601.1Skardel} 261