xref: /onnv-gate/usr/src/uts/sun4u/io/i2c/clients/max1617.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * The max1617 I2C is a temp acquisition device.  As implemented on some
31*0Sstevel@tonic-gate  * processor modules, it contains both a local and a remote temp.  The
32*0Sstevel@tonic-gate  * local temp measures the ambient (room) temperature, while the remote
33*0Sstevel@tonic-gate  * sensor is connected to the processor die.  There are ioctl's for retrieving
34*0Sstevel@tonic-gate  * temperatures, and setting temperature alarm ranges.
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <sys/modctl.h>
39*0Sstevel@tonic-gate #include <sys/open.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/kmem.h>
42*0Sstevel@tonic-gate #include <sys/ddi.h>
43*0Sstevel@tonic-gate #include <sys/sunddi.h>
44*0Sstevel@tonic-gate #include <sys/conf.h>
45*0Sstevel@tonic-gate #include <sys/file.h>
46*0Sstevel@tonic-gate #include <sys/note.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <sys/i2c/misc/i2c_svc.h>
49*0Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
50*0Sstevel@tonic-gate #include <sys/i2c/clients/max1617.h>
51*0Sstevel@tonic-gate #include <sys/i2c/clients/max1617_impl.h>
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate  * cb ops (only need ioctl)
55*0Sstevel@tonic-gate  */
56*0Sstevel@tonic-gate static int max1617_open(dev_t *, int, int, cred_t *);
57*0Sstevel@tonic-gate static int max1617_close(dev_t, int, int, cred_t *);
58*0Sstevel@tonic-gate static int max1617_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * dev ops
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate static int max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
64*0Sstevel@tonic-gate 		void **result);
65*0Sstevel@tonic-gate static int max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
66*0Sstevel@tonic-gate static int max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static struct cb_ops max1617_cbops = {
69*0Sstevel@tonic-gate 	max1617_open,			/* open */
70*0Sstevel@tonic-gate 	max1617_close,			/* close */
71*0Sstevel@tonic-gate 	nodev,				/* strategy */
72*0Sstevel@tonic-gate 	nodev,				/* print */
73*0Sstevel@tonic-gate 	nodev,				/* dump */
74*0Sstevel@tonic-gate 	nodev,				/* read */
75*0Sstevel@tonic-gate 	nodev,				/* write */
76*0Sstevel@tonic-gate 	max1617_ioctl,			/* ioctl */
77*0Sstevel@tonic-gate 	nodev,				/* devmap */
78*0Sstevel@tonic-gate 	nodev,				/* mmap */
79*0Sstevel@tonic-gate 	nodev,				/* segmap */
80*0Sstevel@tonic-gate 	nochpoll,			/* poll */
81*0Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
82*0Sstevel@tonic-gate 	NULL,				/* streamtab */
83*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
84*0Sstevel@tonic-gate 	CB_REV,				/* rev */
85*0Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
86*0Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
87*0Sstevel@tonic-gate };
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate static struct dev_ops max1617_ops = {
90*0Sstevel@tonic-gate 	DEVO_REV,
91*0Sstevel@tonic-gate 	0,
92*0Sstevel@tonic-gate 	max1617_info,
93*0Sstevel@tonic-gate 	nulldev,
94*0Sstevel@tonic-gate 	nulldev,
95*0Sstevel@tonic-gate 	max1617_attach,
96*0Sstevel@tonic-gate 	max1617_detach,
97*0Sstevel@tonic-gate 	nodev,
98*0Sstevel@tonic-gate 	&max1617_cbops,
99*0Sstevel@tonic-gate 	NULL
100*0Sstevel@tonic-gate };
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate static struct modldrv max1617_modldrv = {
103*0Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
104*0Sstevel@tonic-gate 	"max1617 device driver v%I%",
105*0Sstevel@tonic-gate 	&max1617_ops,
106*0Sstevel@tonic-gate };
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate static struct modlinkage max1617_modlinkage = {
109*0Sstevel@tonic-gate 	MODREV_1,
110*0Sstevel@tonic-gate 	&max1617_modldrv,
111*0Sstevel@tonic-gate 	0
112*0Sstevel@tonic-gate };
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate static int max1617_debug = 0;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate static void *max1617_soft_statep;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate int
119*0Sstevel@tonic-gate _init(void)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	int error;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	error = mod_install(&max1617_modlinkage);
124*0Sstevel@tonic-gate 	if (error == 0) {
125*0Sstevel@tonic-gate 		(void) ddi_soft_state_init(&max1617_soft_statep,
126*0Sstevel@tonic-gate 			sizeof (struct max1617_unit), 1);
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	return (error);
130*0Sstevel@tonic-gate }
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate int
133*0Sstevel@tonic-gate _fini(void)
134*0Sstevel@tonic-gate {
135*0Sstevel@tonic-gate 	int error;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	error = mod_remove(&max1617_modlinkage);
138*0Sstevel@tonic-gate 	if (error == 0) {
139*0Sstevel@tonic-gate 		ddi_soft_state_fini(&max1617_soft_statep);
140*0Sstevel@tonic-gate 	}
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	return (error);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate int
146*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	return (mod_info(&max1617_modlinkage, modinfop));
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate /* ARGSUSED */
152*0Sstevel@tonic-gate static int
153*0Sstevel@tonic-gate max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	dev_t	dev;
156*0Sstevel@tonic-gate 	int	instance;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
159*0Sstevel@tonic-gate 		dev = (dev_t)arg;
160*0Sstevel@tonic-gate 		instance = MAX1617_MINOR_TO_INST(getminor(dev));
161*0Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
162*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 	return (DDI_FAILURE);
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate static int
168*0Sstevel@tonic-gate max1617_do_attach(dev_info_t *dip)
169*0Sstevel@tonic-gate {
170*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
171*0Sstevel@tonic-gate 	int instance;
172*0Sstevel@tonic-gate 	char minor_name[MAXNAMELEN];
173*0Sstevel@tonic-gate 	minor_t minor_number;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(max1617_soft_statep, instance) != 0) {
178*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate",
179*0Sstevel@tonic-gate 		    ddi_get_name(dip), instance);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 		return (DDI_FAILURE);
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(max1617_soft_statep, instance);
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	(void) snprintf(unitp->max1617_name, sizeof (unitp->max1617_name),
187*0Sstevel@tonic-gate 	    "%sd", ddi_node_name(dip), instance);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	(void) sprintf(minor_name, "die_temp");
190*0Sstevel@tonic-gate 	minor_number = MAX1617_INST_TO_MINOR(instance) |
191*0Sstevel@tonic-gate 	    MAX1617_FCN_TO_MINOR(MAX1617_CPU_TEMP);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, minor_name, S_IFCHR,
194*0Sstevel@tonic-gate 	    minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) {
195*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed for minor "
196*0Sstevel@tonic-gate 		    " name '%s'", unitp->max1617_name, minor_name);
197*0Sstevel@tonic-gate 		    ddi_soft_state_free(max1617_soft_statep, instance);
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 		return (DDI_FAILURE);
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	(void) sprintf(minor_name, "amb_temp");
203*0Sstevel@tonic-gate 	minor_number = MAX1617_INST_TO_MINOR(instance) |
204*0Sstevel@tonic-gate 	    MAX1617_FCN_TO_MINOR(MAX1617_AMB_TEMP);
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, minor_name, S_IFCHR,
207*0Sstevel@tonic-gate 	    minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) {
208*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed for %s",
209*0Sstevel@tonic-gate 		    unitp->max1617_name, minor_name);
210*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
211*0Sstevel@tonic-gate 		ddi_soft_state_free(max1617_soft_statep, instance);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 		return (DDI_FAILURE);
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	if (i2c_client_register(dip, &unitp->max1617_hdl) != I2C_SUCCESS) {
217*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
218*0Sstevel@tonic-gate 		ddi_soft_state_free(max1617_soft_statep, instance);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 		return (DDI_FAILURE);
221*0Sstevel@tonic-gate 	}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	mutex_init(&unitp->max1617_mutex, NULL, MUTEX_DRIVER, NULL);
224*0Sstevel@tonic-gate 	cv_init(&unitp->max1617_cv, NULL, CV_DRIVER, NULL);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
227*0Sstevel@tonic-gate }
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate static int
230*0Sstevel@tonic-gate max1617_do_resume(dev_info_t *dip)
231*0Sstevel@tonic-gate {
232*0Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
233*0Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
234*0Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
235*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) ==
238*0Sstevel@tonic-gate 	    NULL) {
239*0Sstevel@tonic-gate 		return (DDI_FAILURE);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl,
243*0Sstevel@tonic-gate 	    &i2ctp, 2, 0, I2C_SLEEP);
244*0Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
245*0Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR;
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG;
249*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_config;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
252*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
253*0Sstevel@tonic-gate 		goto done;
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG;
257*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_conv_rate;
258*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
259*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
260*0Sstevel@tonic-gate 		goto done;
261*0Sstevel@tonic-gate 	}
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_WR_REG;
264*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] =  unitp->max1617_cpr_state.max1617_lcl_hlimit;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
267*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
268*0Sstevel@tonic-gate 		goto done;
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_WR_REG;
272*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] =  unitp->max1617_cpr_state.max1617_remote_hlimit;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
275*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
276*0Sstevel@tonic-gate 		goto done;
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG;
280*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_lcl_llimit;
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
283*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
284*0Sstevel@tonic-gate 		goto done;
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG;
288*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_remote_llimit;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
291*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
292*0Sstevel@tonic-gate 		goto done;
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	done:
296*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
297*0Sstevel@tonic-gate 	unitp->max1617_flags = 0;
298*0Sstevel@tonic-gate 	cv_signal(&unitp->max1617_cv);
299*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
302*0Sstevel@tonic-gate 	return (ret);
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate static int
306*0Sstevel@tonic-gate max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	switch (cmd) {
309*0Sstevel@tonic-gate 	case DDI_ATTACH:
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 		return (max1617_do_attach(dip));
312*0Sstevel@tonic-gate 	case DDI_RESUME:
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 		return (max1617_do_resume(dip));
315*0Sstevel@tonic-gate 	default:
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 		return (DDI_FAILURE);
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate }
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate static int
322*0Sstevel@tonic-gate max1617_do_detach(dev_info_t *dip)
323*0Sstevel@tonic-gate {
324*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
325*0Sstevel@tonic-gate 	int instance;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	unitp = ddi_get_soft_state(max1617_soft_statep, instance);
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	if (unitp == NULL) {
332*0Sstevel@tonic-gate 		return (DDI_FAILURE);
333*0Sstevel@tonic-gate 	}
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	i2c_client_unregister(unitp->max1617_hdl);
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	mutex_destroy(&unitp->max1617_mutex);
340*0Sstevel@tonic-gate 	cv_destroy(&unitp->max1617_cv);
341*0Sstevel@tonic-gate 	ddi_soft_state_free(max1617_soft_statep, instance);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate static int
347*0Sstevel@tonic-gate max1617_do_suspend(dev_info_t *dip)
348*0Sstevel@tonic-gate {
349*0Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
350*0Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
351*0Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
352*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) ==
355*0Sstevel@tonic-gate 	    NULL) {
356*0Sstevel@tonic-gate 		return (DDI_FAILURE);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl,
360*0Sstevel@tonic-gate 	    &i2ctp, 1, 1, I2C_SLEEP);
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * Block new transactions during CPR
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
367*0Sstevel@tonic-gate 	while (unitp->max1617_flags == MAX1617_BUSY) {
368*0Sstevel@tonic-gate 		cv_wait(&unitp->max1617_cv, &unitp->max1617_mutex);
369*0Sstevel@tonic-gate 	}
370*0Sstevel@tonic-gate 	unitp->max1617_flags = MAX1617_BUSY;
371*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
374*0Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR_RD;
375*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG;
376*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
377*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
378*0Sstevel@tonic-gate 		goto done;
379*0Sstevel@tonic-gate 	}
380*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_config = i2ctp->i2c_rbuf[0];
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG;
383*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
384*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
385*0Sstevel@tonic-gate 		goto done;
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_conv_rate = i2ctp->i2c_rbuf[0];
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_REG;
390*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
391*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
392*0Sstevel@tonic-gate 		goto done;
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_lcl_hlimit = i2ctp->i2c_rbuf[0];
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_REG;
397*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
398*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
399*0Sstevel@tonic-gate 		goto done;
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_remote_hlimit = i2ctp->i2c_rbuf[0];
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG;
404*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
405*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
406*0Sstevel@tonic-gate 		goto done;
407*0Sstevel@tonic-gate 	}
408*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_lcl_llimit = i2ctp->i2c_rbuf[0];
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG;
411*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
412*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
413*0Sstevel@tonic-gate 		goto done;
414*0Sstevel@tonic-gate 	}
415*0Sstevel@tonic-gate 	unitp->max1617_cpr_state.max1617_remote_llimit = i2ctp->i2c_rbuf[0];
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	done:
418*0Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	if (ret == DDI_FAILURE) {
421*0Sstevel@tonic-gate 		mutex_enter(&unitp->max1617_mutex);
422*0Sstevel@tonic-gate 		unitp->max1617_flags = 0;
423*0Sstevel@tonic-gate 		cv_broadcast(&unitp->max1617_cv);
424*0Sstevel@tonic-gate 		mutex_exit(&unitp->max1617_mutex);
425*0Sstevel@tonic-gate 	}
426*0Sstevel@tonic-gate 	return (ret);
427*0Sstevel@tonic-gate }
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate static int
430*0Sstevel@tonic-gate max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
431*0Sstevel@tonic-gate {
432*0Sstevel@tonic-gate 	switch (cmd) {
433*0Sstevel@tonic-gate 	case DDI_DETACH:
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		return (max1617_do_detach(dip));
436*0Sstevel@tonic-gate 	case DDI_SUSPEND:
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 		return (max1617_do_suspend(dip));
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	default:
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 		return (DDI_FAILURE);
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate }
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate static int
447*0Sstevel@tonic-gate max1617_open(dev_t *devp, int flags, int otyp, cred_t *credp)
448*0Sstevel@tonic-gate {
449*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp))
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
452*0Sstevel@tonic-gate 	int instance;
453*0Sstevel@tonic-gate 	int err = 0;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	instance = MAX1617_MINOR_TO_INST(getminor(*devp));
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	if (instance < 0) {
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		return (ENXIO);
460*0Sstevel@tonic-gate 	}
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
463*0Sstevel@tonic-gate 		ddi_get_soft_state(max1617_soft_statep, instance);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (unitp == NULL) {
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 		return (ENXIO);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		return (EINVAL);
473*0Sstevel@tonic-gate 	}
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	if (flags & FEXCL) {
478*0Sstevel@tonic-gate 		if (unitp->max1617_oflag != 0) {
479*0Sstevel@tonic-gate 			err = EBUSY;
480*0Sstevel@tonic-gate 		} else {
481*0Sstevel@tonic-gate 			unitp->max1617_oflag = FEXCL;
482*0Sstevel@tonic-gate 		}
483*0Sstevel@tonic-gate 	} else {
484*0Sstevel@tonic-gate 		if (unitp->max1617_oflag == FEXCL) {
485*0Sstevel@tonic-gate 			err = EBUSY;
486*0Sstevel@tonic-gate 		} else {
487*0Sstevel@tonic-gate 			unitp->max1617_oflag = FOPEN;
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate done:
492*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	return (err);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate static int
498*0Sstevel@tonic-gate max1617_close(dev_t dev, int flags, int otyp, cred_t *credp)
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(flags, otyp, credp))
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
503*0Sstevel@tonic-gate 	int instance = MAX1617_MINOR_TO_INST(getminor(dev));
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	if (instance < 0) {
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 		return (ENXIO);
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
511*0Sstevel@tonic-gate 		ddi_get_soft_state(max1617_soft_statep, instance);
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	if (unitp == NULL) {
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 		return (ENXIO);
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	unitp->max1617_oflag = 0;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
525*0Sstevel@tonic-gate }
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate int
528*0Sstevel@tonic-gate set_temp_limit(struct max1617_unit *unitp,
529*0Sstevel@tonic-gate 		uchar_t device_reg,
530*0Sstevel@tonic-gate 		caddr_t arg,
531*0Sstevel@tonic-gate 		int mode)
532*0Sstevel@tonic-gate {
533*0Sstevel@tonic-gate 	int err = 0;
534*0Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
535*0Sstevel@tonic-gate 	int16_t temp;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 2, 0, I2C_SLEEP);
538*0Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
539*0Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR;
540*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = device_reg;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	if (ddi_copyin(arg, (caddr_t)&temp, sizeof (int16_t), mode) !=
543*0Sstevel@tonic-gate 	    DDI_SUCCESS) {
544*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		return (EFAULT);
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[1] = (int8_t)temp;
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
552*0Sstevel@tonic-gate 		err = EIO;
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	return (err);
558*0Sstevel@tonic-gate }
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate int
561*0Sstevel@tonic-gate get_temp_limit(struct max1617_unit *unitp,
562*0Sstevel@tonic-gate 		uchar_t reg,
563*0Sstevel@tonic-gate 		caddr_t arg,
564*0Sstevel@tonic-gate 		int mode)
565*0Sstevel@tonic-gate {
566*0Sstevel@tonic-gate 	int err = 0;
567*0Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
568*0Sstevel@tonic-gate 	int16_t temp16;
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1, I2C_SLEEP);
571*0Sstevel@tonic-gate 	i2ctp->i2c_version = I2C_XFER_REV;
572*0Sstevel@tonic-gate 	i2ctp->i2c_flags = I2C_WR_RD;
573*0Sstevel@tonic-gate 	i2ctp->i2c_wbuf[0] = reg;
574*0Sstevel@tonic-gate 	if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
575*0Sstevel@tonic-gate 		/*
576*0Sstevel@tonic-gate 		 * This double cast is required so that the sign is preserved
577*0Sstevel@tonic-gate 		 * when expanding the 8 bit value to 16.
578*0Sstevel@tonic-gate 		 */
579*0Sstevel@tonic-gate 		temp16 = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
580*0Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&temp16, arg, sizeof (int16_t),
581*0Sstevel@tonic-gate 		    mode) != DDI_SUCCESS) {
582*0Sstevel@tonic-gate 			err = EFAULT;
583*0Sstevel@tonic-gate 		}
584*0Sstevel@tonic-gate 	} else {
585*0Sstevel@tonic-gate 		err = EIO;
586*0Sstevel@tonic-gate 	}
587*0Sstevel@tonic-gate 	i2c_transfer_free(unitp->max1617_hdl, i2ctp);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	return (err);
590*0Sstevel@tonic-gate }
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate static int
593*0Sstevel@tonic-gate max1617_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
594*0Sstevel@tonic-gate 		cred_t *credp, int *rvalp)
595*0Sstevel@tonic-gate {
596*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp, rvalp))
597*0Sstevel@tonic-gate 	struct max1617_unit *unitp;
598*0Sstevel@tonic-gate 	int err = 0;
599*0Sstevel@tonic-gate 	i2c_transfer_t *i2ctp;
600*0Sstevel@tonic-gate 	int fcn = MAX1617_MINOR_TO_FCN(getminor(dev));
601*0Sstevel@tonic-gate 	int instance = MAX1617_MINOR_TO_INST(getminor(dev));
602*0Sstevel@tonic-gate 	uchar_t reg;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	unitp = (struct max1617_unit *)
605*0Sstevel@tonic-gate 		ddi_get_soft_state(max1617_soft_statep, instance);
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	if (max1617_debug) {
608*0Sstevel@tonic-gate 		printf("max1617_ioctl: fcn=%d instance=%d\n", fcn, instance);
609*0Sstevel@tonic-gate 	}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	/*
612*0Sstevel@tonic-gate 	 * Serialize here, in order to block transacations during CPR.
613*0Sstevel@tonic-gate 	 * This is not a bottle neck since i2c_transfer would serialize
614*0Sstevel@tonic-gate 	 * anyway.
615*0Sstevel@tonic-gate 	 */
616*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
617*0Sstevel@tonic-gate 	while (unitp->max1617_flags == MAX1617_BUSY) {
618*0Sstevel@tonic-gate 		if (cv_wait_sig(&unitp->max1617_cv,
619*0Sstevel@tonic-gate 		    &unitp->max1617_mutex) <= 0) {
620*0Sstevel@tonic-gate 			mutex_exit(&unitp->max1617_mutex);
621*0Sstevel@tonic-gate 			return (EINTR);
622*0Sstevel@tonic-gate 		}
623*0Sstevel@tonic-gate 	}
624*0Sstevel@tonic-gate 	unitp->max1617_flags = MAX1617_BUSY;
625*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	switch (cmd) {
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	/*
630*0Sstevel@tonic-gate 	 * I2C_GET_TEMPERATURE reads a temperature from the device and
631*0Sstevel@tonic-gate 	 * copies a single byte representing the celcius temp
632*0Sstevel@tonic-gate 	 * to user space.
633*0Sstevel@tonic-gate 	 */
634*0Sstevel@tonic-gate 	case I2C_GET_TEMPERATURE:
635*0Sstevel@tonic-gate 		switch (fcn) {
636*0Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
637*0Sstevel@tonic-gate 			reg = MAX1617_LOCAL_TEMP_REG;
638*0Sstevel@tonic-gate 			break;
639*0Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
640*0Sstevel@tonic-gate 			reg = MAX1617_REMOTE_TEMP_REG;
641*0Sstevel@tonic-gate 			break;
642*0Sstevel@tonic-gate 		default:
643*0Sstevel@tonic-gate 			err = EINVAL;
644*0Sstevel@tonic-gate 			goto done;
645*0Sstevel@tonic-gate 		}
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
648*0Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
649*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
650*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
651*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = reg;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 			/*
656*0Sstevel@tonic-gate 			 * This double cast is needed so that the sign bit
657*0Sstevel@tonic-gate 			 * is preserved when casting from unsigned char to
658*0Sstevel@tonic-gate 			 * signed 16 bit value.
659*0Sstevel@tonic-gate 			 */
660*0Sstevel@tonic-gate 			int16_t temp = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
661*0Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
662*0Sstevel@tonic-gate 			    sizeof (int16_t), mode) != DDI_SUCCESS) {
663*0Sstevel@tonic-gate 				err = EFAULT;
664*0Sstevel@tonic-gate 			}
665*0Sstevel@tonic-gate 		} else {
666*0Sstevel@tonic-gate 			err = EIO;
667*0Sstevel@tonic-gate 		}
668*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
669*0Sstevel@tonic-gate 		break;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	case MAX1617_GET_STATUS:
672*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
673*0Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
674*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
675*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
676*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_STATUS_REG;
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
679*0Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
680*0Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
681*0Sstevel@tonic-gate 				err = EFAULT;
682*0Sstevel@tonic-gate 			}
683*0Sstevel@tonic-gate 		} else {
684*0Sstevel@tonic-gate 			err = EIO;
685*0Sstevel@tonic-gate 		}
686*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
687*0Sstevel@tonic-gate 		break;
688*0Sstevel@tonic-gate 	case MAX1617_GET_CONFIG:
689*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1,
690*0Sstevel@tonic-gate 		    I2C_SLEEP);
691*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
692*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
693*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG;
694*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
695*0Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
696*0Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
697*0Sstevel@tonic-gate 				err = EFAULT;
698*0Sstevel@tonic-gate 			}
699*0Sstevel@tonic-gate 		} else {
700*0Sstevel@tonic-gate 			err = EIO;
701*0Sstevel@tonic-gate 		}
702*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
703*0Sstevel@tonic-gate 		break;
704*0Sstevel@tonic-gate 	case MAX1617_GET_CONV_RATE:
705*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
706*0Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
707*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
708*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR_RD;
709*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG;
710*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
711*0Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
712*0Sstevel@tonic-gate 			    sizeof (uint8_t), mode) != DDI_SUCCESS) {
713*0Sstevel@tonic-gate 				err = EFAULT;
714*0Sstevel@tonic-gate 			}
715*0Sstevel@tonic-gate 		} else {
716*0Sstevel@tonic-gate 			err = EIO;
717*0Sstevel@tonic-gate 		}
718*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
719*0Sstevel@tonic-gate 		break;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	case MAX1617_GET_HIGH_LIMIT:
722*0Sstevel@tonic-gate 		switch (fcn) {
723*0Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
724*0Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_LOCALTEMP_HIGH_REG,
725*0Sstevel@tonic-gate 			    (caddr_t)arg, mode);
726*0Sstevel@tonic-gate 			break;
727*0Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
728*0Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_REMOTETEMP_HIGH_REG,
729*0Sstevel@tonic-gate 			    (caddr_t)arg, mode);
730*0Sstevel@tonic-gate 			break;
731*0Sstevel@tonic-gate 		default:
732*0Sstevel@tonic-gate 			err = EINVAL;
733*0Sstevel@tonic-gate 			break;
734*0Sstevel@tonic-gate 		}
735*0Sstevel@tonic-gate 		break;
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	case MAX1617_GET_LOW_LIMIT:
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 		switch (fcn) {
740*0Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
741*0Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_LOCALTEMP_LOW_REG,
742*0Sstevel@tonic-gate 			    (caddr_t)arg, mode);
743*0Sstevel@tonic-gate 			break;
744*0Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
745*0Sstevel@tonic-gate 			err = get_temp_limit(unitp, MAX1617_REMOTETEMP_LOW_REG,
746*0Sstevel@tonic-gate 			    (caddr_t)arg, mode);
747*0Sstevel@tonic-gate 			break;
748*0Sstevel@tonic-gate 		default:
749*0Sstevel@tonic-gate 			err = EINVAL;
750*0Sstevel@tonic-gate 		}
751*0Sstevel@tonic-gate 		break;
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	case MAX1617_SET_CONV_RATE:
754*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
755*0Sstevel@tonic-gate 		    2, 0, I2C_SLEEP);
756*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
757*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
758*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG;
759*0Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
760*0Sstevel@tonic-gate 		    sizeof (uint8_t), mode) != DDI_SUCCESS) {
761*0Sstevel@tonic-gate 			err = EFAULT;
762*0Sstevel@tonic-gate 			break;
763*0Sstevel@tonic-gate 		}
764*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
765*0Sstevel@tonic-gate 			err = EIO;
766*0Sstevel@tonic-gate 		}
767*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
768*0Sstevel@tonic-gate 		break;
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	case MAX1617_SET_CONFIG:
771*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
772*0Sstevel@tonic-gate 		    2, 0, I2C_SLEEP);
773*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
774*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
775*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG;
776*0Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
777*0Sstevel@tonic-gate 		    sizeof (uint8_t), mode) != DDI_SUCCESS) {
778*0Sstevel@tonic-gate 			err = EFAULT;
779*0Sstevel@tonic-gate 			break;
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
782*0Sstevel@tonic-gate 			err = EIO;
783*0Sstevel@tonic-gate 		}
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
786*0Sstevel@tonic-gate 		break;
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	case MAX1617_SET_HIGH_LIMIT:
789*0Sstevel@tonic-gate 		switch (fcn) {
790*0Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
791*0Sstevel@tonic-gate 			err = set_temp_limit(unitp,
792*0Sstevel@tonic-gate 			    MAX1617_LOCALTEMP_HIGH_WR_REG, (caddr_t)arg, mode);
793*0Sstevel@tonic-gate 			break;
794*0Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
795*0Sstevel@tonic-gate 			err = set_temp_limit(unitp,
796*0Sstevel@tonic-gate 			    MAX1617_REMOTETEMP_HIGH_WR_REG, (caddr_t)arg, mode);
797*0Sstevel@tonic-gate 			break;
798*0Sstevel@tonic-gate 		default:
799*0Sstevel@tonic-gate 			err = EINVAL;
800*0Sstevel@tonic-gate 		}
801*0Sstevel@tonic-gate 		break;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	case MAX1617_SET_LOW_LIMIT:
804*0Sstevel@tonic-gate 		switch (fcn) {
805*0Sstevel@tonic-gate 		case MAX1617_AMB_TEMP:
806*0Sstevel@tonic-gate 			err = set_temp_limit(unitp,
807*0Sstevel@tonic-gate 			    MAX1617_LOCALTEMP_LOW_WR_REG, (caddr_t)arg, mode);
808*0Sstevel@tonic-gate 			break;
809*0Sstevel@tonic-gate 		case MAX1617_CPU_TEMP:
810*0Sstevel@tonic-gate 			err = set_temp_limit(unitp,
811*0Sstevel@tonic-gate 			    MAX1617_REMOTETEMP_LOW_WR_REG, (caddr_t)arg, mode);
812*0Sstevel@tonic-gate 			break;
813*0Sstevel@tonic-gate 		default:
814*0Sstevel@tonic-gate 			err = EINVAL;
815*0Sstevel@tonic-gate 		}
816*0Sstevel@tonic-gate 		break;
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	case MAX1617_ONE_SHOT_CMD:
819*0Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 0,
820*0Sstevel@tonic-gate 		    I2C_SLEEP);
821*0Sstevel@tonic-gate 		i2ctp->i2c_version = I2C_XFER_REV;
822*0Sstevel@tonic-gate 		i2ctp->i2c_flags = I2C_WR;
823*0Sstevel@tonic-gate 		i2ctp->i2c_wbuf[0] = MAX1617_ONE_SHOT_CMD_REG;
824*0Sstevel@tonic-gate 		if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
825*0Sstevel@tonic-gate 			err = EIO;
826*0Sstevel@tonic-gate 		}
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 		i2c_transfer_free(unitp->max1617_hdl, i2ctp);
829*0Sstevel@tonic-gate 		break;
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 	default:
832*0Sstevel@tonic-gate 		err = EINVAL;
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	done:
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 	mutex_enter(&unitp->max1617_mutex);
838*0Sstevel@tonic-gate 	unitp->max1617_flags = 0;
839*0Sstevel@tonic-gate 	cv_signal(&unitp->max1617_cv);
840*0Sstevel@tonic-gate 	mutex_exit(&unitp->max1617_mutex);
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	return (err);
843*0Sstevel@tonic-gate }
844