118334Speter/* $OpenBSD: plgpio.c,v 1.3 2021/10/24 17:52:26 mpi Exp $ */ 290075Sobrien/* 3132718Skan * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 418334Speter * 590075Sobrien * Permission to use, copy, modify, and distribute this software for any 618334Speter * purpose with or without fee is hereby granted, provided that the above 790075Sobrien * copyright notice and this permission notice appear in all copies. 890075Sobrien * 990075Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1090075Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1118334Speter * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1290075Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1390075Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1490075Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1590075Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1618334Speter */ 1718334Speter 1890075Sobrien#include <sys/param.h> 1990075Sobrien#include <sys/systm.h> 2090075Sobrien#include <sys/device.h> 2118334Speter 2218334Speter#include <machine/intr.h> 2318334Speter#include <machine/bus.h> 2450397Sobrien#include <machine/fdt.h> 25132718Skan 26132718Skan#include <dev/ofw/openfirm.h> 2790075Sobrien#include <dev/ofw/ofw_gpio.h> 2818334Speter#include <dev/ofw/fdt.h> 2990075Sobrien 30117395Skan/* Registers. */ 31117395Skan#define GPIODATA(pin) ((1 << pin) << 2) 3290075Sobrien#define GPIODIR 0x400 33117395Skan 34117395Skan#define HREAD1(sc, reg) \ 35117395Skan (bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg))) 3618334Speter#define HWRITE1(sc, reg, val) \ 3750397Sobrien bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 38132718Skan#define HSET1(sc, reg, bits) \ 39132718Skan HWRITE1((sc), (reg), HREAD1((sc), (reg)) | (bits)) 40132718Skan#define HCLR1(sc, reg, bits) \ 41132718Skan HWRITE1((sc), (reg), HREAD1((sc), (reg)) & ~(bits)) 42132718Skan 43132718Skanstruct plgpio_softc { 44132718Skan struct device sc_dev; 45132718Skan bus_space_tag_t sc_iot; 4650397Sobrien bus_space_handle_t sc_ioh; 4718334Speter 4818334Speter struct gpio_controller sc_gc; 4918334Speter}; 5018334Speter 5118334Speterint plgpio_match(struct device *, void *, void *); 5218334Spetervoid plgpio_attach(struct device *, struct device *, void *); 5318334Speter 5418334Speterconst struct cfattach plgpio_ca = { 5518334Speter sizeof (struct plgpio_softc), plgpio_match, plgpio_attach 5618334Speter}; 5718334Speter 5818334Speterstruct cfdriver plgpio_cd = { 59132718Skan NULL, "plgpio", DV_DULL 6018334Speter}; 6190075Sobrien 6290075Sobrienvoid plgpio_config_pin(void *, uint32_t *, int); 6390075Sobrienint plgpio_get_pin(void *, uint32_t *); 6418334Spetervoid plgpio_set_pin(void *, uint32_t *, int); 6590075Sobrien 6690075Sobrienint 6790075Sobrienplgpio_match(struct device *parent, void *match, void *aux) 6890075Sobrien{ 6918334Speter struct fdt_attach_args *faa = aux; 7090075Sobrien 7190075Sobrien return OF_is_compatible(faa->fa_node, "arm,pl061"); 7218334Speter} 7390075Sobrien 7490075Sobrienvoid 7590075Sobrienplgpio_attach(struct device *parent, struct device *self, void *aux) 7690075Sobrien{ 7796263Sobrien struct plgpio_softc *sc = (struct plgpio_softc *)self; 7890075Sobrien struct fdt_attach_args *faa = aux; 7990075Sobrien 8090075Sobrien if (faa->fa_nreg < 1) { 8118334Speter printf(": no registers\n"); 8290075Sobrien return; 8390075Sobrien } 8490075Sobrien 8590075Sobrien sc->sc_iot = faa->fa_iot; 8690075Sobrien 8790075Sobrien if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 8890075Sobrien faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 8990075Sobrien printf(": can't map registers\n"); 9090075Sobrien return; 9190075Sobrien } 9290075Sobrien 9390075Sobrien sc->sc_gc.gc_node = faa->fa_node; 9490075Sobrien sc->sc_gc.gc_cookie = sc; 9590075Sobrien sc->sc_gc.gc_config_pin = plgpio_config_pin; 9690075Sobrien sc->sc_gc.gc_get_pin = plgpio_get_pin; 9718334Speter sc->sc_gc.gc_set_pin = plgpio_set_pin; 9890075Sobrien gpio_controller_register(&sc->sc_gc); 9990075Sobrien 10090075Sobrien printf("\n"); 10190075Sobrien} 102132718Skan 10390075Sobrienvoid 10490075Sobrienplgpio_config_pin(void *cookie, uint32_t *cells, int config) 10590075Sobrien{ 10690075Sobrien struct plgpio_softc *sc = cookie; 10790075Sobrien uint32_t pin = cells[0]; 10818334Speter 10918334Speter if (pin >= 8) 11018334Speter return; 11190075Sobrien 11290075Sobrien if (config & GPIO_CONFIG_OUTPUT) 11390075Sobrien HSET1(sc, GPIODIR, (1 << pin)); 11490075Sobrien else 11590075Sobrien HCLR1(sc, GPIODIR, (1 << pin)); 11690075Sobrien} 11790075Sobrien 11890075Sobrienint 11990075Sobrienplgpio_get_pin(void *cookie, uint32_t *cells) 12090075Sobrien{ 12190075Sobrien struct plgpio_softc *sc = cookie; 12290075Sobrien uint32_t pin = cells[0]; 12318334Speter uint32_t flags = cells[1]; 12418334Speter uint32_t reg; 12518334Speter int val; 12618334Speter 12718334Speter if (pin >= 8) 12818334Speter return 0; 12990075Sobrien 13090075Sobrien reg = HREAD1(sc, GPIODATA(pin)); 13118334Speter val = !!reg; 13218334Speter if (flags & GPIO_ACTIVE_LOW) 13318334Speter val = !val; 134132718Skan return val; 13518334Speter} 136132718Skan 13790075Sobrienvoid 13890075Sobrienplgpio_set_pin(void *cookie, uint32_t *cells, int val) 13918334Speter{ 140132718Skan struct plgpio_softc *sc = cookie; 141132718Skan uint32_t pin = cells[0]; 142132718Skan uint32_t flags = cells[1]; 143132718Skan 14418334Speter if (pin >= 8) 14518334Speter return; 14618334Speter 14790075Sobrien if (flags & GPIO_ACTIVE_LOW) 14890075Sobrien val = !val; 14918334Speter if (val) 15018334Speter HWRITE1(sc, GPIODATA(pin), (1 << pin)); 15118334Speter else 15218334Speter HWRITE1(sc, GPIODATA(pin), 0); 15318334Speter} 15418334Speter