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