1239278Sgonzo/*-
2239278Sgonzo * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org>
3239278Sgonzo * All rights reserved.
4239278Sgonzo *
5239278Sgonzo * Redistribution and use in source and binary forms, with or without
6239278Sgonzo * modification, are permitted provided that the following conditions
7239278Sgonzo * are met:
8239278Sgonzo * 1. Redistributions of source code must retain the above copyright
9239278Sgonzo *    notice, this list of conditions and the following disclaimer.
10239278Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11239278Sgonzo *    notice, this list of conditions and the following disclaimer in the
12239278Sgonzo *    documentation and/or other materials provided with the distribution.
13239278Sgonzo *
14239278Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239278Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239278Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239278Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239278Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239278Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239278Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239278Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239278Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239278Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239278Sgonzo * SUCH DAMAGE.
25239278Sgonzo *
26239278Sgonzo */
27239278Sgonzo
28239278Sgonzo/*
29239278Sgonzo * GPIO on LPC32x0 consist of 4 ports:
30239278Sgonzo * - Port0 with 8 input/output pins
31239278Sgonzo * - Port1 with 24 input/output pins
32239278Sgonzo * - Port2 with 13 input/output pins
33239278Sgonzo * - Port3 with:
34239278Sgonzo *   - 26 input pins (GPI_00..GPI_09 + GPI_15..GPI_23 + GPI_25 + GPI_27..GPI_28)
35239278Sgonzo *   - 24 output pins (GPO_00..GPO_23)
36242692Skevlo *   - 6 input/output pins (GPIO_00..GPIO_05)
37239278Sgonzo *
38239278Sgonzo * Pins are mapped to logical pin number as follows:
39239278Sgonzo * [0..9] -> GPI_00..GPI_09 		(port 3)
40239278Sgonzo * [10..18] -> GPI_15..GPI_23 		(port 3)
41239278Sgonzo * [19] -> GPI_25			(port 3)
42239278Sgonzo * [20..21] -> GPI_27..GPI_28		(port 3)
43239278Sgonzo * [22..45] -> GPO_00..GPO_23		(port 3)
44239278Sgonzo * [46..51] -> GPIO_00..GPIO_05		(port 3)
45239278Sgonzo * [52..64] -> P2.0..P2.12		(port 2)
46239278Sgonzo * [65..88] -> P1.0..P1.23		(port 1)
47239278Sgonzo * [89..96] -> P0.0..P0.7		(port 0)
48239278Sgonzo *
49239278Sgonzo */
50239278Sgonzo
51239278Sgonzo
52239278Sgonzo#include <sys/cdefs.h>
53239278Sgonzo__FBSDID("$FreeBSD: releng/11.0/sys/arm/lpc/lpc_gpio.c 277996 2015-01-31 19:32:14Z loos $");
54239278Sgonzo
55239278Sgonzo#include <sys/param.h>
56239278Sgonzo#include <sys/systm.h>
57239278Sgonzo#include <sys/bio.h>
58239278Sgonzo#include <sys/bus.h>
59239278Sgonzo#include <sys/conf.h>
60239278Sgonzo#include <sys/endian.h>
61239278Sgonzo#include <sys/kernel.h>
62239278Sgonzo#include <sys/kthread.h>
63239278Sgonzo#include <sys/lock.h>
64239278Sgonzo#include <sys/malloc.h>
65239278Sgonzo#include <sys/module.h>
66239278Sgonzo#include <sys/mutex.h>
67239278Sgonzo#include <sys/queue.h>
68239278Sgonzo#include <sys/resource.h>
69239278Sgonzo#include <sys/rman.h>
70239278Sgonzo#include <sys/time.h>
71239278Sgonzo#include <sys/timetc.h>
72239278Sgonzo#include <sys/watchdog.h>
73239278Sgonzo#include <sys/gpio.h>
74239278Sgonzo
75239278Sgonzo#include <machine/bus.h>
76239278Sgonzo#include <machine/cpu.h>
77239278Sgonzo#include <machine/cpufunc.h>
78239278Sgonzo#include <machine/resource.h>
79239278Sgonzo#include <machine/intr.h>
80239278Sgonzo#include <machine/fdt.h>
81239278Sgonzo
82277996Sloos#include <dev/gpio/gpiobusvar.h>
83239278Sgonzo#include <dev/ofw/ofw_bus.h>
84239278Sgonzo#include <dev/ofw/ofw_bus_subr.h>
85239278Sgonzo
86239278Sgonzo#include <arm/lpc/lpcreg.h>
87239278Sgonzo#include <arm/lpc/lpcvar.h>
88239278Sgonzo
89239278Sgonzo#include "gpio_if.h"
90239278Sgonzo
91239278Sgonzostruct lpc_gpio_softc
92239278Sgonzo{
93239278Sgonzo	device_t		lg_dev;
94277996Sloos	device_t		lg_busdev;
95239278Sgonzo	struct resource *	lg_res;
96239278Sgonzo	bus_space_tag_t		lg_bst;
97239278Sgonzo	bus_space_handle_t	lg_bsh;
98239278Sgonzo};
99239278Sgonzo
100239278Sgonzostruct lpc_gpio_pinmap
101239278Sgonzo{
102239278Sgonzo	int			lp_start_idx;
103239278Sgonzo	int			lp_pin_count;
104239278Sgonzo	int			lp_port;
105239278Sgonzo	int			lp_start_bit;
106239278Sgonzo	int			lp_flags;
107239278Sgonzo};
108239278Sgonzo
109239278Sgonzostatic const struct lpc_gpio_pinmap lpc_gpio_pins[] = {
110239278Sgonzo	{ 0,	10,	3,	0,	GPIO_PIN_INPUT },
111239278Sgonzo	{ 10,	9,	3,	15,	GPIO_PIN_INPUT },
112239278Sgonzo	{ 19,	1,	3,	25,	GPIO_PIN_INPUT },
113239278Sgonzo	{ 20,	2,	3,	27,	GPIO_PIN_INPUT },
114239278Sgonzo	{ 22,	24,	3,	0,	GPIO_PIN_OUTPUT },
115239278Sgonzo	/*
116239278Sgonzo	 * -1 below is to mark special case for Port3 GPIO pins, as they
117239278Sgonzo	 * have other bits in Port 3 registers as inputs and as outputs
118239278Sgonzo	 */
119239278Sgonzo	{ 46,	6,	3,	-1,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
120239278Sgonzo	{ 52,	13,	2,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
121239278Sgonzo	{ 65,	24,	1,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
122239278Sgonzo	{ 89,	8,	0,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
123239278Sgonzo	{ -1,	-1,	-1,	-1,	-1 },
124239278Sgonzo};
125239278Sgonzo
126239278Sgonzo#define	LPC_GPIO_NPINS				\
127239278Sgonzo    (LPC_GPIO_P0_COUNT + LPC_GPIO_P1_COUNT +	\
128239278Sgonzo    LPC_GPIO_P2_COUNT + LPC_GPIO_P3_COUNT)
129239278Sgonzo
130239278Sgonzo#define	LPC_GPIO_PIN_IDX(_map, _idx)	\
131239278Sgonzo    (_idx - _map->lp_start_idx)
132239278Sgonzo
133239278Sgonzo#define	LPC_GPIO_PIN_BIT(_map, _idx)	\
134239278Sgonzo    (_map->lp_start_bit + LPC_GPIO_PIN_IDX(_map, _idx))
135239278Sgonzo
136239278Sgonzostatic int lpc_gpio_probe(device_t);
137239278Sgonzostatic int lpc_gpio_attach(device_t);
138239278Sgonzostatic int lpc_gpio_detach(device_t);
139239278Sgonzo
140277996Sloosstatic device_t lpc_gpio_get_bus(device_t);
141239278Sgonzostatic int lpc_gpio_pin_max(device_t, int *);
142239278Sgonzostatic int lpc_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
143239278Sgonzostatic int lpc_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
144239278Sgonzostatic int lpc_gpio_pin_setflags(device_t, uint32_t, uint32_t);
145239278Sgonzostatic int lpc_gpio_pin_getname(device_t, uint32_t, char *);
146239278Sgonzostatic int lpc_gpio_pin_get(device_t, uint32_t, uint32_t *);
147239278Sgonzostatic int lpc_gpio_pin_set(device_t, uint32_t, uint32_t);
148239278Sgonzostatic int lpc_gpio_pin_toggle(device_t, uint32_t);
149239278Sgonzo
150239278Sgonzostatic const struct lpc_gpio_pinmap *lpc_gpio_get_pinmap(int);
151239278Sgonzo
152239278Sgonzostatic struct lpc_gpio_softc *lpc_gpio_sc = NULL;
153239278Sgonzo
154239278Sgonzo#define	lpc_gpio_read_4(_sc, _reg) \
155239278Sgonzo    bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg)
156239278Sgonzo#define	lpc_gpio_write_4(_sc, _reg, _val) \
157239278Sgonzo    bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val)
158239278Sgonzo#define	lpc_gpio_get_4(_sc, _test, _reg1, _reg2) \
159239278Sgonzo    lpc_gpio_read_4(_sc, ((_test) ? _reg1 : _reg2))
160239278Sgonzo#define	lpc_gpio_set_4(_sc, _test, _reg1, _reg2, _val) \
161239278Sgonzo    lpc_gpio_write_4(_sc, ((_test) ? _reg1 : _reg2), _val)
162239278Sgonzo
163239278Sgonzostatic int
164239278Sgonzolpc_gpio_probe(device_t dev)
165239278Sgonzo{
166261410Sian
167261410Sian	if (!ofw_bus_status_okay(dev))
168261410Sian		return (ENXIO);
169261410Sian
170239278Sgonzo	if (!ofw_bus_is_compatible(dev, "lpc,gpio"))
171239278Sgonzo		return (ENXIO);
172239278Sgonzo
173239278Sgonzo	device_set_desc(dev, "LPC32x0 GPIO");
174239278Sgonzo	return (BUS_PROBE_DEFAULT);
175239278Sgonzo}
176239278Sgonzo
177239278Sgonzostatic int
178239278Sgonzolpc_gpio_attach(device_t dev)
179239278Sgonzo{
180239278Sgonzo	struct lpc_gpio_softc *sc = device_get_softc(dev);
181239278Sgonzo	int rid;
182239278Sgonzo
183239278Sgonzo	sc->lg_dev = dev;
184239278Sgonzo
185239278Sgonzo	rid = 0;
186239278Sgonzo	sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
187239278Sgonzo	    RF_ACTIVE);
188239278Sgonzo	if (!sc->lg_res) {
189239278Sgonzo		device_printf(dev, "cannot allocate memory window\n");
190239278Sgonzo		return (ENXIO);
191239278Sgonzo	}
192239278Sgonzo
193239278Sgonzo	sc->lg_bst = rman_get_bustag(sc->lg_res);
194239278Sgonzo	sc->lg_bsh = rman_get_bushandle(sc->lg_res);
195239278Sgonzo
196239278Sgonzo	lpc_gpio_sc = sc;
197239278Sgonzo
198277996Sloos	sc->lg_busdev = gpiobus_attach_bus(dev);
199277996Sloos	if (sc->lg_busdev == NULL) {
200277996Sloos		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lg_res);
201277996Sloos		return (ENXIO);
202277996Sloos	}
203239278Sgonzo
204277996Sloos	return (0);
205239278Sgonzo}
206239278Sgonzo
207239278Sgonzostatic int
208239278Sgonzolpc_gpio_detach(device_t dev)
209239278Sgonzo{
210239278Sgonzo	return (EBUSY);
211239278Sgonzo}
212239278Sgonzo
213277996Sloosstatic device_t
214277996Slooslpc_gpio_get_bus(device_t dev)
215277996Sloos{
216277996Sloos	struct lpc_gpio_softc *sc;
217277996Sloos
218277996Sloos	sc = device_get_softc(dev);
219277996Sloos
220277996Sloos	return (sc->lg_busdev);
221277996Sloos}
222277996Sloos
223239278Sgonzostatic int
224239278Sgonzolpc_gpio_pin_max(device_t dev, int *npins)
225239278Sgonzo{
226239278Sgonzo	*npins = LPC_GPIO_NPINS - 1;
227239278Sgonzo	return (0);
228239278Sgonzo}
229239278Sgonzo
230239278Sgonzostatic int
231239278Sgonzolpc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
232239278Sgonzo{
233239278Sgonzo	const struct lpc_gpio_pinmap *map;
234239278Sgonzo
235239278Sgonzo	if (pin > LPC_GPIO_NPINS)
236239278Sgonzo		return (ENODEV);
237239278Sgonzo
238239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
239239278Sgonzo
240239278Sgonzo	*caps = map->lp_flags;
241239278Sgonzo	return (0);
242239278Sgonzo}
243239278Sgonzo
244239278Sgonzostatic int
245239278Sgonzolpc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
246239278Sgonzo{
247239278Sgonzo	struct lpc_gpio_softc *sc = device_get_softc(dev);
248239278Sgonzo	const struct lpc_gpio_pinmap *map;
249239278Sgonzo	uint32_t state;
250239278Sgonzo	int dir;
251239278Sgonzo
252239278Sgonzo	if (pin > LPC_GPIO_NPINS)
253239278Sgonzo		return (ENODEV);
254239278Sgonzo
255239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
256239278Sgonzo
257239278Sgonzo	/* Check whether it's bidirectional pin */
258239278Sgonzo	if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
259239278Sgonzo	    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
260239278Sgonzo		*flags = map->lp_flags;
261239278Sgonzo		return (0);
262239278Sgonzo	}
263239278Sgonzo
264239278Sgonzo	switch (map->lp_port) {
265239278Sgonzo	case 0:
266239278Sgonzo		state = lpc_gpio_read_4(sc, LPC_GPIO_P0_DIR_STATE);
267239278Sgonzo		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
268239278Sgonzo		break;
269239278Sgonzo	case 1:
270239278Sgonzo		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
271239278Sgonzo		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
272239278Sgonzo		break;
273239278Sgonzo	case 2:
274239278Sgonzo		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
275239278Sgonzo		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
276239278Sgonzo		break;
277239278Sgonzo	case 3:
278239278Sgonzo		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
279239278Sgonzo		dir = (state & (1 << (25 + LPC_GPIO_PIN_IDX(map, pin))));
280239278Sgonzo		break;
281239278Sgonzo	default:
282239278Sgonzo		panic("unknown GPIO port");
283239278Sgonzo	}
284239278Sgonzo
285239278Sgonzo	*flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
286239278Sgonzo
287239278Sgonzo	return (0);
288239278Sgonzo}
289239278Sgonzo
290239278Sgonzostatic int
291239278Sgonzolpc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
292239278Sgonzo{
293239278Sgonzo	struct lpc_gpio_softc *sc = device_get_softc(dev);
294239278Sgonzo	const struct lpc_gpio_pinmap *map;
295239278Sgonzo	uint32_t dir, state;
296239278Sgonzo
297239278Sgonzo	if (pin > LPC_GPIO_NPINS)
298239278Sgonzo		return (ENODEV);
299239278Sgonzo
300239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
301239278Sgonzo
302239278Sgonzo	/* Check whether it's bidirectional pin */
303239278Sgonzo	if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) !=
304239278Sgonzo	    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
305239278Sgonzo		return (ENOTSUP);
306239278Sgonzo
307239278Sgonzo	if (flags & GPIO_PIN_INPUT)
308239278Sgonzo		dir = 0;
309239278Sgonzo
310239278Sgonzo	if (flags & GPIO_PIN_OUTPUT)
311239278Sgonzo		dir = 1;
312239278Sgonzo
313239278Sgonzo	switch (map->lp_port) {
314239278Sgonzo	case 0:
315239278Sgonzo		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
316239278Sgonzo		lpc_gpio_set_4(sc, dir, LPC_GPIO_P0_DIR_SET,
317239278Sgonzo		    LPC_GPIO_P0_DIR_CLR, state);
318239278Sgonzo		break;
319239278Sgonzo	case 1:
320239278Sgonzo		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
321239278Sgonzo		lpc_gpio_set_4(sc, dir, LPC_GPIO_P1_DIR_SET,
322239278Sgonzo		    LPC_GPIO_P0_DIR_CLR, state);
323239278Sgonzo		break;
324239278Sgonzo	case 2:
325239278Sgonzo		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
326239278Sgonzo		lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET,
327239278Sgonzo		    LPC_GPIO_P0_DIR_CLR, state);
328239278Sgonzo		break;
329239278Sgonzo	case 3:
330239278Sgonzo		state = (1 << (25 + (pin - map->lp_start_idx)));
331239278Sgonzo		lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET,
332239278Sgonzo		    LPC_GPIO_P0_DIR_CLR, state);
333239278Sgonzo		break;
334239278Sgonzo	}
335239278Sgonzo
336239278Sgonzo	return (0);
337239278Sgonzo}
338239278Sgonzo
339239278Sgonzostatic int
340239278Sgonzolpc_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
341239278Sgonzo{
342239278Sgonzo	const struct lpc_gpio_pinmap *map;
343239278Sgonzo	int idx;
344239278Sgonzo
345239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
346239278Sgonzo	idx = LPC_GPIO_PIN_IDX(map, pin);
347239278Sgonzo
348239278Sgonzo	switch (map->lp_port) {
349239278Sgonzo	case 0:
350239278Sgonzo	case 1:
351239278Sgonzo	case 2:
352239278Sgonzo		snprintf(name, GPIOMAXNAME - 1, "P%d.%d", map->lp_port,
353239278Sgonzo		    map->lp_start_bit + LPC_GPIO_PIN_IDX(map, pin));
354239278Sgonzo		break;
355239278Sgonzo	case 3:
356239278Sgonzo		if (map->lp_start_bit == -1) {
357239278Sgonzo			snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", idx);
358239278Sgonzo			break;
359239278Sgonzo		}
360239278Sgonzo
361239278Sgonzo		snprintf(name, GPIOMAXNAME - 1, "GP%c_%02d",
362239278Sgonzo		    (map->lp_flags & GPIO_PIN_INPUT) ? 'I' : 'O',
363239278Sgonzo		    map->lp_start_bit + idx);
364239278Sgonzo		break;
365239278Sgonzo	}
366239278Sgonzo
367239278Sgonzo	return (0);
368239278Sgonzo}
369239278Sgonzo
370239278Sgonzostatic int
371239278Sgonzolpc_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
372239278Sgonzo{
373239278Sgonzo	struct lpc_gpio_softc *sc = device_get_softc(dev);
374239278Sgonzo	const struct lpc_gpio_pinmap *map;
375239278Sgonzo	uint32_t state, flags;
376239278Sgonzo	int dir;
377239278Sgonzo
378239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
379239278Sgonzo
380239278Sgonzo	if (lpc_gpio_pin_getflags(dev, pin, &flags))
381239278Sgonzo		return (ENXIO);
382239278Sgonzo
383239278Sgonzo	if (flags & GPIO_PIN_OUTPUT)
384239278Sgonzo		dir = 1;
385239278Sgonzo
386239278Sgonzo	if (flags & GPIO_PIN_INPUT)
387239278Sgonzo		dir = 0;
388239278Sgonzo
389239278Sgonzo	switch (map->lp_port) {
390239278Sgonzo	case 0:
391239278Sgonzo		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P0_OUTP_STATE,
392239278Sgonzo		    LPC_GPIO_P0_INP_STATE);
393239278Sgonzo		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
394239278Sgonzo	case 1:
395239278Sgonzo		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P1_OUTP_STATE,
396239278Sgonzo		    LPC_GPIO_P1_INP_STATE);
397239278Sgonzo		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
398239278Sgonzo	case 2:
399239278Sgonzo		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_INP_STATE);
400239278Sgonzo		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
401239278Sgonzo	case 3:
402239278Sgonzo		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P3_OUTP_STATE,
403239278Sgonzo		    LPC_GPIO_P3_INP_STATE);
404239278Sgonzo		if (map->lp_start_bit == -1) {
405239278Sgonzo			if (dir)
406239278Sgonzo				*value = !!(state & (1 << (25 +
407239278Sgonzo				    LPC_GPIO_PIN_IDX(map, pin))));
408239278Sgonzo			else
409239278Sgonzo				*value = !!(state & (1 << (10 +
410239278Sgonzo				    LPC_GPIO_PIN_IDX(map, pin))));
411239278Sgonzo		}
412239278Sgonzo
413239278Sgonzo		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
414239278Sgonzo	}
415239278Sgonzo
416239278Sgonzo	return (0);
417239278Sgonzo}
418239278Sgonzo
419239278Sgonzostatic int
420239278Sgonzolpc_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
421239278Sgonzo{
422239278Sgonzo	struct lpc_gpio_softc *sc = device_get_softc(dev);
423239278Sgonzo	const struct lpc_gpio_pinmap *map;
424239278Sgonzo	uint32_t state, flags;
425239278Sgonzo
426239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
427239278Sgonzo
428239278Sgonzo	if (lpc_gpio_pin_getflags(dev, pin, &flags))
429239278Sgonzo		return (ENXIO);
430239278Sgonzo
431239278Sgonzo	if ((flags & GPIO_PIN_OUTPUT) == 0)
432239278Sgonzo		return (EINVAL);
433239278Sgonzo
434239278Sgonzo	state = (1 << LPC_GPIO_PIN_BIT(map, pin));
435239278Sgonzo
436239278Sgonzo	switch (map->lp_port) {
437239278Sgonzo	case 0:
438239278Sgonzo		lpc_gpio_set_4(sc, value, LPC_GPIO_P0_OUTP_SET,
439239278Sgonzo		    LPC_GPIO_P0_OUTP_CLR, state);
440239278Sgonzo		break;
441239278Sgonzo	case 1:
442239278Sgonzo		lpc_gpio_set_4(sc, value, LPC_GPIO_P1_OUTP_SET,
443239278Sgonzo		    LPC_GPIO_P1_OUTP_CLR, state);
444239278Sgonzo		break;
445239278Sgonzo	case 2:
446239278Sgonzo		lpc_gpio_set_4(sc, value, LPC_GPIO_P2_OUTP_SET,
447239278Sgonzo		    LPC_GPIO_P2_OUTP_CLR, state);
448239278Sgonzo		break;
449239278Sgonzo	case 3:
450239278Sgonzo		if (map->lp_start_bit == -1)
451239278Sgonzo			state = (1 << (25 + LPC_GPIO_PIN_IDX(map, pin)));
452239278Sgonzo
453239278Sgonzo		lpc_gpio_set_4(sc, value, LPC_GPIO_P3_OUTP_SET,
454239278Sgonzo		    LPC_GPIO_P3_OUTP_CLR, state);
455239278Sgonzo		break;
456239278Sgonzo	}
457239278Sgonzo
458239278Sgonzo	return (0);
459239278Sgonzo}
460239278Sgonzo
461239278Sgonzostatic int
462239278Sgonzolpc_gpio_pin_toggle(device_t dev, uint32_t pin)
463239278Sgonzo{
464239278Sgonzo	const struct lpc_gpio_pinmap *map;
465239278Sgonzo	uint32_t flags;
466239278Sgonzo
467239278Sgonzo	map = lpc_gpio_get_pinmap(pin);
468239278Sgonzo
469239278Sgonzo	if (lpc_gpio_pin_getflags(dev, pin, &flags))
470239278Sgonzo		return (ENXIO);
471239278Sgonzo
472239278Sgonzo	if ((flags & GPIO_PIN_OUTPUT) == 0)
473239278Sgonzo		return (EINVAL);
474239278Sgonzo
475239278Sgonzo	panic("not implemented yet");
476239278Sgonzo
477239278Sgonzo	return (0);
478239278Sgonzo
479239278Sgonzo}
480239278Sgonzo
481239278Sgonzostatic const struct lpc_gpio_pinmap *
482239278Sgonzolpc_gpio_get_pinmap(int pin)
483239278Sgonzo{
484239278Sgonzo	const struct lpc_gpio_pinmap *map;
485239278Sgonzo
486239278Sgonzo	for (map = &lpc_gpio_pins[0]; map->lp_start_idx != -1; map++) {
487239278Sgonzo		if (pin >= map->lp_start_idx &&
488239278Sgonzo		    pin < map->lp_start_idx + map->lp_pin_count)
489239278Sgonzo			return map;
490239278Sgonzo	}
491239278Sgonzo
492239278Sgonzo	panic("pin number %d out of range", pin);
493239278Sgonzo}
494239278Sgonzo
495239278Sgonzoint
496239278Sgonzolpc_gpio_set_flags(device_t dev, int pin, int flags)
497239278Sgonzo{
498239278Sgonzo	if (lpc_gpio_sc == NULL)
499239278Sgonzo		return (ENXIO);
500239278Sgonzo
501239278Sgonzo	return lpc_gpio_pin_setflags(lpc_gpio_sc->lg_dev, pin, flags);
502239278Sgonzo}
503239278Sgonzo
504239278Sgonzoint
505239278Sgonzolpc_gpio_set_state(device_t dev, int pin, int state)
506239278Sgonzo{
507239278Sgonzo	if (lpc_gpio_sc == NULL)
508239278Sgonzo		return (ENXIO);
509239278Sgonzo
510239278Sgonzo	return lpc_gpio_pin_set(lpc_gpio_sc->lg_dev, pin, state);
511239278Sgonzo}
512239278Sgonzo
513239278Sgonzoint
514239278Sgonzolpc_gpio_get_state(device_t dev, int pin, int *state)
515239278Sgonzo{
516239278Sgonzo	if (lpc_gpio_sc == NULL)
517239278Sgonzo		return (ENXIO);
518239278Sgonzo
519239278Sgonzo	return lpc_gpio_pin_get(lpc_gpio_sc->lg_dev, pin, state);
520239278Sgonzo}
521239278Sgonzo
522239278Sgonzovoid
523265858Sandrewlpc_gpio_init()
524239278Sgonzo{
525260326Sian	bus_space_tag_t bst;
526260326Sian	bus_space_handle_t bsh;
527260326Sian
528260326Sian	bst = fdtbus_bs_tag;
529260326Sian
530239278Sgonzo	/* Preset SPI devices CS pins to one */
531260326Sian	bus_space_map(bst, LPC_GPIO_PHYS_BASE, LPC_GPIO_SIZE, 0, &bsh);
532260326Sian	bus_space_write_4(bst, bsh, LPC_GPIO_P3_OUTP_SET,
533239278Sgonzo	    1 << (SSD1289_CS_PIN - LPC_GPIO_GPO_00(0)) |
534239278Sgonzo	    1 << (SSD1289_DC_PIN - LPC_GPIO_GPO_00(0)) |
535239278Sgonzo	    1 << (ADS7846_CS_PIN - LPC_GPIO_GPO_00(0)));
536260326Sian	bus_space_unmap(bst, bsh, LPC_GPIO_SIZE);
537239278Sgonzo}
538239278Sgonzo
539239278Sgonzostatic device_method_t lpc_gpio_methods[] = {
540239278Sgonzo	/* Device interface */
541239278Sgonzo	DEVMETHOD(device_probe,		lpc_gpio_probe),
542239278Sgonzo	DEVMETHOD(device_attach,	lpc_gpio_attach),
543239278Sgonzo	DEVMETHOD(device_detach,	lpc_gpio_detach),
544239278Sgonzo
545239278Sgonzo	/* GPIO interface */
546277996Sloos	DEVMETHOD(gpio_get_bus,		lpc_gpio_get_bus),
547239278Sgonzo	DEVMETHOD(gpio_pin_max,		lpc_gpio_pin_max),
548239278Sgonzo	DEVMETHOD(gpio_pin_getcaps,	lpc_gpio_pin_getcaps),
549239278Sgonzo	DEVMETHOD(gpio_pin_getflags,	lpc_gpio_pin_getflags),
550239278Sgonzo	DEVMETHOD(gpio_pin_setflags,	lpc_gpio_pin_setflags),
551239278Sgonzo	DEVMETHOD(gpio_pin_getname,	lpc_gpio_pin_getname),
552239278Sgonzo	DEVMETHOD(gpio_pin_set,		lpc_gpio_pin_set),
553239278Sgonzo	DEVMETHOD(gpio_pin_get,		lpc_gpio_pin_get),
554239278Sgonzo	DEVMETHOD(gpio_pin_toggle,	lpc_gpio_pin_toggle),
555239278Sgonzo
556239278Sgonzo	{ 0, 0 }
557239278Sgonzo};
558239278Sgonzo
559239278Sgonzostatic devclass_t lpc_gpio_devclass;
560239278Sgonzo
561239278Sgonzostatic driver_t lpc_gpio_driver = {
562239278Sgonzo	"lpcgpio",
563239278Sgonzo	lpc_gpio_methods,
564239278Sgonzo	sizeof(struct lpc_gpio_softc),
565239278Sgonzo};
566239278Sgonzo
567239278Sgonzoextern devclass_t gpiobus_devclass, gpioc_devclass;
568239278Sgonzoextern driver_t gpiobus_driver, gpioc_driver;
569239278Sgonzo
570239278SgonzoDRIVER_MODULE(lpcgpio, simplebus, lpc_gpio_driver, lpc_gpio_devclass, 0, 0);
571239278SgonzoDRIVER_MODULE(gpiobus, lpcgpio, gpiobus_driver, gpiobus_devclass, 0, 0);
572239278SgonzoDRIVER_MODULE(gpioc, lpcgpio, gpioc_driver, gpioc_devclass, 0, 0);
573239278SgonzoMODULE_VERSION(lpcgpio, 1);
574