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 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 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 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 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 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 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 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 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 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 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 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