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