1ab6df5bcSAlex Hornung /* $OpenBSD: blambert $ */
2ab6df5bcSAlex Hornung /* $NetBSD: nsclpcsio_isa.c,v 1.5 2002/10/22 16:18:26 drochner Exp $ */
3ab6df5bcSAlex Hornung 
4ab6df5bcSAlex Hornung /*
5ab6df5bcSAlex Hornung  * Copyright (c) 2002 Matthias Drochner.  All rights reserved.
6ab6df5bcSAlex Hornung  * Copyright (c) 2004 Markus Friedl.  All rights reserved.
7ab6df5bcSAlex Hornung  * Copyright (c) 2004 Alexander Yurchenko.  All rights reserved.
8ab6df5bcSAlex Hornung  *
9ab6df5bcSAlex Hornung  * Redistribution and use in source and binary forms, with or without
10ab6df5bcSAlex Hornung  * modification, are permitted provided that the following conditions
11ab6df5bcSAlex Hornung  * are met:
12ab6df5bcSAlex Hornung  * 1. Redistributions of source code must retain the above copyright
13ab6df5bcSAlex Hornung  *    notice, this list of conditions, and the following disclaimer.
14ab6df5bcSAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
15ab6df5bcSAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
16ab6df5bcSAlex Hornung  *    documentation and/or other materials provided with the distribution.
17ab6df5bcSAlex Hornung  *
18ab6df5bcSAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ab6df5bcSAlex Hornung  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ab6df5bcSAlex Hornung  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ab6df5bcSAlex Hornung  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22ab6df5bcSAlex Hornung  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ab6df5bcSAlex Hornung  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ab6df5bcSAlex Hornung  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ab6df5bcSAlex Hornung  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ab6df5bcSAlex Hornung  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ab6df5bcSAlex Hornung  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ab6df5bcSAlex Hornung  * SUCH DAMAGE.
29ab6df5bcSAlex Hornung  */
30ab6df5bcSAlex Hornung 
31ab6df5bcSAlex Hornung /*
32ab6df5bcSAlex Hornung  * National Semiconductor PC87366 LPC Super I/O.
33ab6df5bcSAlex Hornung  * Supported logical devices: GPIO, TMS, VLM.
34ab6df5bcSAlex Hornung  */
35ab6df5bcSAlex Hornung 
36c8cb1400SAlex Hornung #include "use_gpio.h"
37c8cb1400SAlex Hornung 
38ab6df5bcSAlex Hornung #include <sys/param.h>
39ab6df5bcSAlex Hornung #include <sys/systm.h>
40ab6df5bcSAlex Hornung #include <sys/device.h>
41ab6df5bcSAlex Hornung #include <sys/kernel.h>
42ab6df5bcSAlex Hornung #include <sys/sensors.h>
43c8cb1400SAlex Hornung #include <sys/module.h>
44c8cb1400SAlex Hornung #include <sys/rman.h>
45ab6df5bcSAlex Hornung 
46c8cb1400SAlex Hornung #include <sys/bus.h>
47ab6df5bcSAlex Hornung 
48c8cb1400SAlex Hornung #include <bus/isa/isareg.h>
49c8cb1400SAlex Hornung #include <bus/isa/isavar.h>
50ab6df5bcSAlex Hornung 
51c8cb1400SAlex Hornung #include <dev/misc/gpio/gpio.h>
52ab6df5bcSAlex Hornung 
53ab6df5bcSAlex Hornung #if defined(NSC_LPC_SIO_DEBUG)
54c8cb1400SAlex Hornung #define DPRINTF(x)              do { kprintf x; } while (0)
55ab6df5bcSAlex Hornung #else
56ab6df5bcSAlex Hornung #define DPRINTF(x)
57ab6df5bcSAlex Hornung #endif
58ab6df5bcSAlex Hornung 
59ab6df5bcSAlex Hornung #define SIO_REG_SID	0x20	/* Super I/O ID */
60ab6df5bcSAlex Hornung #define SIO_SID_PC87366	0xE9 	/* PC87366 is identified by 0xE9.*/
61ab6df5bcSAlex Hornung 
62ab6df5bcSAlex Hornung #define SIO_REG_SRID	0x27	/* Super I/O Revision */
63ab6df5bcSAlex Hornung 
64ab6df5bcSAlex Hornung #define SIO_REG_LDN	0x07	/* Logical Device Number */
65ab6df5bcSAlex Hornung #define SIO_LDN_FDC	0x00	/* Floppy Disk Controller (FDC) */
66ab6df5bcSAlex Hornung #define SIO_LDN_PP	0x01	/* Parallel Port (PP) */
67ab6df5bcSAlex Hornung #define SIO_LDN_SP2	0x02	/* Serial Port 2 with IR (SP2) */
68ab6df5bcSAlex Hornung #define SIO_LDN_SP1	0x03	/* Serial Port 1 (SP1) */
69ab6df5bcSAlex Hornung #define SIO_LDN_SWC	0x04	/* System Wake-Up Control (SWC) */
70ab6df5bcSAlex Hornung #define SIO_LDN_KBCM	0x05	/* Mouse Controller (KBC) */
71ab6df5bcSAlex Hornung #define SIO_LDN_KBCK	0x06	/* Keyboard Controller (KBC) */
72ab6df5bcSAlex Hornung #define SIO_LDN_GPIO	0x07	/* General-Purpose I/O (GPIO) Ports */
73ab6df5bcSAlex Hornung #define SIO_LDN_ACB	0x08	/* ACCESS.bus Interface (ACB) */
74ab6df5bcSAlex Hornung #define SIO_LDN_FSCM	0x09	/* Fan Speed Control and Monitor (FSCM) */
75ab6df5bcSAlex Hornung #define SIO_LDN_WDT	0x0A	/* WATCHDOG Timer (WDT) */
76ab6df5bcSAlex Hornung #define SIO_LDN_GMP	0x0B	/* Game Port (GMP) */
77ab6df5bcSAlex Hornung #define SIO_LDN_MIDI	0x0C	/* Musical Instrument Digital Interface */
78ab6df5bcSAlex Hornung #define SIO_LDN_VLM	0x0D	/* Voltage Level Monitor (VLM) */
79ab6df5bcSAlex Hornung #define SIO_LDN_TMS	0x0E	/* Temperature Sensor (TMS) */
80ab6df5bcSAlex Hornung 
81ab6df5bcSAlex Hornung #define SIO_REG_ACTIVE	0x30	/* Logical Device Activate Register */
82ab6df5bcSAlex Hornung #define SIO_ACTIVE_EN		0x01	/* enabled */
83ab6df5bcSAlex Hornung 
84ab6df5bcSAlex Hornung #define SIO_REG_IO_MSB	0x60	/* I/O Port Base, bits 15-8 */
85ab6df5bcSAlex Hornung #define SIO_REG_IO_LSB	0x61	/* I/O Port Base, bits 7-0 */
86ab6df5bcSAlex Hornung 
87ab6df5bcSAlex Hornung #define SIO_LDNUM	15	/* total number of logical devices */
88ab6df5bcSAlex Hornung 
89ab6df5bcSAlex Hornung /* Supported logical devices description */
90ab6df5bcSAlex Hornung static const struct {
91ab6df5bcSAlex Hornung 	const char *ld_name;
92ab6df5bcSAlex Hornung 	int ld_num;
93ab6df5bcSAlex Hornung 	int ld_iosize;
94ab6df5bcSAlex Hornung } sio_ld[] = {
95ab6df5bcSAlex Hornung 	{ "GPIO", SIO_LDN_GPIO, 16 },
96ab6df5bcSAlex Hornung 	{ "VLM", SIO_LDN_VLM, 16 },
97ab6df5bcSAlex Hornung 	{ "TMS", SIO_LDN_TMS, 16 },
98ab6df5bcSAlex Hornung };
99ab6df5bcSAlex Hornung 
100ab6df5bcSAlex Hornung /* GPIO */
101ab6df5bcSAlex Hornung #define SIO_GPIO_PINSEL	0xf0
102ab6df5bcSAlex Hornung #define SIO_GPIO_PINCFG	0xf1
103ab6df5bcSAlex Hornung #define SIO_GPIO_PINEV	0xf2
104ab6df5bcSAlex Hornung 
105ab6df5bcSAlex Hornung #define SIO_GPIO_CONF_OUTPUTEN	(1 << 0)
106ab6df5bcSAlex Hornung #define SIO_GPIO_CONF_PUSHPULL	(1 << 1)
107ab6df5bcSAlex Hornung #define SIO_GPIO_CONF_PULLUP	(1 << 2)
108ab6df5bcSAlex Hornung 
109ab6df5bcSAlex Hornung #define SIO_GPDO0	0x00
110ab6df5bcSAlex Hornung #define SIO_GPDI0	0x01
111ab6df5bcSAlex Hornung #define SIO_GPEVEN0	0x02
112ab6df5bcSAlex Hornung #define SIO_GPEVST0	0x03
113ab6df5bcSAlex Hornung #define SIO_GPDO1	0x04
114ab6df5bcSAlex Hornung #define SIO_GPDI1	0x05
115ab6df5bcSAlex Hornung #define SIO_GPEVEN1	0x06
116ab6df5bcSAlex Hornung #define SIO_GPEVST1	0x07
117ab6df5bcSAlex Hornung #define SIO_GPDO2	0x08
118ab6df5bcSAlex Hornung #define SIO_GPDI2	0x09
119ab6df5bcSAlex Hornung #define SIO_GPDO3	0x0a
120ab6df5bcSAlex Hornung #define SIO_GPDI3	0x0b
121ab6df5bcSAlex Hornung 
122ab6df5bcSAlex Hornung #define SIO_GPIO_NPINS	29
123ab6df5bcSAlex Hornung 
124ab6df5bcSAlex Hornung /* TMS */
125ab6df5bcSAlex Hornung #define SIO_TEVSTS	0x00	/* Temperature Event Status */
126ab6df5bcSAlex Hornung #define SIO_TEVSMI	0x02	/* Temperature Event to SMI */
127ab6df5bcSAlex Hornung #define SIO_TEVIRQ	0x04	/* Temperature Event to IRQ */
128ab6df5bcSAlex Hornung #define SIO_TMSCFG	0x08	/* TMS Configuration */
129ab6df5bcSAlex Hornung #define SIO_TMSBS	0x09	/* TMS Bank Select */
130ab6df5bcSAlex Hornung #define SIO_TCHCFST	0x0A	/* Temperature Channel Config and Status */
131ab6df5bcSAlex Hornung #define SIO_RDCHT	0x0B	/* Read Channel Temperature */
132ab6df5bcSAlex Hornung #define SIO_CHTH	0x0C	/* Channel Temperature High Limit */
133ab6df5bcSAlex Hornung #define SIO_CHTL	0x0D	/* Channel Temperature Low Limit */
134ab6df5bcSAlex Hornung #define SIO_CHOTL	0x0E	/* Channel Overtemperature Limit */
135ab6df5bcSAlex Hornung 
136ab6df5bcSAlex Hornung /* VLM */
137ab6df5bcSAlex Hornung #define SIO_VEVSTS0	0x00	/* Voltage Event Status 0 */
138ab6df5bcSAlex Hornung #define SIO_VEVSTS1	0x01	/* Voltage Event Status 1 */
139ab6df5bcSAlex Hornung #define SIO_VEVSMI0	0x02	/* Voltage Event to SMI 0 */
140ab6df5bcSAlex Hornung #define SIO_VEVSMI1	0x03	/* Voltage Event to SMI 1 */
141ab6df5bcSAlex Hornung #define SIO_VEVIRQ0	0x04	/* Voltage Event to IRQ 0 */
142ab6df5bcSAlex Hornung #define SIO_VEVIRQ1	0x05	/* Voltage Event to IRQ 1 */
143ab6df5bcSAlex Hornung #define SIO_VID		0x06	/* Voltage ID */
144ab6df5bcSAlex Hornung #define SIO_VCNVR	0x07	/* Voltage Conversion Rate */
145ab6df5bcSAlex Hornung #define SIO_VLMCFG	0x08	/* VLM Configuration */
146ab6df5bcSAlex Hornung #define SIO_VLMBS	0x09	/* VLM Bank Select */
147ab6df5bcSAlex Hornung #define SIO_VCHCFST	0x0A	/* Voltage Channel Config and Status */
148ab6df5bcSAlex Hornung #define SIO_RDCHV	0x0B	/* Read Channel Voltage */
149ab6df5bcSAlex Hornung #define SIO_CHVH	0x0C	/* Channel Voltage High Limit */
150ab6df5bcSAlex Hornung #define SIO_CHVL	0x0D	/* Channel Voltage Low Limit */
151ab6df5bcSAlex Hornung #define SIO_OTSL	0x0E	/* Overtemperature Shutdown Limit */
152ab6df5bcSAlex Hornung 
153ab6df5bcSAlex Hornung #define SIO_REG_SIOCF1	0x21
154ab6df5bcSAlex Hornung #define SIO_REG_SIOCF2	0x22
155ab6df5bcSAlex Hornung #define SIO_REG_SIOCF3	0x23
156ab6df5bcSAlex Hornung #define SIO_REG_SIOCF4	0x24
157ab6df5bcSAlex Hornung #define SIO_REG_SIOCF5	0x25
158ab6df5bcSAlex Hornung #define SIO_REG_SIOCF8	0x28
159ab6df5bcSAlex Hornung #define SIO_REG_SIOCFA	0x2A
160ab6df5bcSAlex Hornung #define SIO_REG_SIOCFB	0x2B
161ab6df5bcSAlex Hornung #define SIO_REG_SIOCFC	0x2C
162ab6df5bcSAlex Hornung #define SIO_REG_SIOCFD	0x2D
163ab6df5bcSAlex Hornung 
164ab6df5bcSAlex Hornung #define	SIO_NUM_SENSORS	(3+14)
165ab6df5bcSAlex Hornung #define SIO_VLM_OFF	3
166ab6df5bcSAlex Hornung #define SIO_VREF	1235	/* 1000.0 * VREF */
167ab6df5bcSAlex Hornung 
168ab6df5bcSAlex Hornung struct nsclpcsio_softc {
1695d302545SFrançois Tigeot 	device_t sc_dev;
170c8cb1400SAlex Hornung 	struct resource *sc_iores;
171c8cb1400SAlex Hornung 	int sc_iorid;
172ab6df5bcSAlex Hornung 	bus_space_tag_t sc_iot;
173ab6df5bcSAlex Hornung 	bus_space_handle_t sc_ioh;
174ab6df5bcSAlex Hornung 
175ab6df5bcSAlex Hornung 	bus_space_handle_t sc_ld_ioh[SIO_LDNUM];
176ab6df5bcSAlex Hornung 	int sc_ld_en[SIO_LDNUM];
177c8cb1400SAlex Hornung #if NGPIO > 0
178ab6df5bcSAlex Hornung 	/* GPIO */
179c8cb1400SAlex Hornung 	struct gpio		sc_gpio_gc;
180ab6df5bcSAlex Hornung 	struct gpio_pin sc_gpio_pins[SIO_GPIO_NPINS];
181c8cb1400SAlex Hornung #endif
182ab6df5bcSAlex Hornung 
183ab6df5bcSAlex Hornung 	/* TMS and VLM */
184ab6df5bcSAlex Hornung 	struct ksensor sensors[SIO_NUM_SENSORS];
185ab6df5bcSAlex Hornung 	struct ksensordev sensordev;
186ab6df5bcSAlex Hornung };
187ab6df5bcSAlex Hornung 
188ab6df5bcSAlex Hornung #define GPIO_READ(sc, reg) \
189ab6df5bcSAlex Hornung 	bus_space_read_1((sc)->sc_iot,				\
190ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg))
191ab6df5bcSAlex Hornung #define GPIO_WRITE(sc, reg, val) \
192ab6df5bcSAlex Hornung 	bus_space_write_1((sc)->sc_iot,				\
193ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_GPIO], (reg), (val))
194ab6df5bcSAlex Hornung #define TMS_WRITE(sc, reg, val) \
195ab6df5bcSAlex Hornung 	bus_space_write_1((sc)->sc_iot,				\
196ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg), (val))
197ab6df5bcSAlex Hornung #define TMS_READ(sc, reg) \
198ab6df5bcSAlex Hornung 	bus_space_read_1((sc)->sc_iot,				\
199ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_TMS], (reg))
200ab6df5bcSAlex Hornung #define VLM_WRITE(sc, reg, val) \
201ab6df5bcSAlex Hornung 	bus_space_write_1((sc)->sc_iot,				\
202ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg), (val))
203ab6df5bcSAlex Hornung #define VLM_READ(sc, reg) \
204ab6df5bcSAlex Hornung 	bus_space_read_1((sc)->sc_iot,				\
205ab6df5bcSAlex Hornung 	    (sc)->sc_ld_ioh[SIO_LDN_VLM], (reg))
206ab6df5bcSAlex Hornung 
2075d302545SFrançois Tigeot int	 nsclpcsio_isa_probe(device_t);
2085d302545SFrançois Tigeot int	 nsclpcsio_isa_attach(device_t);
209ab6df5bcSAlex Hornung 
210c8cb1400SAlex Hornung 
211c8cb1400SAlex Hornung static device_method_t nsclpcsio_isa_methods[] = {
212c8cb1400SAlex Hornung 	DEVMETHOD(device_probe,		nsclpcsio_isa_probe),
213c8cb1400SAlex Hornung 	DEVMETHOD(device_attach,		nsclpcsio_isa_attach),
214d3c9c58eSSascha Wildner 	DEVMETHOD_END
215ab6df5bcSAlex Hornung };
216ab6df5bcSAlex Hornung 
217c8cb1400SAlex Hornung static driver_t nsclpcsio_isa_driver = {
218c8cb1400SAlex Hornung 	"nsclpcsio",
219c8cb1400SAlex Hornung 	nsclpcsio_isa_methods,
220c8cb1400SAlex Hornung 	sizeof (struct nsclpcsio_softc)
221ab6df5bcSAlex Hornung };
222ab6df5bcSAlex Hornung 
223c8cb1400SAlex Hornung static devclass_t nsclpcsio_devclass;
224c8cb1400SAlex Hornung 
225c8cb1400SAlex Hornung DRIVER_MODULE(nsclpcsio_isa, isa, nsclpcsio_isa_driver, nsclpcsio_devclass, NULL, NULL);
226c8cb1400SAlex Hornung 
227c8cb1400SAlex Hornung 
228ab6df5bcSAlex Hornung 
229ab6df5bcSAlex Hornung static u_int8_t	nsread(bus_space_tag_t, bus_space_handle_t, int);
230ab6df5bcSAlex Hornung static void	nswrite(bus_space_tag_t, bus_space_handle_t, int, u_int8_t);
231ab6df5bcSAlex Hornung 
232c8cb1400SAlex Hornung #if NGPIO > 0
233ab6df5bcSAlex Hornung void	nsclpcsio_gpio_init(struct nsclpcsio_softc *);
234ab6df5bcSAlex Hornung int	nsclpcsio_gpio_pin_read(void *, int);
235ab6df5bcSAlex Hornung void	nsclpcsio_gpio_pin_write(void *, int, int);
236ab6df5bcSAlex Hornung void	nsclpcsio_gpio_pin_ctl(void *, int, int);
237c8cb1400SAlex Hornung #endif
238ab6df5bcSAlex Hornung 
239ab6df5bcSAlex Hornung void	nsclpcsio_tms_init(struct nsclpcsio_softc *);
240ab6df5bcSAlex Hornung void	nsclpcsio_vlm_init(struct nsclpcsio_softc *);
241ab6df5bcSAlex Hornung void	nsclpcsio_tms_update(struct nsclpcsio_softc *);
242ab6df5bcSAlex Hornung void	nsclpcsio_vlm_update(struct nsclpcsio_softc *);
243ab6df5bcSAlex Hornung void	nsclpcsio_refresh(void *);
244ab6df5bcSAlex Hornung 
245ab6df5bcSAlex Hornung static u_int8_t
nsread(bus_space_tag_t iot,bus_space_handle_t ioh,int idx)246ab6df5bcSAlex Hornung nsread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx)
247ab6df5bcSAlex Hornung {
248ab6df5bcSAlex Hornung 	bus_space_write_1(iot, ioh, 0, idx);
249ab6df5bcSAlex Hornung 	return (bus_space_read_1(iot, ioh, 1));
250ab6df5bcSAlex Hornung }
251ab6df5bcSAlex Hornung 
252ab6df5bcSAlex Hornung static void
nswrite(bus_space_tag_t iot,bus_space_handle_t ioh,int idx,u_int8_t data)253ab6df5bcSAlex Hornung nswrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data)
254ab6df5bcSAlex Hornung {
255ab6df5bcSAlex Hornung 	bus_space_write_1(iot, ioh, 0, idx);
256ab6df5bcSAlex Hornung 	bus_space_write_1(iot, ioh, 1, data);
257ab6df5bcSAlex Hornung }
258ab6df5bcSAlex Hornung 
259ab6df5bcSAlex Hornung int
nsclpcsio_isa_probe(device_t dev)2605d302545SFrançois Tigeot nsclpcsio_isa_probe(device_t dev)
261ab6df5bcSAlex Hornung {
262c8cb1400SAlex Hornung 	struct resource *iores;
263c8cb1400SAlex Hornung 	int iorid = 0;
264ab6df5bcSAlex Hornung 	bus_space_tag_t iot;
265ab6df5bcSAlex Hornung 	bus_space_handle_t ioh;
266ab6df5bcSAlex Hornung 	int rv = 0;
267ab6df5bcSAlex Hornung 
268c8cb1400SAlex Hornung 	iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 0ul, ~0ul, 8, RF_ACTIVE);
269c8cb1400SAlex Hornung 	if (iores == NULL) {
270c8cb1400SAlex Hornung 		return 1;
271c8cb1400SAlex Hornung 	}
272c8cb1400SAlex Hornung 	iot = rman_get_bustag(iores);
273c8cb1400SAlex Hornung 	ioh = rman_get_bushandle(iores);
274ab6df5bcSAlex Hornung 
275ab6df5bcSAlex Hornung 	if (nsread(iot, ioh, SIO_REG_SID) == SIO_SID_PC87366)
276ab6df5bcSAlex Hornung 		rv = 1;
277ab6df5bcSAlex Hornung 
278c8cb1400SAlex Hornung 	bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
279ab6df5bcSAlex Hornung 	if (rv) {
280c8cb1400SAlex Hornung 		return 0;
281ab6df5bcSAlex Hornung 	}
282ab6df5bcSAlex Hornung 
283c8cb1400SAlex Hornung 	return 1;
284ab6df5bcSAlex Hornung }
285ab6df5bcSAlex Hornung 
286c8cb1400SAlex Hornung int
nsclpcsio_isa_attach(device_t dev)2875d302545SFrançois Tigeot nsclpcsio_isa_attach(device_t dev)
288ab6df5bcSAlex Hornung {
289ab6df5bcSAlex Hornung 	int iobase;
290c8cb1400SAlex Hornung 	struct nsclpcsio_softc *sc = device_get_softc(dev);
291ab6df5bcSAlex Hornung 	int i;
292ab6df5bcSAlex Hornung 
293c8cb1400SAlex Hornung 	sc->sc_dev = dev;
294c8cb1400SAlex Hornung 	sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 0ul, ~0ul, 8, RF_ACTIVE);
295c8cb1400SAlex Hornung 	if (sc->sc_iores == NULL) {
296c8cb1400SAlex Hornung 		return 1;
297ab6df5bcSAlex Hornung 	}
298c8cb1400SAlex Hornung 	sc->sc_iot = rman_get_bustag(sc->sc_iores);
299c8cb1400SAlex Hornung 	sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
300c8cb1400SAlex Hornung 
301c8cb1400SAlex Hornung 	kprintf("%s: NSC PC87366 rev %d:", device_get_nameunit(sc->sc_dev),
302ab6df5bcSAlex Hornung 	    nsread(sc->sc_iot, sc->sc_ioh, SIO_REG_SRID));
303ab6df5bcSAlex Hornung 
304ab6df5bcSAlex Hornung 	/* Configure all supported logical devices */
305c157ff7aSSascha Wildner 	for (i = 0; i < NELEM(sio_ld); i++) {
306ab6df5bcSAlex Hornung 		sc->sc_ld_en[sio_ld[i].ld_num] = 0;
307ab6df5bcSAlex Hornung 
308ab6df5bcSAlex Hornung 		/* Select the device and check if it's activated */
309ab6df5bcSAlex Hornung 		nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, sio_ld[i].ld_num);
310ab6df5bcSAlex Hornung 		if ((nsread(sc->sc_iot, sc->sc_ioh,
311ab6df5bcSAlex Hornung 		    SIO_REG_ACTIVE) & SIO_ACTIVE_EN) == 0)
312ab6df5bcSAlex Hornung 			continue;
313ab6df5bcSAlex Hornung 
314ab6df5bcSAlex Hornung 		/* Map I/O space if necessary */
315ab6df5bcSAlex Hornung 		if (sio_ld[i].ld_iosize != 0) {
316c8cb1400SAlex Hornung 
317ab6df5bcSAlex Hornung 			iobase = (nsread(sc->sc_iot, sc->sc_ioh,
318ab6df5bcSAlex Hornung 			    SIO_REG_IO_MSB) << 8);
319c8cb1400SAlex Hornung 
320ab6df5bcSAlex Hornung 			iobase |= nsread(sc->sc_iot, sc->sc_ioh,
321ab6df5bcSAlex Hornung 			    SIO_REG_IO_LSB);
322c8cb1400SAlex Hornung #if 0
323c8cb1400SAlex Hornung 			/* XXX: Not elegant without alloc_resource, but works */
324c8cb1400SAlex Hornung 			kprintf("debugging: iobase = %x\n", iobase);
325c8cb1400SAlex Hornung 			iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
326c8cb1400SAlex Hornung 			    iobase, sio_ld[i].ld_iosize, sio_ld[i].ld_iosize, RF_ACTIVE);
327c8cb1400SAlex Hornung 			if (iores == NULL) {
328c8cb1400SAlex Hornung 				kprintf("messed up alloc3\n");
329ab6df5bcSAlex Hornung 				continue;
330ab6df5bcSAlex Hornung 			}
331c8cb1400SAlex Hornung 			/* XXX: if implemented, also use the rman get handle stuff */
332c8cb1400SAlex Hornung #endif
333c8cb1400SAlex Hornung 			sc->sc_ld_ioh[sio_ld[i].ld_num] = iobase;
334c8cb1400SAlex Hornung 		}
335ab6df5bcSAlex Hornung 
336ab6df5bcSAlex Hornung 		sc->sc_ld_en[sio_ld[i].ld_num] = 1;
337c8cb1400SAlex Hornung 		kprintf(" %s", sio_ld[i].ld_name);
338ab6df5bcSAlex Hornung 	}
339ab6df5bcSAlex Hornung 
340c8cb1400SAlex Hornung 	kprintf("\n");
341c8cb1400SAlex Hornung #if NGPIO > 0
342ab6df5bcSAlex Hornung 	nsclpcsio_gpio_init(sc);
343c8cb1400SAlex Hornung #endif
344ab6df5bcSAlex Hornung 	nsclpcsio_tms_init(sc);
345ab6df5bcSAlex Hornung 	nsclpcsio_vlm_init(sc);
346ab6df5bcSAlex Hornung 
347ab6df5bcSAlex Hornung 	/* Hook into hw.sensors sysctl */
348c8cb1400SAlex Hornung 	strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
349ab6df5bcSAlex Hornung 	    sizeof(sc->sensordev.xname));
350ab6df5bcSAlex Hornung 	for (i = 0; i < SIO_NUM_SENSORS; i++) {
351ab6df5bcSAlex Hornung 		if (i < SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_TMS])
352ab6df5bcSAlex Hornung 			continue;
353ab6df5bcSAlex Hornung 		if (i >= SIO_VLM_OFF && !sc->sc_ld_en[SIO_LDN_VLM])
354ab6df5bcSAlex Hornung 			continue;
355ab6df5bcSAlex Hornung 		sensor_attach(&sc->sensordev, &sc->sensors[i]);
356ab6df5bcSAlex Hornung 	}
357ab6df5bcSAlex Hornung 	sensordev_install(&sc->sensordev);
358ab6df5bcSAlex Hornung 	if (sc->sc_ld_en[SIO_LDN_TMS] || sc->sc_ld_en[SIO_LDN_VLM]) {
359c8cb1400SAlex Hornung 		sensor_task_register(sc, nsclpcsio_refresh, 2);
360ab6df5bcSAlex Hornung 	}
361ab6df5bcSAlex Hornung 
362c8cb1400SAlex Hornung #if NGPIO > 0
363ab6df5bcSAlex Hornung 	/* Attach GPIO framework */
364ab6df5bcSAlex Hornung 	if (sc->sc_ld_en[SIO_LDN_GPIO]) {
365c8cb1400SAlex Hornung 		sc->sc_gpio_gc.driver_name = "pc83766";
366c8cb1400SAlex Hornung 		sc->sc_gpio_gc.arg = sc;
367c8cb1400SAlex Hornung 		sc->sc_gpio_gc.pin_read = nsclpcsio_gpio_pin_read;
368c8cb1400SAlex Hornung 		sc->sc_gpio_gc.pin_write = nsclpcsio_gpio_pin_write;
369c8cb1400SAlex Hornung 		sc->sc_gpio_gc.pin_ctl = nsclpcsio_gpio_pin_ctl;
370c8cb1400SAlex Hornung 		sc->sc_gpio_gc.pins = sc->sc_gpio_pins;
371c8cb1400SAlex Hornung 		sc->sc_gpio_gc.npins = SIO_GPIO_NPINS;
372c8cb1400SAlex Hornung 		gpio_register(&sc->sc_gpio_gc);
373ab6df5bcSAlex Hornung 	}
374c8cb1400SAlex Hornung #endif
375c8cb1400SAlex Hornung 
376c8cb1400SAlex Hornung 	return 0;
377ab6df5bcSAlex Hornung }
378ab6df5bcSAlex Hornung 
379ab6df5bcSAlex Hornung void
nsclpcsio_refresh(void * arg)380ab6df5bcSAlex Hornung nsclpcsio_refresh(void *arg)
381ab6df5bcSAlex Hornung {
382ab6df5bcSAlex Hornung 	struct nsclpcsio_softc *sc = (struct nsclpcsio_softc *)arg;
383ab6df5bcSAlex Hornung 
384ab6df5bcSAlex Hornung 	if (sc->sc_ld_en[SIO_LDN_TMS])
385ab6df5bcSAlex Hornung 		nsclpcsio_tms_update(sc);
386ab6df5bcSAlex Hornung 	if (sc->sc_ld_en[SIO_LDN_VLM])
387ab6df5bcSAlex Hornung 		nsclpcsio_vlm_update(sc);
388ab6df5bcSAlex Hornung }
389ab6df5bcSAlex Hornung 
390ab6df5bcSAlex Hornung void
nsclpcsio_tms_init(struct nsclpcsio_softc * sc)391ab6df5bcSAlex Hornung nsclpcsio_tms_init(struct nsclpcsio_softc *sc)
392ab6df5bcSAlex Hornung {
393ab6df5bcSAlex Hornung 	int i;
394ab6df5bcSAlex Hornung 
395ab6df5bcSAlex Hornung 	/* Initialisation, PC87366.pdf, page 208 */
396ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x08, 0x00);
397ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x09, 0x0f);
398ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x0a, 0x08);
399ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x0b, 0x04);
400ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x0c, 0x35);
401ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x0d, 0x05);
402ab6df5bcSAlex Hornung 	TMS_WRITE(sc, 0x0e, 0x05);
403ab6df5bcSAlex Hornung 
404ab6df5bcSAlex Hornung 	TMS_WRITE(sc, SIO_TMSCFG, 0x00);
405ab6df5bcSAlex Hornung 
406ab6df5bcSAlex Hornung 	/* Enable the sensors */
407ab6df5bcSAlex Hornung 	for (i = 0; i < 3; i++) {
408ab6df5bcSAlex Hornung 		TMS_WRITE(sc, SIO_TMSBS, i);
409ab6df5bcSAlex Hornung 		TMS_WRITE(sc, SIO_TCHCFST, 0x01);
410ab6df5bcSAlex Hornung 
411ab6df5bcSAlex Hornung 		sc->sensors[i].type = SENSOR_TEMP;
412ab6df5bcSAlex Hornung 	}
413ab6df5bcSAlex Hornung 
414ab6df5bcSAlex Hornung 	strlcpy(sc->sensors[0].desc, "Remote", sizeof(sc->sensors[0].desc));
415ab6df5bcSAlex Hornung 	strlcpy(sc->sensors[1].desc, "Remote", sizeof(sc->sensors[1].desc));
416ab6df5bcSAlex Hornung 	strlcpy(sc->sensors[2].desc, "Local", sizeof(sc->sensors[2].desc));
417ab6df5bcSAlex Hornung 
418ab6df5bcSAlex Hornung 	nsclpcsio_tms_update(sc);
419ab6df5bcSAlex Hornung }
420ab6df5bcSAlex Hornung 
421ab6df5bcSAlex Hornung void
nsclpcsio_tms_update(struct nsclpcsio_softc * sc)422ab6df5bcSAlex Hornung nsclpcsio_tms_update(struct nsclpcsio_softc *sc)
423ab6df5bcSAlex Hornung {
424ab6df5bcSAlex Hornung 	u_int8_t status;
425ab6df5bcSAlex Hornung 	int8_t sdata;
426ab6df5bcSAlex Hornung 	int i;
427ab6df5bcSAlex Hornung 
428ab6df5bcSAlex Hornung 	for (i = 0; i < 3; i++) {
429ab6df5bcSAlex Hornung 		TMS_WRITE(sc, SIO_TMSBS, i);
430ab6df5bcSAlex Hornung 		status = TMS_READ(sc, SIO_TCHCFST);
431ab6df5bcSAlex Hornung 		if (!(status & 0x01)) {
432ab6df5bcSAlex Hornung 			DPRINTF(("%s: status %d: disabled\n",
433ab6df5bcSAlex Hornung 			    sc->sensors[i].desc, status));
434ab6df5bcSAlex Hornung 			sc->sensors[i].value = 0;
435ab6df5bcSAlex Hornung 			continue;
436ab6df5bcSAlex Hornung 		}
437ab6df5bcSAlex Hornung 		sdata = TMS_READ(sc, SIO_RDCHT);
438ab6df5bcSAlex Hornung 		DPRINTF(("%s: status %d C %d\n", sc->sensors[i].desc,
439ab6df5bcSAlex Hornung 		    status, sdata));
440ab6df5bcSAlex Hornung 		sc->sensors[i].value = sdata * 1000000 + 273150000;
441ab6df5bcSAlex Hornung 	}
442ab6df5bcSAlex Hornung }
443ab6df5bcSAlex Hornung 
444ab6df5bcSAlex Hornung void
nsclpcsio_vlm_init(struct nsclpcsio_softc * sc)445ab6df5bcSAlex Hornung nsclpcsio_vlm_init(struct nsclpcsio_softc *sc)
446ab6df5bcSAlex Hornung {
447ab6df5bcSAlex Hornung 	int i;
448ab6df5bcSAlex Hornung 	char *desc = NULL;
449ab6df5bcSAlex Hornung 
450ab6df5bcSAlex Hornung 	VLM_WRITE(sc, SIO_VLMCFG, 0x00);
451ab6df5bcSAlex Hornung 
452ab6df5bcSAlex Hornung 	/* Enable the sensors */
453ab6df5bcSAlex Hornung 	for (i = 0; i < 14; i++) {
454ab6df5bcSAlex Hornung 		VLM_WRITE(sc, SIO_VLMBS, i);
455ab6df5bcSAlex Hornung 		VLM_WRITE(sc, SIO_VCHCFST, 0x01);
456ab6df5bcSAlex Hornung 
457ab6df5bcSAlex Hornung 		desc = NULL;
458ab6df5bcSAlex Hornung 		switch (i) {
459ab6df5bcSAlex Hornung 		case 7:
460ab6df5bcSAlex Hornung 			desc = "VSB";
461ab6df5bcSAlex Hornung 			break;
462ab6df5bcSAlex Hornung 		case 8:
463ab6df5bcSAlex Hornung 			desc = "VDD";
464ab6df5bcSAlex Hornung 			break;
465ab6df5bcSAlex Hornung 		case 9:
466ab6df5bcSAlex Hornung 			desc = "VBAT";
467ab6df5bcSAlex Hornung 			break;
468ab6df5bcSAlex Hornung 		case 10:
469ab6df5bcSAlex Hornung 			desc = "AVDD";
470ab6df5bcSAlex Hornung 			break;
471ab6df5bcSAlex Hornung 		case 11:
472ab6df5bcSAlex Hornung 			desc = "TS1";
473ab6df5bcSAlex Hornung 			break;
474ab6df5bcSAlex Hornung 		case 12:
475ab6df5bcSAlex Hornung 			desc = "TS2";
476ab6df5bcSAlex Hornung 			break;
477ab6df5bcSAlex Hornung 		case 13:
478ab6df5bcSAlex Hornung 			desc = "TS3";
479ab6df5bcSAlex Hornung 			break;
480ab6df5bcSAlex Hornung 		}
481ab6df5bcSAlex Hornung 		/* only init .desc if we have something meaningful to say */
482ab6df5bcSAlex Hornung 		if (desc != NULL)
483ab6df5bcSAlex Hornung 			strlcpy(sc->sensors[SIO_VLM_OFF + i].desc, desc,
484ab6df5bcSAlex Hornung 			    sizeof(sc->sensors[SIO_VLM_OFF + i].desc));
485ab6df5bcSAlex Hornung 		sc->sensors[SIO_VLM_OFF + i].type = SENSOR_VOLTS_DC;
486ab6df5bcSAlex Hornung 
487ab6df5bcSAlex Hornung 	}
488ab6df5bcSAlex Hornung 	nsclpcsio_vlm_update(sc);
489ab6df5bcSAlex Hornung }
490ab6df5bcSAlex Hornung 
491ab6df5bcSAlex Hornung void
nsclpcsio_vlm_update(struct nsclpcsio_softc * sc)492ab6df5bcSAlex Hornung nsclpcsio_vlm_update(struct nsclpcsio_softc *sc)
493ab6df5bcSAlex Hornung {
494ab6df5bcSAlex Hornung 	u_int8_t status;
495ab6df5bcSAlex Hornung 	u_int8_t data;
496ab6df5bcSAlex Hornung 	int scale, rfact, i;
497ab6df5bcSAlex Hornung 
498ab6df5bcSAlex Hornung 	for (i = 0; i < 14; i++) {
499ab6df5bcSAlex Hornung 		VLM_WRITE(sc, SIO_VLMBS, i);
500ab6df5bcSAlex Hornung 		status = VLM_READ(sc, SIO_VCHCFST);
501ab6df5bcSAlex Hornung 		if (!(status & 0x01)) {
502ab6df5bcSAlex Hornung 			DPRINTF(("%s: status %d: disabled\n",
503ab6df5bcSAlex Hornung 			    sc->sensors[SIO_VLM_OFF + i].desc, status));
504ab6df5bcSAlex Hornung 			sc->sensors[SIO_VLM_OFF + i].value = 0;
505ab6df5bcSAlex Hornung 			continue;
506ab6df5bcSAlex Hornung 		}
507ab6df5bcSAlex Hornung 		data = VLM_READ(sc, SIO_RDCHV);
508ab6df5bcSAlex Hornung 		DPRINTF(("%s: status %d V %d\n",
509ab6df5bcSAlex Hornung 		    sc->sensors[SIO_VLM_OFF + i].desc, status, data));
510ab6df5bcSAlex Hornung 
511ab6df5bcSAlex Hornung 		scale = 1;
512ab6df5bcSAlex Hornung 		switch (i) {
513ab6df5bcSAlex Hornung 		case 7:
514ab6df5bcSAlex Hornung 		case 8:
515ab6df5bcSAlex Hornung 		case 10:
516ab6df5bcSAlex Hornung 			scale = 2;
517ab6df5bcSAlex Hornung 		}
518ab6df5bcSAlex Hornung 
519*5c0a8865Szrj 		/* Vi = (2.45 +/- 0.05)*VREF *RDCHVi / 256 */
520ab6df5bcSAlex Hornung 		rfact = 10 * scale * ((245 * SIO_VREF) >> 8);
521ab6df5bcSAlex Hornung 		sc->sensors[SIO_VLM_OFF + i].value = data * rfact;
522ab6df5bcSAlex Hornung 	}
523ab6df5bcSAlex Hornung }
524ab6df5bcSAlex Hornung 
525c8cb1400SAlex Hornung #if NGPIO > 0
526ab6df5bcSAlex Hornung static __inline void
nsclpcsio_gpio_pin_select(struct nsclpcsio_softc * sc,int pin)527ab6df5bcSAlex Hornung nsclpcsio_gpio_pin_select(struct nsclpcsio_softc *sc, int pin)
528ab6df5bcSAlex Hornung {
529ab6df5bcSAlex Hornung 	int port, shift;
530ab6df5bcSAlex Hornung 	u_int8_t data;
531ab6df5bcSAlex Hornung 
532ab6df5bcSAlex Hornung 	port = pin / 8;
533ab6df5bcSAlex Hornung 	shift = pin % 8;
534ab6df5bcSAlex Hornung 	data = (port << 4) | shift;
535ab6df5bcSAlex Hornung 
536ab6df5bcSAlex Hornung 	nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO);
537ab6df5bcSAlex Hornung 	nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINSEL, data);
538ab6df5bcSAlex Hornung }
539ab6df5bcSAlex Hornung 
540ab6df5bcSAlex Hornung void
nsclpcsio_gpio_init(struct nsclpcsio_softc * sc)541ab6df5bcSAlex Hornung nsclpcsio_gpio_init(struct nsclpcsio_softc *sc)
542ab6df5bcSAlex Hornung {
543ab6df5bcSAlex Hornung 	int i;
544ab6df5bcSAlex Hornung 
545ab6df5bcSAlex Hornung 	for (i = 0; i < SIO_GPIO_NPINS; i++) {
546ab6df5bcSAlex Hornung 		sc->sc_gpio_pins[i].pin_num = i;
547ab6df5bcSAlex Hornung 		sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT |
548ab6df5bcSAlex Hornung 		    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN |
549ab6df5bcSAlex Hornung 		    GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE |
550ab6df5bcSAlex Hornung 		    GPIO_PIN_PULLUP;
551ab6df5bcSAlex Hornung 
552ab6df5bcSAlex Hornung 		/* Read initial state */
553ab6df5bcSAlex Hornung 		sc->sc_gpio_pins[i].pin_state = nsclpcsio_gpio_pin_read(sc,
554ab6df5bcSAlex Hornung 		    i) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
555ab6df5bcSAlex Hornung 	}
556ab6df5bcSAlex Hornung }
557ab6df5bcSAlex Hornung 
558ab6df5bcSAlex Hornung int
nsclpcsio_gpio_pin_read(void * arg,int pin)559ab6df5bcSAlex Hornung nsclpcsio_gpio_pin_read(void *arg, int pin)
560ab6df5bcSAlex Hornung {
561ab6df5bcSAlex Hornung 	struct nsclpcsio_softc *sc = arg;
562ab6df5bcSAlex Hornung 	int port, shift, reg;
563ab6df5bcSAlex Hornung 	u_int8_t data;
564ab6df5bcSAlex Hornung 
565ab6df5bcSAlex Hornung 	port = pin / 8;
566ab6df5bcSAlex Hornung 	shift = pin % 8;
567ab6df5bcSAlex Hornung 
568ab6df5bcSAlex Hornung 	switch (port) {
569ab6df5bcSAlex Hornung 	case 0:
570ab6df5bcSAlex Hornung 		reg = SIO_GPDI0;
571ab6df5bcSAlex Hornung 		break;
572ab6df5bcSAlex Hornung 	case 1:
573ab6df5bcSAlex Hornung 		reg = SIO_GPDI1;
574ab6df5bcSAlex Hornung 		break;
575ab6df5bcSAlex Hornung 	case 2:
576ab6df5bcSAlex Hornung 		reg = SIO_GPDI2;
577ab6df5bcSAlex Hornung 		break;
578ab6df5bcSAlex Hornung 	case 3:
579ab6df5bcSAlex Hornung 		reg = SIO_GPDI3;
580ab6df5bcSAlex Hornung 		break;
581c8cb1400SAlex Hornung 	default:
582c8cb1400SAlex Hornung 		return 0;
583ab6df5bcSAlex Hornung 	}
584ab6df5bcSAlex Hornung 
585ab6df5bcSAlex Hornung 	data = GPIO_READ(sc, reg);
586ab6df5bcSAlex Hornung 
587ab6df5bcSAlex Hornung 	return ((data >> shift) & 0x1);
588ab6df5bcSAlex Hornung }
589ab6df5bcSAlex Hornung 
590ab6df5bcSAlex Hornung void
nsclpcsio_gpio_pin_write(void * arg,int pin,int value)591ab6df5bcSAlex Hornung nsclpcsio_gpio_pin_write(void *arg, int pin, int value)
592ab6df5bcSAlex Hornung {
593ab6df5bcSAlex Hornung 	struct nsclpcsio_softc *sc = arg;
594ab6df5bcSAlex Hornung 	int port, shift, reg;
595ab6df5bcSAlex Hornung 	u_int8_t data;
596ab6df5bcSAlex Hornung 
597ab6df5bcSAlex Hornung 	port = pin / 8;
598ab6df5bcSAlex Hornung 	shift = pin % 8;
599ab6df5bcSAlex Hornung 
600ab6df5bcSAlex Hornung 	switch (port) {
601ab6df5bcSAlex Hornung 	case 0:
602ab6df5bcSAlex Hornung 		reg = SIO_GPDO0;
603ab6df5bcSAlex Hornung 		break;
604ab6df5bcSAlex Hornung 	case 1:
605ab6df5bcSAlex Hornung 		reg = SIO_GPDO1;
606ab6df5bcSAlex Hornung 		break;
607ab6df5bcSAlex Hornung 	case 2:
608ab6df5bcSAlex Hornung 		reg = SIO_GPDO2;
609ab6df5bcSAlex Hornung 		break;
610ab6df5bcSAlex Hornung 	case 3:
611ab6df5bcSAlex Hornung 		reg = SIO_GPDO3;
612ab6df5bcSAlex Hornung 		break;
613c8cb1400SAlex Hornung 	default:
614c8cb1400SAlex Hornung 		return;
615ab6df5bcSAlex Hornung 	}
616ab6df5bcSAlex Hornung 
617ab6df5bcSAlex Hornung 	data = GPIO_READ(sc, reg);
618ab6df5bcSAlex Hornung 	if (value == 0)
619ab6df5bcSAlex Hornung 		data &= ~(1 << shift);
620ab6df5bcSAlex Hornung 	else if (value == 1)
621ab6df5bcSAlex Hornung 		data |= (1 << shift);
622ab6df5bcSAlex Hornung 
623ab6df5bcSAlex Hornung 	GPIO_WRITE(sc, reg, data);
624ab6df5bcSAlex Hornung }
625ab6df5bcSAlex Hornung 
626ab6df5bcSAlex Hornung void
nsclpcsio_gpio_pin_ctl(void * arg,int pin,int flags)627ab6df5bcSAlex Hornung nsclpcsio_gpio_pin_ctl(void *arg, int pin, int flags)
628ab6df5bcSAlex Hornung {
629ab6df5bcSAlex Hornung 	struct nsclpcsio_softc *sc = arg;
630ab6df5bcSAlex Hornung 	u_int8_t conf = 1;
631ab6df5bcSAlex Hornung 
632ab6df5bcSAlex Hornung 	nswrite(sc->sc_iot, sc->sc_ioh, SIO_REG_LDN, SIO_LDN_GPIO);
633ab6df5bcSAlex Hornung 	nsclpcsio_gpio_pin_select(sc, pin);
634ab6df5bcSAlex Hornung 	conf = nsread(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG);
635ab6df5bcSAlex Hornung 
636ab6df5bcSAlex Hornung 	conf &= ~(SIO_GPIO_CONF_OUTPUTEN | SIO_GPIO_CONF_PUSHPULL |
637ab6df5bcSAlex Hornung 	    SIO_GPIO_CONF_PULLUP);
638ab6df5bcSAlex Hornung 	if ((flags & GPIO_PIN_TRISTATE) == 0)
639ab6df5bcSAlex Hornung 		conf |= SIO_GPIO_CONF_OUTPUTEN;
640ab6df5bcSAlex Hornung 	if (flags & GPIO_PIN_PUSHPULL)
641ab6df5bcSAlex Hornung 		conf |= SIO_GPIO_CONF_PUSHPULL;
642ab6df5bcSAlex Hornung 	if (flags & GPIO_PIN_PULLUP)
643ab6df5bcSAlex Hornung 		conf |= SIO_GPIO_CONF_PULLUP;
644ab6df5bcSAlex Hornung 
645ab6df5bcSAlex Hornung 	nswrite(sc->sc_iot, sc->sc_ioh, SIO_GPIO_PINCFG, conf);
646ab6df5bcSAlex Hornung }
647c8cb1400SAlex Hornung #endif /* NGPIO */
648