2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright 2008 by Nathan Whitehorn. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Driver for MacIO GPIO controller
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
43 #include <machine/bus.h>
44 #include <machine/intr_machdep.h>
45 #include <machine/resource.h>
46 #include <machine/vmparam.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50 #include <dev/ofw/openfirm.h>
52 #include <powerpc/powermac/macgpiovar.h>
57 struct macgpio_softc
{
59 struct resource
*sc_gpios
;
61 uint32_t sc_saved_gpio_levels
[2];
62 uint32_t sc_saved_gpios
[GPIO_COUNT
];
63 uint32_t sc_saved_extint_gpios
[GPIO_EXTINT_COUNT
];
66 static MALLOC_DEFINE(M_MACGPIO
, "macgpio", "macgpio device information");
68 static int macgpio_probe(device_t
);
69 static int macgpio_attach(device_t
);
70 static int macgpio_print_child(device_t dev
, device_t child
);
71 static void macgpio_probe_nomatch(device_t
, device_t
);
72 static struct resource
*macgpio_alloc_resource(device_t
, device_t
, int, int *,
73 rman_res_t
, rman_res_t
, rman_res_t
, u_int
);
74 static int macgpio_activate_resource(device_t
, device_t
,
76 static int macgpio_deactivate_resource(device_t
, device_t
,
78 static ofw_bus_get_devinfo_t macgpio_get_devinfo
;
79 static int macgpio_suspend(device_t dev
);
80 static int macgpio_resume(device_t dev
);
83 * Bus interface definition
85 static device_method_t macgpio_methods
[] = {
86 /* Device interface */
87 DEVMETHOD(device_probe
, macgpio_probe
),
88 DEVMETHOD(device_attach
, macgpio_attach
),
89 DEVMETHOD(device_detach
, bus_generic_detach
),
90 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
91 DEVMETHOD(device_suspend
, macgpio_suspend
),
92 DEVMETHOD(device_resume
, macgpio_resume
),
95 DEVMETHOD(bus_print_child
, macgpio_print_child
),
96 DEVMETHOD(bus_probe_nomatch
, macgpio_probe_nomatch
),
97 DEVMETHOD(bus_setup_intr
, bus_generic_setup_intr
),
98 DEVMETHOD(bus_teardown_intr
, bus_generic_teardown_intr
),
100 DEVMETHOD(bus_alloc_resource
, macgpio_alloc_resource
),
101 DEVMETHOD(bus_activate_resource
, macgpio_activate_resource
),
102 DEVMETHOD(bus_deactivate_resource
, macgpio_deactivate_resource
),
103 DEVMETHOD(bus_release_resource
, bus_generic_release_resource
),
105 DEVMETHOD(bus_child_pnpinfo
, ofw_bus_gen_child_pnpinfo
),
107 /* ofw_bus interface */
108 DEVMETHOD(ofw_bus_get_devinfo
, macgpio_get_devinfo
),
109 DEVMETHOD(ofw_bus_get_compat
, ofw_bus_gen_get_compat
),
110 DEVMETHOD(ofw_bus_get_model
, ofw_bus_gen_get_model
),
111 DEVMETHOD(ofw_bus_get_name
, ofw_bus_gen_get_name
),
112 DEVMETHOD(ofw_bus_get_node
, ofw_bus_gen_get_node
),
113 DEVMETHOD(ofw_bus_get_type
, ofw_bus_gen_get_type
),
117 static driver_t macgpio_pci_driver
= {
120 sizeof(struct macgpio_softc
)
123 EARLY_DRIVER_MODULE(macgpio
, macio
, macgpio_pci_driver
, 0, 0, BUS_PASS_BUS
);
125 struct macgpio_devinfo
{
126 struct ofw_bus_devinfo mdi_obdinfo
;
127 struct resource_list mdi_resources
;
133 macgpio_probe(device_t dev
)
137 name
= ofw_bus_get_name(dev
);
138 if (name
&& strcmp(name
, "gpio") == 0) {
139 device_set_desc(dev
, "MacIO GPIO Controller");
147 * Scan Open Firmware child nodes, and attach these as children
151 macgpio_attach(device_t dev
)
153 struct macgpio_softc
*sc
;
154 struct macgpio_devinfo
*dinfo
;
155 phandle_t root
, child
, iparent
;
159 sc
= device_get_softc(dev
);
160 root
= sc
->sc_node
= ofw_bus_get_node(dev
);
162 sc
->sc_gpios
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
,
163 &sc
->sc_gpios_rid
, RF_ACTIVE
);
166 * Iterate through the sub-devices
168 for (child
= OF_child(root
); child
!= 0; child
= OF_peer(child
)) {
169 dinfo
= malloc(sizeof(*dinfo
), M_MACGPIO
, M_WAITOK
| M_ZERO
);
170 if (ofw_bus_gen_setup_devinfo(&dinfo
->mdi_obdinfo
, child
) !=
172 free(dinfo
, M_MACGPIO
);
176 if (OF_getencprop(child
, "reg", &dinfo
->gpio_num
,
177 sizeof(dinfo
->gpio_num
)) != sizeof(dinfo
->gpio_num
)) {
179 * Some early GPIO controllers don't provide GPIO
180 * numbers for GPIOs designed only to provide
181 * interrupt resources. We should still allow these
182 * to attach, but with caution.
185 dinfo
->gpio_num
= -1;
188 resource_list_init(&dinfo
->mdi_resources
);
190 if (OF_getencprop(child
, "interrupts", irq
, sizeof(irq
)) ==
192 OF_searchencprop(child
, "interrupt-parent", &iparent
,
194 resource_list_add(&dinfo
->mdi_resources
, SYS_RES_IRQ
,
195 0, MAP_IRQ(iparent
, irq
[0]),
196 MAP_IRQ(iparent
, irq
[0]), 1);
199 /* Fix messed-up offsets */
200 if (dinfo
->gpio_num
> 0x50)
201 dinfo
->gpio_num
-= 0x50;
203 cdev
= device_add_child(dev
, NULL
, DEVICE_UNIT_ANY
);
205 device_printf(dev
, "<%s>: device_add_child failed\n",
206 dinfo
->mdi_obdinfo
.obd_name
);
207 ofw_bus_gen_destroy_devinfo(&dinfo
->mdi_obdinfo
);
208 free(dinfo
, M_MACGPIO
);
211 device_set_ivars(cdev
, dinfo
);
214 bus_attach_children(dev
);
219 macgpio_print_child(device_t dev
, device_t child
)
221 struct macgpio_devinfo
*dinfo
;
224 dinfo
= device_get_ivars(child
);
226 retval
+= bus_print_child_header(dev
, child
);
228 if (dinfo
->gpio_num
>= GPIO_BASE
)
229 printf(" gpio %d", dinfo
->gpio_num
- GPIO_BASE
);
230 else if (dinfo
->gpio_num
>= GPIO_EXTINT_BASE
)
231 printf(" extint-gpio %d", dinfo
->gpio_num
- GPIO_EXTINT_BASE
);
232 else if (dinfo
->gpio_num
>= 0)
233 printf(" addr 0x%02x", dinfo
->gpio_num
); /* should not happen */
235 resource_list_print_type(&dinfo
->mdi_resources
, "irq", SYS_RES_IRQ
,
237 retval
+= bus_print_child_footer(dev
, child
);
243 macgpio_probe_nomatch(device_t dev
, device_t child
)
245 struct macgpio_devinfo
*dinfo
;
249 dinfo
= device_get_ivars(child
);
251 if ((type
= ofw_bus_get_type(child
)) == NULL
)
253 device_printf(dev
, "<%s, %s>", type
, ofw_bus_get_name(child
));
254 if (dinfo
->gpio_num
>= 0)
255 printf(" gpio %d",dinfo
->gpio_num
);
256 resource_list_print_type(&dinfo
->mdi_resources
, "irq",
258 printf(" (no driver attached)\n");
262 static struct resource
*
263 macgpio_alloc_resource(device_t bus
, device_t child
, int type
, int *rid
,
264 rman_res_t start
, rman_res_t end
, rman_res_t count
,
267 struct macgpio_devinfo
*dinfo
;
269 dinfo
= device_get_ivars(child
);
271 if (type
!= SYS_RES_IRQ
)
274 return (resource_list_alloc(&dinfo
->mdi_resources
, bus
, child
, type
,
275 rid
, start
, end
, count
, flags
));
279 macgpio_activate_resource(device_t bus
, device_t child
, struct resource
*res
)
281 struct macgpio_softc
*sc
;
282 struct macgpio_devinfo
*dinfo
;
285 sc
= device_get_softc(bus
);
286 dinfo
= device_get_ivars(child
);
288 if (rman_get_type(res
) != SYS_RES_IRQ
)
291 if (dinfo
->gpio_num
>= 0) {
292 val
= bus_read_1(sc
->sc_gpios
,dinfo
->gpio_num
);
294 bus_write_1(sc
->sc_gpios
,dinfo
->gpio_num
,val
);
297 return (bus_generic_activate_resource(bus
, child
, res
));
301 macgpio_deactivate_resource(device_t bus
, device_t child
, struct resource
*res
)
303 struct macgpio_softc
*sc
;
304 struct macgpio_devinfo
*dinfo
;
307 sc
= device_get_softc(bus
);
308 dinfo
= device_get_ivars(child
);
310 if (rman_get_type(res
) != SYS_RES_IRQ
)
313 if (dinfo
->gpio_num
>= 0) {
314 val
= bus_read_1(sc
->sc_gpios
,dinfo
->gpio_num
);
316 bus_write_1(sc
->sc_gpios
,dinfo
->gpio_num
,val
);
319 return (bus_generic_deactivate_resource(bus
, child
, res
));
323 macgpio_read(device_t dev
)
325 struct macgpio_softc
*sc
;
326 struct macgpio_devinfo
*dinfo
;
328 sc
= device_get_softc(device_get_parent(dev
));
329 dinfo
= device_get_ivars(dev
);
331 if (dinfo
->gpio_num
< 0)
334 return (bus_read_1(sc
->sc_gpios
,dinfo
->gpio_num
));
338 macgpio_write(device_t dev
, uint8_t val
)
340 struct macgpio_softc
*sc
;
341 struct macgpio_devinfo
*dinfo
;
343 sc
= device_get_softc(device_get_parent(dev
));
344 dinfo
= device_get_ivars(dev
);
346 if (dinfo
->gpio_num
< 0)
349 bus_write_1(sc
->sc_gpios
,dinfo
->gpio_num
,val
);
352 static const struct ofw_bus_devinfo
*
353 macgpio_get_devinfo(device_t dev
, device_t child
)
355 struct macgpio_devinfo
*dinfo
;
357 dinfo
= device_get_ivars(child
);
358 return (&dinfo
->mdi_obdinfo
);
362 macgpio_suspend(device_t dev
)
364 struct macgpio_softc
*sc
;
367 sc
= device_get_softc(dev
);
368 sc
->sc_saved_gpio_levels
[0] = bus_read_4(sc
->sc_gpios
, GPIO_LEVELS_0
);
369 sc
->sc_saved_gpio_levels
[1] = bus_read_4(sc
->sc_gpios
, GPIO_LEVELS_1
);
371 for (i
= 0; i
< GPIO_COUNT
; i
++)
372 sc
->sc_saved_gpios
[i
] = bus_read_1(sc
->sc_gpios
, GPIO_BASE
+ i
);
373 for (i
= 0; i
< GPIO_EXTINT_COUNT
; i
++)
374 sc
->sc_saved_extint_gpios
[i
] = bus_read_1(sc
->sc_gpios
, GPIO_EXTINT_BASE
+ i
);
380 macgpio_resume(device_t dev
)
382 struct macgpio_softc
*sc
;
385 sc
= device_get_softc(dev
);
386 bus_write_4(sc
->sc_gpios
, GPIO_LEVELS_0
, sc
->sc_saved_gpio_levels
[0]);
387 bus_write_4(sc
->sc_gpios
, GPIO_LEVELS_1
, sc
->sc_saved_gpio_levels
[1]);
389 for (i
= 0; i
< GPIO_COUNT
; i
++)
390 bus_write_1(sc
->sc_gpios
, GPIO_BASE
+ i
, sc
->sc_saved_gpios
[i
]);
391 for (i
= 0; i
< GPIO_EXTINT_COUNT
; i
++)
392 bus_write_1(sc
->sc_gpios
, GPIO_EXTINT_BASE
+ i
, sc
->sc_saved_extint_gpios
[i
]);