1 /* $NetBSD: gscpcib.c,v 1.14 2009/08/18 19:51:45 dyoung Exp $ */
2 /* $OpenBSD: gscpcib.c,v 1.3 2004/10/05 19:02:33 grange Exp $ */
4 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Special driver for the National Semiconductor Geode SC1100 PCI-ISA bridge
21 * that attaches instead of pcib(4). In addition to the core pcib(4)
22 * functionality this driver provides support for the GPIO interface.
25 #include <sys/cdefs.h>
26 __KERNEL_RCSID(0, "$NetBSD: gscpcib.c,v 1.14 2009/08/18 19:51:45 dyoung Exp $");
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/device.h>
32 #include <sys/kernel.h>
34 #include <machine/bus.h>
36 #include <dev/pci/pcireg.h>
37 #include <dev/pci/pcivar.h>
38 #include <dev/pci/pcidevs.h>
40 #include <dev/gpio/gpiovar.h>
42 #include <i386/pci/gscpcibreg.h>
43 #include <arch/x86/pci/pcibvar.h>
45 struct gscpcib_softc
{
46 struct pcib_softc sc_pcib
;
52 bus_space_tag_t sc_gpio_iot
;
53 bus_space_handle_t sc_gpio_ioh
;
54 struct gpio_chipset_tag sc_gpio_gc
;
55 gpio_pin_t sc_gpio_pins
[GSCGPIO_NPINS
];
58 int gscpcib_match(device_t
, cfdata_t
, void *);
59 void gscpcib_attach(device_t
, device_t
, void *);
60 int gscpcib_detach(device_t
, int);
61 int gscpcib_rescan(device_t
, const char *, const int *);
62 void gscpcib_childdetached(device_t
, device_t
);
64 int gscpcib_gpio_pin_read(void *, int);
65 void gscpcib_gpio_pin_write(void *, int, int);
66 void gscpcib_gpio_pin_ctl(void *, int, int);
68 CFATTACH_DECL3_NEW(gscpcib
, sizeof(struct gscpcib_softc
),
69 gscpcib_match
, gscpcib_attach
, gscpcib_detach
, NULL
, gscpcib_rescan
,
70 gscpcib_childdetached
, DVF_DETACH_SHUTDOWN
);
72 extern struct cfdriver gscpcib_cd
;
75 gscpcib_childdetached(device_t self
, device_t child
)
77 struct gscpcib_softc
*sc
= device_private(self
);
79 if (sc
->sc_gpiobus
== child
)
80 sc
->sc_gpiobus
= NULL
;
82 pcibchilddet(self
, child
);
86 gscpcib_rescan(device_t self
, const char *ifattr
, const int *loc
)
88 struct gscpcib_softc
*sc
= device_private(self
);
90 /* Attach GPIO framework */
91 if (sc
->sc_gpio_present
&& ifattr_match(ifattr
, "gpiobus") &&
92 sc
->sc_gpiobus
== NULL
) {
93 struct gpiobus_attach_args gba
;
95 gba
.gba_gc
= &sc
->sc_gpio_gc
;
96 gba
.gba_pins
= sc
->sc_gpio_pins
;
97 gba
.gba_npins
= GSCGPIO_NPINS
;
99 sc
->sc_gpiobus
= config_found_sm_loc(self
, "gpiobus", loc
,
100 &gba
, gpiobus_print
, NULL
);
103 return pcibrescan(self
, ifattr
, loc
);
107 gscpcib_match(device_t parent
, cfdata_t match
, void *aux
)
109 struct pci_attach_args
*pa
= aux
;
111 if (PCI_CLASS(pa
->pa_class
) != PCI_CLASS_BRIDGE
||
112 PCI_SUBCLASS(pa
->pa_class
) != PCI_SUBCLASS_BRIDGE_ISA
)
115 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_NS
&&
116 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_NS_SC1100_ISA
)
117 return (2); /* supersede pcib(4) */
123 gscpcib_attach(device_t parent
, device_t self
, void *aux
)
125 struct gscpcib_softc
*sc
= device_private(self
);
126 struct pci_attach_args
*pa
= aux
;
130 /* Map GPIO I/O space */
131 gpiobase
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, GSCGPIO_BASE
);
132 sc
->sc_gpio_iot
= pa
->pa_iot
;
133 if (bus_space_map(sc
->sc_gpio_iot
, PCI_MAPREG_IO_ADDR(gpiobase
),
134 GSCGPIO_SIZE
, 0, &sc
->sc_gpio_ioh
)) {
135 printf(": failed to map GPIO I/O space");
139 /* Initialize pins array */
140 for (i
= 0; i
< GSCGPIO_NPINS
; i
++) {
141 sc
->sc_gpio_pins
[i
].pin_num
= i
;
142 sc
->sc_gpio_pins
[i
].pin_caps
= GPIO_PIN_INPUT
|
143 GPIO_PIN_OUTPUT
| GPIO_PIN_OPENDRAIN
|
144 GPIO_PIN_PUSHPULL
| GPIO_PIN_TRISTATE
|
148 sc
->sc_gpio_pins
[i
].pin_flags
= GPIO_PIN_TRISTATE
;
149 sc
->sc_gpio_pins
[i
].pin_state
= GPIO_PIN_LOW
;
150 gscpcib_gpio_pin_ctl(sc
, i
, sc
->sc_gpio_pins
[i
].pin_flags
);
151 gscpcib_gpio_pin_write(sc
, i
, sc
->sc_gpio_pins
[i
].pin_state
);
154 /* Create controller tag */
155 sc
->sc_gpio_gc
.gp_cookie
= sc
;
156 sc
->sc_gpio_gc
.gp_pin_read
= gscpcib_gpio_pin_read
;
157 sc
->sc_gpio_gc
.gp_pin_write
= gscpcib_gpio_pin_write
;
158 sc
->sc_gpio_gc
.gp_pin_ctl
= gscpcib_gpio_pin_ctl
;
160 sc
->sc_gpio_present
= true;
163 /* Provide core pcib(4) functionality */
164 pcibattach(parent
, self
, aux
);
166 gscpcib_rescan(self
, "gpiobus", NULL
);
170 gscpcib_detach(device_t self
, int flags
)
173 struct gscpcib_softc
*sc
= device_private(self
);
175 if ((rc
= config_detach_children(self
, flags
)) != 0)
178 if ((rc
= pcibdetach(self
, flags
)) != 0)
181 if (sc
->sc_gpio_present
)
182 bus_space_unmap(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
, GSCGPIO_SIZE
);
188 gscpcib_gpio_pin_select(struct gscpcib_softc
*sc
, int pin
)
190 bus_space_write_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
, GSCGPIO_SEL
, pin
);
194 gscpcib_gpio_pin_read(void *arg
, int pin
)
196 struct gscpcib_softc
*sc
= arg
;
200 reg
= (pin
< 32 ? GSCGPIO_GPDI0
: GSCGPIO_GPDI1
);
202 data
= bus_space_read_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
, reg
);
204 return ((data
>> shift
) & 0x1);
208 gscpcib_gpio_pin_write(void *arg
, int pin
, int value
)
210 struct gscpcib_softc
*sc
= arg
;
214 reg
= (pin
< 32 ? GSCGPIO_GPDO0
: GSCGPIO_GPDO1
);
216 data
= bus_space_read_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
, reg
);
218 data
&= ~(1 << shift
);
220 data
|= (1 << shift
);
222 bus_space_write_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
, reg
, data
);
226 gscpcib_gpio_pin_ctl(void *arg
, int pin
, int flags
)
228 struct gscpcib_softc
*sc
= arg
;
231 gscpcib_gpio_pin_select(sc
, pin
);
232 conf
= bus_space_read_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
,
235 conf
&= ~(GSCGPIO_CONF_OUTPUTEN
| GSCGPIO_CONF_PUSHPULL
|
236 GSCGPIO_CONF_PULLUP
);
237 if ((flags
& GPIO_PIN_TRISTATE
) == 0)
238 conf
|= GSCGPIO_CONF_OUTPUTEN
;
239 if (flags
& GPIO_PIN_PUSHPULL
)
240 conf
|= GSCGPIO_CONF_PUSHPULL
;
241 if (flags
& GPIO_PIN_PULLUP
)
242 conf
|= GSCGPIO_CONF_PULLUP
;
243 bus_space_write_4(sc
->sc_gpio_iot
, sc
->sc_gpio_ioh
,