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.
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.
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]
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.
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/signal.h>
31 #include <sys/errno.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>
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 */
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>
64 #define dbg_print(level, str) cmn_err(level, str);
65 static int pcf8574_debug
= 0x00000102;
67 #define dbg_print(level, str) {; }
70 #define CV_LOCK(retval) \
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); \
80 unitp->pcf8574_flags = PCF8574_BUSY; \
81 mutex_exit(&unitp->umutex); \
86 mutex_enter(&unitp->umutex); \
87 unitp->pcf8574_flags = 0; \
88 cv_signal(&unitp->pcf8574_cv); \
89 mutex_exit(&unitp->umutex); \
92 static int nct_p10fan_patch
= 0; /* Fan patch for P1.0 */
93 static void *pcf8574_soft_statep
;
96 * cb ops (only need open,close,read,write,ioctl)
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);
106 static struct cb_ops pcf8574_cbops
= {
107 pcf8574_open
, /* open */
108 pcf8574_close
, /* close */
109 nodev
, /* strategy */
112 pcf8574_read
, /* read */
114 pcf8574_ioctl
, /* ioctl */
118 pcf8574_chpoll
, /* poll */
119 ddi_prop_op
, /* cb_prop_op */
120 NULL
, /* streamtab */
121 D_NEW
| D_MP
| D_HOTPLUG
, /* Driver compatibility flag */
123 nodev
, /* int (*cb_aread)() */
124 nodev
/* int (*cb_awrite)() */
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
);
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
,
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);
144 * SCSB callback function
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
,
149 extern int scsb_intr_unregister(fru_id_t
);
151 extern int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl
, i2c_transfer_t
*i2c_tran
);
153 static struct dev_ops pcf8574_ops
= {
165 ddi_quiesce_not_supported
, /* devo_quiesce */
168 extern struct mod_ops mod_driverops
;
170 static struct modldrv pcf8574_modldrv
= {
171 &mod_driverops
, /* type of module - driver */
172 "Netract pcf8574 (gpio)",
176 static struct modlinkage pcf8574_modlinkage
= {
187 error
= mod_install(&pcf8574_modlinkage
);
189 (void) ddi_soft_state_init(&pcf8574_soft_statep
,
190 sizeof (struct pcf8574_unit
), PCF8574_MAX_DEVS
);
201 error
= mod_remove(&pcf8574_modlinkage
);
203 ddi_soft_state_fini(&pcf8574_soft_statep
);
209 _info(struct modinfo
*modinfop
)
211 return (mod_info(&pcf8574_modlinkage
, modinfop
));
216 pcf8574_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
218 struct pcf8574_unit
*unitp
;
219 register int instance
;
220 int err
= DDI_SUCCESS
;
222 instance
= getminor(*devp
);
227 unitp
= (struct pcf8574_unit
*)
228 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
234 if (otyp
!= OTYP_CHR
) {
238 mutex_enter(&unitp
->umutex
);
241 if (unitp
->pcf8574_oflag
!= 0) {
244 unitp
->pcf8574_oflag
= FEXCL
;
247 if (unitp
->pcf8574_oflag
== FEXCL
) {
250 unitp
->pcf8574_oflag
= FREAD
|FWRITE
;
254 mutex_exit(&unitp
->umutex
);
261 pcf8574_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
263 struct pcf8574_unit
*unitp
;
264 register int instance
;
267 instance
= getminor(dev
);
273 unitp
= (struct pcf8574_unit
*)
274 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
280 mutex_enter(&unitp
->umutex
);
282 unitp
->pcf8574_oflag
= 0;
284 mutex_exit(&unitp
->umutex
);
286 return (DDI_SUCCESS
);
292 pcf8574_read(dev_t dev
, struct uio
*uiop
, cred_t
*cred_p
)
294 return (pcf8574_io(dev
, uiop
, B_READ
));
298 pcf8574_io(dev_t dev
, struct uio
*uiop
, int rw
)
300 struct pcf8574_unit
*unitp
;
301 register int instance
;
302 uint16_t bytes_to_rw
;
303 int err
= DDI_SUCCESS
;
306 instance
= getminor(dev
);
312 unitp
= (struct pcf8574_unit
*)
313 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
317 if ((bytes_to_rw
= uiop
->uio_resid
) > PCF8574_TRAN_SIZE
) {
324 err
= uiomove(unitp
->i2c_tran
->i2c_wbuf
,
325 bytes_to_rw
, UIO_WRITE
, uiop
);
328 err
= pcf8574_write_chip(unitp
, bytes_to_rw
,
333 err
= pcf8574_read_chip(unitp
, bytes_to_rw
);
335 err
= uiomove(unitp
->i2c_tran
->i2c_rbuf
,
336 bytes_to_rw
, UIO_READ
, uiop
);
348 pcf8574_do_resume(dev_info_t
*dip
)
350 int instance
= ddi_get_instance(dip
);
351 struct pcf8574_unit
*unitp
=
352 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
360 return (DDI_SUCCESS
);
364 pcf8574_do_detach(dev_info_t
*dip
)
366 struct pcf8574_unit
*unitp
;
370 instance
= ddi_get_instance(dip
);
371 unitp
= ddi_get_soft_state(pcf8574_soft_statep
, instance
);
373 attach_flag
= unitp
->attach_flag
;
375 if (attach_flag
& PCF8574_INTR_ADDED
) {
376 (void) scsb_intr_unregister(
377 (fru_id_t
)unitp
->props
.slave_address
);
380 if (attach_flag
& PCF8574_KSTAT_INIT
) {
381 pcf8574_delete_kstat(unitp
);
384 if (attach_flag
& PCF8574_LOCK_INIT
) {
385 mutex_destroy(&unitp
->umutex
);
386 cv_destroy(&unitp
->pcf8574_cv
);
389 scsb_fru_unregister((void *)unitp
,
390 (fru_id_t
)unitp
->props
.slave_address
);
392 if (attach_flag
& PCF8574_ALLOC_TRANSFER
) {
394 * restore the lengths to allocated lengths
397 unitp
->i2c_tran
->i2c_wlen
= MAX_WLEN
;
398 unitp
->i2c_tran
->i2c_rlen
= MAX_RLEN
;
399 i2c_transfer_free(unitp
->pcf8574_hdl
, unitp
->i2c_tran
);
402 if (attach_flag
& PCF8574_REGISTER_CLIENT
) {
403 i2c_client_unregister(unitp
->pcf8574_hdl
);
406 if (attach_flag
& PCF8574_MINORS_CREATED
) {
407 ddi_remove_minor_node(dip
, NULL
);
410 if (attach_flag
& PCF8574_PROPS_READ
) {
411 if (unitp
->pcf8574_type
== PCF8574_ADR_CPUVOLTAGE
&&
412 unitp
->props
.num_chans_used
!= 0) {
413 ddi_prop_free(unitp
->props
.channels_in_use
);
415 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
,
416 "interrupt-priorities");
420 if (attach_flag
& PCF8574_SOFT_STATE_ALLOC
) {
421 ddi_soft_state_free(pcf8574_soft_statep
, instance
);
424 return (DDI_SUCCESS
);
429 * The OBP will create device tree node for all I2C devices which
430 * may be present in a system. This means, even if the device is
431 * not physically present, the device tree node exists. We also
432 * will succeed the attach routine, since currently there is no
433 * hotplug support in the I2C bus, and the FRUs need to be hot
434 * swappable. Only during an I2C transaction we figure out whether
435 * the particular I2C device is actually present in the system
436 * by looking at the system controller board register. The fantray
437 * and power-supply devices may be swapped any time after system
438 * reboot, and the way we can make sure that the device is attached
439 * to the driver, is by always keeping the driver loaded, and report
440 * an error during the actual transaction.
443 pcf8574_do_attach(dev_info_t
*dip
)
445 register struct pcf8574_unit
*unitp
;
447 char name
[MAXNAMELEN
];
449 pcf8574_channel_t
*chp
;
450 scsb_fru_status_t dev_presence
;
452 instance
= ddi_get_instance(dip
);
454 if (pcf8574_debug
& 0x04)
455 cmn_err(CE_NOTE
, "pcf8574_attach: instance=%d\n",
459 if (ddi_soft_state_zalloc(pcf8574_soft_statep
, instance
) !=
461 return (DDI_FAILURE
);
463 unitp
= ddi_get_soft_state(pcf8574_soft_statep
, instance
);
466 ddi_soft_state_free(pcf8574_soft_statep
, instance
);
467 return (DDI_FAILURE
);
472 unitp
->attach_flag
= PCF8574_SOFT_STATE_ALLOC
;
474 if (pcf8574_read_props(unitp
) != DDI_PROP_SUCCESS
) {
475 ddi_soft_state_free(pcf8574_soft_statep
, instance
);
476 return (DDI_FAILURE
);
479 unitp
->attach_flag
|= PCF8574_PROPS_READ
;
482 * Set the current operating mode to NORMAL_MODE.
484 unitp
->current_mode
= ENVCTRL_NORMAL_MODE
;
486 (void) snprintf(unitp
->pcf8574_name
, PCF8574_NAMELEN
,
487 "%s%d", ddi_driver_name(dip
), instance
);
489 if (unitp
->pcf8574_type
== PCF8574_TYPE_PWRSUPP
) {
490 (void) sprintf(name
, "pwrsuppply");
491 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, instance
,
492 PCF8574_NODE_TYPE
, NULL
) == DDI_FAILURE
) {
493 ddi_remove_minor_node(dip
, NULL
);
494 (void) pcf8574_do_detach(dip
);
496 return (DDI_FAILURE
);
500 if (unitp
->pcf8574_type
== PCF8574_TYPE_FANTRAY
) {
501 (void) sprintf(name
, "fantray");
502 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, instance
,
503 PCF8574_NODE_TYPE
, NULL
) == DDI_FAILURE
) {
504 ddi_remove_minor_node(dip
, NULL
);
505 (void) pcf8574_do_detach(dip
);
507 return (DDI_FAILURE
);
511 if (unitp
->pcf8574_type
== PCF8574_TYPE_CPUVOLTAGE
) {
512 (void) sprintf(name
, "cpuvoltage");
513 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, instance
,
514 PCF8574_NODE_TYPE
, NULL
) == DDI_FAILURE
) {
515 ddi_remove_minor_node(dip
, NULL
);
516 (void) pcf8574_do_detach(dip
);
518 return (DDI_FAILURE
);
521 return (DDI_FAILURE
);
524 unitp
->attach_flag
|= PCF8574_MINORS_CREATED
;
527 * Now we need read/write masks since all the 8574 bits can be either
528 * read/written, but some ports are intended to be RD/WR only, or RW
529 * If no channels-in-use propoerty, set default values.
531 if (unitp
->pcf8574_type
== PCF8574_TYPE_FANTRAY
) {
532 unitp
->readmask
= PCF8574_FAN_READMASK
;
533 unitp
->writemask
= PCF8574_FAN_WRITEMASK
;
535 if (unitp
->pcf8574_type
== PCF8574_TYPE_PWRSUPP
) {
536 unitp
->readmask
= PCF8574_PS_READMASK
;
537 unitp
->writemask
= PCF8574_PS_WRITEMASK
;
540 for (i
= unitp
->props
.num_chans_used
,
541 chp
= unitp
->props
.channels_in_use
; i
; --i
, ++chp
) {
542 unitp
->readmask
|= (uint8_t)(
543 (chp
->io_dir
== I2C_PROP_IODIR_IN
||
544 chp
->io_dir
== I2C_PROP_IODIR_INOUT
) << chp
->port
);
545 unitp
->writemask
|= (uint8_t)(
546 (chp
->io_dir
== I2C_PROP_IODIR_OUT
||
547 chp
->io_dir
== I2C_PROP_IODIR_INOUT
) << chp
->port
);
551 cmn_err(CE_NOTE
, "pcf8574_do_attach: readmask = 0x%x \
552 writemask = 0x%x\n", unitp
->readmask
, unitp
->writemask
);
555 if (i2c_client_register(dip
, &unitp
->pcf8574_hdl
)
557 (void) pcf8574_do_detach(dip
);
558 return (DDI_FAILURE
);
560 unitp
->attach_flag
|= PCF8574_REGISTER_CLIENT
;
563 * Allocate the I2C_transfer structure. The same structure
564 * is used throughout the driver.
566 if (i2c_transfer_alloc(unitp
->pcf8574_hdl
, &unitp
->i2c_tran
,
567 MAX_WLEN
, MAX_RLEN
, KM_SLEEP
) != I2C_SUCCESS
) {
568 (void) pcf8574_do_detach(dip
);
569 return (DDI_FAILURE
);
571 unitp
->attach_flag
|= PCF8574_ALLOC_TRANSFER
;
574 * To begin with we set the mode to I2C_RD.
576 unitp
->i2c_tran
->i2c_flags
= I2C_RD
;
577 unitp
->i2c_tran
->i2c_version
= I2C_XFER_REV
;
580 * Set the busy flag and open flag to 0.
582 unitp
->pcf8574_flags
= 0;
583 unitp
->pcf8574_oflag
= 0;
585 mutex_init(&unitp
->umutex
, NULL
, MUTEX_DRIVER
, NULL
);
586 cv_init(&unitp
->pcf8574_cv
, NULL
, CV_DRIVER
, NULL
);
588 unitp
->attach_flag
|= PCF8574_LOCK_INIT
;
591 * Register out callback function with the SCSB driver, and save
592 * the returned value to check that the device instance exists.
594 dev_presence
= scsb_fru_register(pcf8574_callback
, (void *)unitp
,
595 (fru_id_t
)unitp
->props
.slave_address
);
596 if (dev_presence
== FRU_NOT_AVAILABLE
) {
597 scsb_fru_unregister((void *)unitp
,
598 (fru_id_t
)unitp
->props
.slave_address
);
602 * Add the kstats. First we need to get the property values
603 * depending on the device type. For example, for the fan
604 * tray there will be a different set of properties, and there
605 * will be another for the powersupplies, and another one for
606 * the CPU voltage monitor. Initialize the kstat structures with
610 if (pcf8574_add_kstat(unitp
, dev_presence
) != DDI_SUCCESS
) {
611 (void) pcf8574_do_detach(dip
);
612 return (DDI_FAILURE
);
615 unitp
->attach_flag
|= PCF8574_KSTAT_INIT
;
618 * Due to observed behavior on Solaris 8, the handler must be
619 * registered before any interrupts are enabled,
620 * in spite of what the ddi_get_iblock_cookie() manual says.
621 * As per the HW/SW spec, by default interrupts are disabled.
624 if (dev_presence
== FRU_PRESENT
) { /* program the chip */
625 (void) pcf8574_init_chip(unitp
, 0); /* Disable intr first */
628 if (unitp
->pcf8574_canintr
== PCF8574_INTR_ON
) {
630 if (pcf8574_debug
& 0x0004)
631 cmn_err(CE_NOTE
, "registering pcf9574 interrupt "
634 if (scsb_intr_register(pcf8574_intr
, (void *)unitp
,
635 (fru_id_t
)unitp
->props
.slave_address
) == DDI_SUCCESS
) {
636 unitp
->pcf8574_canintr
|= PCF8574_INTR_ENABLED
;
637 unitp
->attach_flag
|= PCF8574_INTR_ADDED
;
639 (void) pcf8574_do_detach(dip
);
640 return (DDI_FAILURE
);
646 return (DDI_SUCCESS
);
650 pcf8574_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
654 return (pcf8574_do_attach(dip
));
656 return (pcf8574_do_resume(dip
));
658 return (DDI_FAILURE
);
663 pcf8574_do_suspend(dev_info_t
*dip
)
665 int instance
= ddi_get_instance(dip
);
666 struct pcf8574_unit
*unitp
=
667 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
674 * Set the busy flag so that future transactions block
679 return (DDI_SUCCESS
);
683 pcf8574_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
687 return (pcf8574_do_detach(dip
));
689 return (pcf8574_do_suspend(dip
));
691 return (DDI_FAILURE
);
696 pcf8574_chpoll(dev_t dev
, short events
, int anyyet
, short *reventsp
,
697 struct pollhead
**phpp
)
699 struct pcf8574_unit
*unitp
;
702 instance
= getminor(dev
);
703 if ((unitp
= (struct pcf8574_unit
*)ddi_get_soft_state(
704 pcf8574_soft_statep
, instance
)) == NULL
) {
708 mutex_enter(&unitp
->umutex
);
709 if (unitp
->poll_event
) {
710 *reventsp
= unitp
->poll_event
;
711 unitp
->poll_event
= 0;
712 } else if ((events
& POLLIN
) && !anyyet
)
713 *phpp
= &unitp
->poll
;
714 mutex_exit(&unitp
->umutex
);
719 * In normal scenarios, this function should never get called.
720 * But, we will still come back and call this function if scsb
721 * interrupt sources does not indicate an scsb interrupt. We may
722 * come to this situation when SunVTS env4test is independently
723 * changing the device registers.
726 pcf8574_intr(caddr_t arg
)
730 struct pcf8574_unit
*unitp
= (struct pcf8574_unit
*)(void *)arg
;
731 scsb_fru_status_t dev_presence
;
732 i2c_transfer_t
*tp
= unitp
->i2c_tran
;
734 ic
= DDI_INTR_CLAIMED
;
736 cmn_err(CE_NOTE
, " In the interrupt service routine, %x",
737 unitp
->props
.slave_address
);
741 * Initiate an I2C transaction to find out
742 * whether this is the device which interrupted.
744 mutex_enter(&unitp
->umutex
);
745 while (unitp
->pcf8574_flags
== PCF8574_BUSY
) {
746 if (cv_wait_sig(&unitp
->pcf8574_cv
, &unitp
->umutex
) <= 0) {
747 mutex_exit(&unitp
->umutex
);
748 return (DDI_INTR_UNCLAIMED
);
752 unitp
->pcf8574_flags
= PCF8574_BUSY
;
753 mutex_exit(&unitp
->umutex
);
755 switch (unitp
->pcf8574_type
) {
756 case PCF8574_TYPE_CPUVOLTAGE
: {
757 dev_presence
= FRU_PRESENT
;
760 case PCF8574_TYPE_PWRSUPP
: {
761 envctrl_pwrsupp_t
*envp
=
762 (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
763 dev_presence
= envp
->ps_present
;
766 case PCF8574_TYPE_FANTRAY
: {
767 envctrl_fantray_t
*envp
=
768 (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
769 dev_presence
= envp
->fan_present
;
773 if (dev_presence
!= FRU_PRESENT
) {
774 ic
= DDI_INTR_UNCLAIMED
;
777 if (pcf8574_read_chip(unitp
, 1) != I2C_SUCCESS
) {
778 ic
= DDI_INTR_UNCLAIMED
;
781 value
= unitp
->i2c_tran
->i2c_rbuf
[0];
783 * If interrupt is already masked, return
785 if (value
& PCF8574_INTRMASK_BIT
) {
786 ic
= DDI_INTR_UNCLAIMED
;
791 * In case a fault bit is set, claim the interrupt.
793 switch (unitp
->pcf8574_type
) {
794 case PCF8574_TYPE_PWRSUPP
:
796 envctrl_pwrsupp_t
*envp
=
797 (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
799 if (PCF8574_PS_FAULT(value
) ||
800 PCF8574_PS_TEMPOK(value
) ||
801 PCF8574_PS_ONOFF(value
) ||
802 PCF8574_PS_FANOK(value
)) {
804 envp
->ps_ok
= PCF8574_PS_FAULT(value
);
805 envp
->temp_ok
= PCF8574_PS_TEMPOK(value
);
806 envp
->psfan_ok
= PCF8574_PS_FANOK(value
);
807 envp
->on_state
= PCF8574_PS_ONOFF(value
);
808 envp
->ps_ver
= PCF8574_PS_TYPE(value
);
811 PCF8574_PS_DEFAULT
| PCF8574_PS_MASKINTR
;
814 tp
->i2c_flags
= I2C_WR
;
817 nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
819 unitp
->poll_event
= POLLIN
;
820 pollwakeup(&unitp
->poll
, POLLIN
);
822 ic
= DDI_INTR_UNCLAIMED
;
827 case PCF8574_TYPE_FANTRAY
:
829 envctrl_fantray_t
*envp
=
830 (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
832 if (!PCF8574_FAN_FAULT(value
)) {
834 envp
->fan_ver
= PCF8574_FAN_TYPE(value
);
835 envp
->fan_ok
= PCF8574_FAN_FAULT(value
);
836 envp
->fanspeed
= PCF8574_FAN_FANSPD(value
);
839 PCF8574_FAN_DEFAULT
| PCF8574_FAN_MASKINTR
;
842 tp
->i2c_flags
= I2C_WR
;
845 nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
847 unitp
->poll_event
= POLLIN
;
848 pollwakeup(&unitp
->poll
, POLLIN
);
851 ic
= DDI_INTR_UNCLAIMED
;
857 ic
= DDI_INTR_UNCLAIMED
;
861 mutex_enter(&unitp
->umutex
);
862 unitp
->pcf8574_flags
= 0;
863 cv_signal(&unitp
->pcf8574_cv
);
864 mutex_exit(&unitp
->umutex
);
870 call_copyin(caddr_t arg
, struct pcf8574_unit
*unitp
, int mode
)
875 i2c_transfer_t
*i2ctp
= unitp
->i2c_tran
;
878 if (ddi_copyin((void *)arg
, (caddr_t
)&i2ct
,
879 sizeof (i2c_transfer_t
), mode
) != DDI_SUCCESS
) {
880 return (I2C_FAILURE
);
884 * Save the read and write buffer pointers in the transfer
885 * structure, otherwise these will get overwritten when we
886 * do a bcopy. Restore once done.
889 wbuf
= i2ctp
->i2c_wbuf
;
890 rbuf
= i2ctp
->i2c_rbuf
;
892 bcopy(&i2ct
, i2ctp
, sizeof (i2c_transfer_t
));
894 i2ctp
->i2c_wbuf
= wbuf
;
895 i2ctp
->i2c_rbuf
= rbuf
;
898 * copyin the read and write buffers to the saved buffers.
901 if (i2ct
.i2c_wlen
!= 0) {
902 if (ddi_copyin(i2ct
.i2c_wbuf
, (caddr_t
)i2ctp
->i2c_wbuf
,
903 i2ct
.i2c_wlen
, mode
) != DDI_SUCCESS
) {
904 return (I2C_FAILURE
);
908 return (I2C_SUCCESS
);
912 call_copyout(caddr_t arg
, struct pcf8574_unit
*unitp
, int mode
)
915 i2c_transfer_t
*i2ctp
= unitp
->i2c_tran
;
918 * We will copyout the last three fields only, skipping
919 * the remaining ones, before copying the rbuf to the
923 int uskip
= sizeof (i2c_transfer_t
) - 3*sizeof (int16_t),
924 kskip
= sizeof (i2c_transfer_t
) - 3*sizeof (int16_t);
927 * First copyin the user structure to the temporary i2ct,
928 * so that we have the wbuf and rbuf addresses in it.
931 uskip
= sizeof (i2c_transfer_t
) - 3 * (sizeof (uint16_t));
934 * copyout the last three out fields now.
937 if (ddi_copyout((void *)((intptr_t)i2ctp
+kskip
), (void *)
938 ((intptr_t)arg
+ uskip
), 3*sizeof (uint16_t), mode
)
940 return (I2C_FAILURE
);
944 * In case we have something to write, get the address of the read
948 if (i2ctp
->i2c_rlen
> i2ctp
->i2c_r_resid
) {
950 if (ddi_copyin((void *)arg
, &i2ct
,
951 sizeof (i2c_transfer_t
), mode
) != DDI_SUCCESS
) {
952 return (I2C_FAILURE
);
956 * copyout the read buffer to the saved user buffer in i2ct.
959 if (ddi_copyout(i2ctp
->i2c_rbuf
, i2ct
.i2c_rbuf
,
960 i2ctp
->i2c_rlen
- i2ctp
->i2c_r_resid
, mode
)
962 return (I2C_FAILURE
);
966 return (I2C_SUCCESS
);
971 pcf8574_ioctl(dev_t dev
, int cmd
, intptr_t arg
,
972 int mode
, cred_t
*credp
, int *rvalp
)
974 struct pcf8574_unit
*unitp
;
975 register int instance
;
977 uint8_t value
, inval
, outval
;
978 scsb_fru_status_t dev_presence
;
980 instance
= getminor(dev
);
985 unitp
= (struct pcf8574_unit
*)
986 ddi_get_soft_state(pcf8574_soft_statep
, instance
);
993 scsb_fru_status((uchar_t
)unitp
->props
.slave_address
);
998 case ENVC_IOC_INTRMASK
:
999 if (dev_presence
== FRU_NOT_PRESENT
) {
1003 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&inval
,
1004 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
1009 if (inval
!= 0 && inval
!= 1) {
1012 unitp
->i2c_tran
->i2c_wbuf
[0] =
1013 PCF8574_INT_MASK(inval
);
1014 if (pcf8574_write_chip(unitp
, 1, PCF8574_INTRMASK_BIT
)
1021 case ENVC_IOC_SETFAN
:
1022 if (unitp
->pcf8574_type
!= PCF8574_TYPE_FANTRAY
) {
1026 if (dev_presence
== FRU_NOT_PRESENT
) {
1030 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&inval
, sizeof (uint8_t),
1031 mode
) != DDI_SUCCESS
) {
1035 if (inval
!= PCF8574_FAN_SPEED_LOW
&&
1036 inval
!= PCF8574_FAN_SPEED_HIGH
) {
1041 unitp
->i2c_tran
->i2c_wbuf
[0] = PCF8574_FAN_SPEED(inval
);
1043 if (pcf8574_write_chip(unitp
, 1, PCF8574_FANSPEED_BIT
)
1049 case ENVC_IOC_SETSTATUS
:
1051 * Allow this ioctl only in DIAG mode.
1053 if (unitp
->current_mode
!= ENVCTRL_DIAG_MODE
) {
1056 if (dev_presence
== FRU_NOT_PRESENT
) {
1060 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&inval
,
1061 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
1064 unitp
->i2c_tran
->i2c_wbuf
[0] = inval
& 0xff;
1065 if (pcf8574_write_chip(unitp
, 1, 0xff)
1073 case ENVC_IOC_GETFAN
:
1074 case ENVC_IOC_GETSTATUS
:
1075 case ENVC_IOC_GETTYPE
:
1076 case ENVC_IOC_GETFAULT
:
1077 case ENVC_IOC_PSTEMPOK
:
1078 case ENVC_IOC_PSFANOK
:
1079 case ENVC_IOC_PSONOFF
: {
1080 if (dev_presence
== FRU_NOT_PRESENT
) {
1084 if (pcf8574_read_chip(unitp
, 1)
1089 value
= unitp
->i2c_tran
->i2c_rbuf
[0];
1090 if (cmd
== ENVC_IOC_GETFAN
) {
1091 if (unitp
->pcf8574_type
!= PCF8574_TYPE_FANTRAY
) {
1095 outval
= PCF8574_FAN_FANSPD(value
);
1099 if (cmd
== ENVC_IOC_GETSTATUS
) {
1103 if (cmd
== ENVC_IOC_GETTYPE
) {
1104 if (unitp
->pcf8574_type
== PCF8574_TYPE_PWRSUPP
)
1105 outval
= PCF8574_PS_TYPE(value
);
1106 if (unitp
->pcf8574_type
== PCF8574_TYPE_FANTRAY
)
1107 outval
= PCF8574_FAN_TYPE(value
);
1110 if (cmd
== ENVC_IOC_GETFAULT
) {
1111 if (unitp
->pcf8574_type
== PCF8574_TYPE_PWRSUPP
)
1112 outval
= PCF8574_PS_FAULT(value
);
1113 if (unitp
->pcf8574_type
== PCF8574_TYPE_FANTRAY
)
1114 outval
= PCF8574_PS_FAULT(value
);
1117 if (cmd
== ENVC_IOC_PSTEMPOK
) {
1118 outval
= PCF8574_PS_TEMPOK(value
);
1121 if (cmd
== ENVC_IOC_PSFANOK
) {
1122 outval
= PCF8574_PS_FANOK(value
);
1125 if (cmd
== ENVC_IOC_PSONOFF
) {
1126 outval
= PCF8574_PS_ONOFF(value
);
1131 if (ddi_copyout((caddr_t
)&outval
, (caddr_t
)arg
,
1132 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
1138 case ENVC_IOC_GETMODE
: {
1139 uint8_t curr_mode
= unitp
->current_mode
;
1141 if (ddi_copyout((caddr_t
)&curr_mode
, (caddr_t
)arg
,
1142 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
1148 case ENVC_IOC_SETMODE
: {
1150 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&curr_mode
,
1151 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
1155 if (curr_mode
== ENVCTRL_DIAG_MODE
||
1156 curr_mode
== ENVCTRL_NORMAL_MODE
) {
1157 unitp
->current_mode
= curr_mode
; /* Don't do anything */
1164 if (call_copyin((caddr_t
)arg
, unitp
, mode
) != DDI_SUCCESS
) {
1168 unitp
->i2c_status
= err
=
1169 nct_i2c_transfer(unitp
->pcf8574_hdl
, unitp
->i2c_tran
);
1171 if (err
!= I2C_SUCCESS
) {
1174 if (call_copyout((caddr_t
)arg
, unitp
, mode
)
1192 pcf8574_add_kstat(struct pcf8574_unit
*unitp
, scsb_fru_status_t dev_presence
)
1196 uint8_t i2c_address
= unitp
->props
.slave_address
;
1199 * We create the kstat depending on the device function,
1200 * allocate the kstat placeholder and initialize the
1203 unitp
->envctrl_kstat
= NULL
;
1204 switch (unitp
->pcf8574_type
) {
1205 case PCF8574_TYPE_CPUVOLTAGE
:
1207 if ((unitp
->kstatp
= kstat_create(I2C_PCF8574_NAME
,
1208 unitp
->instance
, I2C_KSTAT_CPUVOLTAGE
, "misc",
1209 KSTAT_TYPE_RAW
, sizeof (envctrl_cpuvoltage_t
),
1210 KSTAT_FLAG_PERSISTENT
)) != NULL
) {
1212 if ((unitp
->envctrl_kstat
= kmem_zalloc(
1213 sizeof (envctrl_cpuvoltage_t
), KM_NOSLEEP
)) ==
1215 kstat_delete(unitp
->kstatp
);
1216 return (DDI_FAILURE
);
1219 return (DDI_FAILURE
);
1224 case PCF8574_TYPE_PWRSUPP
:
1226 envctrl_pwrsupp_t
*envp
;
1227 if (i2c_address
== PCF8574_ADR_PWRSUPPLY1
) {
1229 } else if (i2c_address
== PCF8574_ADR_PWRSUPPLY2
) {
1232 id
= i2c_address
- PCF8574_ADR_PWRSUPPLY1
;
1234 (void) sprintf(ksname
, "%s%d", I2C_KSTAT_PWRSUPPLY
, id
);
1235 if ((unitp
->kstatp
= kstat_create(I2C_PCF8574_NAME
,
1236 unitp
->instance
, ksname
, "misc",
1237 KSTAT_TYPE_RAW
, sizeof (envctrl_pwrsupp_t
),
1238 KSTAT_FLAG_PERSISTENT
)) != NULL
) {
1240 if ((unitp
->envctrl_kstat
= kmem_zalloc(
1241 sizeof (envctrl_pwrsupp_t
), KM_NOSLEEP
)) ==
1243 kstat_delete(unitp
->kstatp
);
1244 return (DDI_FAILURE
);
1247 * Initialize the kstat fields. Need to initialize
1248 * the present field from SCSB info (dev_presence)
1250 envp
= (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
1252 envp
->ps_present
= dev_presence
;
1259 return (DDI_FAILURE
);
1264 case PCF8574_TYPE_FANTRAY
:
1266 envctrl_fantray_t
*envp
;
1267 if (i2c_address
== PCF8574_ADR_FANTRAY1
) {
1269 } else if (i2c_address
== PCF8574_ADR_FANTRAY2
) {
1272 id
= i2c_address
- PCF8574_ADR_FANTRAY1
;
1274 (void) sprintf(ksname
, "%s%d", I2C_KSTAT_FANTRAY
, id
);
1275 if ((unitp
->kstatp
= kstat_create(I2C_PCF8574_NAME
,
1276 unitp
->instance
, ksname
, "misc",
1277 KSTAT_TYPE_RAW
, sizeof (envctrl_fantray_t
),
1278 KSTAT_FLAG_PERSISTENT
| KSTAT_FLAG_WRITABLE
)) != NULL
) {
1280 if ((unitp
->envctrl_kstat
= kmem_zalloc(
1281 sizeof (envctrl_fantray_t
), KM_NOSLEEP
)) ==
1283 kstat_delete(unitp
->kstatp
);
1284 return (DDI_FAILURE
);
1288 * Initialize the kstat fields. Need to initialize
1289 * the present field from SCSB info (dev_presence)
1291 envp
= (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
1293 envp
->fan_present
= dev_presence
;
1295 envp
->fanspeed
= PCF8574_FAN_SPEED60
;
1298 return (DDI_FAILURE
);
1304 return (DDI_FAILURE
);
1307 unitp
->kstatp
->ks_private
= (void *)unitp
;
1308 unitp
->kstatp
->ks_update
= pcf8574_kstat_update
;
1310 kstat_install(unitp
->kstatp
);
1312 return (DDI_SUCCESS
);
1316 * This function reads a single byte from the pcf8574 chip, for use by the
1317 * kstat routines. The protocol for read will depend on the function.
1321 pcf8574_read_chip(struct pcf8574_unit
*unitp
, uint16_t size
)
1324 i2c_transfer_t
*tp
= unitp
->i2c_tran
;
1327 tp
->i2c_flags
= I2C_RD
;
1328 tp
->i2c_rlen
= size
;
1332 * Read the bytes from the pcf8574, mask off the
1333 * non-read bits and return the value. Block with
1334 * the driverwide lock.
1336 unitp
->i2c_status
= retval
=
1337 nct_i2c_transfer(unitp
->pcf8574_hdl
, unitp
->i2c_tran
);
1339 if (retval
!= I2C_SUCCESS
) {
1343 for (i
= 0; i
< size
; i
++) {
1344 tp
->i2c_rbuf
[i
] &= unitp
->readmask
;
1347 return (I2C_SUCCESS
);
1351 * This function writes a single byte to the pcf8574 chip, for use by the
1352 * ioctl routines. The protocol for write will depend on the function.
1353 * The bitpattern tells which bits are being modified, by setting these
1354 * bits in bitpattern to 1, e.g for fanspeed, bitpattern = 0x08, fanspeed
1355 * and intr 0x0c, only intr 0x04.
1359 pcf8574_write_chip(struct pcf8574_unit
*unitp
,
1360 uint16_t size
, uint8_t bitpattern
)
1362 i2c_transfer_t
*tp
= unitp
->i2c_tran
;
1368 * First read the byte, modify only the writable
1369 * ports, then write back the modified data.
1372 tp
->i2c_rlen
= size
;
1373 tp
->i2c_flags
= I2C_RD
;
1375 unitp
->i2c_status
= nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
1377 if (unitp
->i2c_status
!= I2C_SUCCESS
) {
1378 return (I2C_FAILURE
);
1382 * Our concern is when we have to write only a few bits.
1383 * We need to make sure we write the same value to those
1384 * bit positions which does not appear in bitpattern.
1388 * 1) Ignore all bits than the one we are writing
1389 * 2) Now 0 the bits we intend to modify in the value
1390 * read from the chip, preserving all others.
1391 * 3) Now turn all non-writable ( read only/reserved )
1392 * bits to 1. The value now should contain:
1393 * 1 in all non-writable bits.
1394 * 0 in the bis(s) we intend to modify.
1395 * no change in the writable bits we don't modify.
1396 * 4) Now OR it with the bits we got before, i.e. after
1397 * ignoring all bits other than one we are writing.
1400 for (i
= 0; i
< size
; i
++) {
1401 tp
->i2c_rbuf
[i
] &= ~(bitpattern
);
1403 tp
->i2c_rbuf
[i
] |= ~(unitp
->writemask
);
1405 tp
->i2c_wbuf
[i
] = tp
->i2c_rbuf
[i
] |
1406 (tp
->i2c_wbuf
[i
] & bitpattern
);
1410 tp
->i2c_wlen
= size
;
1411 tp
->i2c_flags
= I2C_WR
;
1413 unitp
->i2c_status
= nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
1415 return (unitp
->i2c_status
);
1419 pcf8574_kstat_update(kstat_t
*ksp
, int rw
)
1421 struct pcf8574_unit
*unitp
;
1424 int err
= DDI_SUCCESS
;
1425 scsb_fru_status_t dev_presence
;
1427 unitp
= (struct pcf8574_unit
*)ksp
->ks_private
;
1428 if (unitp
->envctrl_kstat
== NULL
) { /* May be detaching */
1435 * Need to call scsb to find whether device is present.
1436 * For I2C devices, the I2C address is used as a FRU ID.
1438 if (unitp
->pcf8574_type
== PCF8574_TYPE_CPUVOLTAGE
) {
1439 dev_presence
= FRU_PRESENT
;
1442 scsb_fru_status((uchar_t
)unitp
->props
.slave_address
);
1445 kstatp
= (char *)ksp
->ks_data
;
1448 * We could have write on the power supply and the fantray
1449 * pcf8574 chips. For masking the interrupt on both, or
1450 * controlling the fan speed on the fantray. But write
1451 * will not be allowed through the kstat interface. For
1452 * the present field, call SCSB.
1455 if (rw
== KSTAT_WRITE
) {
1456 if (unitp
->pcf8574_type
!= PCF8574_TYPE_FANTRAY
) {
1460 value
= ((envctrl_fantray_t
*)kstatp
)->fanspeed
;
1461 if (value
!= PCF8574_FAN_SPEED_LOW
&&
1462 value
!= PCF8574_FAN_SPEED_HIGH
) {
1467 unitp
->i2c_tran
->i2c_wbuf
[0] = PCF8574_FAN_SPEED(value
);
1469 if (dev_presence
== FRU_PRESENT
&&
1470 pcf8574_write_chip(unitp
, 1, PCF8574_FANSPEED_BIT
)
1478 * First make sure that the FRU exists by checking the SCSB
1479 * dev_presence info. If not present, set the change field,
1480 * clear the kstat fields and make sure the kstat *_present
1481 * field is set to dev_presence from the SCSB driver.
1483 if (dev_presence
== FRU_PRESENT
&&
1484 pcf8574_read_chip(unitp
, 1) != I2C_SUCCESS
) {
1486 * Looks like a real IO error.
1493 if (dev_presence
== FRU_PRESENT
)
1494 value
= unitp
->i2c_tran
->i2c_rbuf
[0];
1498 switch (unitp
->pcf8574_type
) {
1499 case PCF8574_TYPE_CPUVOLTAGE
: {
1500 envctrl_cpuvoltage_t
*envp
=
1501 (envctrl_cpuvoltage_t
*)unitp
->envctrl_kstat
;
1502 envp
->value
= value
;
1503 bcopy((caddr_t
)envp
, kstatp
,
1504 sizeof (envctrl_cpuvoltage_t
));
1508 case PCF8574_TYPE_PWRSUPP
: {
1509 envctrl_pwrsupp_t
*envp
=
1510 (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
1512 envp
->ps_present
= dev_presence
;
1513 envp
->ps_ok
= PCF8574_PS_FAULT(value
);
1514 envp
->temp_ok
= PCF8574_PS_TEMPOK(value
);
1515 envp
->psfan_ok
= PCF8574_PS_FANOK(value
);
1516 envp
->on_state
= PCF8574_PS_ONOFF(value
);
1517 envp
->ps_ver
= PCF8574_PS_TYPE(value
);
1519 bcopy((caddr_t
)envp
, kstatp
,
1520 sizeof (envctrl_pwrsupp_t
));
1524 case PCF8574_TYPE_FANTRAY
: {
1525 envctrl_fantray_t
*envp
=
1526 (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
1528 envp
->fan_present
= dev_presence
;
1529 envp
->fan_ver
= PCF8574_FAN_TYPE(value
);
1530 envp
->fan_ok
= PCF8574_FAN_FAULT(value
);
1531 envp
->fanspeed
= PCF8574_FAN_FANSPD(value
);
1533 bcopy((caddr_t
)unitp
->envctrl_kstat
, kstatp
,
1534 sizeof (envctrl_fantray_t
));
1552 pcf8574_delete_kstat(struct pcf8574_unit
*unitp
)
1555 * Depending on the function, deallocate the correct
1556 * kernel allocated memory.
1558 if (unitp
->kstatp
!= NULL
) {
1559 kstat_delete(unitp
->kstatp
);
1562 switch (unitp
->pcf8574_type
) {
1563 case PCF8574_TYPE_CPUVOLTAGE
: {
1564 if (unitp
->envctrl_kstat
!= NULL
) {
1565 kmem_free(unitp
->envctrl_kstat
,
1566 sizeof (envctrl_cpuvoltage_t
));
1570 case PCF8574_TYPE_PWRSUPP
: {
1571 if (unitp
->envctrl_kstat
!= NULL
) {
1572 kmem_free(unitp
->envctrl_kstat
,
1573 sizeof (envctrl_pwrsupp_t
));
1578 case PCF8574_TYPE_FANTRAY
: {
1579 if (unitp
->envctrl_kstat
!= NULL
) {
1580 kmem_free(unitp
->envctrl_kstat
,
1581 sizeof (envctrl_fantray_t
));
1589 unitp
->envctrl_kstat
= NULL
;
1593 pcf8574_read_props(struct pcf8574_unit
*unitp
)
1595 dev_info_t
*dip
= unitp
->dip
;
1596 int retval
= 0, prop_len
;
1597 uint32_t *prop_value
= NULL
;
1598 uint8_t i2c_address
;
1602 * read the pcf8574_function property. If this property is not
1603 * found, return ERROR. Else, make sure it's either powersupply
1607 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1608 "pcf8574_function", &function
) != DDI_SUCCESS
) {
1609 dbg_print(CE_WARN
, "Couldn't find pcf8574_function property");
1611 return (DDI_FAILURE
);
1614 if (strcmp(function
, "fantray") == 0) {
1615 unitp
->pcf8574_type
= PCF8574_TYPE_FANTRAY
;
1617 * Will fail the fantray attach if patch - 1.
1619 if (nct_p10fan_patch
) {
1621 cmn_err(CE_WARN
, "nct_p10fan_patch set: will not load "
1622 "fantary:address %x,%x", unitp
->props
.i2c_bus
,
1623 unitp
->props
.slave_address
);
1625 ddi_prop_free(function
);
1626 return (DDI_FAILURE
);
1629 if (strcmp(function
, "powersupply") == 0) {
1630 unitp
->pcf8574_type
= PCF8574_TYPE_PWRSUPP
;
1632 dbg_print(CE_WARN
, "Neither powersupply nor fantray");
1633 ddi_prop_free(function
);
1635 return (DDI_FAILURE
);
1638 ddi_prop_free(function
);
1640 retval
= ddi_getlongprop(DDI_DEV_T_ANY
, dip
,
1641 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
,
1642 "reg", (caddr_t
)&prop_value
, &prop_len
);
1643 if (retval
== DDI_PROP_SUCCESS
) {
1644 unitp
->props
.i2c_bus
= (uint16_t)prop_value
[0];
1645 unitp
->props
.slave_address
= i2c_address
=
1646 (uint8_t)prop_value
[1];
1647 kmem_free(prop_value
, prop_len
);
1649 if (i2c_address
>>4 == 7)
1650 unitp
->sensor_type
= PCF8574A
;
1651 else if (i2c_address
>>4 == 4)
1652 unitp
->sensor_type
= PCF8574
;
1654 unitp
->sensor_type
= PCF8574A
;
1655 dbg_print(CE_WARN
, "Not a pcf8574/a device");
1659 unitp
->props
.i2c_bus
= (uint16_t)-1;
1660 unitp
->props
.slave_address
= (uint16_t)-1;
1664 * Get the Property information that the driver will be using
1665 * see typedef struct pcf8574_properties_t;
1668 unitp
->pcf8574_canintr
= 0;
1669 retval
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1672 int prop_len
, intr_pri
= 4;
1673 unitp
->pcf8574_canintr
|= PCF8574_INTR_ON
;
1674 if (ddi_getproplen(DDI_DEV_T_ANY
, dip
,
1675 DDI_PROP_DONTPASS
, "interrupt-priorities",
1676 &prop_len
) == DDI_PROP_NOT_FOUND
) {
1677 retval
= ddi_prop_create(DDI_DEV_T_NONE
, dip
,
1678 DDI_PROP_CANSLEEP
, "interrupt-priorities",
1679 (caddr_t
)&intr_pri
, sizeof (int));
1681 if (retval
!= DDI_PROP_SUCCESS
) {
1682 cmn_err(CE_WARN
, "Failed to create interrupt- \
1683 priorities property, retval %d", retval
);
1690 * No channels-in-use property for the fan and powersupplies.
1692 unitp
->props
.num_chans_used
= 0;
1693 if (i2c_address
== PCF8574_ADR_CPUVOLTAGE
) {
1694 if (ddi_getproplen(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1695 "channels-in-use", &prop_len
) == DDI_PROP_SUCCESS
) {
1696 retval
= ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
,
1697 dip
, DDI_PROP_DONTPASS
,
1699 (uchar_t
**)&unitp
->props
.channels_in_use
,
1700 &unitp
->props
.num_chans_used
);
1701 if (retval
!= DDI_PROP_SUCCESS
) {
1702 unitp
->props
.num_chans_used
= 0;
1704 unitp
->props
.num_chans_used
/=
1705 sizeof (pcf8574_channel_t
);
1710 return (DDI_PROP_SUCCESS
);
1714 * callback function to register with the SCSB driver in order to be
1715 * informed about changes in device instance presence.
1719 pcf8574_callback(void *softstate
, scsb_fru_event_t cb_event
,
1720 scsb_fru_status_t dev_presence
)
1722 struct pcf8574_unit
*unitp
= (struct pcf8574_unit
*)softstate
;
1724 if (pcf8574_debug
& 0x00800001)
1725 cmn_err(CE_NOTE
, "pcf8574_callback(unitp,%d,%d)",
1726 (int)cb_event
, (int)dev_presence
);
1729 switch (unitp
->pcf8574_type
) {
1730 case PCF8574_TYPE_CPUVOLTAGE
: {
1732 * This Unit is not Field Replacable and will not
1733 * generate any events at the SCB.
1737 case PCF8574_TYPE_PWRSUPP
: {
1738 envctrl_pwrsupp_t
*envp
;
1740 envp
= (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
1741 if (dev_presence
== FRU_NOT_PRESENT
) {
1748 if (dev_presence
== FRU_PRESENT
&&
1749 envp
->ps_present
== FRU_NOT_PRESENT
) {
1750 (void) pcf8574_init_chip(unitp
, 0);
1752 envp
->ps_present
= dev_presence
;
1753 unitp
->poll_event
= POLLIN
;
1754 pollwakeup(&unitp
->poll
, POLLIN
);
1757 case PCF8574_TYPE_FANTRAY
: {
1758 envctrl_fantray_t
*envp
;
1760 envp
= (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
1762 if (dev_presence
== FRU_NOT_PRESENT
) {
1764 envp
->fanspeed
= PCF8574_FAN_SPEED60
;
1767 if (dev_presence
== FRU_PRESENT
&&
1768 envp
->fan_present
== FRU_NOT_PRESENT
) {
1769 (void) pcf8574_init_chip(unitp
, 0);
1771 envp
->fan_present
= dev_presence
;
1772 unitp
->poll_event
= POLLIN
;
1773 pollwakeup(&unitp
->poll
, POLLIN
);
1780 * Initializes the chip after attach or after being inserted.
1781 * intron = 0 => disable interrupt.
1782 * intron = 1 => read register, enable interrupt if no fault.
1786 pcf8574_init_chip(struct pcf8574_unit
*unitp
, int intron
)
1788 int ret
= I2C_SUCCESS
;
1789 i2c_transfer_t
*tp
= unitp
->i2c_tran
;
1791 boolean_t device_faulty
= B_FALSE
; /* true is faulty */
1793 if (unitp
->pcf8574_type
!= PCF8574_TYPE_PWRSUPP
&&
1794 unitp
->pcf8574_type
!= PCF8574_TYPE_FANTRAY
) {
1797 switch (unitp
->pcf8574_type
) {
1798 case PCF8574_TYPE_PWRSUPP
:
1799 tp
->i2c_wbuf
[0] = PCF8574_PS_DEFAULT
;
1802 case PCF8574_TYPE_FANTRAY
:
1803 tp
->i2c_wbuf
[0] = PCF8574_FAN_DEFAULT
;
1811 * First, read the device. If the device is faulty, it does
1812 * not make sense to enable the interrupt, so in this case
1813 * keep interrupt maskked inspite of what "intron" says.
1818 tp
->i2c_flags
= I2C_RD
;
1820 unitp
->i2c_status
= ret
= nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
1822 if (ret
!= I2C_SUCCESS
) {
1826 value
= tp
->i2c_rbuf
[0];
1828 switch (unitp
->pcf8574_type
) {
1829 case PCF8574_TYPE_PWRSUPP
:
1831 envctrl_pwrsupp_t
*envp
=
1832 (envctrl_pwrsupp_t
*)unitp
->envctrl_kstat
;
1834 envp
->ps_ok
= PCF8574_PS_FAULT(value
);
1835 envp
->temp_ok
= PCF8574_PS_TEMPOK(value
);
1836 envp
->psfan_ok
= PCF8574_PS_FANOK(value
);
1837 envp
->on_state
= PCF8574_PS_ONOFF(value
);
1838 envp
->ps_ver
= PCF8574_PS_TYPE(value
);
1840 if (envp
->ps_ok
|| envp
->temp_ok
||
1841 envp
->psfan_ok
|| envp
->on_state
)
1842 device_faulty
= B_TRUE
;
1846 case PCF8574_TYPE_FANTRAY
:
1848 envctrl_fantray_t
*envp
=
1849 (envctrl_fantray_t
*)unitp
->envctrl_kstat
;
1851 envp
->fan_ver
= PCF8574_FAN_TYPE(value
);
1852 envp
->fan_ok
= PCF8574_FAN_FAULT(value
);
1853 envp
->fanspeed
= PCF8574_FAN_FANSPD(value
);
1856 device_faulty
= B_TRUE
; /* remember, 0 is faulty */
1864 * Mask interrupt, if intron = 0.
1866 if (!intron
|| device_faulty
== B_TRUE
) {
1867 tp
->i2c_wbuf
[0] |= PCF8574_INTRMASK_BIT
;
1872 tp
->i2c_flags
= I2C_WR
;
1874 unitp
->i2c_status
= nct_i2c_transfer(unitp
->pcf8574_hdl
, tp
);
1876 return (unitp
->i2c_status
);