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