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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
28 * I2C leaf driver for the PCF8591
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/signal.h>
34 #include <sys/errno.h>
36 #include <sys/termio.h>
37 #include <sys/termios.h>
38 #include <sys/cmn_err.h>
39 #include <sys/stream.h>
40 #include <sys/strsun.h>
41 #include <sys/stropts.h>
42 #include <sys/strtty.h>
43 #include <sys/debug.h>
44 #include <sys/eucioctl.h>
51 #include <sys/sunddi.h>
52 #include <sys/obpdefs.h>
54 #include <sys/modctl.h>
59 #include <sys/i2c/misc/i2c_svc.h>
60 #include <sys/envctrl_gen.h>
61 #include <sys/netract_gen.h>
62 #include <sys/pcf8591_nct.h>
67 * PCF8591 Temp sensing control register definitions
69 * ---------------------------------------------
70 * | 0 | AOE | X | X | 0 | AIF | X | X |
71 * ---------------------------------------------
72 * AOE = Analog out enable.. not used on out implementation
73 * 5 & 4 = Analog Input Programming.. see data sheet for bits..
75 * AIF = Auto increment flag
76 * bits 1 & 0 are for the Chennel number.
80 #define I2CTRANS_DATA 0
82 #define TEMP_TABLE_SIZE 256
84 #define SHUTDOWN_TEMP_MIN 55
85 #define SHUTDOWN_TEMP_MAX 85
88 #define dbg_print(level, str) cmn_err(level, str);
90 #define dbg_print(level, str) {; }
94 extern int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl
, i2c_transfer_t
*i2c_tran
);
95 static uchar_t _cpu_temps
[TEMP_TABLE_SIZE
+ 4]; /* see attach */
97 static void *pcf8591_soft_statep
;
100 * cb ops (only need ioctl)
102 static int pcf8591_open(dev_t
*, int, int, cred_t
*);
103 static int pcf8591_close(dev_t
, int, int, cred_t
*);
104 static int pcf8591_read(dev_t dev
, struct uio
*uiop
, cred_t
*cred_p
);
105 static int pcf8591_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
107 static struct cb_ops pcf8591_cbops
= {
108 pcf8591_open
, /* open */
109 pcf8591_close
, /* close */
110 nodev
, /* strategy */
113 pcf8591_read
, /* read */
115 pcf8591_ioctl
, /* ioctl */
120 ddi_prop_op
, /* cb_prop_op */
121 NULL
, /* streamtab */
122 D_NEW
| D_MP
| D_HOTPLUG
, /* Driver compatibility flag */
124 nodev
, /* int (*cb_aread)() */
125 nodev
/* int (*cb_awrite)() */
131 static int pcf8591_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
133 static int pcf8591_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
134 static int pcf8591_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
137 static int pcf8591_add_kstats(struct pcf8591_unit
*);
138 static void pcf8591_delete_kstats(struct pcf8591_unit
*);
139 static int pcf8591_temp_kstat_update(kstat_t
*, int);
140 static int pcf8591_read_chip(struct pcf8591_unit
*, uint8_t, int);
141 static int pcf8591_read_props(struct pcf8591_unit
*unitp
);
143 static struct dev_ops pcf8591_ops
= {
155 ddi_quiesce_not_supported
, /* devo_quiesce */
158 extern struct mod_ops mod_driverops
;
160 static struct modldrv pcf8591_modldrv
= {
161 &mod_driverops
, /* type of module - driver */
162 "Netract pcf8591 (adio)",
166 static struct modlinkage pcf8591_modlinkage
= {
172 int pcf8591_debug
= 0x02;
173 static uint8_t translate_cputemp(uint8_t value
);
180 error
= mod_install(&pcf8591_modlinkage
);
182 (void) ddi_soft_state_init(&pcf8591_soft_statep
,
183 sizeof (struct pcf8591_unit
), PCF8591_MAX_DEVS
);
194 error
= mod_remove(&pcf8591_modlinkage
);
196 ddi_soft_state_fini(&pcf8591_soft_statep
);
203 _info(struct modinfo
*modinfop
)
205 return (mod_info(&pcf8591_modlinkage
, modinfop
));
210 pcf8591_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
213 struct pcf8591_unit
*unitp
;
214 minor_t minor
= getminor(*devp
);
216 int instance
= PCF8591_MINOR_TO_DEVINST(minor
);
217 int channel
= PCF8591_MINOR_TO_CHANNEL(minor
);
223 unitp
= (struct pcf8591_unit
*)
224 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
230 if (otyp
!= OTYP_CHR
) {
234 mutex_enter(&unitp
->umutex
);
237 if (unitp
->pcf8591_oflag
[channel
] != 0) {
240 unitp
->pcf8591_oflag
[channel
] = FEXCL
;
243 if (unitp
->pcf8591_oflag
[channel
] == FEXCL
) {
246 unitp
->pcf8591_oflag
[channel
] = FOPEN
;
250 mutex_exit(&unitp
->umutex
);
257 pcf8591_close(dev_t devp
, int flags
, int otyp
, cred_t
*credp
)
259 struct pcf8591_unit
*unitp
;
260 minor_t minor
= getminor(devp
);
262 int instance
= PCF8591_MINOR_TO_DEVINST(minor
);
263 int channel
= PCF8591_MINOR_TO_CHANNEL(minor
);
274 unitp
= (struct pcf8591_unit
*)
275 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
281 mutex_enter(&unitp
->umutex
);
283 unitp
->pcf8591_oflag
[channel
] = 0;
285 mutex_exit(&unitp
->umutex
);
287 return (DDI_SUCCESS
);
291 pcf8591_io(dev_t dev
, struct uio
*uiop
, int rw
)
294 struct pcf8591_unit
*unitp
;
295 minor_t minor
= getminor(dev
);
297 int instance
= PCF8591_MINOR_TO_DEVINST(minor
);
298 int channel
= PCF8591_MINOR_TO_CHANNEL(minor
);
304 * At this point we don't have a write operation to pcf8591.
314 unitp
= (struct pcf8591_unit
*)
315 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
320 if ((bytes_to_rw
= uiop
->uio_resid
) > PCF8591_TRAN_SIZE
) {
325 * Need to serialize all read operations, since there is a single
326 * i2c_transfer_t structure allocated for all read and write ops.
327 * We can't share the i2c bus among multiple transactions anyway,
328 * so this does not affect performance.
330 mutex_enter(&unitp
->umutex
);
331 while (unitp
->pcf8591_flags
== PCF8591_BUSY
) {
332 if (cv_wait_sig(&unitp
->pcf8591_cv
, &unitp
->umutex
) <= 0) {
333 mutex_exit(&unitp
->umutex
);
338 unitp
->pcf8591_flags
= PCF8591_BUSY
;
339 mutex_exit(&unitp
->umutex
);
341 if (bytes_to_rw
== 1)
345 * 1. set up the control register write, for now we'll always read
346 * channel 0, which is the only active 8591 port on the Nordica
347 * TODO: We'll need a minor node for each port that is used.
348 * 2. increment read count to read the throw-away byte
349 * 3. start the write/read of control/data registers
350 * 4. throw the first byte away
351 * 5. then return the data
354 unitp
->i2c_tran
->i2c_flags
= I2C_WR_RD
;
355 unitp
->i2c_tran
->i2c_wlen
= 1;
356 unitp
->i2c_tran
->i2c_wbuf
[0] = (unitp
->pcf8591_inprog
|
359 * read extra byte to throw away the first, (PCF8591 datasheet)
361 unitp
->i2c_tran
->i2c_rlen
= bytes_to_rw
+ 1;
363 if (nct_i2c_transfer(unitp
->pcf8591_hdl
,
364 unitp
->i2c_tran
) != I2C_SUCCESS
) {
368 * Throw away the first byte according to PCF8591 datasheet
369 * If translating, use the second byte.
372 unitp
->i2c_tran
->i2c_rbuf
[0] =
373 translate_cputemp(unitp
->i2c_tran
->i2c_rbuf
[1]);
375 unitp
->i2c_tran
->i2c_rbuf
[0] =
376 unitp
->i2c_tran
->i2c_rbuf
[1];
377 unitp
->i2c_tran
->i2c_rbuf
[1] = 0;
380 err
= uiomove(unitp
->i2c_tran
->i2c_rbuf
,
385 mutex_enter(&unitp
->umutex
);
386 unitp
->pcf8591_flags
= 0;
387 cv_signal(&unitp
->pcf8591_cv
);
388 mutex_exit(&unitp
->umutex
);
395 pcf8591_read(dev_t dev
, struct uio
*uiop
, cred_t
*cred_p
)
397 return (pcf8591_io(dev
, uiop
, B_READ
));
401 call_copyin(caddr_t arg
, struct pcf8591_unit
*unitp
, int mode
)
406 i2c_transfer_t
*i2ctp
= unitp
->i2c_tran
;
409 if (ddi_copyin((void *)arg
, (caddr_t
)&i2ct
,
410 sizeof (i2c_transfer_t
), mode
) != DDI_SUCCESS
) {
411 return (I2C_FAILURE
);
415 * Save the read and write buffer pointers in the transfer
416 * structure, otherwise these will get overwritten when we
417 * do a bcopy. Restore once done.
420 wbuf
= i2ctp
->i2c_wbuf
;
421 rbuf
= i2ctp
->i2c_rbuf
;
423 bcopy(&i2ct
, i2ctp
, sizeof (i2c_transfer_t
));
425 i2ctp
->i2c_wbuf
= wbuf
;
426 i2ctp
->i2c_rbuf
= rbuf
;
429 * copyin the read and write buffers to the saved buffers.
432 if (i2ct
.i2c_wlen
!= 0) {
433 if (ddi_copyin(i2ct
.i2c_wbuf
, (caddr_t
)i2ctp
->i2c_wbuf
,
434 i2ct
.i2c_wlen
, mode
) != DDI_SUCCESS
) {
435 return (I2C_FAILURE
);
439 return (I2C_SUCCESS
);
443 call_copyout(caddr_t arg
, struct pcf8591_unit
*unitp
, int mode
)
446 i2c_transfer_t
*i2ctp
= unitp
->i2c_tran
;
450 * We will copyout the last three fields only, skipping
451 * the remaining ones, before copying the rbuf to the
455 int uskip
= sizeof (i2c_transfer_t
) - 3*sizeof (int16_t),
456 kskip
= sizeof (i2c_transfer_t
) - 3*sizeof (int16_t);
459 * First copyin the user structure to the temporary i2ct,
460 * so that we have the wbuf and rbuf addresses in it.
463 uskip
= sizeof (i2c_transfer_t
) - 3 * (sizeof (uint16_t));
466 * copyout the last three out fields now.
469 if (ddi_copyout((void *)((intptr_t)i2ctp
+kskip
), (void *)
470 ((intptr_t)arg
+ uskip
), 3*sizeof (uint16_t), mode
)
472 return (I2C_FAILURE
);
476 * In case we have something to write, get the address of the read
480 if (i2ctp
->i2c_rlen
- i2ctp
->i2c_r_resid
> 0) {
482 if (ddi_copyin((void *)arg
, &i2ct
,
483 sizeof (i2c_transfer_t
), mode
) != DDI_SUCCESS
) {
484 return (I2C_FAILURE
);
488 * copyout the read buffer to the saved user buffer in i2ct.
491 i2c_actlen
= i2ctp
->i2c_rlen
- i2ctp
->i2c_r_resid
;
492 if (ddi_copyout(i2ctp
->i2c_rbuf
, i2ct
.i2c_rbuf
,
493 i2c_actlen
, mode
) != DDI_SUCCESS
) {
494 return (I2C_FAILURE
);
498 return (I2C_SUCCESS
);
502 * The ioctls will use the same name as the Javelin ioctls. We
503 * will have a very restricted set for MC, and unlike Javelin
504 * will not have a envctrl_chip structure to return values
505 * from the driver. All we will have is a uint8_t value to
506 * get or set values from the driver. Also, unlike the Javelin,
507 * where 'index' is used to specify the input port from where
508 * temperature is collected, here different minor nodes will be
509 * created by the driver for each port, eliminating the need for
510 * 'index' - leaving us with only the value to pass.
515 pcf8591_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
516 cred_t
*credp
, int *rvalp
)
519 struct pcf8591_unit
*unitp
;
520 minor_t minor
= getminor(dev
);
522 int instance
= PCF8591_MINOR_TO_DEVINST(minor
);
523 int channel
= PCF8591_MINOR_TO_CHANNEL(minor
);
525 unitp
= (struct pcf8591_unit
*)
526 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
528 mutex_enter(&unitp
->umutex
);
529 while (unitp
->pcf8591_flags
== PCF8591_BUSY
) {
530 if (cv_wait_sig(&unitp
->pcf8591_cv
, &unitp
->umutex
) <= 0) {
531 mutex_exit(&unitp
->umutex
);
536 unitp
->pcf8591_flags
= PCF8591_BUSY
;
537 mutex_exit(&unitp
->umutex
);
541 case ENVC_IOC_GETTEMP
: {
543 * Read the status byte from pcf8591 chip. The value will
544 * be already converted to Celcius by translate_cputemp.
546 (void) pcf8591_read_chip(unitp
, channel
, 1);
547 if (ddi_copyout(unitp
->i2c_tran
->i2c_rbuf
,
548 (caddr_t
)arg
, sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
554 case ENVC_IOC_GETMODE
: {
555 uint8_t curr_mode
= unitp
->current_mode
;
557 if (ddi_copyout((caddr_t
)&curr_mode
, (caddr_t
)arg
,
558 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
564 case ENVC_IOC_SETMODE
: {
566 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&curr_mode
,
567 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
571 if (curr_mode
== ENVCTRL_DIAG_MODE
||
572 curr_mode
== ENVCTRL_NORMAL_MODE
) {
573 unitp
->current_mode
= curr_mode
; /* Don't do anything */
578 /* Testing, may be removed */
580 if (call_copyin((caddr_t
)arg
, unitp
, mode
) != I2C_SUCCESS
) {
584 if (nct_i2c_transfer(unitp
->pcf8591_hdl
, unitp
->i2c_tran
)
589 if (call_copyout((caddr_t
)arg
, unitp
, mode
) != I2C_SUCCESS
) {
596 * TESTING TRANSLATION from "adc" "table" property
597 * translate thermistor index into temp Celcius
599 case I2CDEV_GETTEMP
: {
600 struct i2c_transfer
*tp
;
601 if (call_copyin((caddr_t
)arg
, unitp
, mode
) != I2C_SUCCESS
) {
605 tp
= unitp
->i2c_tran
;
606 if (tp
->i2c_rlen
!= 1) {
611 * Throw away the first byte according to PCF8591 datasheet,
615 if (nct_i2c_transfer(unitp
->pcf8591_hdl
, unitp
->i2c_tran
)
621 if (pcf8591_debug
& 0x0010)
623 "pcf8591_ioctl: i2c_rlen=%d; "
624 "i2c_rbuf[0,1]=0x%x,0x%x\n",
625 tp
->i2c_rlen
, tp
->i2c_rbuf
[0], tp
->i2c_rbuf
[1]);
628 * Throw away the first byte according to PCF8591 datasheet
630 if ((tp
->i2c_rbuf
[0] = translate_cputemp(tp
->i2c_rbuf
[1]))
637 if (call_copyout((caddr_t
)arg
, unitp
, mode
) != I2C_SUCCESS
) {
644 case I2CDEV_GETTABLES
: {
651 mutex_enter(&unitp
->umutex
);
652 unitp
->pcf8591_flags
= 0;
653 cv_signal(&unitp
->pcf8591_cv
);
654 mutex_exit(&unitp
->umutex
);
660 pcf8591_do_detach(dev_info_t
*dip
)
662 register struct pcf8591_unit
*unitp
;
666 instance
= ddi_get_instance(dip
);
667 unitp
= ddi_get_soft_state(pcf8591_soft_statep
, instance
);
668 attach_flag
= unitp
->attach_flag
;
670 if (attach_flag
& PCF8591_KSTAT_INIT
) {
671 pcf8591_delete_kstats(unitp
);
674 if (attach_flag
& PCF8591_LOCK_INIT
) {
675 mutex_destroy(&unitp
->umutex
);
676 cv_destroy(&unitp
->pcf8591_cv
);
680 * Restore the lengths of the rbuf and wbuf, which was originally
681 * allocated so that the appropriate amount of rbuf and wbuf are
684 if (attach_flag
& PCF8591_ALLOC_TRANSFER
) {
685 unitp
->i2c_tran
->i2c_wlen
= MAX_WLEN
;
686 unitp
->i2c_tran
->i2c_rlen
= MAX_RLEN
;
687 i2c_transfer_free(unitp
->pcf8591_hdl
, unitp
->i2c_tran
);
690 if (attach_flag
& PCF8591_REGISTER_CLIENT
) {
691 i2c_client_unregister(unitp
->pcf8591_hdl
);
694 if (attach_flag
& PCF8591_MINORS_CREATED
) {
695 ddi_remove_minor_node(dip
, NULL
);
699 * Free the memory allocated for the properties.
701 if (attach_flag
& PCF8591_PROPS_READ
) {
702 ddi_prop_free(unitp
->props
.name
);
703 if (unitp
->props
.num_chans_used
) {
704 ddi_prop_free(unitp
->props
.channels_in_use
);
707 if (unitp
->props
.channels_description
) {
708 ddi_prop_free(unitp
->props
.channels_description
);
712 if (attach_flag
& PCF8591_SOFT_STATE_ALLOC
) {
713 ddi_soft_state_free(pcf8591_soft_statep
, instance
);
716 return (DDI_SUCCESS
);
720 pcf8591_do_suspend(dev_info_t
*dip
)
722 int instance
= ddi_get_instance(dip
);
723 struct pcf8591_unit
*unitp
= (struct pcf8591_unit
*)
724 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
731 * Set the busy flag so that future transactions block
734 mutex_enter(&unitp
->umutex
);
735 while (unitp
->pcf8591_flags
== PCF8591_BUSY
) {
736 if (cv_wait_sig(&unitp
->pcf8591_cv
,
737 &unitp
->umutex
) <= 0) {
738 mutex_exit(&unitp
->umutex
);
740 return (DDI_FAILURE
);
743 unitp
->pcf8591_flags
= PCF8591_BUSY
;
744 mutex_exit(&unitp
->umutex
);
746 return (DDI_SUCCESS
);
750 pcf8591_do_resume(dev_info_t
*dip
)
752 int instance
= ddi_get_instance(dip
);
753 struct pcf8591_unit
*unitp
= (struct pcf8591_unit
*)
754 ddi_get_soft_state(pcf8591_soft_statep
, instance
);
759 mutex_enter(&unitp
->umutex
);
760 unitp
->pcf8591_flags
= 0;
761 cv_signal(&unitp
->pcf8591_cv
);
762 mutex_exit(&unitp
->umutex
);
764 return (DDI_SUCCESS
);
768 pcf8591_do_attach(dev_info_t
*dip
)
770 register struct pcf8591_unit
*unitp
;
772 char name
[MAXNAMELEN
];
775 instance
= ddi_get_instance(dip
);
777 if (ddi_soft_state_zalloc(pcf8591_soft_statep
, instance
) != 0) {
778 return (DDI_FAILURE
);
781 unitp
= ddi_get_soft_state(pcf8591_soft_statep
, instance
);
784 return (DDI_FAILURE
);
789 unitp
->attach_flag
= PCF8591_SOFT_STATE_ALLOC
;
791 if (pcf8591_read_props(unitp
) != DDI_PROP_SUCCESS
) {
792 (void) pcf8591_do_detach(dip
);
793 return (DDI_FAILURE
);
796 unitp
->attach_flag
|= PCF8591_PROPS_READ
;
799 * Set the current operating mode to NORMAL_MODE.
801 unitp
->current_mode
= ENVCTRL_NORMAL_MODE
; /* normal mode */
803 (void) snprintf(unitp
->pcf8591_name
, PCF8591_NAMELEN
,
804 "%s%d", ddi_driver_name(dip
), instance
);
807 * Create a minor node corresponding to channel 0 to 3
809 for (i
= 0; i
< PCF8591_MAX_CHANS
; i
++) {
811 (void) sprintf(name
, "cputemp");
813 (void) sprintf(name
, "%d", i
);
815 minor
= PCF8591_MINOR_NUM(instance
, i
);
816 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, minor
,
817 PCF8591_NODE_TYPE
, NULL
) == DDI_FAILURE
) {
818 ddi_remove_minor_node(dip
, NULL
);
819 (void) pcf8591_do_detach(dip
);
820 return (DDI_FAILURE
);
824 unitp
->attach_flag
|= PCF8591_MINORS_CREATED
;
826 if (i2c_client_register(dip
, &unitp
->pcf8591_hdl
)
828 (void) pcf8591_do_detach(dip
);
829 return (DDI_FAILURE
);
832 unitp
->attach_flag
|= PCF8591_REGISTER_CLIENT
;
835 * We allocate a single i2c_transfer_t structure for all
838 if (i2c_transfer_alloc(unitp
->pcf8591_hdl
, &unitp
->i2c_tran
,
839 MAX_WLEN
, MAX_RLEN
, KM_SLEEP
) != I2C_SUCCESS
) {
840 (void) pcf8591_do_detach(dip
);
841 return (DDI_FAILURE
);
844 unitp
->attach_flag
|= PCF8591_ALLOC_TRANSFER
;
847 * The flags will be set to I2C_WR because for all reads from
848 * the 8591 we need to also write the control byte.
850 unitp
->i2c_tran
->i2c_flags
= I2C_WR
;
851 unitp
->i2c_tran
->i2c_version
= I2C_XFER_REV
;
855 * Set the analog programming mode to default. Upper nibble
856 * in control byte. Four single ended inputs, output not enabled.
858 unitp
->pcf8591_inprog
= PCF8591_4SINGLE
| PCF8591_ANALOG_INPUT_EN
;
861 * Set the open flag for each channel to 0.
863 for (i
= 0; i
< PCF8591_MAX_CHANS
; i
++) {
864 unitp
->pcf8591_oflag
[i
] = 0;
868 * Set the busy flag to 0.
870 unitp
->pcf8591_flags
= 0;
872 mutex_init(&unitp
->umutex
, NULL
, MUTEX_DRIVER
, NULL
);
873 cv_init(&unitp
->pcf8591_cv
, NULL
, CV_DRIVER
, NULL
);
875 unitp
->attach_flag
|= PCF8591_LOCK_INIT
;
877 if (pcf8591_add_kstats(unitp
) != DDI_SUCCESS
) {
878 (void) pcf8591_do_detach(dip
);
879 return (DDI_FAILURE
);
882 unitp
->attach_flag
|= PCF8591_KSTAT_INIT
;
886 return (DDI_SUCCESS
);
891 pcf8591_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
896 if (infocmd
== DDI_INFO_DEVT2INSTANCE
) {
898 instance
= PCF8591_MINOR_TO_DEVINST(getminor(dev
));
899 *result
= (void *)(uintptr_t)instance
;
900 return (DDI_SUCCESS
);
902 return (DDI_FAILURE
);
906 pcf8591_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
910 return (pcf8591_do_attach(dip
));
912 return (pcf8591_do_resume(dip
));
914 return (DDI_FAILURE
);
919 pcf8591_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
923 return (pcf8591_do_detach(dip
));
925 return (pcf8591_do_suspend(dip
));
927 return (DDI_FAILURE
);
932 translate_cputemp(uint8_t value
)
934 return (_cpu_temps
[value
]);
938 pcf8591_add_kstats(struct pcf8591_unit
*unitp
)
940 if ((unitp
->tempksp
= kstat_create(I2C_PCF8591_NAME
,
941 unitp
->instance
, I2C_KSTAT_CPUTEMP
, "misc",
942 KSTAT_TYPE_RAW
, sizeof (unitp
->temp_kstats
),
943 KSTAT_FLAG_PERSISTENT
| KSTAT_FLAG_WRITABLE
)) == NULL
) {
945 return (DDI_FAILURE
);
949 * The kstat fields are already initialized in the attach routine..
952 unitp
->tempksp
->ks_update
= pcf8591_temp_kstat_update
;
953 unitp
->tempksp
->ks_private
= (void *)unitp
;
955 (void) strcpy(unitp
->temp_kstats
.label
,
956 unitp
->props
.channels_description
[0]);
957 unitp
->temp_kstats
.type
= ENVC_NETRACT_CPU_SENSOR
;
959 kstat_install(unitp
->tempksp
);
961 return (DDI_SUCCESS
);
965 pcf8591_delete_kstats(struct pcf8591_unit
*unitp
)
967 kstat_delete(unitp
->tempksp
);
971 pcf8591_temp_kstat_update(kstat_t
*ksp
, int rw
)
973 struct pcf8591_unit
*unitp
;
978 int shutdown_temp
= 0;
980 unitp
= (struct pcf8591_unit
*)ksp
->ks_private
;
982 mutex_enter(&unitp
->umutex
);
983 while (unitp
->pcf8591_flags
== PCF8591_BUSY
) {
984 if (cv_wait_sig(&unitp
->pcf8591_cv
,
985 &unitp
->umutex
) <= 0) {
986 mutex_exit(&unitp
->umutex
);
992 unitp
->pcf8591_flags
= PCF8591_BUSY
;
993 mutex_exit(&unitp
->umutex
);
995 kstatp
= (char *)ksp
->ks_data
;
997 if (rw
== KSTAT_WRITE
) {
999 /* check for the size of buffer */
1000 if (ksp
->ks_data_size
!= sizeof (unitp
->temp_kstats
)) {
1005 warn_temp
= ((envctrl_temp_t
*)kstatp
)->warning_threshold
;
1006 shutdown_temp
= ((envctrl_temp_t
*)kstatp
)->shutdown_threshold
;
1008 if (shutdown_temp
< SHUTDOWN_TEMP_MIN
|| shutdown_temp
>
1009 SHUTDOWN_TEMP_MAX
) {
1014 if (warn_temp
< 0 || shutdown_temp
<= warn_temp
) {
1019 /* write into kstat fields */
1020 unitp
->temp_kstats
.warning_threshold
= warn_temp
;
1021 unitp
->temp_kstats
.shutdown_threshold
= shutdown_temp
;
1024 (void) pcf8591_read_chip(unitp
, channel
, 1);
1025 unitp
->temp_kstats
.value
=
1026 unitp
->i2c_tran
->i2c_rbuf
[0];
1027 bcopy((caddr_t
)&unitp
->temp_kstats
, kstatp
,
1028 sizeof (unitp
->temp_kstats
));
1033 mutex_enter(&unitp
->umutex
);
1034 unitp
->pcf8591_flags
= 0;
1035 cv_signal(&unitp
->pcf8591_cv
);
1036 mutex_exit(&unitp
->umutex
);
1042 pcf8591_read_chip(struct pcf8591_unit
*unitp
, uint8_t channel
,
1045 int retval
= I2C_SUCCESS
;
1048 * We need to read an extra byte, since as per specification
1049 * the first byte read should be discarded.
1051 i2c_transfer_t
*tp
= unitp
->i2c_tran
;
1052 tp
->i2c_flags
= I2C_WR_RD
;
1053 tp
->i2c_rlen
= size
+1;
1055 tp
->i2c_wbuf
[0] = (unitp
->pcf8591_inprog
|
1058 retval
= nct_i2c_transfer(unitp
->pcf8591_hdl
, tp
);
1059 if (retval
== I2C_SUCCESS
) {
1060 tp
->i2c_rbuf
[0] = translate_cputemp(tp
->i2c_rbuf
[1]);
1063 if (tp
->i2c_rbuf
[0] == 0) {
1064 retval
= I2C_FAILURE
;
1071 * Reads the properties of the pcf8591 device.
1074 pcf8591_read_props(struct pcf8591_unit
*unitp
)
1076 dev_info_t
*dip
= unitp
->dip
;
1077 int i
, retval
= 0, prop_len
;
1078 int instance
= ddi_get_instance(dip
);
1079 int warning_temp
, shutdown_temp
;
1080 uint32_t *prop_value
= NULL
;
1086 instance
= instance
;
1089 * Check for the pcf8591_function property, and make sure it's
1092 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1093 "pcf8591_function", &function
) != DDI_SUCCESS
) {
1094 dbg_print(CE_WARN
, "Couldn't find pcf8591_function property");
1096 return (DDI_FAILURE
);
1099 if (strcmp(function
, "cputemp") != 0) {
1100 dbg_print(CE_WARN
, "pcf8591_function is not cputemp");
1101 ddi_prop_free(function
);
1103 return (DDI_FAILURE
);
1106 ddi_prop_free(function
);
1108 retval
= ddi_prop_lookup_string(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1109 "name", &unitp
->props
.name
);
1110 if (retval
!= DDI_PROP_SUCCESS
) {
1115 else if (pcf8591_debug
& 0x02)
1117 "pcf8591_read_props:ddi_prop_lookup_string(%s): \
1118 found %s ", "name", unitp
->props
.name
);
1121 retval
= ddi_getlongprop(DDI_DEV_T_ANY
, dip
,
1122 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
,
1123 "reg", (caddr_t
)&prop_value
, &prop_len
);
1124 if (retval
== DDI_PROP_SUCCESS
) {
1125 unitp
->props
.i2c_bus
= (uint16_t)prop_value
[0];
1126 unitp
->props
.slave_address
= (uint16_t)prop_value
[1];
1127 kmem_free(prop_value
, prop_len
);
1129 if (pcf8591_debug
& 0x02)
1131 "pcf8591:ddi_getlongprop(%s) returns %d,"
1132 " i2c_bus,slave=0x%x,0x%x",
1133 "reg", retval
, unitp
->props
.i2c_bus
,
1134 unitp
->props
.slave_address
);
1137 unitp
->props
.i2c_bus
= (uint16_t)-1;
1138 unitp
->props
.slave_address
= (uint16_t)-1;
1141 "pcf8591_read_props:ddi_getlongprop(%s) returns %d,"
1142 " default it to 0x%x:0x%X",
1143 "reg", retval
, unitp
->props
.i2c_bus
,
1144 unitp
->props
.slave_address
);
1147 (void) ddi_getproplen(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
1148 "channels-in-use", &prop_len
);
1149 retval
= ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
,
1150 dip
, DDI_PROP_DONTPASS
,
1152 (uchar_t
**)&unitp
->props
.channels_in_use
,
1153 &unitp
->props
.num_chans_used
);
1154 if (retval
== DDI_PROP_SUCCESS
) {
1155 unitp
->props
.num_chans_used
/= sizeof (pcf8591_channel_t
);
1157 unitp
->props
.num_chans_used
= 0;
1161 if (pcf8591_debug
& 0x0002)
1163 "pcf8591_read_props:ddi_prop_lookup_byte_array(%s)"
1165 "\t\tlength=%d, #elements=%d",
1166 "channels-in-use", retval
,
1167 prop_len
, unitp
->props
.num_chans_used
);
1170 retval
= ddi_prop_lookup_string_array(DDI_DEV_T_ANY
, dip
,
1171 DDI_PROP_DONTPASS
, "channels-description",
1172 (char ***)&unitp
->props
.channels_description
,
1173 (uint_t
*)&prop_len
);
1175 if (retval
!= DDI_PROP_SUCCESS
) {
1177 unitp
->props
.channels_description
= NULL
;
1181 if (pcf8591_debug
& 0x0002) {
1183 "pcf8591_read_props:ddi_prop_lookup_string_array(%s)"
1184 "returns %d, length=%d",
1185 "channels-description", retval
, prop_len
);
1186 for (i
= 0; i
< prop_len
; ++i
) {
1187 cmn_err(CE_NOTE
, "channels-description[%d]=<%s>",
1188 i
, unitp
->props
.channels_description
[i
]);
1194 * The following code was borrowed from envctrltwo.c
1195 * I haven't yet investigated why the copy target is index + 2
1197 retval
= ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
1198 DDI_PROP_DONTPASS
, "tables", &creg_prop
, (uint_t
*)&prop_len
);
1200 if (retval
!= DDI_PROP_SUCCESS
) {
1202 cmn_err(CE_WARN
, "%s%d: Unable to read pcf8591 tables property",
1203 ddi_get_name(dip
), instance
);
1206 return (DDI_NOT_WELL_FORMED
);
1209 tblsz
= (sizeof (_cpu_temps
) / sizeof (uchar_t
));
1210 if (prop_len
<= tblsz
) {
1211 for (i
= 0; i
< prop_len
; i
++) {
1212 _cpu_temps
[i
] = creg_prop
[i
];
1216 if (pcf8591_debug
& 0x0002)
1217 cmn_err(CE_NOTE
, "pcf8591_read_props: _cpu_temps size=%d; "
1218 "tables prop_len=%d\n", tblsz
, prop_len
);
1221 ddi_prop_free(creg_prop
);
1224 * Read shutdown temp and warning temp properties.
1226 warning_temp
= (int)ddi_getprop(DDI_DEV_T_ANY
, dip
,
1227 DDI_PROP_DONTPASS
, "warning-temp", PCF8591_WARNING_TEMP
);
1229 shutdown_temp
= (int)ddi_getprop(DDI_DEV_T_ANY
, dip
,
1230 DDI_PROP_DONTPASS
, "shutdown-temp", PCF8591_SHUTDOWN_TEMP
);
1233 * Fill up the warning and shutdown temp values in kstat structure.
1235 unitp
->temp_kstats
.warning_threshold
= warning_temp
;
1236 unitp
->temp_kstats
.shutdown_threshold
= shutdown_temp
;
1238 return (DDI_PROP_SUCCESS
);