xref: /illumos-gate/usr/src/uts/sun4u/io/i2c/clients/pca9556.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/stat.h>
30 #include <sys/file.h>
31 #include <sys/uio.h>
32 #include <sys/modctl.h>
33 #include <sys/open.h>
34 #include <sys/types.h>
35 #include <sys/kmem.h>
36 #include <sys/systm.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/conf.h>
40 #include <sys/mode.h>
41 #include <sys/note.h>
42 #include <sys/i2c/clients/i2c_gpio.h>
43 #include <sys/i2c/clients/pca9556_impl.h>
44 
45 /*
46  * The PCA9556 is a gpio chip with 8 I/O ports.  The ports may be controlled by
47  * an 8 bit input  port register, 8 bit output port register, 8 bit polarity
48  * inversion register and an 8 bit configuration register.
49  *
50  * The input port register is a read only port and writes to this register
51  * will have no effect regardless of whether the pin is an input or output.
52  *
53  * The output port register reflects the outgoing logic levels of the pins
54  * defined as outputs by the configuration register.  Bit values in this
55  * register have no effect on pins defined as inputs.
56  *
57  * The polarity register enables polarity inversion of pins defined as inputs by
58  * the configuration register.  A set bit inverts the corresponding port's
59  * polarity.
60  *
61  * The configuration register configures the directions of the I/O pins.  If a
62  * bit is set the corresponding port is enabled as an input and if cleared,
63  * as an output.
64  *
65  * The commands supported in the ioctl routine are:
66  * GPIO_GET_INPUT	-- Read bits in the input port register.
67  * GPIO_GET_OUTPUT	-- Read bits in the output port register.
68  * GPIO_SET_OUPUT	-- Modify bits in the output port register.
69  * GPIO_GET_POLARITY    -- Read bits in the polarity register.
70  * GPIO_SET_POLARITY    -- Modify bits in the polarity register.
71  * GPIO_GET_CONFIG	-- Read bits in the configuration register.
72  * GPIO_SET_CONFIG	-- Modify bits in the configuration register.
73  *
74  * A pointer to the i2c_gpio_t data structure is sent as the third argument
75  * in the ioctl call.  The reg_mask member identifies the bits that the user
76  * wants to read or modify and reg_val has the actual value of the
77  * corresponding bits set in reg_mask.
78  *
79  * To read a whole register the user has to set all the  bits in reg_mask
80  * and the values will be copied into reg_val.
81  *
82  * In addition the pca9555 device has been added to this driver.  It is similar
83  * to the pca9556 except that it has 2 8 bit I/O ports.
84  */
85 
86 /*
87  * cb ops
88  */
89 static int pca9556_open(dev_t *, int, int, cred_t *);
90 static int pca9556_close(dev_t, int, int, cred_t *);
91 static int pca9556_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
92 
93 /*
94  * dev ops
95  */
96 static int pca9556_s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
97 static int pca9556_s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
98 static int pca9556_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
99 
100 static struct cb_ops pca9556_cb_ops = {
101 	pca9556_open,			/* open */
102 	pca9556_close,			/* close */
103 	nodev,				/* strategy */
104 	nodev,				/* print */
105 	nodev,				/* dump */
106 	nodev,				/* read */
107 	nodev,				/* write */
108 	pca9556_ioctl,			/* ioctl */
109 	nodev,				/* devmap */
110 	nodev,				/* mmap */
111 	nodev,				/* segmap */
112 	nochpoll,			/* poll */
113 	ddi_prop_op,			/* cb_prop_op */
114 	NULL,				/* streamtab */
115 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
116 };
117 
118 static struct dev_ops pca9556_dev_ops = {
119 	DEVO_REV,
120 	0,
121 	pca9556_info,
122 	nulldev,
123 	nulldev,
124 	pca9556_s_attach,
125 	pca9556_s_detach,
126 	nodev,
127 	&pca9556_cb_ops,
128 	NULL
129 };
130 
131 static struct modldrv pca9556_modldrv = {
132 	&mod_driverops,		/* type of module - driver */
133 	"pca9556 device driver v%I%",
134 	&pca9556_dev_ops,
135 };
136 
137 static struct modlinkage pca9556_modlinkage = {
138 	MODREV_1,
139 	&pca9556_modldrv,
140 	0
141 };
142 
143 static void *pca9556_soft_statep;
144 int pca9556_debug;
145 
146 int
147 _init(void)
148 {
149 	int    err;
150 
151 	err = mod_install(&pca9556_modlinkage);
152 	if (err == 0) {
153 		(void) ddi_soft_state_init(&pca9556_soft_statep,
154 		    sizeof (pca9556_unit_t), PCA9556_MAX_SIZE);
155 	}
156 	return (err);
157 }
158 
159 int
160 _fini(void)
161 {
162 	int    err;
163 
164 	err = mod_remove(&pca9556_modlinkage);
165 	if (err == 0) {
166 		ddi_soft_state_fini(&pca9556_soft_statep);
167 	}
168 	return (err);
169 }
170 
171 int
172 _info(struct modinfo *modinfop)
173 {
174 	return (mod_info(&pca9556_modlinkage, modinfop));
175 }
176 
177 static int
178 pca9556_resume(dev_info_t *dip)
179 {
180 	int 		instance = ddi_get_instance(dip);
181 	pca9556_unit_t	*pcap;
182 	int 		err = DDI_SUCCESS;
183 	int		reg_offset, num_of_ports;
184 	int		i, j;
185 	uint8_t		reg, reg_num = 0;
186 
187 	pcap = (pca9556_unit_t *)
188 	    ddi_get_soft_state(pca9556_soft_statep, instance);
189 
190 	if (pcap == NULL)
191 		return (ENXIO);
192 
193 	/*
194 	 * Restore registers to status existing before cpr
195 	 */
196 	pcap->pca9556_transfer->i2c_flags = I2C_WR;
197 	pcap->pca9556_transfer->i2c_wlen = 2;
198 	pcap->pca9556_transfer->i2c_rlen = 0;
199 
200 	if (pcap->pca9555_device) {
201 		reg_offset = 2;
202 		num_of_ports = PCA9555_NUM_PORTS;
203 	} else {
204 		reg_offset = 1;
205 		num_of_ports = PCA9556_NUM_PORTS;
206 	}
207 
208 	for (i = 0; i < num_of_ports; i++) {
209 		if (pcap->pca9555_device)
210 			reg = PCA9555_OUTPUT_REG;
211 		else
212 			reg = PCA9556_OUTPUT_REG;
213 
214 		for (j = 0; j < PCA9556_NUM_REG; j++) {
215 			pcap->pca9556_transfer->i2c_wbuf[0] = reg + i;
216 			pcap->pca9556_transfer->i2c_wbuf[1] =
217 			    pcap->pca9556_cpr_state[reg_num++];
218 
219 			if (i2c_transfer(pcap->pca9556_hdl,
220 				pcap->pca9556_transfer) != DDI_SUCCESS) {
221 				err = EIO;
222 
223 				goto done;
224 			}
225 
226 			reg = reg + reg_offset;
227 		}
228 	}
229 
230 	/*
231 	 * Clear busy flag so that transactions may continue
232 	 */
233 done:
234 	if (err != DDI_SUCCESS) {
235 		cmn_err(CE_WARN, "%s Unable to restore registers",
236 		    pcap->pca9556_name);
237 	}
238 	mutex_enter(&pcap->pca9556_mutex);
239 	pcap->pca9556_flags = pcap->pca9556_flags & ~PCA9556_BUSYFLAG;
240 	cv_broadcast(&pcap->pca9556_cv);
241 	mutex_exit(&pcap->pca9556_mutex);
242 	return (err);
243 }
244 
245 static void
246 pca9556_detach(dev_info_t *dip)
247 {
248 	pca9556_unit_t *pcap;
249 	int 		instance = ddi_get_instance(dip);
250 
251 	pcap = ddi_get_soft_state(pca9556_soft_statep, instance);
252 
253 	if ((pcap->pca9556_flags & PCA9556_REGFLAG) == PCA9556_REGFLAG) {
254 		i2c_client_unregister(pcap->pca9556_hdl);
255 	}
256 	if ((pcap->pca9556_flags & PCA9556_TBUFFLAG) == PCA9556_TBUFFLAG) {
257 		i2c_transfer_free(pcap->pca9556_hdl, pcap->pca9556_transfer);
258 	}
259 	if ((pcap->pca9556_flags & PCA9556_MINORFLAG) == PCA9556_MINORFLAG) {
260 		ddi_remove_minor_node(dip, NULL);
261 	}
262 	cv_destroy(&pcap->pca9556_cv);
263 	mutex_destroy(&pcap->pca9556_mutex);
264 	ddi_soft_state_free(pca9556_soft_statep, instance);
265 
266 }
267 
268 static int
269 pca9556_attach(dev_info_t *dip)
270 {
271 	pca9556_unit_t 		*pcap;
272 	int 			instance = ddi_get_instance(dip);
273 	char			name[MAXNAMELEN];
274 	char *device_name;
275 	minor_t 		minor;
276 	int			i, num_ports;
277 
278 	if (ddi_soft_state_zalloc(pca9556_soft_statep, instance) != 0) {
279 		cmn_err(CE_WARN, "%s%d failed to zalloc softstate",
280 		    ddi_get_name(dip), instance);
281 		return (DDI_FAILURE);
282 	}
283 
284 	pcap = ddi_get_soft_state(pca9556_soft_statep, instance);
285 
286 	if (pcap == NULL)
287 		return (DDI_FAILURE);
288 
289 	mutex_init(&pcap->pca9556_mutex, NULL, MUTEX_DRIVER, NULL);
290 	cv_init(&pcap->pca9556_cv, NULL, CV_DRIVER, NULL);
291 
292 	(void) snprintf(pcap->pca9556_name, sizeof (pcap->pca9556_name),
293 	    "%s_%d", ddi_driver_name(dip), instance);
294 
295 	device_name = ddi_get_name(dip);
296 
297 	if (strcmp(device_name, "i2c-pca9555") == 0) {
298 		num_ports = PCA9555_NUM_PORTS;
299 		pcap->pca9555_device = B_TRUE;
300 	} else {
301 		num_ports = PCA9556_NUM_PORTS;
302 		pcap->pca9555_device = B_FALSE;
303 		minor = INST_TO_MINOR(instance);
304 	}
305 
306 	for (i = 0; i < num_ports; i++) {
307 		if (!(pcap->pca9555_device)) {
308 			(void) snprintf(pcap->pca9556_name,
309 			    sizeof (pcap->pca9556_name), "%s_%d",
310 			    ddi_driver_name(dip), instance);
311 			(void) snprintf(name, sizeof (name), "%s",
312 			    pcap->pca9556_name);
313 		} else {
314 			(void) sprintf(name, "port_%d", i);
315 			minor = INST_TO_MINOR(instance) |
316 			    PORT_TO_MINOR(I2C_PORT(i));
317 		}
318 
319 		if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
320 			PCA9556_NODE_TYPE, NULL) == DDI_FAILURE) {
321 			cmn_err(CE_WARN, "%s: failed to create node for %s",
322 			    pcap->pca9556_name, name);
323 			pca9556_detach(dip);
324 			return (DDI_FAILURE);
325 		}
326 	}
327 	pcap->pca9556_flags |= PCA9556_MINORFLAG;
328 
329 	/*
330 	 * Add a zero-length attribute to tell the world we support
331 	 * kernel ioctls (for layered drivers)
332 	 */
333 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
334 	    DDI_KERNEL_IOCTL, NULL, 0);
335 
336 
337 	/*
338 	 * preallocate a single buffer for all reads and writes
339 	 */
340 	if (i2c_transfer_alloc(pcap->pca9556_hdl, &pcap->pca9556_transfer,
341 	    2, 2, I2C_SLEEP) != I2C_SUCCESS) {
342 		cmn_err(CE_WARN, "%s i2c_transfer_alloc failed",
343 		    pcap->pca9556_name);
344 		pca9556_detach(dip);
345 		return (DDI_FAILURE);
346 	}
347 	pcap->pca9556_flags |= PCA9556_TBUFFLAG;
348 	pcap->pca9556_transfer->i2c_version = I2C_XFER_REV;
349 
350 	if (i2c_client_register(dip, &pcap->pca9556_hdl) != I2C_SUCCESS) {
351 		ddi_remove_minor_node(dip, NULL);
352 		cmn_err(CE_WARN, "%s i2c_client_register failed",
353 		    pcap->pca9556_name);
354 		pca9556_detach(dip);
355 		return (DDI_FAILURE);
356 	}
357 	pcap->pca9556_flags |= PCA9556_REGFLAG;
358 
359 	/*
360 	 * Store the dip for future dip.
361 	 */
362 	pcap->pca9556_dip = dip;
363 	return (DDI_SUCCESS);
364 }
365 
366 
367 static int
368 pca9556_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
369 {
370 	_NOTE(ARGUNUSED(dip))
371 
372 	pca9556_unit_t	*pcap;
373 	int		instance = MINOR_TO_INST(getminor((dev_t)arg));
374 
375 	switch (cmd) {
376 	case DDI_INFO_DEVT2DEVINFO:
377 		pcap = ddi_get_soft_state(pca9556_soft_statep, instance);
378 		if (pcap == NULL)
379 			return (DDI_FAILURE);
380 		*result = (void *)pcap->pca9556_dip;
381 		return (DDI_SUCCESS);
382 	case DDI_INFO_DEVT2INSTANCE:
383 		*result = (void *)instance;
384 		return (DDI_SUCCESS);
385 	default:
386 		return (DDI_FAILURE);
387 	}
388 }
389 
390 static int
391 pca9556_s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
392 {
393 	switch (cmd) {
394 	case DDI_ATTACH:
395 		return (pca9556_attach(dip));
396 	case DDI_RESUME:
397 		return (pca9556_resume(dip));
398 	default:
399 		return (DDI_FAILURE);
400 	}
401 }
402 
403 static int
404 pca9556_suspend(dev_info_t *dip)
405 {
406 	pca9556_unit_t 	*pcap;
407 	int 		instance = ddi_get_instance(dip);
408 	int		err = DDI_SUCCESS;
409 	int		reg_offset, num_of_ports;
410 	int		i, j;
411 	uint8_t		reg, reg_num = 0;
412 
413 	pcap = ddi_get_soft_state(pca9556_soft_statep, instance);
414 
415 	mutex_enter(&pcap->pca9556_mutex);
416 	while ((pcap->pca9556_flags & PCA9556_BUSYFLAG) == PCA9556_BUSYFLAG) {
417 		if (cv_wait_sig(&pcap->pca9556_cv,
418 		    &pcap->pca9556_mutex) <= 0) {
419 			mutex_exit(&pcap->pca9556_mutex);
420 			return (DDI_FAILURE);
421 		}
422 	}
423 	pcap->pca9556_flags |= PCA9556_BUSYFLAG;
424 	mutex_exit(&pcap->pca9556_mutex);
425 
426 	/*
427 	 * A pca9555 devices command registers are offset by 2 and it has 2
428 	 * ports to save. A pca9556 devices command registers are offset by 1
429 	 * while it only has one "port"
430 	 */
431 	if (pcap->pca9555_device) {
432 		reg_offset = 2;
433 		num_of_ports = PCA9555_NUM_PORTS;
434 	} else {
435 		reg_offset = 1;
436 		num_of_ports = PCA9556_NUM_PORTS;
437 	}
438 	/*
439 	 * Save the state of the registers
440 	 */
441 	pcap->pca9556_transfer->i2c_flags = I2C_WR_RD;
442 	pcap->pca9556_transfer->i2c_wlen = 1;
443 	pcap->pca9556_transfer->i2c_rlen = 1;
444 
445 	/*
446 	 * The following for loop will run through once for a pca9556 device
447 	 * and twice for a pca9555 device. i will represent the port number
448 	 * for the pca9555.
449 	 */
450 	for (i = 0; i < num_of_ports; i++) {
451 		/*
452 		 * We set the first Register here so it can be reset if we
453 		 * loop through (pca9555 device).
454 		 */
455 		if (pcap->pca9555_device)
456 			reg = PCA9555_OUTPUT_REG;
457 		else
458 			reg = PCA9556_OUTPUT_REG;
459 
460 		/* We run through this loop 3 times. Once for each register */
461 		for (j = 0; j < PCA9556_NUM_REG; j++) {
462 
463 			/*
464 			 * We add the port number (0 for pca9556, 0 or 1 for
465 			 * a pca9555) to the register.
466 			 */
467 			pcap->pca9556_transfer->i2c_wbuf[0] = reg + i;
468 			if (i2c_transfer(pcap->pca9556_hdl,
469 				pcap->pca9556_transfer) != DDI_SUCCESS) {
470 				err = EIO;
471 				goto done;
472 			}
473 
474 			pcap->pca9556_cpr_state[reg_num++] =
475 			    pcap->pca9556_transfer->i2c_rbuf[0];
476 			/*
477 			 * The register is then added to the offset and saved
478 			 * to go and read the next command register.
479 			 */
480 			reg = reg + reg_offset;
481 		}
482 	}
483 
484 done:
485 	if (err != DDI_SUCCESS) {
486 		mutex_enter(&pcap->pca9556_mutex);
487 		pcap->pca9556_flags = pcap->pca9556_flags & ~PCA9556_BUSYFLAG;
488 		cv_broadcast(&pcap->pca9556_cv);
489 		mutex_exit(&pcap->pca9556_mutex);
490 		cmn_err(CE_WARN, "%s Suspend failed, unable to save registers",
491 		    pcap->pca9556_name);
492 		return (err);
493 	}
494 	return (DDI_SUCCESS);
495 }
496 
497 static int
498 pca9556_s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
499 {
500 	switch (cmd) {
501 	case DDI_DETACH:
502 		pca9556_detach(dip);
503 		return (DDI_SUCCESS);
504 	case DDI_SUSPEND:
505 		return (pca9556_suspend(dip));
506 	default:
507 		return (DDI_FAILURE);
508 	}
509 }
510 
511 static int
512 pca9556_open(dev_t *devp, int flags, int otyp, cred_t *credp)
513 {
514 	int			instance;
515 	pca9556_unit_t		*pcap;
516 	int			err = EBUSY;
517 
518 	/*
519 	 * Make sure the open is for the right file type
520 	 */
521 	if (otyp != OTYP_CHR)
522 		return (EINVAL);
523 
524 	instance = MINOR_TO_INST(getminor(*devp));
525 
526 	pcap = (pca9556_unit_t *)
527 	    ddi_get_soft_state(pca9556_soft_statep, instance);
528 	if (pcap == NULL)
529 		return (ENXIO);
530 
531 	/* must be privileged to access this device */
532 	if (drv_priv(credp) != 0)
533 		return (EPERM);
534 
535 	/*
536 	 * Enforce exclusive access if required
537 	 */
538 	mutex_enter(&pcap->pca9556_mutex);
539 	if (flags & FEXCL) {
540 		if (pcap->pca9556_oflag == 0) {
541 			pcap->pca9556_oflag = FEXCL;
542 			err = DDI_SUCCESS;
543 		}
544 	} else if (pcap->pca9556_oflag != FEXCL) {
545 		pcap->pca9556_oflag = FOPEN;
546 		err = DDI_SUCCESS;
547 	}
548 	mutex_exit(&pcap->pca9556_mutex);
549 	return (err);
550 }
551 
552 static int
553 pca9556_close(dev_t dev, int flags, int otyp, cred_t *credp)
554 {
555 	int		instance;
556 	pca9556_unit_t 	*pcap;
557 
558 	_NOTE(ARGUNUSED(flags, credp))
559 
560 	/*
561 	 * Make sure the close is for the right file type
562 	 */
563 	if (otyp != OTYP_CHR)
564 		return (EINVAL);
565 
566 	instance = MINOR_TO_INST(getminor(dev));
567 
568 	pcap = (pca9556_unit_t *)
569 	    ddi_get_soft_state(pca9556_soft_statep, instance);
570 	if (pcap == NULL)
571 		return (ENXIO);
572 
573 	mutex_enter(&pcap->pca9556_mutex);
574 	pcap->pca9556_oflag = 0;
575 	mutex_exit(&pcap->pca9556_mutex);
576 	return (0);
577 }
578 
579 static int
580 pca9556_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
581 	int *rvalp)
582 {
583 	pca9556_unit_t		*pcap;
584 	int			err = 0;
585 	int			instance = MINOR_TO_INST(getminor(dev));
586 	int			port;
587 	i2c_gpio_t		g_buf;
588 	uchar_t			temp;
589 	boolean_t		write_io = B_FALSE;
590 
591 	_NOTE(ARGUNUSED(credp, rvalp))
592 
593 	pcap = (pca9556_unit_t *)
594 	    ddi_get_soft_state(pca9556_soft_statep, instance);
595 
596 	if (pcap->pca9555_device) {
597 		port =  MINOR_TO_PORT(getminor(dev));
598 	}
599 	if (pca9556_debug) {
600 		prom_printf("pca9556_ioctl: instance=%d\n", instance);
601 	}
602 
603 	/*
604 	 * We serialize here and  block any pending transacations.
605 	 */
606 	mutex_enter(&pcap->pca9556_mutex);
607 	while ((pcap->pca9556_flags & PCA9556_BUSYFLAG) == PCA9556_BUSYFLAG) {
608 		if (cv_wait_sig(&pcap->pca9556_cv,
609 		    &pcap->pca9556_mutex) <= 0) {
610 			mutex_exit(&pcap->pca9556_mutex);
611 			return (EINTR);
612 		}
613 	}
614 	pcap->pca9556_flags |= PCA9556_BUSYFLAG;
615 	mutex_exit(&pcap->pca9556_mutex);
616 	if (ddi_copyin((caddr_t)arg, &g_buf,
617 	    sizeof (i2c_gpio_t), mode) != DDI_SUCCESS) {
618 
619 		err = EFAULT;
620 
621 		goto cleanup;
622 	}
623 	pcap->pca9556_transfer->i2c_flags = I2C_WR_RD;
624 	pcap->pca9556_transfer->i2c_wlen = 1;
625 	pcap->pca9556_transfer->i2c_rlen = 1;
626 
627 	/*
628 	 * Evaluate which register is to be read or modified
629 	 */
630 
631 	switch (cmd) {
632 	case GPIO_GET_INPUT:
633 		if (pcap->pca9555_device)
634 			pcap->pca9556_transfer->i2c_wbuf[0] =
635 			    PCA9555_INPUT_REG + port;
636 		else
637 			pcap->pca9556_transfer->i2c_wbuf[0] =
638 			    PCA9556_INPUT_REG;
639 		break;
640 
641 	case GPIO_SET_OUTPUT:
642 		write_io = B_TRUE;
643 		/*FALLTHROUGH*/
644 
645 	case GPIO_GET_OUTPUT:
646 		if (pcap->pca9555_device)
647 			pcap->pca9556_transfer->i2c_wbuf[0] =
648 			    PCA9555_OUTPUT_REG + port;
649 		else
650 			pcap->pca9556_transfer->i2c_wbuf[0] =
651 			    PCA9556_OUTPUT_REG;
652 		break;
653 
654 	case GPIO_SET_POLARITY:
655 		write_io = B_TRUE;
656 		/*FALLTHROUGH*/
657 
658 	case GPIO_GET_POLARITY:
659 		if (pcap->pca9555_device)
660 			pcap->pca9556_transfer->i2c_wbuf[0] =
661 			    PCA9555_POLARITY_REG + port;
662 		else
663 			pcap->pca9556_transfer->i2c_wbuf[0] =
664 			    PCA9556_POLARITY_REG;
665 		break;
666 
667 	case GPIO_SET_CONFIG:
668 		write_io = B_TRUE;
669 		/*FALLTHROUGH*/
670 
671 	case GPIO_GET_CONFIG:
672 		if (pcap->pca9555_device)
673 			pcap->pca9556_transfer->i2c_wbuf[0] =
674 			    PCA9555_CONFIG_REG + port;
675 		else
676 			pcap->pca9556_transfer->i2c_wbuf[0] =
677 			    PCA9556_CONFIG_REG;
678 		break;
679 	}
680 
681 	/*
682 	 * Read the required register
683 	 */
684 	if (i2c_transfer(pcap->pca9556_hdl, pcap->pca9556_transfer)
685 	    != I2C_SUCCESS) {
686 		err = EIO;
687 
688 		goto cleanup;
689 	}
690 	/*
691 	 * Evaluate whether the register is to be read or modified
692 	 */
693 	if (!write_io) {
694 		g_buf.reg_val = g_buf.reg_mask &
695 		    pcap->pca9556_transfer->i2c_rbuf[0];
696 		err = ddi_copyout(&g_buf, (caddr_t)arg,
697 		    sizeof (i2c_gpio_t), mode);
698 	} else {
699 		pcap->pca9556_transfer->i2c_flags = I2C_WR;
700 		pcap->pca9556_transfer->i2c_wlen = 2;
701 		pcap->pca9556_transfer->i2c_rlen = 0;
702 
703 		/*
704 		 * Modify register without overwriting existing contents
705 		 */
706 
707 		temp = pcap->pca9556_transfer->i2c_rbuf[0] & (~g_buf.reg_mask);
708 		pcap->pca9556_transfer->i2c_wbuf[1] = temp|
709 		    (g_buf.reg_val & g_buf.reg_mask);
710 		if (i2c_transfer(pcap->pca9556_hdl, pcap->pca9556_transfer)
711 		    != I2C_SUCCESS) {
712 				err = EIO;
713 		}
714 
715 	}
716 cleanup:
717 	mutex_enter(&pcap->pca9556_mutex);
718 	pcap->pca9556_flags  = pcap->pca9556_flags & ~PCA9556_BUSYFLAG;
719 	cv_signal(&pcap->pca9556_cv);
720 	mutex_exit(&pcap->pca9556_mutex);
721 	return (err);
722 	}
723