1564e8256SRuslan Bukin /*-
2564e8256SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause
3564e8256SRuslan Bukin *
4564e8256SRuslan Bukin * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
5564e8256SRuslan Bukin *
6564e8256SRuslan Bukin * This software was developed by SRI International and the University of
7564e8256SRuslan Bukin * Cambridge Computer Laboratory (Department of Computer Science and
8564e8256SRuslan Bukin * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9564e8256SRuslan Bukin * DARPA SSITH research programme.
10564e8256SRuslan Bukin *
11564e8256SRuslan Bukin * Redistribution and use in source and binary forms, with or without
12564e8256SRuslan Bukin * modification, are permitted provided that the following conditions
13564e8256SRuslan Bukin * are met:
14564e8256SRuslan Bukin * 1. Redistributions of source code must retain the above copyright
15564e8256SRuslan Bukin * notice, this list of conditions and the following disclaimer.
16564e8256SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright
17564e8256SRuslan Bukin * notice, this list of conditions and the following disclaimer in the
18564e8256SRuslan Bukin * documentation and/or other materials provided with the distribution.
19564e8256SRuslan Bukin *
20564e8256SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21564e8256SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22564e8256SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23564e8256SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24564e8256SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25564e8256SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26564e8256SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27564e8256SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28564e8256SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29564e8256SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30564e8256SRuslan Bukin * SUCH DAMAGE.
31564e8256SRuslan Bukin */
32564e8256SRuslan Bukin
33564e8256SRuslan Bukin #include <sys/param.h>
34564e8256SRuslan Bukin #include <sys/systm.h>
35564e8256SRuslan Bukin #include <sys/bus.h>
36564e8256SRuslan Bukin #include <sys/kernel.h>
37564e8256SRuslan Bukin #include <sys/module.h>
38564e8256SRuslan Bukin #include <sys/rman.h>
39564e8256SRuslan Bukin
40564e8256SRuslan Bukin #include <machine/bus.h>
41564e8256SRuslan Bukin
42564e8256SRuslan Bukin #include <dev/fdt/simplebus.h>
43564e8256SRuslan Bukin #include <dev/fdt/fdt_common.h>
44564e8256SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
45564e8256SRuslan Bukin
46564e8256SRuslan Bukin #include "dwgpio_if.h"
47564e8256SRuslan Bukin
48564e8256SRuslan Bukin struct dwgpiobus_softc {
49564e8256SRuslan Bukin struct simplebus_softc simplebus_sc;
50564e8256SRuslan Bukin device_t dev;
51564e8256SRuslan Bukin struct resource *res[1];
52564e8256SRuslan Bukin };
53564e8256SRuslan Bukin
54564e8256SRuslan Bukin static struct resource_spec dwgpio_spec[] = {
55564e8256SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE },
56564e8256SRuslan Bukin { -1, 0 }
57564e8256SRuslan Bukin };
58564e8256SRuslan Bukin
59564e8256SRuslan Bukin static int
dwgpiobus_probe(device_t dev)60564e8256SRuslan Bukin dwgpiobus_probe(device_t dev)
61564e8256SRuslan Bukin {
62564e8256SRuslan Bukin
63564e8256SRuslan Bukin if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio"))
64564e8256SRuslan Bukin return (ENXIO);
65564e8256SRuslan Bukin
66564e8256SRuslan Bukin if (!ofw_bus_status_okay(dev))
67564e8256SRuslan Bukin return (ENXIO);
68564e8256SRuslan Bukin
69564e8256SRuslan Bukin device_set_desc(dev, "Synopsys® DesignWare® APB GPIO BUS");
70564e8256SRuslan Bukin
71564e8256SRuslan Bukin return (BUS_PROBE_DEFAULT);
72564e8256SRuslan Bukin }
73564e8256SRuslan Bukin
74564e8256SRuslan Bukin static int
dwgpiobus_attach(device_t dev)75564e8256SRuslan Bukin dwgpiobus_attach(device_t dev)
76564e8256SRuslan Bukin {
77564e8256SRuslan Bukin struct dwgpiobus_softc *sc;
78564e8256SRuslan Bukin phandle_t node;
79564e8256SRuslan Bukin
80564e8256SRuslan Bukin sc = device_get_softc(dev);
81564e8256SRuslan Bukin sc->dev = dev;
82564e8256SRuslan Bukin
83564e8256SRuslan Bukin node = ofw_bus_get_node(dev);
84564e8256SRuslan Bukin if (node == -1)
85564e8256SRuslan Bukin return (ENXIO);
86564e8256SRuslan Bukin
87564e8256SRuslan Bukin if (bus_alloc_resources(dev, dwgpio_spec, sc->res)) {
88564e8256SRuslan Bukin device_printf(dev, "Could not allocate resources.\n");
89564e8256SRuslan Bukin return (ENXIO);
90564e8256SRuslan Bukin }
91564e8256SRuslan Bukin
92564e8256SRuslan Bukin simplebus_init(dev, node);
93564e8256SRuslan Bukin
94564e8256SRuslan Bukin /*
95564e8256SRuslan Bukin * Allow devices to identify.
96564e8256SRuslan Bukin */
97723da5d9SJohn Baldwin bus_identify_children(dev);
98564e8256SRuslan Bukin
99564e8256SRuslan Bukin /*
100564e8256SRuslan Bukin * Now walk the OFW tree and attach top-level devices.
101564e8256SRuslan Bukin */
102564e8256SRuslan Bukin for (node = OF_child(node); node > 0; node = OF_peer(node))
103564e8256SRuslan Bukin simplebus_add_device(dev, node, 0, NULL, -1, NULL);
104564e8256SRuslan Bukin
105*18250ec6SJohn Baldwin bus_attach_children(dev);
106*18250ec6SJohn Baldwin return (0);
107564e8256SRuslan Bukin }
108564e8256SRuslan Bukin
109564e8256SRuslan Bukin static int
dwgpiobus_detach(device_t dev)110564e8256SRuslan Bukin dwgpiobus_detach(device_t dev)
111564e8256SRuslan Bukin {
112564e8256SRuslan Bukin struct dwgpiobus_softc *sc;
113564e8256SRuslan Bukin
114564e8256SRuslan Bukin sc = device_get_softc(dev);
115564e8256SRuslan Bukin
116564e8256SRuslan Bukin bus_release_resources(dev, dwgpio_spec, sc->res);
117564e8256SRuslan Bukin
118564e8256SRuslan Bukin return (0);
119564e8256SRuslan Bukin }
120564e8256SRuslan Bukin
121564e8256SRuslan Bukin static int
dwgpiobus_write(device_t dev,bus_size_t offset,int val)122564e8256SRuslan Bukin dwgpiobus_write(device_t dev, bus_size_t offset, int val)
123564e8256SRuslan Bukin {
124564e8256SRuslan Bukin struct dwgpiobus_softc *sc;
125564e8256SRuslan Bukin
126564e8256SRuslan Bukin sc = device_get_softc(dev);
127564e8256SRuslan Bukin
128564e8256SRuslan Bukin bus_write_4(sc->res[0], offset, val);
129564e8256SRuslan Bukin
130564e8256SRuslan Bukin return (0);
131564e8256SRuslan Bukin };
132564e8256SRuslan Bukin
133564e8256SRuslan Bukin static int
dwgpiobus_read(device_t dev,bus_size_t offset)134564e8256SRuslan Bukin dwgpiobus_read(device_t dev, bus_size_t offset)
135564e8256SRuslan Bukin {
136564e8256SRuslan Bukin struct dwgpiobus_softc *sc;
137564e8256SRuslan Bukin int val;
138564e8256SRuslan Bukin
139564e8256SRuslan Bukin sc = device_get_softc(dev);
140564e8256SRuslan Bukin
141564e8256SRuslan Bukin val = bus_read_4(sc->res[0], offset);
142564e8256SRuslan Bukin
143564e8256SRuslan Bukin return (val);
144564e8256SRuslan Bukin };
145564e8256SRuslan Bukin
146564e8256SRuslan Bukin static device_method_t dwgpiobus_methods[] = {
147564e8256SRuslan Bukin DEVMETHOD(device_probe, dwgpiobus_probe),
148564e8256SRuslan Bukin DEVMETHOD(device_attach, dwgpiobus_attach),
149564e8256SRuslan Bukin DEVMETHOD(device_detach, dwgpiobus_detach),
150564e8256SRuslan Bukin
151564e8256SRuslan Bukin DEVMETHOD(dwgpio_write, dwgpiobus_write),
152564e8256SRuslan Bukin DEVMETHOD(dwgpio_read, dwgpiobus_read),
153564e8256SRuslan Bukin
154564e8256SRuslan Bukin DEVMETHOD_END
155564e8256SRuslan Bukin };
156564e8256SRuslan Bukin
157564e8256SRuslan Bukin DEFINE_CLASS_1(dwgpiobus, dwgpiobus_driver, dwgpiobus_methods,
158564e8256SRuslan Bukin sizeof(struct dwgpiobus_softc), simplebus_driver);
159564e8256SRuslan Bukin
16084c5f982SJohn Baldwin EARLY_DRIVER_MODULE(dwgpiobus, simplebus, dwgpiobus_driver, 0, 0,
16184c5f982SJohn Baldwin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
162564e8256SRuslan Bukin MODULE_VERSION(dwgpiobus, 1);
163