xref: /titanic_44/usr/src/uts/sun4u/io/i2c/clients/max1617.c (revision 193974072f41a843678abf5f61979c748687e66b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*19397407SSherry Moore  * Common Development and Distribution License (the "License").
6*19397407SSherry Moore  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23f47a9c50Smathue  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * The max1617 I2C is a temp acquisition device.  As implemented on some
297c478bd9Sstevel@tonic-gate  * processor modules, it contains both a local and a remote temp.  The
307c478bd9Sstevel@tonic-gate  * local temp measures the ambient (room) temperature, while the remote
317c478bd9Sstevel@tonic-gate  * sensor is connected to the processor die.  There are ioctl's for retrieving
327c478bd9Sstevel@tonic-gate  * temperatures, and setting temperature alarm ranges.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
377c478bd9Sstevel@tonic-gate #include <sys/open.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/conf.h>
437c478bd9Sstevel@tonic-gate #include <sys/file.h>
447c478bd9Sstevel@tonic-gate #include <sys/note.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <sys/i2c/misc/i2c_svc.h>
477c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
487c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/max1617.h>
497c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/max1617_impl.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * cb ops (only need ioctl)
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate static int max1617_open(dev_t *, int, int, cred_t *);
557c478bd9Sstevel@tonic-gate static int max1617_close(dev_t, int, int, cred_t *);
567c478bd9Sstevel@tonic-gate static int max1617_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * dev ops
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate static int max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
627c478bd9Sstevel@tonic-gate 		void **result);
637c478bd9Sstevel@tonic-gate static int max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
647c478bd9Sstevel@tonic-gate static int max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static struct cb_ops max1617_cbops = {
677c478bd9Sstevel@tonic-gate 	max1617_open,			/* open */
687c478bd9Sstevel@tonic-gate 	max1617_close,			/* close */
697c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
707c478bd9Sstevel@tonic-gate 	nodev,				/* print */
717c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
727c478bd9Sstevel@tonic-gate 	nodev,				/* read */
737c478bd9Sstevel@tonic-gate 	nodev,				/* write */
747c478bd9Sstevel@tonic-gate 	max1617_ioctl,			/* ioctl */
757c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
767c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
777c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
787c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
797c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
807c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
817c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
827c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
837c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
847c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static struct dev_ops max1617_ops = {
887c478bd9Sstevel@tonic-gate 	DEVO_REV,
897c478bd9Sstevel@tonic-gate 	0,
907c478bd9Sstevel@tonic-gate 	max1617_info,
917c478bd9Sstevel@tonic-gate 	nulldev,
927c478bd9Sstevel@tonic-gate 	nulldev,
937c478bd9Sstevel@tonic-gate 	max1617_attach,
947c478bd9Sstevel@tonic-gate 	max1617_detach,
957c478bd9Sstevel@tonic-gate 	nodev,
967c478bd9Sstevel@tonic-gate 	&max1617_cbops,
97*19397407SSherry Moore 	NULL,
98*19397407SSherry Moore 	NULL,
99*19397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static struct modldrv max1617_modldrv = {
1037c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
104*19397407SSherry Moore 	"max1617 device driver",
1057c478bd9Sstevel@tonic-gate 	&max1617_ops,
1067c478bd9Sstevel@tonic-gate };
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static struct modlinkage max1617_modlinkage = {
1097c478bd9Sstevel@tonic-gate 	MODREV_1,
1107c478bd9Sstevel@tonic-gate 	&max1617_modldrv,
1117c478bd9Sstevel@tonic-gate 	0
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static int max1617_debug = 0;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static void *max1617_soft_statep;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate int
_init(void)1197c478bd9Sstevel@tonic-gate _init(void)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	int error;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	error = mod_install(&max1617_modlinkage);
1247c478bd9Sstevel@tonic-gate 	if (error == 0) {
1257c478bd9Sstevel@tonic-gate 		(void) ddi_soft_state_init(&max1617_soft_statep,
1267c478bd9Sstevel@tonic-gate 		    sizeof (struct max1617_unit), 1);
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	return (error);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate int
_fini(void)1337c478bd9Sstevel@tonic-gate _fini(void)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	int error;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	error = mod_remove(&max1617_modlinkage);
1387c478bd9Sstevel@tonic-gate 	if (error == 0) {
1397c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&max1617_soft_statep);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	return (error);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1467c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	return (mod_info(&max1617_modlinkage, modinfop));
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /* ARGSUSED */
1527c478bd9Sstevel@tonic-gate static int
max1617_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1537c478bd9Sstevel@tonic-gate max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	dev_t	dev;
1567c478bd9Sstevel@tonic-gate 	int	instance;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
1597c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
1607c478bd9Sstevel@tonic-gate 		instance = MAX1617_MINOR_TO_INST(getminor(dev));
1617c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
1627c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static int
max1617_do_attach(dev_info_t * dip)1687c478bd9Sstevel@tonic-gate max1617_do_attach(dev_info_t *dip)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
1717c478bd9Sstevel@tonic-gate 	int instance;
1727c478bd9Sstevel@tonic-gate 	char minor_name[MAXNAMELEN];
1737c478bd9Sstevel@tonic-gate 	minor_t minor_number;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(max1617_soft_statep, instance) != 0) {
1787c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate",
1797c478bd9Sstevel@tonic-gate 		    ddi_get_name(dip), instance);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	unitp = ddi_get_soft_state(max1617_soft_statep, instance);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	(void) snprintf(unitp->max1617_name, sizeof (unitp->max1617_name),
187f47a9c50Smathue 	    "%s%d", ddi_node_name(dip), instance);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	(void) sprintf(minor_name, "die_temp");
1907c478bd9Sstevel@tonic-gate 	minor_number = MAX1617_INST_TO_MINOR(instance) |
1917c478bd9Sstevel@tonic-gate 	    MAX1617_FCN_TO_MINOR(MAX1617_CPU_TEMP);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, minor_name, S_IFCHR,
1947c478bd9Sstevel@tonic-gate 	    minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) {
1957c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed for minor "
1967c478bd9Sstevel@tonic-gate 		    " name '%s'", unitp->max1617_name, minor_name);
1977c478bd9Sstevel@tonic-gate 			ddi_soft_state_free(max1617_soft_statep, instance);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	(void) sprintf(minor_name, "amb_temp");
2037c478bd9Sstevel@tonic-gate 	minor_number = MAX1617_INST_TO_MINOR(instance) |
2047c478bd9Sstevel@tonic-gate 	    MAX1617_FCN_TO_MINOR(MAX1617_AMB_TEMP);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, minor_name, S_IFCHR,
2077c478bd9Sstevel@tonic-gate 	    minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) {
2087c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed for %s",
2097c478bd9Sstevel@tonic-gate 		    unitp->max1617_name, minor_name);
2107c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
2117c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(max1617_soft_statep, instance);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (i2c_client_register(dip, &unitp->max1617_hdl) != I2C_SUCCESS) {
2177c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
2187c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(max1617_soft_statep, instance);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	mutex_init(&unitp->max1617_mutex, NULL, MUTEX_DRIVER, NULL);
2247c478bd9Sstevel@tonic-gate 	cv_init(&unitp->max1617_cv, NULL, CV_DRIVER, NULL);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static int
max1617_do_resume(dev_info_t * dip)2307c478bd9Sstevel@tonic-gate max1617_do_resume(dev_info_t *dip)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
2337c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
2347c478bd9Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
2357c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) ==
2387c478bd9Sstevel@tonic-gate 	    NULL) {
2397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl,
2437c478bd9Sstevel@tonic-gate 	    &i2ctp, 2, 0, I2C_SLEEP);
2447c478bd9Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
2457c478bd9Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG;
2497c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_config;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2527c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2537c478bd9Sstevel@tonic-gate 		goto done;
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG;
2577c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_conv_rate;
2587c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2597c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2607c478bd9Sstevel@tonic-gate 		goto done;
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_WR_REG;
2647c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] =  unitp->max1617_cpr_state.max1617_lcl_hlimit;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2677c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2687c478bd9Sstevel@tonic-gate 		goto done;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_WR_REG;
2727c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] =  unitp->max1617_cpr_state.max1617_remote_hlimit;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2757c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2767c478bd9Sstevel@tonic-gate 		goto done;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG;
2807c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_lcl_llimit;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2837c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2847c478bd9Sstevel@tonic-gate 		goto done;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG;
2887c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_remote_llimit;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
2917c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
2927c478bd9Sstevel@tonic-gate 		goto done;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	done:
2967c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
2977c478bd9Sstevel@tonic-gate 	unitp->max1617_flags = 0;
2987c478bd9Sstevel@tonic-gate 	cv_signal(&unitp->max1617_cv);
2997c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
3027c478bd9Sstevel@tonic-gate 	return (ret);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate static int
max1617_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3067c478bd9Sstevel@tonic-gate max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	switch (cmd) {
3097c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		return (max1617_do_attach(dip));
3127c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 		return (max1617_do_resume(dip));
3157c478bd9Sstevel@tonic-gate 	default:
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static int
max1617_do_detach(dev_info_t * dip)3227c478bd9Sstevel@tonic-gate max1617_do_detach(dev_info_t *dip)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
3257c478bd9Sstevel@tonic-gate 	int instance;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	unitp = ddi_get_soft_state(max1617_soft_statep, instance);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
3327c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	i2c_client_unregister(unitp->max1617_hdl);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	mutex_destroy(&unitp->max1617_mutex);
3407c478bd9Sstevel@tonic-gate 	cv_destroy(&unitp->max1617_cv);
3417c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(max1617_soft_statep, instance);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate static int
max1617_do_suspend(dev_info_t * dip)3477c478bd9Sstevel@tonic-gate max1617_do_suspend(dev_info_t *dip)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
3507c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
3517c478bd9Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
3527c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) ==
3557c478bd9Sstevel@tonic-gate 	    NULL) {
3567c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl,
3607c478bd9Sstevel@tonic-gate 	    &i2ctp, 1, 1, I2C_SLEEP);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * Block new transactions during CPR
3657c478bd9Sstevel@tonic-gate 	 */
3667c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
3677c478bd9Sstevel@tonic-gate 	while (unitp->max1617_flags == MAX1617_BUSY) {
3687c478bd9Sstevel@tonic-gate 		cv_wait(&unitp->max1617_cv, &unitp->max1617_mutex);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	unitp->max1617_flags = MAX1617_BUSY;
3717c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
3747c478bd9Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR_RD;
3757c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG;
3767c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
3777c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
3787c478bd9Sstevel@tonic-gate 		goto done;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_config = i2ctp->i2c_rbuf[0];
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG;
3837c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
3847c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
3857c478bd9Sstevel@tonic-gate 		goto done;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_conv_rate = i2ctp->i2c_rbuf[0];
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_REG;
3907c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
3917c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
3927c478bd9Sstevel@tonic-gate 		goto done;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_lcl_hlimit = i2ctp->i2c_rbuf[0];
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_REG;
3977c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
3987c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
3997c478bd9Sstevel@tonic-gate 		goto done;
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_remote_hlimit = i2ctp->i2c_rbuf[0];
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG;
4047c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
4057c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
4067c478bd9Sstevel@tonic-gate 		goto done;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_lcl_llimit = i2ctp->i2c_rbuf[0];
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG;
4117c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
4127c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
4137c478bd9Sstevel@tonic-gate 		goto done;
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_remote_llimit = i2ctp->i2c_rbuf[0];
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	done:
4187c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
4217c478bd9Sstevel@tonic-gate 		mutex_enter(&unitp->max1617_mutex);
4227c478bd9Sstevel@tonic-gate 		unitp->max1617_flags = 0;
4237c478bd9Sstevel@tonic-gate 		cv_broadcast(&unitp->max1617_cv);
4247c478bd9Sstevel@tonic-gate 		mutex_exit(&unitp->max1617_mutex);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 	return (ret);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate static int
max1617_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4307c478bd9Sstevel@tonic-gate max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	switch (cmd) {
4337c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 		return (max1617_do_detach(dip));
4367c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		return (max1617_do_suspend(dip));
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	default:
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate static int
max1617_open(dev_t * devp,int flags,int otyp,cred_t * credp)4477c478bd9Sstevel@tonic-gate max1617_open(dev_t *devp, int flags, int otyp, cred_t *credp)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp))
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
4527c478bd9Sstevel@tonic-gate 	int instance;
4537c478bd9Sstevel@tonic-gate 	int err = 0;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	instance = MAX1617_MINOR_TO_INST(getminor(*devp));
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (instance < 0) {
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		return (ENXIO);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
4637c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(max1617_soft_statep, instance);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		return (ENXIO);
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		return (EINVAL);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	if (flags & FEXCL) {
4787c478bd9Sstevel@tonic-gate 		if (unitp->max1617_oflag != 0) {
4797c478bd9Sstevel@tonic-gate 			err = EBUSY;
4807c478bd9Sstevel@tonic-gate 		} else {
4817c478bd9Sstevel@tonic-gate 			unitp->max1617_oflag = FEXCL;
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 	} else {
4847c478bd9Sstevel@tonic-gate 		if (unitp->max1617_oflag == FEXCL) {
4857c478bd9Sstevel@tonic-gate 			err = EBUSY;
4867c478bd9Sstevel@tonic-gate 		} else {
487f47a9c50Smathue 			unitp->max1617_oflag = (uint16_t)FOPEN;
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate done:
4927c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	return (err);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate static int
max1617_close(dev_t dev,int flags,int otyp,cred_t * credp)4987c478bd9Sstevel@tonic-gate max1617_close(dev_t dev, int flags, int otyp, cred_t *credp)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(flags, otyp, credp))
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
5037c478bd9Sstevel@tonic-gate 	int instance = MAX1617_MINOR_TO_INST(getminor(dev));
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (instance < 0) {
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 		return (ENXIO);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
5117c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(max1617_soft_statep, instance);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		return (ENXIO);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	unitp->max1617_oflag = 0;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate int
set_temp_limit(struct max1617_unit * unitp,uchar_t device_reg,caddr_t arg,int mode)5287c478bd9Sstevel@tonic-gate set_temp_limit(struct max1617_unit *unitp,
5297c478bd9Sstevel@tonic-gate 		uchar_t device_reg,
5307c478bd9Sstevel@tonic-gate 		caddr_t arg,
5317c478bd9Sstevel@tonic-gate 		int mode)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	int err = 0;
5347c478bd9Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
5357c478bd9Sstevel@tonic-gate 	int16_t temp;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 2, 0, I2C_SLEEP);
5387c478bd9Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
5397c478bd9Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR;
5407c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = device_reg;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)&temp, sizeof (int16_t), mode) !=
5437c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
5447c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		return (EFAULT);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = (int8_t)temp;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
5527c478bd9Sstevel@tonic-gate 		err = EIO;
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	return (err);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate int
get_temp_limit(struct max1617_unit * unitp,uchar_t reg,caddr_t arg,int mode)5617c478bd9Sstevel@tonic-gate get_temp_limit(struct max1617_unit *unitp,
5627c478bd9Sstevel@tonic-gate 		uchar_t reg,
5637c478bd9Sstevel@tonic-gate 		caddr_t arg,
5647c478bd9Sstevel@tonic-gate 		int mode)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate 	int err = 0;
5677c478bd9Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
5687c478bd9Sstevel@tonic-gate 	int16_t temp16;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1, I2C_SLEEP);
5717c478bd9Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
5727c478bd9Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR_RD;
5737c478bd9Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = reg;
5747c478bd9Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
5757c478bd9Sstevel@tonic-gate 		/*
5767c478bd9Sstevel@tonic-gate 		 * This double cast is required so that the sign is preserved
5777c478bd9Sstevel@tonic-gate 		 * when expanding the 8 bit value to 16.
5787c478bd9Sstevel@tonic-gate 		 */
5797c478bd9Sstevel@tonic-gate 		temp16 = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
5807c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&temp16, arg, sizeof (int16_t),
5817c478bd9Sstevel@tonic-gate 		    mode) != DDI_SUCCESS) {
5827c478bd9Sstevel@tonic-gate 			err = EFAULT;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	} else {
5857c478bd9Sstevel@tonic-gate 		err = EIO;
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	return (err);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate static int
max1617_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)5937c478bd9Sstevel@tonic-gate max1617_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5947c478bd9Sstevel@tonic-gate 		cred_t *credp, int *rvalp)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp, rvalp))
5977c478bd9Sstevel@tonic-gate 	struct max1617_unit *unitp;
5987c478bd9Sstevel@tonic-gate 	int err = 0;
5997c478bd9Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
6007c478bd9Sstevel@tonic-gate 	int fcn = MAX1617_MINOR_TO_FCN(getminor(dev));
6017c478bd9Sstevel@tonic-gate 	int instance = MAX1617_MINOR_TO_INST(getminor(dev));
6027c478bd9Sstevel@tonic-gate 	uchar_t reg;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
6057c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(max1617_soft_statep, instance);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (max1617_debug) {
6087c478bd9Sstevel@tonic-gate 		printf("max1617_ioctl: fcn=%d instance=%d\n", fcn, instance);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/*
6127c478bd9Sstevel@tonic-gate 	 * Serialize here, in order to block transacations during CPR.
6137c478bd9Sstevel@tonic-gate 	 * This is not a bottle neck since i2c_transfer would serialize
6147c478bd9Sstevel@tonic-gate 	 * anyway.
6157c478bd9Sstevel@tonic-gate 	 */
6167c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
6177c478bd9Sstevel@tonic-gate 	while (unitp->max1617_flags == MAX1617_BUSY) {
6187c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&unitp->max1617_cv,
6197c478bd9Sstevel@tonic-gate 		    &unitp->max1617_mutex) <= 0) {
6207c478bd9Sstevel@tonic-gate 			mutex_exit(&unitp->max1617_mutex);
6217c478bd9Sstevel@tonic-gate 			return (EINTR);
6227c478bd9Sstevel@tonic-gate 		}
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 	unitp->max1617_flags = MAX1617_BUSY;
6257c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	switch (cmd) {
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * I2C_GET_TEMPERATURE reads a temperature from the device and
6317c478bd9Sstevel@tonic-gate 	 * copies a single byte representing the celcius temp
6327c478bd9Sstevel@tonic-gate 	 * to user space.
6337c478bd9Sstevel@tonic-gate 	 */
6347c478bd9Sstevel@tonic-gate 	case I2C_GET_TEMPERATURE:
6357c478bd9Sstevel@tonic-gate 		switch (fcn) {
6367c478bd9Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
6377c478bd9Sstevel@tonic-gate 			reg = MAX1617_LOCAL_TEMP_REG;
6387c478bd9Sstevel@tonic-gate 			break;
6397c478bd9Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
6407c478bd9Sstevel@tonic-gate 			reg = MAX1617_REMOTE_TEMP_REG;
6417c478bd9Sstevel@tonic-gate 			break;
6427c478bd9Sstevel@tonic-gate 		default:
6437c478bd9Sstevel@tonic-gate 			err = EINVAL;
6447c478bd9Sstevel@tonic-gate 			goto done;
6457c478bd9Sstevel@tonic-gate 		}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
6487c478bd9Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
6497c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
6507c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
6517c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = reg;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 			/*
6567c478bd9Sstevel@tonic-gate 			 * This double cast is needed so that the sign bit
6577c478bd9Sstevel@tonic-gate 			 * is preserved when casting from unsigned char to
6587c478bd9Sstevel@tonic-gate 			 * signed 16 bit value.
6597c478bd9Sstevel@tonic-gate 			 */
6607c478bd9Sstevel@tonic-gate 			int16_t temp = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
6617c478bd9Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
6627c478bd9Sstevel@tonic-gate 			    sizeof (int16_t), mode) != DDI_SUCCESS) {
6637c478bd9Sstevel@tonic-gate 				err = EFAULT;
6647c478bd9Sstevel@tonic-gate 			}
6657c478bd9Sstevel@tonic-gate 		} else {
6667c478bd9Sstevel@tonic-gate 			err = EIO;
6677c478bd9Sstevel@tonic-gate 		}
6687c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
6697c478bd9Sstevel@tonic-gate 		break;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	case MAX1617_GET_STATUS:
6727c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
6737c478bd9Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
6747c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
6757c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
6767c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_STATUS_REG;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
6797c478bd9Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
6807c478bd9Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
6817c478bd9Sstevel@tonic-gate 				err = EFAULT;
6827c478bd9Sstevel@tonic-gate 			}
6837c478bd9Sstevel@tonic-gate 		} else {
6847c478bd9Sstevel@tonic-gate 			err = EIO;
6857c478bd9Sstevel@tonic-gate 		}
6867c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
6877c478bd9Sstevel@tonic-gate 		break;
6887c478bd9Sstevel@tonic-gate 	case MAX1617_GET_CONFIG:
6897c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1,
6907c478bd9Sstevel@tonic-gate 		    I2C_SLEEP);
6917c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
6927c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
6937c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG;
6947c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
6957c478bd9Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
6967c478bd9Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
6977c478bd9Sstevel@tonic-gate 				err = EFAULT;
6987c478bd9Sstevel@tonic-gate 			}
6997c478bd9Sstevel@tonic-gate 		} else {
7007c478bd9Sstevel@tonic-gate 			err = EIO;
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
7037c478bd9Sstevel@tonic-gate 		break;
7047c478bd9Sstevel@tonic-gate 	case MAX1617_GET_CONV_RATE:
7057c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
7067c478bd9Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
7077c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
7087c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
7097c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG;
7107c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
7117c478bd9Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
7127c478bd9Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
7137c478bd9Sstevel@tonic-gate 				err = EFAULT;
7147c478bd9Sstevel@tonic-gate 			}
7157c478bd9Sstevel@tonic-gate 		} else {
7167c478bd9Sstevel@tonic-gate 			err = EIO;
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
7197c478bd9Sstevel@tonic-gate 		break;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	case MAX1617_GET_HIGH_LIMIT:
7227c478bd9Sstevel@tonic-gate 		switch (fcn) {
7237c478bd9Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
7247c478bd9Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_LOCALTEMP_HIGH_REG,
7257c478bd9Sstevel@tonic-gate 			    (caddr_t)arg, mode);
7267c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
7287c478bd9Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_REMOTETEMP_HIGH_REG,
7297c478bd9Sstevel@tonic-gate 			    (caddr_t)arg, mode);
7307c478bd9Sstevel@tonic-gate 			break;
7317c478bd9Sstevel@tonic-gate 		default:
7327c478bd9Sstevel@tonic-gate 			err = EINVAL;
7337c478bd9Sstevel@tonic-gate 			break;
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 		break;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	case MAX1617_GET_LOW_LIMIT:
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 		switch (fcn) {
7407c478bd9Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
7417c478bd9Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_LOCALTEMP_LOW_REG,
7427c478bd9Sstevel@tonic-gate 			    (caddr_t)arg, mode);
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
7457c478bd9Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_REMOTETEMP_LOW_REG,
7467c478bd9Sstevel@tonic-gate 			    (caddr_t)arg, mode);
7477c478bd9Sstevel@tonic-gate 			break;
7487c478bd9Sstevel@tonic-gate 		default:
7497c478bd9Sstevel@tonic-gate 			err = EINVAL;
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 		break;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	case MAX1617_SET_CONV_RATE:
7547c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
7557c478bd9Sstevel@tonic-gate 		    2, 0, I2C_SLEEP);
7567c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
7577c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
7587c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG;
7597c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
7607c478bd9Sstevel@tonic-gate 		    sizeof (uint8_t), mode) != DDI_SUCCESS) {
7617c478bd9Sstevel@tonic-gate 			err = EFAULT;
7627c478bd9Sstevel@tonic-gate 			break;
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
7657c478bd9Sstevel@tonic-gate 			err = EIO;
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
7687c478bd9Sstevel@tonic-gate 		break;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	case MAX1617_SET_CONFIG:
7717c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
7727c478bd9Sstevel@tonic-gate 		    2, 0, I2C_SLEEP);
7737c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
7747c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
7757c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG;
7767c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
7777c478bd9Sstevel@tonic-gate 		    sizeof (uint8_t), mode) != DDI_SUCCESS) {
7787c478bd9Sstevel@tonic-gate 			err = EFAULT;
7797c478bd9Sstevel@tonic-gate 			break;
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
7827c478bd9Sstevel@tonic-gate 			err = EIO;
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
7867c478bd9Sstevel@tonic-gate 		break;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	case MAX1617_SET_HIGH_LIMIT:
7897c478bd9Sstevel@tonic-gate 		switch (fcn) {
7907c478bd9Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
7917c478bd9Sstevel@tonic-gate 			err = set_temp_limit(unitp,
7927c478bd9Sstevel@tonic-gate 			    MAX1617_LOCALTEMP_HIGH_WR_REG, (caddr_t)arg, mode);
7937c478bd9Sstevel@tonic-gate 			break;
7947c478bd9Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
7957c478bd9Sstevel@tonic-gate 			err = set_temp_limit(unitp,
7967c478bd9Sstevel@tonic-gate 			    MAX1617_REMOTETEMP_HIGH_WR_REG, (caddr_t)arg, mode);
7977c478bd9Sstevel@tonic-gate 			break;
7987c478bd9Sstevel@tonic-gate 		default:
7997c478bd9Sstevel@tonic-gate 			err = EINVAL;
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 		break;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	case MAX1617_SET_LOW_LIMIT:
8047c478bd9Sstevel@tonic-gate 		switch (fcn) {
8057c478bd9Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
8067c478bd9Sstevel@tonic-gate 			err = set_temp_limit(unitp,
8077c478bd9Sstevel@tonic-gate 			    MAX1617_LOCALTEMP_LOW_WR_REG, (caddr_t)arg, mode);
8087c478bd9Sstevel@tonic-gate 			break;
8097c478bd9Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
8107c478bd9Sstevel@tonic-gate 			err = set_temp_limit(unitp,
8117c478bd9Sstevel@tonic-gate 			    MAX1617_REMOTETEMP_LOW_WR_REG, (caddr_t)arg, mode);
8127c478bd9Sstevel@tonic-gate 			break;
8137c478bd9Sstevel@tonic-gate 		default:
8147c478bd9Sstevel@tonic-gate 			err = EINVAL;
8157c478bd9Sstevel@tonic-gate 		}
8167c478bd9Sstevel@tonic-gate 		break;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	case MAX1617_ONE_SHOT_CMD:
8197c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 0,
8207c478bd9Sstevel@tonic-gate 		    I2C_SLEEP);
8217c478bd9Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
8227c478bd9Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
8237c478bd9Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_ONE_SHOT_CMD_REG;
8247c478bd9Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
8257c478bd9Sstevel@tonic-gate 			err = EIO;
8267c478bd9Sstevel@tonic-gate 		}
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
8297c478bd9Sstevel@tonic-gate 		break;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	default:
8327c478bd9Sstevel@tonic-gate 		err = EINVAL;
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	done:
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
8387c478bd9Sstevel@tonic-gate 	unitp->max1617_flags = 0;
8397c478bd9Sstevel@tonic-gate 	cv_signal(&unitp->max1617_cv);
8407c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	return (err);
8437c478bd9Sstevel@tonic-gate }
844