1215142Sthompsa/*-
2215142Sthompsa * Copyright (c) 2010, Andrew Thompson <thompsa@FreeBSD.org>
3215142Sthompsa * All rights reserved.
4215142Sthompsa *
5215142Sthompsa * Redistribution and use in source and binary forms, with or without
6215142Sthompsa * modification, are permitted provided that the following conditions
7215142Sthompsa * are met:
8215142Sthompsa * 1. Redistributions of source code must retain the above copyright
9215142Sthompsa *    notice unmodified, this list of conditions, and the following
10215142Sthompsa *    disclaimer.
11215142Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
12215142Sthompsa *    notice, this list of conditions and the following disclaimer in the
13215142Sthompsa *    documentation and/or other materials provided with the distribution.
14215142Sthompsa *
15215142Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16215142Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17215142Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18215142Sthompsa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19215142Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20215142Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21215142Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22215142Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23215142Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24215142Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25215142Sthompsa * SUCH DAMAGE.
26215142Sthompsa */
27215142Sthompsa
28215142Sthompsa/*
29215142Sthompsa * GPIO driver for Gateworks Cambria
30215142Sthompsa *
31215142Sthompsa * Note:
32215142Sthompsa * The Cambria PLD does not set the i2c ack bit after each write, if we used the
33215142Sthompsa * regular iicbus interface it would abort the xfer after the address byte
34215142Sthompsa * times out and not write our latch. To get around this we grab the iicbus and
35215142Sthompsa * then do our own bit banging. This is a comprimise to changing all the iicbb
36215142Sthompsa * device methods to allow a flag to be passed down and is similir to how Linux
37215142Sthompsa * does it.
38215142Sthompsa *
39215142Sthompsa */
40215142Sthompsa
41215142Sthompsa#include <sys/cdefs.h>
42215142Sthompsa__FBSDID("$FreeBSD$");
43215142Sthompsa
44215142Sthompsa#include <sys/param.h>
45215142Sthompsa#include <sys/systm.h>
46215142Sthompsa#include <sys/bus.h>
47215142Sthompsa
48215142Sthompsa#include <sys/kernel.h>
49215142Sthompsa#include <sys/module.h>
50215142Sthompsa#include <sys/rman.h>
51215142Sthompsa#include <sys/lock.h>
52215142Sthompsa#include <sys/mutex.h>
53215142Sthompsa#include <sys/gpio.h>
54215142Sthompsa
55215142Sthompsa#include <arm/xscale/ixp425/ixp425reg.h>
56215142Sthompsa#include <arm/xscale/ixp425/ixp425var.h>
57215142Sthompsa#include <arm/xscale/ixp425/ixdp425reg.h>
58215142Sthompsa
59215142Sthompsa#include <dev/iicbus/iiconf.h>
60215142Sthompsa#include <dev/iicbus/iicbus.h>
61215142Sthompsa
62215142Sthompsa#include "iicbb_if.h"
63215142Sthompsa#include "gpio_if.h"
64215142Sthompsa
65215142Sthompsa#define	IIC_M_WR	0	/* write operation */
66215142Sthompsa#define	PLD_ADDR	0xac	/* slave address */
67215142Sthompsa
68215142Sthompsa#define	I2C_DELAY	10
69215142Sthompsa
70215142Sthompsa#define	GPIO_CONF_CLR(sc, reg, mask)	\
71215142Sthompsa	GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask))
72215142Sthompsa#define	GPIO_CONF_SET(sc, reg, mask)	\
73215142Sthompsa	GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask))
74215142Sthompsa
75215142Sthompsa#define	GPIO_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
76215142Sthompsa#define	GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
77215142Sthompsa#define	GPIO_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
78215142Sthompsa
79215142Sthompsa#define	GPIO_PINS		5
80215142Sthompsastruct cambria_gpio_softc {
81215142Sthompsa	device_t		sc_dev;
82215142Sthompsa	bus_space_tag_t		sc_iot;
83215142Sthompsa	bus_space_handle_t	sc_gpio_ioh;
84215142Sthompsa        struct mtx		sc_mtx;
85215142Sthompsa	struct gpio_pin		sc_pins[GPIO_PINS];
86215142Sthompsa	uint8_t			sc_latch;
87226324Sthompsa	uint8_t			sc_val;
88215142Sthompsa};
89215142Sthompsa
90215142Sthompsastruct cambria_gpio_pin {
91215142Sthompsa	const char *name;
92215142Sthompsa	int pin;
93215142Sthompsa	int flags;
94215142Sthompsa};
95215142Sthompsa
96215142Sthompsaextern struct ixp425_softc *ixp425_softc;
97215142Sthompsa
98215142Sthompsastatic struct cambria_gpio_pin cambria_gpio_pins[GPIO_PINS] = {
99226325Sthompsa	{ "PLD0", 0, GPIO_PIN_OUTPUT },
100226325Sthompsa	{ "PLD1", 1, GPIO_PIN_OUTPUT },
101226325Sthompsa	{ "PLD2", 2, GPIO_PIN_OUTPUT },
102226325Sthompsa	{ "PLD3", 3, GPIO_PIN_OUTPUT },
103226325Sthompsa	{ "PLD4", 4, GPIO_PIN_OUTPUT },
104215142Sthompsa};
105215142Sthompsa
106215142Sthompsa/*
107215142Sthompsa * Helpers
108215142Sthompsa */
109215142Sthompsastatic int cambria_gpio_read(struct cambria_gpio_softc *, uint32_t, unsigned int *);
110215142Sthompsastatic int cambria_gpio_write(struct cambria_gpio_softc *);
111215142Sthompsa
112215142Sthompsa/*
113215142Sthompsa * Driver stuff
114215142Sthompsa */
115215142Sthompsastatic int cambria_gpio_probe(device_t dev);
116215142Sthompsastatic int cambria_gpio_attach(device_t dev);
117215142Sthompsastatic int cambria_gpio_detach(device_t dev);
118215142Sthompsa
119215142Sthompsa/*
120215142Sthompsa * GPIO interface
121215142Sthompsa */
122215142Sthompsastatic int cambria_gpio_pin_max(device_t dev, int *maxpin);
123215142Sthompsastatic int cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
124215142Sthompsastatic int cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
125215142Sthompsa    *flags);
126215142Sthompsastatic int cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
127215142Sthompsastatic int cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
128215142Sthompsastatic int cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
129215142Sthompsastatic int cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
130215142Sthompsastatic int cambria_gpio_pin_toggle(device_t dev, uint32_t pin);
131215142Sthompsa
132215142Sthompsastatic int
133215142Sthompsai2c_getsda(struct cambria_gpio_softc *sc)
134215142Sthompsa{
135215142Sthompsa	uint32_t reg;
136215142Sthompsa
137215319Sthompsa	IXP4XX_GPIO_LOCK();
138215142Sthompsa	GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
139215142Sthompsa
140215142Sthompsa	reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR);
141215319Sthompsa	IXP4XX_GPIO_UNLOCK();
142215142Sthompsa	return (reg & GPIO_I2C_SDA_BIT);
143215142Sthompsa}
144215142Sthompsa
145215142Sthompsastatic void
146215142Sthompsai2c_setsda(struct cambria_gpio_softc *sc, int val)
147215142Sthompsa{
148215142Sthompsa
149215319Sthompsa	IXP4XX_GPIO_LOCK();
150215142Sthompsa	GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT);
151215142Sthompsa	if (val)
152215142Sthompsa		GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
153215142Sthompsa	else
154215142Sthompsa		GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
155215319Sthompsa	IXP4XX_GPIO_UNLOCK();
156215142Sthompsa	DELAY(I2C_DELAY);
157215142Sthompsa}
158215142Sthompsa
159215142Sthompsastatic void
160215142Sthompsai2c_setscl(struct cambria_gpio_softc *sc, int val)
161215142Sthompsa{
162215142Sthompsa
163215319Sthompsa	IXP4XX_GPIO_LOCK();
164215142Sthompsa	GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT);
165215142Sthompsa	if (val)
166215142Sthompsa		GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
167215142Sthompsa	else
168215142Sthompsa		GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
169215319Sthompsa	IXP4XX_GPIO_UNLOCK();
170215142Sthompsa	DELAY(I2C_DELAY);
171215142Sthompsa}
172215142Sthompsa
173215142Sthompsastatic void
174215142Sthompsai2c_sendstart(struct cambria_gpio_softc *sc)
175215142Sthompsa{
176215142Sthompsa	i2c_setsda(sc, 1);
177215142Sthompsa	i2c_setscl(sc, 1);
178215142Sthompsa	i2c_setsda(sc, 0);
179215142Sthompsa	i2c_setscl(sc, 0);
180215142Sthompsa}
181215142Sthompsa
182215142Sthompsastatic void
183215142Sthompsai2c_sendstop(struct cambria_gpio_softc *sc)
184215142Sthompsa{
185215142Sthompsa	i2c_setscl(sc, 1);
186215142Sthompsa	i2c_setsda(sc, 1);
187215142Sthompsa	i2c_setscl(sc, 0);
188215142Sthompsa	i2c_setsda(sc, 0);
189215142Sthompsa}
190215142Sthompsa
191215142Sthompsastatic void
192215142Sthompsai2c_sendbyte(struct cambria_gpio_softc *sc, u_char data)
193215142Sthompsa{
194215142Sthompsa	int i;
195215142Sthompsa
196215142Sthompsa	for (i=7; i>=0; i--) {
197215142Sthompsa		i2c_setsda(sc, data & (1<<i));
198215142Sthompsa		i2c_setscl(sc, 1);
199215142Sthompsa		i2c_setscl(sc, 0);
200215142Sthompsa	}
201215142Sthompsa	i2c_setscl(sc, 1);
202215142Sthompsa	i2c_getsda(sc);
203215142Sthompsa	i2c_setscl(sc, 0);
204215142Sthompsa}
205215142Sthompsa
206215142Sthompsastatic u_char
207215142Sthompsai2c_readbyte(struct cambria_gpio_softc *sc)
208215142Sthompsa{
209215142Sthompsa	int i;
210215142Sthompsa	unsigned char data=0;
211215142Sthompsa
212215142Sthompsa	for (i=7; i>=0; i--)
213215142Sthompsa	{
214215142Sthompsa		i2c_setscl(sc, 1);
215215142Sthompsa		if (i2c_getsda(sc))
216215142Sthompsa			data |= (1<<i);
217215142Sthompsa		i2c_setscl(sc, 0);
218215142Sthompsa	}
219215142Sthompsa	return data;
220215142Sthompsa}
221215142Sthompsa
222215142Sthompsastatic int
223215142Sthompsacambria_gpio_read(struct cambria_gpio_softc *sc, uint32_t pin, unsigned int *val)
224215142Sthompsa{
225215142Sthompsa	device_t dev = sc->sc_dev;
226215142Sthompsa	int error;
227215142Sthompsa
228215142Sthompsa	error = iicbus_request_bus(device_get_parent(dev), dev,
229215142Sthompsa	    IIC_DONTWAIT);
230215142Sthompsa	if (error)
231215142Sthompsa		return (error);
232215142Sthompsa
233215142Sthompsa	i2c_sendstart(sc);
234215142Sthompsa	i2c_sendbyte(sc, PLD_ADDR | LSB);
235215142Sthompsa	*val = (i2c_readbyte(sc) & (1 << pin)) != 0;
236215142Sthompsa	i2c_sendstop(sc);
237215142Sthompsa
238215142Sthompsa	iicbus_release_bus(device_get_parent(dev), dev);
239215142Sthompsa
240215142Sthompsa	return (0);
241215142Sthompsa}
242215142Sthompsa
243215142Sthompsastatic int
244215142Sthompsacambria_gpio_write(struct cambria_gpio_softc *sc)
245215142Sthompsa{
246215142Sthompsa	device_t dev = sc->sc_dev;
247215142Sthompsa	int error;
248215142Sthompsa
249215142Sthompsa	error = iicbus_request_bus(device_get_parent(dev), dev,
250215142Sthompsa	    IIC_DONTWAIT);
251215142Sthompsa	if (error)
252215142Sthompsa		return (error);
253215142Sthompsa
254215142Sthompsa	i2c_sendstart(sc);
255215142Sthompsa	i2c_sendbyte(sc, PLD_ADDR & ~LSB);
256215142Sthompsa	i2c_sendbyte(sc, sc->sc_latch);
257215142Sthompsa	i2c_sendstop(sc);
258215142Sthompsa
259215142Sthompsa	iicbus_release_bus(device_get_parent(dev), dev);
260215142Sthompsa
261215142Sthompsa	return (0);
262215142Sthompsa}
263215142Sthompsa
264215142Sthompsastatic int
265215142Sthompsacambria_gpio_pin_max(device_t dev, int *maxpin)
266215142Sthompsa{
267215142Sthompsa
268215142Sthompsa	*maxpin = GPIO_PINS - 1;
269215142Sthompsa	return (0);
270215142Sthompsa}
271215142Sthompsa
272215142Sthompsastatic int
273215142Sthompsacambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
274215142Sthompsa{
275215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
276215142Sthompsa
277215142Sthompsa	if (pin >= GPIO_PINS)
278215142Sthompsa		return (EINVAL);
279215142Sthompsa
280215142Sthompsa	*caps = sc->sc_pins[pin].gp_caps;
281215142Sthompsa	return (0);
282215142Sthompsa}
283215142Sthompsa
284215142Sthompsastatic int
285215142Sthompsacambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
286215142Sthompsa{
287215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
288215142Sthompsa
289215142Sthompsa	if (pin >= GPIO_PINS)
290215142Sthompsa		return (EINVAL);
291215142Sthompsa
292215142Sthompsa	*flags = sc->sc_pins[pin].gp_flags;
293215142Sthompsa	return (0);
294215142Sthompsa}
295215142Sthompsa
296215142Sthompsastatic int
297215142Sthompsacambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
298215142Sthompsa{
299215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
300215142Sthompsa
301215142Sthompsa	if (pin >= GPIO_PINS)
302215142Sthompsa		return (EINVAL);
303215142Sthompsa
304215142Sthompsa	memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
305215142Sthompsa	return (0);
306215142Sthompsa}
307215142Sthompsa
308215142Sthompsastatic int
309215142Sthompsacambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
310215142Sthompsa{
311215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
312215142Sthompsa	int error;
313226324Sthompsa	uint8_t mask;
314215142Sthompsa
315226324Sthompsa	mask = 1 << pin;
316226324Sthompsa
317215142Sthompsa	if (pin >= GPIO_PINS)
318215142Sthompsa		return (EINVAL);
319215142Sthompsa
320249449Sdim	/* Check for unwanted flags. */
321249449Sdim	if ((flags & sc->sc_pins[pin].gp_caps) != flags)
322215142Sthompsa		return (EINVAL);
323215142Sthompsa
324215142Sthompsa	/* Can't mix input/output together */
325215142Sthompsa	if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
326215142Sthompsa	    (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
327215142Sthompsa		return (EINVAL);
328215142Sthompsa
329215142Sthompsa	GPIO_LOCK(sc);
330215142Sthompsa	sc->sc_pins[pin].gp_flags = flags;
331215142Sthompsa
332226324Sthompsa	/*
333226324Sthompsa	 * Writing a logical one sets the signal high and writing a logical
334226324Sthompsa	 * zero sets the signal low. To configure a digital I/O signal as an
335226324Sthompsa	 * input, a logical one must first be written to the data bit to
336226324Sthompsa	 * three-state the associated output.
337226324Sthompsa	 */
338226324Sthompsa	if (flags & GPIO_PIN_INPUT || sc->sc_val & mask)
339226324Sthompsa		sc->sc_latch |= mask; /* input or output & high */
340226324Sthompsa	else
341226324Sthompsa		sc->sc_latch &= ~mask;
342215142Sthompsa	error = cambria_gpio_write(sc);
343215142Sthompsa	GPIO_UNLOCK(sc);
344215142Sthompsa
345215142Sthompsa	return (error);
346215142Sthompsa}
347215142Sthompsa
348215142Sthompsastatic int
349215142Sthompsacambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
350215142Sthompsa{
351215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
352215142Sthompsa	int error;
353226324Sthompsa	uint8_t mask;
354215142Sthompsa
355226324Sthompsa	mask = 1 << pin;
356226324Sthompsa
357226324Sthompsa	if (pin >= GPIO_PINS)
358215142Sthompsa		return (EINVAL);
359215142Sthompsa	GPIO_LOCK(sc);
360215142Sthompsa	if (value)
361226324Sthompsa		sc->sc_val |= mask;
362215142Sthompsa	else
363226324Sthompsa		sc->sc_val &= ~mask;
364226324Sthompsa
365226324Sthompsa	if (sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) {
366226324Sthompsa		/* just save, altering the latch will disable input */
367226324Sthompsa		GPIO_UNLOCK(sc);
368226324Sthompsa		return (0);
369226324Sthompsa	}
370226324Sthompsa
371226324Sthompsa	if (value)
372226324Sthompsa		sc->sc_latch |= mask;
373226324Sthompsa	else
374226324Sthompsa		sc->sc_latch &= ~mask;
375215142Sthompsa	error = cambria_gpio_write(sc);
376215142Sthompsa	GPIO_UNLOCK(sc);
377215142Sthompsa
378215142Sthompsa	return (error);
379215142Sthompsa}
380215142Sthompsa
381215142Sthompsastatic int
382215142Sthompsacambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
383215142Sthompsa{
384215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
385215142Sthompsa	int error = 0;
386215142Sthompsa
387215142Sthompsa	if (pin >= GPIO_PINS)
388215142Sthompsa		return (EINVAL);
389215142Sthompsa
390215142Sthompsa	GPIO_LOCK(sc);
391215142Sthompsa	if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT)
392215142Sthompsa		*val = (sc->sc_latch & (1 << pin)) ? 1 : 0;
393215142Sthompsa	else
394215142Sthompsa		error = cambria_gpio_read(sc, pin, val);
395215142Sthompsa	GPIO_UNLOCK(sc);
396215142Sthompsa
397215142Sthompsa	return (error);
398215142Sthompsa}
399215142Sthompsa
400215142Sthompsastatic int
401215142Sthompsacambria_gpio_pin_toggle(device_t dev, uint32_t pin)
402215142Sthompsa{
403215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
404226324Sthompsa	int error = 0;
405215142Sthompsa
406226324Sthompsa	if (pin >= GPIO_PINS)
407215142Sthompsa		return (EINVAL);
408215142Sthompsa
409215142Sthompsa	GPIO_LOCK(sc);
410226324Sthompsa	sc->sc_val ^= (1 << pin);
411226324Sthompsa	if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT) {
412226324Sthompsa		sc->sc_latch ^= (1 << pin);
413226324Sthompsa		error = cambria_gpio_write(sc);
414226324Sthompsa	}
415215142Sthompsa	GPIO_UNLOCK(sc);
416215142Sthompsa
417215142Sthompsa	return (error);
418215142Sthompsa}
419215142Sthompsa
420215142Sthompsastatic int
421215142Sthompsacambria_gpio_probe(device_t dev)
422215142Sthompsa{
423215142Sthompsa
424215142Sthompsa	device_set_desc(dev, "Gateworks Cambria GPIO driver");
425215142Sthompsa	return (0);
426215142Sthompsa}
427215142Sthompsa
428215142Sthompsastatic int
429215142Sthompsacambria_gpio_attach(device_t dev)
430215142Sthompsa{
431215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
432215142Sthompsa	int pin;
433215142Sthompsa
434215142Sthompsa	sc->sc_dev = dev;
435215142Sthompsa	sc->sc_iot = ixp425_softc->sc_iot;
436215142Sthompsa	sc->sc_gpio_ioh = ixp425_softc->sc_gpio_ioh;
437215142Sthompsa
438239351Srpaulo	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
439215142Sthompsa
440215142Sthompsa	for (pin = 0; pin < GPIO_PINS; pin++) {
441215142Sthompsa		struct cambria_gpio_pin *p = &cambria_gpio_pins[pin];
442215142Sthompsa
443215142Sthompsa		strncpy(sc->sc_pins[pin].gp_name, p->name, GPIOMAXNAME);
444215142Sthompsa		sc->sc_pins[pin].gp_pin = pin;
445215142Sthompsa		sc->sc_pins[pin].gp_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
446215142Sthompsa		sc->sc_pins[pin].gp_flags = 0;
447215142Sthompsa		cambria_gpio_pin_setflags(dev, pin, p->flags);
448215142Sthompsa	}
449215142Sthompsa
450215142Sthompsa	device_add_child(dev, "gpioc", device_get_unit(dev));
451215142Sthompsa	device_add_child(dev, "gpiobus", device_get_unit(dev));
452215142Sthompsa	return (bus_generic_attach(dev));
453215142Sthompsa}
454215142Sthompsa
455215142Sthompsastatic int
456215142Sthompsacambria_gpio_detach(device_t dev)
457215142Sthompsa{
458215142Sthompsa	struct cambria_gpio_softc *sc = device_get_softc(dev);
459215142Sthompsa
460215142Sthompsa	KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
461215142Sthompsa
462215142Sthompsa	bus_generic_detach(dev);
463215142Sthompsa
464215142Sthompsa	mtx_destroy(&sc->sc_mtx);
465215142Sthompsa
466215142Sthompsa	return(0);
467215142Sthompsa}
468215142Sthompsa
469215142Sthompsastatic device_method_t cambria_gpio_methods[] = {
470215142Sthompsa	DEVMETHOD(device_probe, cambria_gpio_probe),
471215142Sthompsa	DEVMETHOD(device_attach, cambria_gpio_attach),
472215142Sthompsa	DEVMETHOD(device_detach, cambria_gpio_detach),
473215142Sthompsa
474215142Sthompsa	/* GPIO protocol */
475215142Sthompsa	DEVMETHOD(gpio_pin_max, cambria_gpio_pin_max),
476215142Sthompsa	DEVMETHOD(gpio_pin_getname, cambria_gpio_pin_getname),
477215142Sthompsa	DEVMETHOD(gpio_pin_getflags, cambria_gpio_pin_getflags),
478215142Sthompsa	DEVMETHOD(gpio_pin_getcaps, cambria_gpio_pin_getcaps),
479215142Sthompsa	DEVMETHOD(gpio_pin_setflags, cambria_gpio_pin_setflags),
480215142Sthompsa	DEVMETHOD(gpio_pin_get, cambria_gpio_pin_get),
481215142Sthompsa	DEVMETHOD(gpio_pin_set, cambria_gpio_pin_set),
482215142Sthompsa	DEVMETHOD(gpio_pin_toggle, cambria_gpio_pin_toggle),
483215142Sthompsa	{0, 0},
484215142Sthompsa};
485215142Sthompsa
486215142Sthompsastatic driver_t cambria_gpio_driver = {
487215142Sthompsa	"gpio_cambria",
488215142Sthompsa	cambria_gpio_methods,
489215142Sthompsa	sizeof(struct cambria_gpio_softc),
490215142Sthompsa};
491215142Sthompsastatic devclass_t cambria_gpio_devclass;
492215142Sthompsaextern devclass_t gpiobus_devclass, gpioc_devclass;
493215142Sthompsaextern driver_t gpiobus_driver, gpioc_driver;
494215142Sthompsa
495215142SthompsaDRIVER_MODULE(gpio_cambria, iicbus, cambria_gpio_driver, cambria_gpio_devclass, 0, 0);
496215142SthompsaDRIVER_MODULE(gpiobus, gpio_cambria, gpiobus_driver, gpiobus_devclass, 0, 0);
497215142SthompsaDRIVER_MODULE(gpioc, gpio_cambria, gpioc_driver, gpioc_devclass, 0, 0);
498215142SthompsaMODULE_VERSION(gpio_cambria, 1);
499215142SthompsaMODULE_DEPEND(gpio_cambria, iicbus, 1, 1, 1);
500