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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/types.h> 29 #include <sys/signal.h> 30 #include <sys/errno.h> 31 #include <sys/file.h> 32 #include <sys/termio.h> 33 #include <sys/termios.h> 34 #include <sys/cmn_err.h> 35 #include <sys/stream.h> 36 #include <sys/strsun.h> 37 #include <sys/stropts.h> 38 #include <sys/strtty.h> 39 #include <sys/debug.h> 40 #include <sys/eucioctl.h> 41 #include <sys/cred.h> 42 #include <sys/uio.h> 43 #include <sys/stat.h> 44 #include <sys/kmem.h> 45 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/obpdefs.h> 49 #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 50 #include <sys/modctl.h> /* for modldrv */ 51 #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 52 #include <sys/open.h> /* for open params. */ 53 #include <sys/uio.h> /* for read/write */ 54 55 #include <sys/i2c/misc/i2c_svc.h> 56 #include <sys/mct_topology.h> 57 #include <sys/envctrl_gen.h> /* must be before netract_gen.h */ 58 #include <sys/netract_gen.h> 59 #include <sys/pcf8574_nct.h> 60 #include <sys/scsb_cbi.h> 61 62 #ifdef DEBUG 63 #define dbg_print(level, str) cmn_err(level, str); 64 static int pcf8574_debug = 0x00000102; 65 #else 66 #define dbg_print(level, str) {; } 67 #endif 68 69 #define CV_LOCK(retval) \ 70 { \ 71 mutex_enter(&unitp->umutex); \ 72 while (unitp->pcf8574_flags == PCF8574_BUSY) { \ 73 if (cv_wait_sig(&unitp->pcf8574_cv, \ 74 &unitp->umutex) <= 0) { \ 75 mutex_exit(&unitp->umutex); \ 76 return (retval); \ 77 } \ 78 } \ 79 unitp->pcf8574_flags = PCF8574_BUSY; \ 80 mutex_exit(&unitp->umutex); \ 81 } 82 83 #define CV_UNLOCK \ 84 { \ 85 mutex_enter(&unitp->umutex); \ 86 unitp->pcf8574_flags = 0; \ 87 cv_signal(&unitp->pcf8574_cv); \ 88 mutex_exit(&unitp->umutex); \ 89 } 90 91 static int nct_p10fan_patch = 0; /* Fan patch for P1.0 */ 92 static void *pcf8574_soft_statep; 93 94 /* 95 * cb ops (only need open,close,read,write,ioctl) 96 */ 97 static int pcf8574_open(dev_t *, int, int, cred_t *); 98 static int pcf8574_close(dev_t, int, int, cred_t *); 99 static int pcf8574_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 100 static int pcf8574_read(dev_t dev, struct uio *uiop, cred_t *cred_p); 101 static int pcf8574_chpoll(dev_t, short, int, short *, struct pollhead **); 102 static uint_t pcf8574_intr(caddr_t arg); 103 static int pcf8574_io(dev_t, struct uio *, int); 104 105 static struct cb_ops pcf8574_cbops = { 106 pcf8574_open, /* open */ 107 pcf8574_close, /* close */ 108 nodev, /* strategy */ 109 nodev, /* print */ 110 nodev, /* dump */ 111 pcf8574_read, /* read */ 112 nodev, /* write */ 113 pcf8574_ioctl, /* ioctl */ 114 nodev, /* devmap */ 115 nodev, /* mmap */ 116 nodev, /* segmap */ 117 pcf8574_chpoll, /* poll */ 118 ddi_prop_op, /* cb_prop_op */ 119 NULL, /* streamtab */ 120 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 121 CB_REV, /* rev */ 122 nodev, /* int (*cb_aread)() */ 123 nodev /* int (*cb_awrite)() */ 124 }; 125 126 /* 127 * dev ops 128 */ 129 static int pcf8574_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 130 static int pcf8574_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 131 132 /* kstat routines */ 133 static int pcf8574_add_kstat(struct pcf8574_unit *, scsb_fru_status_t); 134 static void pcf8574_delete_kstat(struct pcf8574_unit *); 135 static int pcf8574_kstat_update(kstat_t *, int); 136 static int pcf8574_read_chip(struct pcf8574_unit *unitp, 137 uint16_t size); 138 static int pcf8574_write_chip(struct pcf8574_unit *unitp, 139 uint16_t size, uint8_t bitpattern); 140 static int pcf8574_read_props(struct pcf8574_unit *unitp); 141 static int pcf8574_init_chip(struct pcf8574_unit *unitp, int); 142 /* 143 * SCSB callback function 144 */ 145 static void pcf8574_callback(void *, scsb_fru_event_t, scsb_fru_status_t); 146 extern int scsb_intr_register(uint_t (*intr_handler)(caddr_t), caddr_t, 147 fru_id_t); 148 extern int scsb_intr_unregister(fru_id_t); 149 150 extern int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran); 151 152 static struct dev_ops pcf8574_ops = { 153 DEVO_REV, 154 0, 155 ddi_getinfo_1to1, 156 nulldev, 157 nulldev, 158 pcf8574_attach, 159 pcf8574_detach, 160 nodev, 161 &pcf8574_cbops, 162 NULL, /* bus_ops */ 163 NULL, /* power */ 164 ddi_quiesce_not_supported, /* devo_quiesce */ 165 }; 166 167 extern struct mod_ops mod_driverops; 168 169 static struct modldrv pcf8574_modldrv = { 170 &mod_driverops, /* type of module - driver */ 171 "Netract pcf8574 (gpio)", 172 &pcf8574_ops, 173 }; 174 175 static struct modlinkage pcf8574_modlinkage = { 176 MODREV_1, 177 &pcf8574_modldrv, 178 0 179 }; 180 181 /* char _depends_on[] = "misc/i2c_svc drv/scsb"; */ 182 183 int 184 _init(void) 185 { 186 register int error; 187 188 error = mod_install(&pcf8574_modlinkage); 189 if (!error) { 190 (void) ddi_soft_state_init(&pcf8574_soft_statep, 191 sizeof (struct pcf8574_unit), PCF8574_MAX_DEVS); 192 } 193 194 return (error); 195 } 196 197 int 198 _fini(void) 199 { 200 register int error; 201 202 error = mod_remove(&pcf8574_modlinkage); 203 if (!error) 204 ddi_soft_state_fini(&pcf8574_soft_statep); 205 206 return (error); 207 } 208 209 int 210 _info(struct modinfo *modinfop) 211 { 212 return (mod_info(&pcf8574_modlinkage, modinfop)); 213 } 214 215 /*ARGSUSED*/ 216 static int 217 pcf8574_open(dev_t *devp, int flags, int otyp, cred_t *credp) 218 { 219 struct pcf8574_unit *unitp; 220 register int instance; 221 int err = DDI_SUCCESS; 222 223 instance = getminor(*devp); 224 if (instance < 0) { 225 return (ENXIO); 226 } 227 228 unitp = (struct pcf8574_unit *) 229 ddi_get_soft_state(pcf8574_soft_statep, instance); 230 231 if (unitp == NULL) { 232 return (ENXIO); 233 } 234 235 if (otyp != OTYP_CHR) { 236 return (EINVAL); 237 } 238 239 mutex_enter(&unitp->umutex); 240 241 if (flags & FEXCL) { 242 if (unitp->pcf8574_oflag != 0) { 243 err = EBUSY; 244 } else { 245 unitp->pcf8574_oflag = FEXCL; 246 } 247 } else { 248 if (unitp->pcf8574_oflag == FEXCL) { 249 err = EBUSY; 250 } else { 251 unitp->pcf8574_oflag = FOPEN; 252 } 253 } 254 255 mutex_exit(&unitp->umutex); 256 257 return (err); 258 } 259 260 /*ARGSUSED*/ 261 static int 262 pcf8574_close(dev_t dev, int flags, int otyp, cred_t *credp) 263 { 264 struct pcf8574_unit *unitp; 265 register int instance; 266 267 #ifdef lint 268 flags = flags; 269 otyp = otyp; 270 #endif 271 272 instance = getminor(dev); 273 274 if (instance < 0) { 275 return (ENXIO); 276 } 277 278 unitp = (struct pcf8574_unit *) 279 ddi_get_soft_state(pcf8574_soft_statep, instance); 280 281 if (unitp == NULL) { 282 return (ENXIO); 283 } 284 285 mutex_enter(&unitp->umutex); 286 287 unitp->pcf8574_oflag = 0; 288 289 mutex_exit(&unitp->umutex); 290 291 return (DDI_SUCCESS); 292 } 293 294 295 /*ARGSUSED*/ 296 static int 297 pcf8574_read(dev_t dev, struct uio *uiop, cred_t *cred_p) 298 { 299 return (pcf8574_io(dev, uiop, B_READ)); 300 } 301 302 static int 303 pcf8574_io(dev_t dev, struct uio *uiop, int rw) 304 { 305 struct pcf8574_unit *unitp; 306 register int instance; 307 uint16_t bytes_to_rw; 308 int err = DDI_SUCCESS; 309 310 err = 0; 311 instance = getminor(dev); 312 313 if (instance < 0) { 314 return (ENXIO); 315 } 316 317 unitp = (struct pcf8574_unit *) 318 ddi_get_soft_state(pcf8574_soft_statep, instance); 319 if (unitp == NULL) { 320 return (ENXIO); 321 } 322 if ((bytes_to_rw = uiop->uio_resid) > PCF8574_TRAN_SIZE) { 323 return (EINVAL); 324 } 325 326 CV_LOCK(EINTR) 327 328 if (rw == B_WRITE) { 329 err = uiomove(unitp->i2c_tran->i2c_wbuf, 330 bytes_to_rw, UIO_WRITE, uiop); 331 332 if (!err) { 333 err = pcf8574_write_chip(unitp, bytes_to_rw, 334 unitp->writemask); 335 } 336 337 } else { 338 err = pcf8574_read_chip(unitp, bytes_to_rw); 339 if (!err) { 340 err = uiomove(unitp->i2c_tran->i2c_rbuf, 341 bytes_to_rw, UIO_READ, uiop); 342 } 343 } 344 345 CV_UNLOCK 346 if (err) 347 err = EIO; 348 349 return (err); 350 } 351 352 static int 353 pcf8574_do_resume(dev_info_t *dip) 354 { 355 int instance = ddi_get_instance(dip); 356 struct pcf8574_unit *unitp = 357 ddi_get_soft_state(pcf8574_soft_statep, instance); 358 359 if (unitp == NULL) { 360 return (ENXIO); 361 } 362 363 CV_UNLOCK 364 365 return (DDI_SUCCESS); 366 } 367 368 static int 369 pcf8574_do_detach(dev_info_t *dip) 370 { 371 struct pcf8574_unit *unitp; 372 int instance; 373 uint_t attach_flag; 374 375 instance = ddi_get_instance(dip); 376 unitp = ddi_get_soft_state(pcf8574_soft_statep, instance); 377 378 attach_flag = unitp->attach_flag; 379 380 if (attach_flag & PCF8574_INTR_ADDED) { 381 (void) scsb_intr_unregister( 382 (fru_id_t)unitp->props.slave_address); 383 } 384 385 if (attach_flag & PCF8574_KSTAT_INIT) { 386 pcf8574_delete_kstat(unitp); 387 } 388 389 if (attach_flag & PCF8574_LOCK_INIT) { 390 mutex_destroy(&unitp->umutex); 391 cv_destroy(&unitp->pcf8574_cv); 392 } 393 394 scsb_fru_unregister((void *)unitp, 395 (fru_id_t)unitp->props.slave_address); 396 397 if (attach_flag & PCF8574_ALLOC_TRANSFER) { 398 /* 399 * restore the lengths to allocated lengths 400 * before freeing. 401 */ 402 unitp->i2c_tran->i2c_wlen = MAX_WLEN; 403 unitp->i2c_tran->i2c_rlen = MAX_RLEN; 404 i2c_transfer_free(unitp->pcf8574_hdl, unitp->i2c_tran); 405 } 406 407 if (attach_flag & PCF8574_REGISTER_CLIENT) { 408 i2c_client_unregister(unitp->pcf8574_hdl); 409 } 410 411 if (attach_flag & PCF8574_MINORS_CREATED) { 412 ddi_remove_minor_node(dip, NULL); 413 } 414 415 if (attach_flag & PCF8574_PROPS_READ) { 416 if (unitp->pcf8574_type == PCF8574_ADR_CPUVOLTAGE && 417 unitp->props.num_chans_used != 0) { 418 ddi_prop_free(unitp->props.channels_in_use); 419 } else { 420 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 421 "interrupt-priorities"); 422 } 423 } 424 425 if (attach_flag & PCF8574_SOFT_STATE_ALLOC) { 426 ddi_soft_state_free(pcf8574_soft_statep, instance); 427 } 428 429 return (DDI_SUCCESS); 430 } 431 432 /* 433 * NOTE**** 434 * The OBP will create device tree node for all I2C devices which 435 * may be present in a system. This means, even if the device is 436 * not physically present, the device tree node exists. We also 437 * will succeed the attach routine, since currently there is no 438 * hotplug support in the I2C bus, and the FRUs need to be hot 439 * swappable. Only during an I2C transaction we figure out whether 440 * the particular I2C device is actually present in the system 441 * by looking at the system controller board register. The fantray 442 * and power-supply devices may be swapped any time after system 443 * reboot, and the way we can make sure that the device is attached 444 * to the driver, is by always keeping the driver loaded, and report 445 * an error during the actual transaction. 446 */ 447 static int 448 pcf8574_do_attach(dev_info_t *dip) 449 { 450 register struct pcf8574_unit *unitp; 451 int instance; 452 char name[MAXNAMELEN]; 453 int i; 454 pcf8574_channel_t *chp; 455 scsb_fru_status_t dev_presence; 456 457 instance = ddi_get_instance(dip); 458 #ifdef DEBUG 459 if (pcf8574_debug & 0x04) 460 cmn_err(CE_NOTE, "pcf8574_attach: instance=%d\n", 461 instance); 462 #endif /* DEBUG */ 463 464 if (ddi_soft_state_zalloc(pcf8574_soft_statep, instance) != 465 DDI_SUCCESS) { 466 return (DDI_FAILURE); 467 } 468 unitp = ddi_get_soft_state(pcf8574_soft_statep, instance); 469 470 if (unitp == NULL) { 471 ddi_soft_state_free(pcf8574_soft_statep, instance); 472 return (DDI_FAILURE); 473 } 474 475 unitp->dip = dip; 476 477 unitp->attach_flag = PCF8574_SOFT_STATE_ALLOC; 478 479 if (pcf8574_read_props(unitp) != DDI_PROP_SUCCESS) { 480 ddi_soft_state_free(pcf8574_soft_statep, instance); 481 return (DDI_FAILURE); 482 } 483 484 unitp->attach_flag |= PCF8574_PROPS_READ; 485 486 /* 487 * Set the current operating mode to NORMAL_MODE. 488 */ 489 unitp->current_mode = ENVCTRL_NORMAL_MODE; 490 491 (void) snprintf(unitp->pcf8574_name, PCF8574_NAMELEN, 492 "%s%d", ddi_driver_name(dip), instance); 493 494 if (unitp->pcf8574_type == PCF8574_TYPE_PWRSUPP) { 495 (void) sprintf(name, "pwrsuppply"); 496 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 497 PCF8574_NODE_TYPE, NULL) == DDI_FAILURE) { 498 ddi_remove_minor_node(dip, NULL); 499 (void) pcf8574_do_detach(dip); 500 501 return (DDI_FAILURE); 502 } 503 } 504 else 505 if (unitp->pcf8574_type == PCF8574_TYPE_FANTRAY) { 506 (void) sprintf(name, "fantray"); 507 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 508 PCF8574_NODE_TYPE, NULL) == DDI_FAILURE) { 509 ddi_remove_minor_node(dip, NULL); 510 (void) pcf8574_do_detach(dip); 511 512 return (DDI_FAILURE); 513 } 514 } 515 else 516 if (unitp->pcf8574_type == PCF8574_TYPE_CPUVOLTAGE) { 517 (void) sprintf(name, "cpuvoltage"); 518 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 519 PCF8574_NODE_TYPE, NULL) == DDI_FAILURE) { 520 ddi_remove_minor_node(dip, NULL); 521 (void) pcf8574_do_detach(dip); 522 523 return (DDI_FAILURE); 524 } 525 } else { 526 return (DDI_FAILURE); 527 } 528 529 unitp->attach_flag |= PCF8574_MINORS_CREATED; 530 531 /* 532 * Now we need read/write masks since all the 8574 bits can be either 533 * read/written, but some ports are intended to be RD/WR only, or RW 534 * If no channels-in-use propoerty, set default values. 535 */ 536 if (unitp->pcf8574_type == PCF8574_TYPE_FANTRAY) { 537 unitp->readmask = PCF8574_FAN_READMASK; 538 unitp->writemask = PCF8574_FAN_WRITEMASK; 539 } 540 if (unitp->pcf8574_type == PCF8574_TYPE_PWRSUPP) { 541 unitp->readmask = PCF8574_PS_READMASK; 542 unitp->writemask = PCF8574_PS_WRITEMASK; 543 } 544 545 for (i = unitp->props.num_chans_used, 546 chp = unitp->props.channels_in_use; i; --i, ++chp) { 547 unitp->readmask |= (uint8_t)( 548 (chp->io_dir == I2C_PROP_IODIR_IN || 549 chp->io_dir == I2C_PROP_IODIR_INOUT) << chp->port); 550 unitp->writemask |= (uint8_t)( 551 (chp->io_dir == I2C_PROP_IODIR_OUT || 552 chp->io_dir == I2C_PROP_IODIR_INOUT) << chp->port); 553 } 554 555 #ifdef DEBUG 556 cmn_err(CE_NOTE, "pcf8574_do_attach: readmask = 0x%x \ 557 writemask = 0x%x\n", unitp->readmask, unitp->writemask); 558 #endif /* DEBUG */ 559 560 if (i2c_client_register(dip, &unitp->pcf8574_hdl) 561 != I2C_SUCCESS) { 562 (void) pcf8574_do_detach(dip); 563 return (DDI_FAILURE); 564 } 565 unitp->attach_flag |= PCF8574_REGISTER_CLIENT; 566 567 /* 568 * Allocate the I2C_transfer structure. The same structure 569 * is used throughout the driver. 570 */ 571 if (i2c_transfer_alloc(unitp->pcf8574_hdl, &unitp->i2c_tran, 572 MAX_WLEN, MAX_RLEN, KM_SLEEP) != I2C_SUCCESS) { 573 (void) pcf8574_do_detach(dip); 574 return (DDI_FAILURE); 575 } 576 unitp->attach_flag |= PCF8574_ALLOC_TRANSFER; 577 578 /* 579 * To begin with we set the mode to I2C_RD. 580 */ 581 unitp->i2c_tran->i2c_flags = I2C_RD; 582 unitp->i2c_tran->i2c_version = I2C_XFER_REV; 583 584 /* 585 * Set the busy flag and open flag to 0. 586 */ 587 unitp->pcf8574_flags = 0; 588 unitp->pcf8574_oflag = 0; 589 590 mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER, NULL); 591 cv_init(&unitp->pcf8574_cv, NULL, CV_DRIVER, NULL); 592 593 unitp->attach_flag |= PCF8574_LOCK_INIT; 594 595 /* 596 * Register out callback function with the SCSB driver, and save 597 * the returned value to check that the device instance exists. 598 */ 599 dev_presence = scsb_fru_register(pcf8574_callback, (void *)unitp, 600 (fru_id_t)unitp->props.slave_address); 601 if (dev_presence == FRU_NOT_AVAILABLE) { 602 scsb_fru_unregister((void *)unitp, 603 (fru_id_t)unitp->props.slave_address); 604 } 605 606 /* 607 * Add the kstats. First we need to get the property values 608 * depending on the device type. For example, for the fan 609 * tray there will be a different set of properties, and there 610 * will be another for the powersupplies, and another one for 611 * the CPU voltage monitor. Initialize the kstat structures with 612 * these values. 613 */ 614 615 if (pcf8574_add_kstat(unitp, dev_presence) != DDI_SUCCESS) { 616 (void) pcf8574_do_detach(dip); 617 return (DDI_FAILURE); 618 } 619 620 unitp->attach_flag |= PCF8574_KSTAT_INIT; 621 622 /* 623 * Due to observed behavior on Solaris 8, the handler must be 624 * registered before any interrupts are enabled, 625 * in spite of what the ddi_get_iblock_cookie() manual says. 626 * As per the HW/SW spec, by default interrupts are disabled. 627 */ 628 629 if (dev_presence == FRU_PRESENT) { /* program the chip */ 630 (void) pcf8574_init_chip(unitp, 0); /* Disable intr first */ 631 } 632 633 if (unitp->pcf8574_canintr == PCF8574_INTR_ON) { 634 #ifdef DEBUG 635 if (pcf8574_debug & 0x0004) 636 cmn_err(CE_NOTE, "registering pcf9574 interrupt " 637 "handler"); 638 #endif /* DEBUG */ 639 if (scsb_intr_register(pcf8574_intr, (void *)unitp, 640 (fru_id_t)unitp->props.slave_address) == DDI_SUCCESS) { 641 unitp->pcf8574_canintr |= PCF8574_INTR_ENABLED; 642 unitp->attach_flag |= PCF8574_INTR_ADDED; 643 } else { 644 (void) pcf8574_do_detach(dip); 645 return (DDI_FAILURE); 646 } 647 } 648 649 ddi_report_dev(dip); 650 651 return (DDI_SUCCESS); 652 } 653 654 static int 655 pcf8574_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 656 { 657 switch (cmd) { 658 case DDI_ATTACH: 659 return (pcf8574_do_attach(dip)); 660 case DDI_RESUME: 661 return (pcf8574_do_resume(dip)); 662 default: 663 return (DDI_FAILURE); 664 } 665 } 666 667 static int 668 pcf8574_do_suspend(dev_info_t *dip) 669 { 670 int instance = ddi_get_instance(dip); 671 struct pcf8574_unit *unitp = 672 ddi_get_soft_state(pcf8574_soft_statep, instance); 673 674 if (unitp == NULL) { 675 return (ENXIO); 676 } 677 678 /* 679 * Set the busy flag so that future transactions block 680 * until resume. 681 */ 682 CV_LOCK(ENXIO) 683 684 return (DDI_SUCCESS); 685 } 686 687 static int 688 pcf8574_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 689 { 690 switch (cmd) { 691 case DDI_DETACH: 692 return (pcf8574_do_detach(dip)); 693 case DDI_SUSPEND: 694 return (pcf8574_do_suspend(dip)); 695 default: 696 return (DDI_FAILURE); 697 } 698 } 699 700 static int 701 pcf8574_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 702 struct pollhead **phpp) 703 { 704 struct pcf8574_unit *unitp; 705 int instance; 706 707 instance = getminor(dev); 708 if ((unitp = (struct pcf8574_unit *)ddi_get_soft_state( 709 pcf8574_soft_statep, instance)) == NULL) { 710 return (ENXIO); 711 } 712 *reventsp = 0; 713 mutex_enter(&unitp->umutex); 714 if (unitp->poll_event) { 715 *reventsp = unitp->poll_event; 716 unitp->poll_event = 0; 717 } else if ((events & POLLIN) && !anyyet) 718 *phpp = &unitp->poll; 719 mutex_exit(&unitp->umutex); 720 return (0); 721 } 722 723 /* 724 * In normal scenarios, this function should never get called. 725 * But, we will still come back and call this function if scsb 726 * interrupt sources does not indicate an scsb interrupt. We may 727 * come to this situation when SunVTS env4test is independently 728 * changing the device registers. 729 */ 730 uint_t 731 pcf8574_intr(caddr_t arg) 732 { 733 int ic; 734 uint8_t value; 735 struct pcf8574_unit *unitp = (struct pcf8574_unit *)(void *)arg; 736 scsb_fru_status_t dev_presence; 737 i2c_transfer_t *tp = unitp->i2c_tran; 738 739 ic = DDI_INTR_CLAIMED; 740 #ifdef DEBUG 741 cmn_err(CE_NOTE, " In the interrupt service routine, %x", 742 unitp->props.slave_address); 743 #endif 744 745 /* 746 * Initiate an I2C transaction to find out 747 * whether this is the device which interrupted. 748 */ 749 mutex_enter(&unitp->umutex); 750 while (unitp->pcf8574_flags == PCF8574_BUSY) { 751 if (cv_wait_sig(&unitp->pcf8574_cv, &unitp->umutex) <= 0) { 752 mutex_exit(&unitp->umutex); 753 return (DDI_INTR_UNCLAIMED); 754 } 755 } 756 757 unitp->pcf8574_flags = PCF8574_BUSY; 758 mutex_exit(&unitp->umutex); 759 760 switch (unitp->pcf8574_type) { 761 case PCF8574_TYPE_CPUVOLTAGE: { 762 dev_presence = FRU_PRESENT; 763 break; 764 } 765 case PCF8574_TYPE_PWRSUPP: { 766 envctrl_pwrsupp_t *envp = 767 (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 768 dev_presence = envp->ps_present; 769 break; 770 } 771 case PCF8574_TYPE_FANTRAY: { 772 envctrl_fantray_t *envp = 773 (envctrl_fantray_t *)unitp->envctrl_kstat; 774 dev_presence = envp->fan_present; 775 break; 776 } 777 } 778 if (dev_presence != FRU_PRESENT) { 779 ic = DDI_INTR_UNCLAIMED; 780 goto intr_exit; 781 } 782 if (pcf8574_read_chip(unitp, 1) != I2C_SUCCESS) { 783 ic = DDI_INTR_UNCLAIMED; 784 goto intr_exit; 785 } 786 value = unitp->i2c_tran->i2c_rbuf[0]; 787 /* 788 * If interrupt is already masked, return 789 */ 790 if (value & PCF8574_INTRMASK_BIT) { 791 ic = DDI_INTR_UNCLAIMED; 792 goto intr_exit; 793 } 794 795 /* 796 * In case a fault bit is set, claim the interrupt. 797 */ 798 switch (unitp->pcf8574_type) { 799 case PCF8574_TYPE_PWRSUPP: 800 { 801 envctrl_pwrsupp_t *envp = 802 (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 803 804 if (PCF8574_PS_FAULT(value) || 805 PCF8574_PS_TEMPOK(value) || 806 PCF8574_PS_ONOFF(value) || 807 PCF8574_PS_FANOK(value)) { 808 809 envp->ps_ok = PCF8574_PS_FAULT(value); 810 envp->temp_ok = PCF8574_PS_TEMPOK(value); 811 envp->psfan_ok = PCF8574_PS_FANOK(value); 812 envp->on_state = PCF8574_PS_ONOFF(value); 813 envp->ps_ver = PCF8574_PS_TYPE(value); 814 815 tp->i2c_wbuf[0] = 816 PCF8574_PS_DEFAULT | PCF8574_PS_MASKINTR; 817 tp->i2c_wlen = 1; 818 tp->i2c_rlen = 0; 819 tp->i2c_flags = I2C_WR; 820 821 unitp->i2c_status = 822 nct_i2c_transfer(unitp->pcf8574_hdl, tp); 823 824 unitp->poll_event = POLLIN; 825 pollwakeup(&unitp->poll, POLLIN); 826 } else { 827 ic = DDI_INTR_UNCLAIMED; 828 } 829 } 830 break; 831 832 case PCF8574_TYPE_FANTRAY: 833 { 834 envctrl_fantray_t *envp = 835 (envctrl_fantray_t *)unitp->envctrl_kstat; 836 837 if (!PCF8574_FAN_FAULT(value)) { 838 839 envp->fan_ver = PCF8574_FAN_TYPE(value); 840 envp->fan_ok = PCF8574_FAN_FAULT(value); 841 envp->fanspeed = PCF8574_FAN_FANSPD(value); 842 843 tp->i2c_wbuf[0] = 844 PCF8574_FAN_DEFAULT | PCF8574_FAN_MASKINTR; 845 tp->i2c_wlen = 1; 846 tp->i2c_rlen = 0; 847 tp->i2c_flags = I2C_WR; 848 849 unitp->i2c_status = 850 nct_i2c_transfer(unitp->pcf8574_hdl, tp); 851 852 unitp->poll_event = POLLIN; 853 pollwakeup(&unitp->poll, POLLIN); 854 855 } else { 856 ic = DDI_INTR_UNCLAIMED; 857 } 858 } 859 break; 860 861 default: 862 ic = DDI_INTR_UNCLAIMED; 863 } /* switch */ 864 865 intr_exit: 866 mutex_enter(&unitp->umutex); 867 unitp->pcf8574_flags = 0; 868 cv_signal(&unitp->pcf8574_cv); 869 mutex_exit(&unitp->umutex); 870 871 return (ic); 872 } 873 874 static int 875 call_copyin(caddr_t arg, struct pcf8574_unit *unitp, int mode) 876 { 877 uchar_t *wbuf; 878 uchar_t *rbuf; 879 i2c_transfer_t i2ct; 880 i2c_transfer_t *i2ctp = unitp->i2c_tran; 881 882 883 if (ddi_copyin((void *)arg, (caddr_t)&i2ct, 884 sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) { 885 return (I2C_FAILURE); 886 } 887 888 /* 889 * Save the read and write buffer pointers in the transfer 890 * structure, otherwise these will get overwritten when we 891 * do a bcopy. Restore once done. 892 */ 893 894 wbuf = i2ctp->i2c_wbuf; 895 rbuf = i2ctp->i2c_rbuf; 896 897 bcopy(&i2ct, i2ctp, sizeof (i2c_transfer_t)); 898 899 i2ctp->i2c_wbuf = wbuf; 900 i2ctp->i2c_rbuf = rbuf; 901 902 /* 903 * copyin the read and write buffers to the saved buffers. 904 */ 905 906 if (i2ct.i2c_wlen != 0) { 907 if (ddi_copyin(i2ct.i2c_wbuf, (caddr_t)i2ctp->i2c_wbuf, 908 i2ct.i2c_wlen, mode) != DDI_SUCCESS) { 909 return (I2C_FAILURE); 910 } 911 } 912 913 return (I2C_SUCCESS); 914 } 915 916 static int 917 call_copyout(caddr_t arg, struct pcf8574_unit *unitp, int mode) 918 { 919 i2c_transfer_t i2ct; 920 i2c_transfer_t *i2ctp = unitp->i2c_tran; 921 922 /* 923 * We will copyout the last three fields only, skipping 924 * the remaining ones, before copying the rbuf to the 925 * user buffer. 926 */ 927 928 int uskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t), 929 kskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t); 930 931 /* 932 * First copyin the user structure to the temporary i2ct, 933 * so that we have the wbuf and rbuf addresses in it. 934 */ 935 936 uskip = sizeof (i2c_transfer_t) - 3 * (sizeof (uint16_t)); 937 938 /* 939 * copyout the last three out fields now. 940 */ 941 942 if (ddi_copyout((void *)((intptr_t)i2ctp+kskip), (void *) 943 ((intptr_t)arg + uskip), 3*sizeof (uint16_t), mode) 944 != DDI_SUCCESS) { 945 return (I2C_FAILURE); 946 } 947 948 /* 949 * In case we have something to write, get the address of the read 950 * buffer. 951 */ 952 953 if (i2ctp->i2c_rlen > i2ctp->i2c_r_resid) { 954 955 if (ddi_copyin((void *)arg, &i2ct, 956 sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) { 957 return (I2C_FAILURE); 958 } 959 960 /* 961 * copyout the read buffer to the saved user buffer in i2ct. 962 */ 963 964 if (ddi_copyout(i2ctp->i2c_rbuf, i2ct.i2c_rbuf, 965 i2ctp->i2c_rlen - i2ctp->i2c_r_resid, mode) 966 != DDI_SUCCESS) { 967 return (I2C_FAILURE); 968 } 969 } 970 971 return (I2C_SUCCESS); 972 } 973 974 /*ARGSUSED*/ 975 static int 976 pcf8574_ioctl(dev_t dev, int cmd, intptr_t arg, 977 int mode, cred_t *credp, int *rvalp) 978 { 979 struct pcf8574_unit *unitp; 980 register int instance; 981 int err = 0; 982 uint8_t value, inval, outval; 983 scsb_fru_status_t dev_presence; 984 985 instance = getminor(dev); 986 987 if (instance < 0) { 988 return (ENXIO); 989 } 990 unitp = (struct pcf8574_unit *) 991 ddi_get_soft_state(pcf8574_soft_statep, instance); 992 993 if (unitp == NULL) { 994 return (ENXIO); 995 } 996 997 dev_presence = 998 scsb_fru_status((uchar_t)unitp->props.slave_address); 999 1000 CV_LOCK(EINTR) 1001 1002 switch (cmd) { 1003 case ENVC_IOC_INTRMASK: 1004 if (dev_presence == FRU_NOT_PRESENT) { 1005 break; 1006 } 1007 1008 if (ddi_copyin((caddr_t)arg, (caddr_t)&inval, 1009 sizeof (uint8_t), mode) != DDI_SUCCESS) { 1010 err = EFAULT; 1011 break; 1012 } 1013 1014 if (inval != 0 && inval != 1) { 1015 err = EINVAL; 1016 } else { 1017 unitp->i2c_tran->i2c_wbuf[0] = 1018 PCF8574_INT_MASK(inval); 1019 if (pcf8574_write_chip(unitp, 1, PCF8574_INTRMASK_BIT) 1020 != I2C_SUCCESS) { 1021 err = EFAULT; 1022 } 1023 } 1024 break; 1025 1026 case ENVC_IOC_SETFAN: 1027 if (unitp->pcf8574_type != PCF8574_TYPE_FANTRAY) { 1028 err = EINVAL; 1029 break; 1030 } 1031 if (dev_presence == FRU_NOT_PRESENT) { 1032 err = EINVAL; 1033 break; 1034 } 1035 if (ddi_copyin((caddr_t)arg, (caddr_t)&inval, sizeof (uint8_t), 1036 mode) != DDI_SUCCESS) { 1037 err = EFAULT; 1038 break; 1039 } 1040 if (inval != PCF8574_FAN_SPEED_LOW && 1041 inval != PCF8574_FAN_SPEED_HIGH) { 1042 err = EINVAL; 1043 break; 1044 } 1045 1046 unitp->i2c_tran->i2c_wbuf[0] = PCF8574_FAN_SPEED(inval); 1047 1048 if (pcf8574_write_chip(unitp, 1, PCF8574_FANSPEED_BIT) 1049 != I2C_SUCCESS) { 1050 err = EFAULT; 1051 } 1052 break; 1053 1054 case ENVC_IOC_SETSTATUS: 1055 /* 1056 * Allow this ioctl only in DIAG mode. 1057 */ 1058 if (unitp->current_mode != ENVCTRL_DIAG_MODE) { 1059 err = EINVAL; 1060 } else { 1061 if (dev_presence == FRU_NOT_PRESENT) { 1062 err = EINVAL; 1063 break; 1064 } 1065 if (ddi_copyin((caddr_t)arg, (caddr_t)&inval, 1066 sizeof (uint8_t), mode) != DDI_SUCCESS) { 1067 err = EFAULT; 1068 } else { 1069 unitp->i2c_tran->i2c_wbuf[0] = inval & 0xff; 1070 if (pcf8574_write_chip(unitp, 1, 0xff) 1071 != I2C_SUCCESS) { 1072 err = EFAULT; 1073 } 1074 } 1075 } 1076 break; 1077 1078 case ENVC_IOC_GETFAN: 1079 case ENVC_IOC_GETSTATUS: 1080 case ENVC_IOC_GETTYPE: 1081 case ENVC_IOC_GETFAULT: 1082 case ENVC_IOC_PSTEMPOK: 1083 case ENVC_IOC_PSFANOK: 1084 case ENVC_IOC_PSONOFF: { 1085 if (dev_presence == FRU_NOT_PRESENT) { 1086 err = EINVAL; 1087 break; 1088 } 1089 if (pcf8574_read_chip(unitp, 1) 1090 != I2C_SUCCESS) { 1091 err = EFAULT; 1092 break; 1093 } 1094 value = unitp->i2c_tran->i2c_rbuf[0]; 1095 if (cmd == ENVC_IOC_GETFAN) { 1096 if (unitp->pcf8574_type != PCF8574_TYPE_FANTRAY) { 1097 err = EINVAL; 1098 break; 1099 } else { 1100 outval = PCF8574_FAN_FANSPD(value); 1101 } 1102 } 1103 else 1104 if (cmd == ENVC_IOC_GETSTATUS) { 1105 outval = value; 1106 } 1107 else 1108 if (cmd == ENVC_IOC_GETTYPE) { 1109 if (unitp->pcf8574_type == PCF8574_TYPE_PWRSUPP) 1110 outval = PCF8574_PS_TYPE(value); 1111 if (unitp->pcf8574_type == PCF8574_TYPE_FANTRAY) 1112 outval = PCF8574_FAN_TYPE(value); 1113 } 1114 else 1115 if (cmd == ENVC_IOC_GETFAULT) { 1116 if (unitp->pcf8574_type == PCF8574_TYPE_PWRSUPP) 1117 outval = PCF8574_PS_FAULT(value); 1118 if (unitp->pcf8574_type == PCF8574_TYPE_FANTRAY) 1119 outval = PCF8574_PS_FAULT(value); 1120 } 1121 else 1122 if (cmd == ENVC_IOC_PSTEMPOK) { 1123 outval = PCF8574_PS_TEMPOK(value); 1124 } 1125 else 1126 if (cmd == ENVC_IOC_PSFANOK) { 1127 outval = PCF8574_PS_FANOK(value); 1128 } 1129 else 1130 if (cmd == ENVC_IOC_PSONOFF) { 1131 outval = PCF8574_PS_ONOFF(value); 1132 } else { 1133 outval = 0; 1134 } 1135 1136 if (ddi_copyout((caddr_t)&outval, (caddr_t)arg, 1137 sizeof (uint8_t), mode) != DDI_SUCCESS) { 1138 err = EFAULT; 1139 } 1140 } 1141 break; 1142 1143 case ENVC_IOC_GETMODE: { 1144 uint8_t curr_mode = unitp->current_mode; 1145 1146 if (ddi_copyout((caddr_t)&curr_mode, (caddr_t)arg, 1147 sizeof (uint8_t), mode) != DDI_SUCCESS) { 1148 err = EFAULT; 1149 } 1150 break; 1151 } 1152 1153 case ENVC_IOC_SETMODE: { 1154 uint8_t curr_mode; 1155 if (ddi_copyin((caddr_t)arg, (caddr_t)&curr_mode, 1156 sizeof (uint8_t), mode) != DDI_SUCCESS) { 1157 err = EFAULT; 1158 break; 1159 } 1160 if (curr_mode == ENVCTRL_DIAG_MODE || 1161 curr_mode == ENVCTRL_NORMAL_MODE) { 1162 unitp->current_mode = curr_mode; /* Don't do anything */ 1163 } 1164 break; 1165 } 1166 1167 1168 case I2CDEV_TRAN: 1169 if (call_copyin((caddr_t)arg, unitp, mode) != DDI_SUCCESS) { 1170 err = EFAULT; 1171 break; 1172 } 1173 unitp->i2c_status = err = 1174 nct_i2c_transfer(unitp->pcf8574_hdl, unitp->i2c_tran); 1175 1176 if (err != I2C_SUCCESS) { 1177 err = EIO; 1178 } else { 1179 if (call_copyout((caddr_t)arg, unitp, mode) 1180 != DDI_SUCCESS) { 1181 err = EFAULT; 1182 break; 1183 } 1184 } 1185 break; 1186 1187 default: 1188 err = EINVAL; 1189 } 1190 1191 CV_UNLOCK 1192 1193 return (err); 1194 } 1195 1196 static int 1197 pcf8574_add_kstat(struct pcf8574_unit *unitp, scsb_fru_status_t dev_presence) 1198 { 1199 char ksname[50]; 1200 int id; 1201 uint8_t i2c_address = unitp->props.slave_address; 1202 1203 /* 1204 * We create the kstat depending on the device function, 1205 * allocate the kstat placeholder and initialize the 1206 * values. 1207 */ 1208 unitp->envctrl_kstat = NULL; 1209 switch (unitp->pcf8574_type) { 1210 case PCF8574_TYPE_CPUVOLTAGE: 1211 { 1212 if ((unitp->kstatp = kstat_create(I2C_PCF8574_NAME, 1213 unitp->instance, I2C_KSTAT_CPUVOLTAGE, "misc", 1214 KSTAT_TYPE_RAW, sizeof (envctrl_cpuvoltage_t), 1215 KSTAT_FLAG_PERSISTENT)) != NULL) { 1216 1217 if ((unitp->envctrl_kstat = kmem_zalloc( 1218 sizeof (envctrl_cpuvoltage_t), KM_NOSLEEP)) == 1219 NULL) { 1220 kstat_delete(unitp->kstatp); 1221 return (DDI_FAILURE); 1222 } 1223 } else { 1224 return (DDI_FAILURE); 1225 } 1226 1227 break; 1228 } 1229 case PCF8574_TYPE_PWRSUPP: 1230 { 1231 envctrl_pwrsupp_t *envp; 1232 if (i2c_address == PCF8574_ADR_PWRSUPPLY1) { 1233 id = 1; 1234 } else if (i2c_address == PCF8574_ADR_PWRSUPPLY2) { 1235 id = 2; 1236 } else { 1237 id = i2c_address - PCF8574_ADR_PWRSUPPLY1; 1238 } 1239 (void) sprintf(ksname, "%s%d", I2C_KSTAT_PWRSUPPLY, id); 1240 if ((unitp->kstatp = kstat_create(I2C_PCF8574_NAME, 1241 unitp->instance, ksname, "misc", 1242 KSTAT_TYPE_RAW, sizeof (envctrl_pwrsupp_t), 1243 KSTAT_FLAG_PERSISTENT)) != NULL) { 1244 1245 if ((unitp->envctrl_kstat = kmem_zalloc( 1246 sizeof (envctrl_pwrsupp_t), KM_NOSLEEP)) == 1247 NULL) { 1248 kstat_delete(unitp->kstatp); 1249 return (DDI_FAILURE); 1250 } 1251 /* 1252 * Initialize the kstat fields. Need to initialize 1253 * the present field from SCSB info (dev_presence) 1254 */ 1255 envp = (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 1256 1257 envp->ps_present = dev_presence; 1258 envp->ps_ok = 0; 1259 envp->temp_ok = 0; 1260 envp->psfan_ok = 0; 1261 envp->on_state = 0; 1262 envp->ps_ver = 0; 1263 } else { 1264 return (DDI_FAILURE); 1265 } 1266 1267 break; 1268 } 1269 case PCF8574_TYPE_FANTRAY: 1270 { 1271 envctrl_fantray_t *envp; 1272 if (i2c_address == PCF8574_ADR_FANTRAY1) { 1273 id = 1; 1274 } else if (i2c_address == PCF8574_ADR_FANTRAY2) { 1275 id = 2; 1276 } else { 1277 id = i2c_address - PCF8574_ADR_FANTRAY1; 1278 } 1279 (void) sprintf(ksname, "%s%d", I2C_KSTAT_FANTRAY, id); 1280 if ((unitp->kstatp = kstat_create(I2C_PCF8574_NAME, 1281 unitp->instance, ksname, "misc", 1282 KSTAT_TYPE_RAW, sizeof (envctrl_fantray_t), 1283 KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) != NULL) { 1284 1285 if ((unitp->envctrl_kstat = kmem_zalloc( 1286 sizeof (envctrl_fantray_t), KM_NOSLEEP)) == 1287 NULL) { 1288 kstat_delete(unitp->kstatp); 1289 return (DDI_FAILURE); 1290 } 1291 1292 /* 1293 * Initialize the kstat fields. Need to initialize 1294 * the present field from SCSB info (dev_presence) 1295 */ 1296 envp = (envctrl_fantray_t *)unitp->envctrl_kstat; 1297 1298 envp->fan_present = dev_presence; 1299 envp->fan_ok = 0; 1300 envp->fanspeed = PCF8574_FAN_SPEED60; 1301 envp->fan_ver = 0; 1302 } else { 1303 return (DDI_FAILURE); 1304 } 1305 1306 break; 1307 } 1308 default: 1309 return (DDI_FAILURE); 1310 } 1311 1312 unitp->kstatp->ks_private = (void *)unitp; 1313 unitp->kstatp->ks_update = pcf8574_kstat_update; 1314 1315 kstat_install(unitp->kstatp); 1316 1317 return (DDI_SUCCESS); 1318 } 1319 1320 /* 1321 * This function reads a single byte from the pcf8574 chip, for use by the 1322 * kstat routines. The protocol for read will depend on the function. 1323 */ 1324 1325 static int 1326 pcf8574_read_chip(struct pcf8574_unit *unitp, uint16_t size) 1327 { 1328 int retval, i; 1329 i2c_transfer_t *tp = unitp->i2c_tran; 1330 1331 1332 tp->i2c_flags = I2C_RD; 1333 tp->i2c_rlen = size; 1334 tp->i2c_wlen = 0; 1335 1336 /* 1337 * Read the bytes from the pcf8574, mask off the 1338 * non-read bits and return the value. Block with 1339 * the driverwide lock. 1340 */ 1341 unitp->i2c_status = retval = 1342 nct_i2c_transfer(unitp->pcf8574_hdl, unitp->i2c_tran); 1343 1344 if (retval != I2C_SUCCESS) { 1345 return (retval); 1346 } 1347 1348 for (i = 0; i < size; i++) { 1349 tp->i2c_rbuf[i] &= unitp->readmask; 1350 } 1351 1352 return (I2C_SUCCESS); 1353 } 1354 1355 /* 1356 * This function writes a single byte to the pcf8574 chip, for use by the 1357 * ioctl routines. The protocol for write will depend on the function. 1358 * The bitpattern tells which bits are being modified, by setting these 1359 * bits in bitpattern to 1, e.g for fanspeed, bitpattern = 0x08, fanspeed 1360 * and intr 0x0c, only intr 0x04. 1361 */ 1362 1363 static int 1364 pcf8574_write_chip(struct pcf8574_unit *unitp, 1365 uint16_t size, uint8_t bitpattern) 1366 { 1367 i2c_transfer_t *tp = unitp->i2c_tran; 1368 int i; 1369 1370 /* 1371 * pcf8574_write 1372 * 1373 * First read the byte, modify only the writable 1374 * ports, then write back the modified data. 1375 */ 1376 tp->i2c_wlen = 0; 1377 tp->i2c_rlen = size; 1378 tp->i2c_flags = I2C_RD; 1379 1380 unitp->i2c_status = nct_i2c_transfer(unitp->pcf8574_hdl, tp); 1381 1382 if (unitp->i2c_status != I2C_SUCCESS) { 1383 return (I2C_FAILURE); 1384 } 1385 1386 /* 1387 * Our concern is when we have to write only a few bits. 1388 * We need to make sure we write the same value to those 1389 * bit positions which does not appear in bitpattern. 1390 */ 1391 1392 /* 1393 * 1) Ignore all bits than the one we are writing 1394 * 2) Now 0 the bits we intend to modify in the value 1395 * read from the chip, preserving all others. 1396 * 3) Now turn all non-writable ( read only/reserved ) 1397 * bits to 1. The value now should contain: 1398 * 1 in all non-writable bits. 1399 * 0 in the bis(s) we intend to modify. 1400 * no change in the writable bits we don't modify. 1401 * 4) Now OR it with the bits we got before, i.e. after 1402 * ignoring all bits other than one we are writing. 1403 */ 1404 1405 for (i = 0; i < size; i++) { 1406 tp->i2c_rbuf[i] &= ~(bitpattern); 1407 1408 tp->i2c_rbuf[i] |= ~(unitp->writemask); 1409 1410 tp->i2c_wbuf[i] = tp->i2c_rbuf[i] | 1411 (tp->i2c_wbuf[i] & bitpattern); 1412 } 1413 1414 tp->i2c_rlen = 0; 1415 tp->i2c_wlen = size; 1416 tp->i2c_flags = I2C_WR; 1417 1418 unitp->i2c_status = nct_i2c_transfer(unitp->pcf8574_hdl, tp); 1419 1420 return (unitp->i2c_status); 1421 } 1422 1423 static int 1424 pcf8574_kstat_update(kstat_t *ksp, int rw) 1425 { 1426 struct pcf8574_unit *unitp; 1427 char *kstatp; 1428 uint8_t value; 1429 int err = DDI_SUCCESS; 1430 scsb_fru_status_t dev_presence; 1431 1432 unitp = (struct pcf8574_unit *)ksp->ks_private; 1433 if (unitp->envctrl_kstat == NULL) { /* May be detaching */ 1434 return (err); 1435 } 1436 1437 CV_LOCK(EINTR) 1438 1439 /* 1440 * Need to call scsb to find whether device is present. 1441 * For I2C devices, the I2C address is used as a FRU ID. 1442 */ 1443 if (unitp->pcf8574_type == PCF8574_TYPE_CPUVOLTAGE) { 1444 dev_presence = FRU_PRESENT; 1445 } else { 1446 dev_presence = 1447 scsb_fru_status((uchar_t)unitp->props.slave_address); 1448 } 1449 1450 kstatp = (char *)ksp->ks_data; 1451 1452 /* 1453 * We could have write on the power supply and the fantray 1454 * pcf8574 chips. For masking the interrupt on both, or 1455 * controlling the fan speed on the fantray. But write 1456 * will not be allowed through the kstat interface. For 1457 * the present field, call SCSB. 1458 */ 1459 1460 if (rw == KSTAT_WRITE) { 1461 if (unitp->pcf8574_type != PCF8574_TYPE_FANTRAY) { 1462 err = EACCES; 1463 goto kstat_exit; 1464 } 1465 value = ((envctrl_fantray_t *)kstatp)->fanspeed; 1466 if (value != PCF8574_FAN_SPEED_LOW && 1467 value != PCF8574_FAN_SPEED_HIGH) { 1468 err = EINVAL; 1469 goto kstat_exit; 1470 } 1471 1472 unitp->i2c_tran->i2c_wbuf[0] = PCF8574_FAN_SPEED(value); 1473 1474 if (dev_presence == FRU_PRESENT && 1475 pcf8574_write_chip(unitp, 1, PCF8574_FANSPEED_BIT) 1476 != I2C_SUCCESS) { 1477 err = EFAULT; 1478 goto kstat_exit; 1479 } 1480 1481 } else { 1482 /* 1483 * First make sure that the FRU exists by checking the SCSB 1484 * dev_presence info. If not present, set the change field, 1485 * clear the kstat fields and make sure the kstat *_present 1486 * field is set to dev_presence from the SCSB driver. 1487 */ 1488 if (dev_presence == FRU_PRESENT && 1489 pcf8574_read_chip(unitp, 1) != I2C_SUCCESS) { 1490 /* 1491 * Looks like a real IO error. 1492 */ 1493 err = EIO; 1494 CV_UNLOCK 1495 1496 return (err); 1497 } 1498 if (dev_presence == FRU_PRESENT) 1499 value = unitp->i2c_tran->i2c_rbuf[0]; 1500 else 1501 value = 0; 1502 1503 switch (unitp->pcf8574_type) { 1504 case PCF8574_TYPE_CPUVOLTAGE: { 1505 envctrl_cpuvoltage_t *envp = 1506 (envctrl_cpuvoltage_t *)unitp->envctrl_kstat; 1507 envp->value = value; 1508 bcopy((caddr_t)envp, kstatp, 1509 sizeof (envctrl_cpuvoltage_t)); 1510 1511 break; 1512 } 1513 case PCF8574_TYPE_PWRSUPP: { 1514 envctrl_pwrsupp_t *envp = 1515 (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 1516 1517 envp->ps_present = dev_presence; 1518 envp->ps_ok = PCF8574_PS_FAULT(value); 1519 envp->temp_ok = PCF8574_PS_TEMPOK(value); 1520 envp->psfan_ok = PCF8574_PS_FANOK(value); 1521 envp->on_state = PCF8574_PS_ONOFF(value); 1522 envp->ps_ver = PCF8574_PS_TYPE(value); 1523 1524 bcopy((caddr_t)envp, kstatp, 1525 sizeof (envctrl_pwrsupp_t)); 1526 1527 break; 1528 } 1529 case PCF8574_TYPE_FANTRAY: { 1530 envctrl_fantray_t *envp = 1531 (envctrl_fantray_t *)unitp->envctrl_kstat; 1532 1533 envp->fan_present = dev_presence; 1534 envp->fan_ver = PCF8574_FAN_TYPE(value); 1535 envp->fan_ok = PCF8574_FAN_FAULT(value); 1536 envp->fanspeed = PCF8574_FAN_FANSPD(value); 1537 1538 bcopy((caddr_t)unitp->envctrl_kstat, kstatp, 1539 sizeof (envctrl_fantray_t)); 1540 1541 break; 1542 } 1543 1544 default: 1545 break; 1546 } 1547 } 1548 1549 kstat_exit: 1550 1551 CV_UNLOCK 1552 1553 return (err); 1554 } 1555 1556 static void 1557 pcf8574_delete_kstat(struct pcf8574_unit *unitp) 1558 { 1559 /* 1560 * Depending on the function, deallocate the correct 1561 * kernel allocated memory. 1562 */ 1563 if (unitp->kstatp != NULL) { 1564 kstat_delete(unitp->kstatp); 1565 } 1566 1567 switch (unitp->pcf8574_type) { 1568 case PCF8574_TYPE_CPUVOLTAGE: { 1569 if (unitp->envctrl_kstat != NULL) { 1570 kmem_free(unitp->envctrl_kstat, 1571 sizeof (envctrl_cpuvoltage_t)); 1572 } 1573 break; 1574 } 1575 case PCF8574_TYPE_PWRSUPP: { 1576 if (unitp->envctrl_kstat != NULL) { 1577 kmem_free(unitp->envctrl_kstat, 1578 sizeof (envctrl_pwrsupp_t)); 1579 } 1580 1581 break; 1582 } 1583 case PCF8574_TYPE_FANTRAY: { 1584 if (unitp->envctrl_kstat != NULL) { 1585 kmem_free(unitp->envctrl_kstat, 1586 sizeof (envctrl_fantray_t)); 1587 } 1588 break; 1589 } 1590 default: 1591 break; 1592 } 1593 1594 unitp->envctrl_kstat = NULL; 1595 } 1596 1597 static int 1598 pcf8574_read_props(struct pcf8574_unit *unitp) 1599 { 1600 dev_info_t *dip = unitp->dip; 1601 int retval = 0, prop_len; 1602 uint32_t *prop_value = NULL; 1603 uint8_t i2c_address; 1604 char *function; 1605 1606 /* 1607 * read the pcf8574_function property. If this property is not 1608 * found, return ERROR. Else, make sure it's either powersupply 1609 * or fantray. 1610 */ 1611 1612 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1613 "pcf8574_function", &function) != DDI_SUCCESS) { 1614 dbg_print(CE_WARN, "Couldn't find pcf8574_function property"); 1615 1616 return (DDI_FAILURE); 1617 } 1618 1619 if (strcmp(function, "fantray") == 0) { 1620 unitp->pcf8574_type = PCF8574_TYPE_FANTRAY; 1621 /* 1622 * Will fail the fantray attach if patch - 1. 1623 */ 1624 if (nct_p10fan_patch) { 1625 #ifdef DEBUG 1626 cmn_err(CE_WARN, "nct_p10fan_patch set: will not load " 1627 "fantary:address %x,%x", unitp->props.i2c_bus, 1628 unitp->props.slave_address); 1629 #endif 1630 ddi_prop_free(function); 1631 return (DDI_FAILURE); 1632 } 1633 } else 1634 if (strcmp(function, "powersupply") == 0) { 1635 unitp->pcf8574_type = PCF8574_TYPE_PWRSUPP; 1636 } else { 1637 dbg_print(CE_WARN, "Neither powersupply nor fantray"); 1638 ddi_prop_free(function); 1639 1640 return (DDI_FAILURE); 1641 } 1642 1643 ddi_prop_free(function); 1644 1645 retval = ddi_getlongprop(DDI_DEV_T_ANY, dip, 1646 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, 1647 "reg", (caddr_t)&prop_value, &prop_len); 1648 if (retval == DDI_PROP_SUCCESS) { 1649 unitp->props.i2c_bus = (uint16_t)prop_value[0]; 1650 unitp->props.slave_address = i2c_address = 1651 (uint8_t)prop_value[1]; 1652 kmem_free(prop_value, prop_len); 1653 1654 if (i2c_address>>4 == 7) 1655 unitp->sensor_type = PCF8574A; 1656 else if (i2c_address>>4 == 4) 1657 unitp->sensor_type = PCF8574; 1658 else { 1659 unitp->sensor_type = PCF8574A; 1660 dbg_print(CE_WARN, "Not a pcf8574/a device"); 1661 } 1662 1663 } else { 1664 unitp->props.i2c_bus = (uint16_t)-1; 1665 unitp->props.slave_address = (uint16_t)-1; 1666 } 1667 1668 /* 1669 * Get the Property information that the driver will be using 1670 * see typedef struct pcf8574_properties_t; 1671 */ 1672 1673 unitp->pcf8574_canintr = 0; 1674 retval = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1675 "interrupts", -1); 1676 if (retval >= 0) { 1677 int prop_len, intr_pri = 4; 1678 unitp->pcf8574_canintr |= PCF8574_INTR_ON; 1679 if (ddi_getproplen(DDI_DEV_T_ANY, dip, 1680 DDI_PROP_DONTPASS, "interrupt-priorities", 1681 &prop_len) == DDI_PROP_NOT_FOUND) { 1682 retval = ddi_prop_create(DDI_DEV_T_NONE, dip, 1683 DDI_PROP_CANSLEEP, "interrupt-priorities", 1684 (caddr_t)&intr_pri, sizeof (int)); 1685 #ifdef DEBUG 1686 if (retval != DDI_PROP_SUCCESS) { 1687 cmn_err(CE_WARN, "Failed to create interrupt- \ 1688 priorities property, retval %d", retval); 1689 } 1690 #endif /* DEBUG */ 1691 } 1692 } 1693 1694 /* 1695 * No channels-in-use property for the fan and powersupplies. 1696 */ 1697 unitp->props.num_chans_used = 0; 1698 if (i2c_address == PCF8574_ADR_CPUVOLTAGE) { 1699 if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1700 "channels-in-use", &prop_len) == DDI_PROP_SUCCESS) { 1701 retval = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, 1702 dip, DDI_PROP_DONTPASS, 1703 "channels-in-use", 1704 (uchar_t **)&unitp->props.channels_in_use, 1705 &unitp->props.num_chans_used); 1706 if (retval != DDI_PROP_SUCCESS) { 1707 unitp->props.num_chans_used = 0; 1708 } else { 1709 unitp->props.num_chans_used /= 1710 sizeof (pcf8574_channel_t); 1711 } 1712 } 1713 } 1714 1715 return (DDI_PROP_SUCCESS); 1716 } 1717 1718 /* 1719 * callback function to register with the SCSB driver in order to be 1720 * informed about changes in device instance presence. 1721 */ 1722 /*ARGSUSED*/ 1723 void 1724 pcf8574_callback(void *softstate, scsb_fru_event_t cb_event, 1725 scsb_fru_status_t dev_presence) 1726 { 1727 struct pcf8574_unit *unitp = (struct pcf8574_unit *)softstate; 1728 #ifdef DEBUG 1729 if (pcf8574_debug & 0x00800001) 1730 cmn_err(CE_NOTE, "pcf8574_callback(unitp,%d,%d)", 1731 (int)cb_event, (int)dev_presence); 1732 #endif /* DEBUG */ 1733 1734 switch (unitp->pcf8574_type) { 1735 case PCF8574_TYPE_CPUVOLTAGE: { 1736 /* 1737 * This Unit is not Field Replacable and will not 1738 * generate any events at the SCB. 1739 */ 1740 break; 1741 } 1742 case PCF8574_TYPE_PWRSUPP: { 1743 envctrl_pwrsupp_t *envp; 1744 1745 envp = (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 1746 if (dev_presence == FRU_NOT_PRESENT) { 1747 envp->ps_ok = 0; 1748 envp->temp_ok = 0; 1749 envp->psfan_ok = 0; 1750 envp->on_state = 0; 1751 envp->ps_ver = 0; 1752 } else 1753 if (dev_presence == FRU_PRESENT && 1754 envp->ps_present == FRU_NOT_PRESENT) { 1755 (void) pcf8574_init_chip(unitp, 0); 1756 } 1757 envp->ps_present = dev_presence; 1758 unitp->poll_event = POLLIN; 1759 pollwakeup(&unitp->poll, POLLIN); 1760 break; 1761 } 1762 case PCF8574_TYPE_FANTRAY: { 1763 envctrl_fantray_t *envp; 1764 1765 envp = (envctrl_fantray_t *)unitp->envctrl_kstat; 1766 1767 if (dev_presence == FRU_NOT_PRESENT) { 1768 envp->fan_ok = 0; 1769 envp->fanspeed = PCF8574_FAN_SPEED60; 1770 envp->fan_ver = 0; 1771 } else 1772 if (dev_presence == FRU_PRESENT && 1773 envp->fan_present == FRU_NOT_PRESENT) { 1774 (void) pcf8574_init_chip(unitp, 0); 1775 } 1776 envp->fan_present = dev_presence; 1777 unitp->poll_event = POLLIN; 1778 pollwakeup(&unitp->poll, POLLIN); 1779 break; 1780 } 1781 } 1782 } 1783 1784 /* 1785 * Initializes the chip after attach or after being inserted. 1786 * intron = 0 => disable interrupt. 1787 * intron = 1 => read register, enable interrupt if no fault. 1788 */ 1789 1790 static int 1791 pcf8574_init_chip(struct pcf8574_unit *unitp, int intron) 1792 { 1793 int ret = I2C_SUCCESS; 1794 i2c_transfer_t *tp = unitp->i2c_tran; 1795 uint8_t value = 0; 1796 boolean_t device_faulty = B_FALSE; /* true is faulty */ 1797 1798 if (unitp->pcf8574_type != PCF8574_TYPE_PWRSUPP && 1799 unitp->pcf8574_type != PCF8574_TYPE_FANTRAY) { 1800 return (ret); 1801 } 1802 switch (unitp->pcf8574_type) { 1803 case PCF8574_TYPE_PWRSUPP: 1804 tp->i2c_wbuf[0] = PCF8574_PS_DEFAULT; 1805 1806 break; 1807 case PCF8574_TYPE_FANTRAY: 1808 tp->i2c_wbuf[0] = PCF8574_FAN_DEFAULT; 1809 1810 break; 1811 default: 1812 break; 1813 } 1814 1815 /* 1816 * First, read the device. If the device is faulty, it does 1817 * not make sense to enable the interrupt, so in this case 1818 * keep interrupt maskked inspite of what "intron" says. 1819 */ 1820 1821 tp->i2c_wlen = 0; 1822 tp->i2c_rlen = 1; 1823 tp->i2c_flags = I2C_RD; 1824 1825 unitp->i2c_status = ret = nct_i2c_transfer(unitp->pcf8574_hdl, tp); 1826 1827 if (ret != I2C_SUCCESS) { 1828 return (ret); 1829 } 1830 1831 value = tp->i2c_rbuf[0]; 1832 1833 switch (unitp->pcf8574_type) { 1834 case PCF8574_TYPE_PWRSUPP: 1835 { 1836 envctrl_pwrsupp_t *envp = 1837 (envctrl_pwrsupp_t *)unitp->envctrl_kstat; 1838 1839 envp->ps_ok = PCF8574_PS_FAULT(value); 1840 envp->temp_ok = PCF8574_PS_TEMPOK(value); 1841 envp->psfan_ok = PCF8574_PS_FANOK(value); 1842 envp->on_state = PCF8574_PS_ONOFF(value); 1843 envp->ps_ver = PCF8574_PS_TYPE(value); 1844 1845 if (envp->ps_ok || envp->temp_ok || 1846 envp->psfan_ok || envp->on_state) 1847 device_faulty = B_TRUE; 1848 1849 break; 1850 } 1851 case PCF8574_TYPE_FANTRAY: 1852 { 1853 envctrl_fantray_t *envp = 1854 (envctrl_fantray_t *)unitp->envctrl_kstat; 1855 1856 envp->fan_ver = PCF8574_FAN_TYPE(value); 1857 envp->fan_ok = PCF8574_FAN_FAULT(value); 1858 envp->fanspeed = PCF8574_FAN_FANSPD(value); 1859 1860 if (!envp->fan_ok) 1861 device_faulty = B_TRUE; /* remember, 0 is faulty */ 1862 1863 break; 1864 } 1865 default: 1866 break; 1867 } 1868 /* 1869 * Mask interrupt, if intron = 0. 1870 */ 1871 if (!intron || device_faulty == B_TRUE) { 1872 tp->i2c_wbuf[0] |= PCF8574_INTRMASK_BIT; 1873 } 1874 1875 tp->i2c_wlen = 1; 1876 tp->i2c_rlen = 0; 1877 tp->i2c_flags = I2C_WR; 1878 1879 unitp->i2c_status = nct_i2c_transfer(unitp->pcf8574_hdl, tp); 1880 1881 return (unitp->i2c_status); 1882 } 1883