xref: /onnv-gate/usr/src/uts/sun4u/io/gpio_87317.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/time.h>
31*0Sstevel@tonic-gate #include <sys/errno.h>
32*0Sstevel@tonic-gate #include <sys/cmn_err.h>
33*0Sstevel@tonic-gate #include <sys/param.h>
34*0Sstevel@tonic-gate #include <sys/modctl.h>
35*0Sstevel@tonic-gate #include <sys/conf.h>
36*0Sstevel@tonic-gate #include <sys/open.h>
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <sys/clock.h>
39*0Sstevel@tonic-gate #include <sys/gpio_87317.h>
40*0Sstevel@tonic-gate #include <sys/ddi.h>
41*0Sstevel@tonic-gate #include <sys/sunddi.h>
42*0Sstevel@tonic-gate #include <sys/file.h>
43*0Sstevel@tonic-gate #ifdef DEBUG
44*0Sstevel@tonic-gate #include <sys/promif.h>
45*0Sstevel@tonic-gate #endif
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /* a non zero value causes debug info to be displayed */
49*0Sstevel@tonic-gate uint_t gpio_debug_flag = 0;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #ifdef DEBUG
53*0Sstevel@tonic-gate static void gpio_debug(dev_info_t *dip, char *format, uint_t arg1, uint_t arg2,
54*0Sstevel@tonic-gate     uint_t arg3, uint_t arg4, uint_t arg5);
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #define	DBG(dip, format, arg1, arg2, arg3, arg4, arg5) \
57*0Sstevel@tonic-gate 	gpio_debug(dip, format, (uint_t)arg1, (uint_t)arg2, (uint_t)arg3, \
58*0Sstevel@tonic-gate 	    (uint_t)arg4, (uint_t)arg5)
59*0Sstevel@tonic-gate #else
60*0Sstevel@tonic-gate #define	DBG(dip, format, arg1, arg2, arg3, arg4, arg5)
61*0Sstevel@tonic-gate #endif
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /* Driver soft state structure */
65*0Sstevel@tonic-gate struct gpio_softc {
66*0Sstevel@tonic-gate 	dev_info_t		*gp_dip;
67*0Sstevel@tonic-gate 	kmutex_t		gp_mutex;
68*0Sstevel@tonic-gate 	int			gp_state;
69*0Sstevel@tonic-gate 	ddi_acc_handle_t	gp_handle;
70*0Sstevel@tonic-gate 	uint8_t			*gp_regs;
71*0Sstevel@tonic-gate };
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate #define	getsoftc(minor)	\
74*0Sstevel@tonic-gate 	((struct gpio_softc *)ddi_get_soft_state(statep, (minor)))
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate /* dev_ops and cb_ops entry point function declarations */
77*0Sstevel@tonic-gate static int gpio_attach(dev_info_t *, ddi_attach_cmd_t);
78*0Sstevel@tonic-gate static int gpio_detach(dev_info_t *, ddi_detach_cmd_t);
79*0Sstevel@tonic-gate static int gpio_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
80*0Sstevel@tonic-gate static int gpio_open(dev_t *, int, int, cred_t *);
81*0Sstevel@tonic-gate static int gpio_close(dev_t, int, int, cred_t *);
82*0Sstevel@tonic-gate static int gpio_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate struct cb_ops gpio_cb_ops = {
85*0Sstevel@tonic-gate 	gpio_open,
86*0Sstevel@tonic-gate 	gpio_close,
87*0Sstevel@tonic-gate 	nodev,
88*0Sstevel@tonic-gate 	nodev,
89*0Sstevel@tonic-gate 	nodev,			/* dump */
90*0Sstevel@tonic-gate 	nodev,
91*0Sstevel@tonic-gate 	nodev,
92*0Sstevel@tonic-gate 	gpio_ioctl,
93*0Sstevel@tonic-gate 	nodev,			/* devmap */
94*0Sstevel@tonic-gate 	nodev,
95*0Sstevel@tonic-gate 	nodev,
96*0Sstevel@tonic-gate 	nochpoll,
97*0Sstevel@tonic-gate 	ddi_prop_op,
98*0Sstevel@tonic-gate 	NULL,			/* for STREAMS drivers */
99*0Sstevel@tonic-gate 	D_NEW | D_MP,		/* driver compatibility flag */
100*0Sstevel@tonic-gate 	CB_REV,
101*0Sstevel@tonic-gate 	nodev,
102*0Sstevel@tonic-gate 	nodev
103*0Sstevel@tonic-gate };
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate static struct dev_ops gpio_dev_ops = {
106*0Sstevel@tonic-gate 	DEVO_REV,			/* driver build version */
107*0Sstevel@tonic-gate 	0,				/* device reference count */
108*0Sstevel@tonic-gate 	gpio_getinfo,
109*0Sstevel@tonic-gate 	nulldev,
110*0Sstevel@tonic-gate 	nulldev,			/* probe */
111*0Sstevel@tonic-gate 	gpio_attach,
112*0Sstevel@tonic-gate 	gpio_detach,
113*0Sstevel@tonic-gate 	nulldev,			/* reset */
114*0Sstevel@tonic-gate 	&gpio_cb_ops,
115*0Sstevel@tonic-gate 	(struct bus_ops *)NULL,
116*0Sstevel@tonic-gate 	nulldev				/* power */
117*0Sstevel@tonic-gate };
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /* module configuration stuff */
120*0Sstevel@tonic-gate static void *statep;
121*0Sstevel@tonic-gate extern struct mod_ops mod_driverops;
122*0Sstevel@tonic-gate static struct modldrv modldrv = {
123*0Sstevel@tonic-gate 	&mod_driverops,
124*0Sstevel@tonic-gate 	"gpio driver 1.0",
125*0Sstevel@tonic-gate 	&gpio_dev_ops
126*0Sstevel@tonic-gate };
127*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
128*0Sstevel@tonic-gate 	MODREV_1,
129*0Sstevel@tonic-gate 	&modldrv,
130*0Sstevel@tonic-gate 	0
131*0Sstevel@tonic-gate };
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate int
135*0Sstevel@tonic-gate _init(void)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	int e;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	if (e = ddi_soft_state_init(&statep, sizeof (struct gpio_softc), 1)) {
140*0Sstevel@tonic-gate 		return (e);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0) {
143*0Sstevel@tonic-gate 		ddi_soft_state_fini(&statep);
144*0Sstevel@tonic-gate 	}
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	return (e);
147*0Sstevel@tonic-gate }
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate int
151*0Sstevel@tonic-gate _fini(void)
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate 	int e;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0) {
156*0Sstevel@tonic-gate 		return (e);
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 	ddi_soft_state_fini(&statep);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate int
165*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
168*0Sstevel@tonic-gate }
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate /* ARGSUSED */
172*0Sstevel@tonic-gate static int
173*0Sstevel@tonic-gate gpio_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	int instance = getminor((dev_t)arg);
176*0Sstevel@tonic-gate 	int retval = DDI_SUCCESS;
177*0Sstevel@tonic-gate 	struct gpio_softc *softc;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	switch (cmd) {
180*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
181*0Sstevel@tonic-gate 		if ((softc = getsoftc(instance)) == NULL) {
182*0Sstevel@tonic-gate 			*result = (void *)NULL;
183*0Sstevel@tonic-gate 			retval = DDI_FAILURE;
184*0Sstevel@tonic-gate 		} else
185*0Sstevel@tonic-gate 		*result = (void *)softc->gp_dip;
186*0Sstevel@tonic-gate 		break;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
189*0Sstevel@tonic-gate 		*result = (void *)instance;
190*0Sstevel@tonic-gate 		break;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	default:
193*0Sstevel@tonic-gate 		retval = DDI_FAILURE;
194*0Sstevel@tonic-gate 	}
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	return (retval);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate static int
201*0Sstevel@tonic-gate gpio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	int instance;
205*0Sstevel@tonic-gate 	struct gpio_softc *softc = NULL;
206*0Sstevel@tonic-gate 	ddi_device_acc_attr_t dev_attr;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	switch (cmd) {
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	case DDI_ATTACH:
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	    /* Allocate and get the soft state structure for this instance. */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	    instance = ddi_get_instance(dip);
215*0Sstevel@tonic-gate 	    DBG(dip, "attach: instance is %d", instance, 0, 0, 0, 0);
216*0Sstevel@tonic-gate 	    if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS)
217*0Sstevel@tonic-gate 		goto attach_failed;
218*0Sstevel@tonic-gate 	    softc = getsoftc(instance);
219*0Sstevel@tonic-gate 	    softc->gp_dip = dip;
220*0Sstevel@tonic-gate 	    softc->gp_state = 0;
221*0Sstevel@tonic-gate 	    mutex_init(&softc->gp_mutex, NULL, MUTEX_DRIVER, NULL);
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	    /* Map in the gpio device registers. */
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	    dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
226*0Sstevel@tonic-gate 	    dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
227*0Sstevel@tonic-gate 	    dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
228*0Sstevel@tonic-gate 	    if (ddi_regs_map_setup(dip, 0, (caddr_t *)&softc->gp_regs, 0, 0,
229*0Sstevel@tonic-gate 		    &dev_attr, &softc->gp_handle) != DDI_SUCCESS)
230*0Sstevel@tonic-gate 		goto attach_failed;
231*0Sstevel@tonic-gate 	    DBG(dip, "attach: regs=0x%x", softc->gp_regs, 0, 0, 0, 0);
232*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 1 data is %x",
233*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[0]), 0, 0, 0, 0);
234*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 1 direction is %x",
235*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[1]), 0, 0, 0, 0);
236*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 1 output type is %x",
237*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[2]), 0, 0, 0, 0);
238*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 1 pull up control type is %x",
239*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[3]), 0, 0, 0, 0);
240*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 2 data is %x",
241*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[4]), 0, 0, 0, 0);
242*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 2 direction is %x",
243*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[5]), 0, 0, 0, 0);
244*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 2 output type is %x",
245*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[6]), 0, 0, 0, 0);
246*0Sstevel@tonic-gate 	    DBG(dip, "attach: port 2 pull up control type is %x",
247*0Sstevel@tonic-gate 		ddi_get8(softc->gp_handle, &softc->gp_regs[7]), 0, 0, 0, 0);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	    /* Create device minor nodes. */
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	    if (ddi_create_minor_node(dip, "gpio", S_IFCHR,
252*0Sstevel@tonic-gate 		instance, NULL, NULL) == DDI_FAILURE) {
253*0Sstevel@tonic-gate 		ddi_regs_map_free(&softc->gp_handle);
254*0Sstevel@tonic-gate 		goto attach_failed;
255*0Sstevel@tonic-gate 	    }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	    ddi_report_dev(dip);
258*0Sstevel@tonic-gate 	    return (DDI_SUCCESS);
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	case DDI_RESUME:
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	    /* Nothing to do for a resume. */
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	    return (DDI_SUCCESS);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	default:
267*0Sstevel@tonic-gate 	    return (DDI_FAILURE);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate attach_failed:
271*0Sstevel@tonic-gate 	if (softc) {
272*0Sstevel@tonic-gate 	    mutex_destroy(&softc->gp_mutex);
273*0Sstevel@tonic-gate 	    if (softc->gp_handle)
274*0Sstevel@tonic-gate 		ddi_regs_map_free(&softc->gp_handle);
275*0Sstevel@tonic-gate 	    ddi_soft_state_free(statep, instance);
276*0Sstevel@tonic-gate 	    ddi_remove_minor_node(dip, NULL);
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 	return (DDI_FAILURE);
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate static int
283*0Sstevel@tonic-gate gpio_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	int instance;
286*0Sstevel@tonic-gate 	struct gpio_softc *softc;
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	switch (cmd) {
289*0Sstevel@tonic-gate 	case DDI_DETACH:
290*0Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
291*0Sstevel@tonic-gate 		DBG(dip, "detach: instance is %d", instance, 0, 0, 0, 0);
292*0Sstevel@tonic-gate 		if ((softc = getsoftc(instance)) == NULL)
293*0Sstevel@tonic-gate 			return (ENXIO);
294*0Sstevel@tonic-gate 		mutex_destroy(&softc->gp_mutex);
295*0Sstevel@tonic-gate 		ddi_regs_map_free(&softc->gp_handle);
296*0Sstevel@tonic-gate 		ddi_soft_state_free(statep, instance);
297*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
298*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	case DDI_SUSPEND:
301*0Sstevel@tonic-gate 		/* Nothing to do in the suspend case. */
302*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	default:
305*0Sstevel@tonic-gate 		return (DDI_FAILURE);
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate /* ARGSUSED */
311*0Sstevel@tonic-gate static int
312*0Sstevel@tonic-gate gpio_open(dev_t *devp, int flag, int otyp, cred_t *credp)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	int instance = getminor(*devp);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	DBG(NULL, "open: instance is %d", instance, 0, 0, 0, 0);
317*0Sstevel@tonic-gate 	return (getsoftc(instance) == NULL ? ENXIO : 0);
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate /* ARGSUSED */
322*0Sstevel@tonic-gate static int
323*0Sstevel@tonic-gate gpio_close(dev_t dev, int flag, int otyp, cred_t *credp)
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	int instance = getminor(dev);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	DBG(NULL, "close: instance is %d", instance, 0, 0, 0, 0);
328*0Sstevel@tonic-gate 	return (getsoftc(instance) == NULL ? ENXIO : 0);
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate /* ARGSUSED */
333*0Sstevel@tonic-gate static int
334*0Sstevel@tonic-gate gpio_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
335*0Sstevel@tonic-gate 	int *rvalp)
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	int instance = getminor(dev);
338*0Sstevel@tonic-gate 	struct gpio_softc *softc = getsoftc(instance);
339*0Sstevel@tonic-gate 	gpio_87317_op_t info;
340*0Sstevel@tonic-gate 	uint8_t byte;
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	DBG(softc->gp_dip, "ioctl: instance is %d", instance, 0, 0, 0, 0);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	if (softc == NULL)
345*0Sstevel@tonic-gate 		return (ENXIO);
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	/* Copy the command from user space. */
348*0Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, (caddr_t)&info, sizeof (gpio_87317_op_t),
349*0Sstevel@tonic-gate 	    mode) != 0)
350*0Sstevel@tonic-gate 		return (EFAULT);
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	/* Check the command arguments.  We only support port 1 in bank 0. */
353*0Sstevel@tonic-gate 	if ((info.gpio_bank != 0) ||
354*0Sstevel@tonic-gate 	    (info.gpio_offset != GPIO_87317_PORT1_DATA)) {
355*0Sstevel@tonic-gate 		return (EINVAL);
356*0Sstevel@tonic-gate 	}
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	/* Grap the instance's mutex to insure exclusive access. */
359*0Sstevel@tonic-gate 	mutex_enter(&softc->gp_mutex);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	/* Get the contents of the GPIO register we're suppose to modify. */
362*0Sstevel@tonic-gate 	byte = ddi_get8(softc->gp_handle, &softc->gp_regs[info.gpio_offset]);
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	switch (cmd) {
365*0Sstevel@tonic-gate 	case GPIO_CMD_SET_BITS:
366*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
367*0Sstevel@tonic-gate 		    0, 0);
368*0Sstevel@tonic-gate 		byte |= info.gpio_data;
369*0Sstevel@tonic-gate 		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
370*0Sstevel@tonic-gate 		    byte);
371*0Sstevel@tonic-gate 		byte = ddi_get8(softc->gp_handle,
372*0Sstevel@tonic-gate 		    &softc->gp_regs[info.gpio_offset]);
373*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
374*0Sstevel@tonic-gate 		    0, 0);
375*0Sstevel@tonic-gate 		break;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	case GPIO_CMD_CLR_BITS:
378*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
379*0Sstevel@tonic-gate 		    0, 0);
380*0Sstevel@tonic-gate 		byte &= ~info.gpio_data;
381*0Sstevel@tonic-gate 		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
382*0Sstevel@tonic-gate 		    byte);
383*0Sstevel@tonic-gate 		byte = ddi_get8(softc->gp_handle,
384*0Sstevel@tonic-gate 		    &softc->gp_regs[info.gpio_offset]);
385*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
386*0Sstevel@tonic-gate 		    0, 0);
387*0Sstevel@tonic-gate 		break;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	case GPIO_CMD_GET:
390*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: GPIO_CMD_GET", 0, 0, 0, 0, 0);
391*0Sstevel@tonic-gate 		info.gpio_data = byte;
392*0Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&info, (caddr_t)arg,
393*0Sstevel@tonic-gate 		    sizeof (gpio_87317_op_t), mode) != 0) {
394*0Sstevel@tonic-gate 			mutex_exit(&softc->gp_mutex);
395*0Sstevel@tonic-gate 			return (EFAULT);
396*0Sstevel@tonic-gate 		}
397*0Sstevel@tonic-gate 		break;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	case GPIO_CMD_SET:
400*0Sstevel@tonic-gate 		DBG(softc->gp_dip, "ioctl: GPIO_CMD_SET", 0, 0, 0, 0, 0);
401*0Sstevel@tonic-gate 		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
402*0Sstevel@tonic-gate 		    info.gpio_data);
403*0Sstevel@tonic-gate 		break;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	default:
406*0Sstevel@tonic-gate 		mutex_exit(&softc->gp_mutex);
407*0Sstevel@tonic-gate 		return (EINVAL);
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	mutex_exit(&softc->gp_mutex);
411*0Sstevel@tonic-gate 	return (0);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate #ifdef DEBUG
416*0Sstevel@tonic-gate void
417*0Sstevel@tonic-gate gpio_debug(dev_info_t *dip, char *format, uint_t arg1, uint_t arg2, uint_t arg3,
418*0Sstevel@tonic-gate 	uint_t arg4, uint_t arg5)
419*0Sstevel@tonic-gate {
420*0Sstevel@tonic-gate 	if (gpio_debug_flag == 0) {
421*0Sstevel@tonic-gate 		return;
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	if (dip == NULL) {
425*0Sstevel@tonic-gate 		prom_printf("gpio: ");
426*0Sstevel@tonic-gate 	} else {
427*0Sstevel@tonic-gate 		prom_printf("%s%d: ", ddi_driver_name(dip),
428*0Sstevel@tonic-gate 			ddi_get_instance(dip));
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 	prom_printf(format, arg1, arg2, arg3, arg4, arg5);
431*0Sstevel@tonic-gate 	prom_printf("\n");
432*0Sstevel@tonic-gate }
433*0Sstevel@tonic-gate #endif
434