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