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