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 */
54 static int max1617_open(dev_t *, int, int, cred_t *);
55 static int max1617_close(dev_t, int, int, cred_t *);
56 static int max1617_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
57
58 /*
59 * dev ops
60 */
61 static int max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
62 void **result);
63 static int max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
64 static int max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
65
66 static 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
87 static 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
102 static struct modldrv max1617_modldrv = {
103 &mod_driverops, /* type of module - driver */
104 "max1617 device driver",
105 &max1617_ops,
106 };
107
108 static struct modlinkage max1617_modlinkage = {
109 MODREV_1,
110 &max1617_modldrv,
111 0
112 };
113
114 static int max1617_debug = 0;
115
116 static void *max1617_soft_statep;
117
118 int
_init(void)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
132 int
_fini(void)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
145 int
_info(struct modinfo * modinfop)146 _info(struct modinfo *modinfop)
147 {
148 return (mod_info(&max1617_modlinkage, modinfop));
149 }
150
151 /* ARGSUSED */
152 static int
max1617_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)153 max1617_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
167 static int
max1617_do_attach(dev_info_t * dip)168 max1617_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, 0) == 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, 0) == 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
229 static int
max1617_do_resume(dev_info_t * dip)230 max1617_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
305 static int
max1617_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)306 max1617_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
321 static int
max1617_do_detach(dev_info_t * dip)322 max1617_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
346 static int
max1617_do_suspend(dev_info_t * dip)347 max1617_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
429 static int
max1617_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)430 max1617_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
446 static int
max1617_open(dev_t * devp,int flags,int otyp,cred_t * credp)447 max1617_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
491 done:
492 mutex_exit(&unitp->max1617_mutex);
493
494 return (err);
495 }
496
497 static int
max1617_close(dev_t dev,int flags,int otyp,cred_t * credp)498 max1617_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
527 int
set_temp_limit(struct max1617_unit * unitp,uchar_t device_reg,caddr_t arg,int mode)528 set_temp_limit(struct max1617_unit *unitp, uchar_t device_reg, caddr_t arg,
529 int mode)
530 {
531 int err = 0;
532 i2c_transfer_t *i2ctp;
533 int16_t temp;
534
535 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 2, 0, I2C_SLEEP);
536 i2ctp->i2c_version = I2C_XFER_REV;
537 i2ctp->i2c_flags = I2C_WR;
538 i2ctp->i2c_wbuf[0] = device_reg;
539
540 if (ddi_copyin(arg, (caddr_t)&temp, sizeof (int16_t), mode) !=
541 DDI_SUCCESS) {
542 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
543
544 return (EFAULT);
545 }
546
547 i2ctp->i2c_wbuf[1] = (int8_t)temp;
548
549 if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
550 err = EIO;
551 }
552
553 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
554
555 return (err);
556 }
557
558 int
get_temp_limit(struct max1617_unit * unitp,uchar_t reg,caddr_t arg,int mode)559 get_temp_limit(struct max1617_unit *unitp, uchar_t reg, caddr_t arg, int mode)
560 {
561 int err = 0;
562 i2c_transfer_t *i2ctp;
563 int16_t temp16;
564
565 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1, I2C_SLEEP);
566 i2ctp->i2c_version = I2C_XFER_REV;
567 i2ctp->i2c_flags = I2C_WR_RD;
568 i2ctp->i2c_wbuf[0] = reg;
569 if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
570 /*
571 * This double cast is required so that the sign is preserved
572 * when expanding the 8 bit value to 16.
573 */
574 temp16 = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
575 if (ddi_copyout((caddr_t)&temp16, arg, sizeof (int16_t),
576 mode) != DDI_SUCCESS) {
577 err = EFAULT;
578 }
579 } else {
580 err = EIO;
581 }
582 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
583
584 return (err);
585 }
586
587 static int
max1617_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)588 max1617_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
589 cred_t *credp, int *rvalp)
590 {
591 _NOTE(ARGUNUSED(credp, rvalp))
592 struct max1617_unit *unitp;
593 int err = 0;
594 i2c_transfer_t *i2ctp;
595 int fcn = MAX1617_MINOR_TO_FCN(getminor(dev));
596 int instance = MAX1617_MINOR_TO_INST(getminor(dev));
597 uchar_t reg;
598
599 unitp = (struct max1617_unit *)
600 ddi_get_soft_state(max1617_soft_statep, instance);
601
602 if (max1617_debug) {
603 printf("max1617_ioctl: fcn=%d instance=%d\n", fcn, instance);
604 }
605
606 /*
607 * Serialize here, in order to block transacations during CPR.
608 * This is not a bottle neck since i2c_transfer would serialize
609 * anyway.
610 */
611 mutex_enter(&unitp->max1617_mutex);
612 while (unitp->max1617_flags == MAX1617_BUSY) {
613 if (cv_wait_sig(&unitp->max1617_cv,
614 &unitp->max1617_mutex) <= 0) {
615 mutex_exit(&unitp->max1617_mutex);
616 return (EINTR);
617 }
618 }
619 unitp->max1617_flags = MAX1617_BUSY;
620 mutex_exit(&unitp->max1617_mutex);
621
622 switch (cmd) {
623
624 /*
625 * I2C_GET_TEMPERATURE reads a temperature from the device and
626 * copies a single byte representing the celcius temp
627 * to user space.
628 */
629 case I2C_GET_TEMPERATURE:
630 switch (fcn) {
631 case MAX1617_AMB_TEMP:
632 reg = MAX1617_LOCAL_TEMP_REG;
633 break;
634 case MAX1617_CPU_TEMP:
635 reg = MAX1617_REMOTE_TEMP_REG;
636 break;
637 default:
638 err = EINVAL;
639 goto done;
640 }
641
642 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
643 1, 1, I2C_SLEEP);
644 i2ctp->i2c_version = I2C_XFER_REV;
645 i2ctp->i2c_flags = I2C_WR_RD;
646 i2ctp->i2c_wbuf[0] = reg;
647
648 if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
649
650 /*
651 * This double cast is needed so that the sign bit
652 * is preserved when casting from unsigned char to
653 * signed 16 bit value.
654 */
655 int16_t temp = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]);
656 if (ddi_copyout((caddr_t)&temp, (caddr_t)arg,
657 sizeof (int16_t), mode) != DDI_SUCCESS) {
658 err = EFAULT;
659 }
660 } else {
661 err = EIO;
662 }
663 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
664 break;
665
666 case MAX1617_GET_STATUS:
667 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
668 1, 1, I2C_SLEEP);
669 i2ctp->i2c_version = I2C_XFER_REV;
670 i2ctp->i2c_flags = I2C_WR_RD;
671 i2ctp->i2c_wbuf[0] = MAX1617_STATUS_REG;
672
673 if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
674 if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
675 sizeof (uint8_t), mode) != DDI_SUCCESS) {
676 err = EFAULT;
677 }
678 } else {
679 err = EIO;
680 }
681 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
682 break;
683 case MAX1617_GET_CONFIG:
684 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1,
685 I2C_SLEEP);
686 i2ctp->i2c_version = I2C_XFER_REV;
687 i2ctp->i2c_flags = I2C_WR_RD;
688 i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG;
689 if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
690 if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
691 sizeof (uint8_t), mode) != DDI_SUCCESS) {
692 err = EFAULT;
693 }
694 } else {
695 err = EIO;
696 }
697 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
698 break;
699 case MAX1617_GET_CONV_RATE:
700 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
701 1, 1, I2C_SLEEP);
702 i2ctp->i2c_version = I2C_XFER_REV;
703 i2ctp->i2c_flags = I2C_WR_RD;
704 i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG;
705 if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) {
706 if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg,
707 sizeof (uint8_t), mode) != DDI_SUCCESS) {
708 err = EFAULT;
709 }
710 } else {
711 err = EIO;
712 }
713 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
714 break;
715
716 case MAX1617_GET_HIGH_LIMIT:
717 switch (fcn) {
718 case MAX1617_AMB_TEMP:
719 err = get_temp_limit(unitp, MAX1617_LOCALTEMP_HIGH_REG,
720 (caddr_t)arg, mode);
721 break;
722 case MAX1617_CPU_TEMP:
723 err = get_temp_limit(unitp, MAX1617_REMOTETEMP_HIGH_REG,
724 (caddr_t)arg, mode);
725 break;
726 default:
727 err = EINVAL;
728 break;
729 }
730 break;
731
732 case MAX1617_GET_LOW_LIMIT:
733
734 switch (fcn) {
735 case MAX1617_AMB_TEMP:
736 err = get_temp_limit(unitp, MAX1617_LOCALTEMP_LOW_REG,
737 (caddr_t)arg, mode);
738 break;
739 case MAX1617_CPU_TEMP:
740 err = get_temp_limit(unitp, MAX1617_REMOTETEMP_LOW_REG,
741 (caddr_t)arg, mode);
742 break;
743 default:
744 err = EINVAL;
745 }
746 break;
747
748 case MAX1617_SET_CONV_RATE:
749 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
750 2, 0, I2C_SLEEP);
751 i2ctp->i2c_version = I2C_XFER_REV;
752 i2ctp->i2c_flags = I2C_WR;
753 i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG;
754 if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
755 sizeof (uint8_t), mode) != DDI_SUCCESS) {
756 err = EFAULT;
757 break;
758 }
759 if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
760 err = EIO;
761 }
762 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
763 break;
764
765 case MAX1617_SET_CONFIG:
766 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp,
767 2, 0, I2C_SLEEP);
768 i2ctp->i2c_version = I2C_XFER_REV;
769 i2ctp->i2c_flags = I2C_WR;
770 i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG;
771 if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1],
772 sizeof (uint8_t), mode) != DDI_SUCCESS) {
773 err = EFAULT;
774 break;
775 }
776 if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
777 err = EIO;
778 }
779
780 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
781 break;
782
783 case MAX1617_SET_HIGH_LIMIT:
784 switch (fcn) {
785 case MAX1617_AMB_TEMP:
786 err = set_temp_limit(unitp,
787 MAX1617_LOCALTEMP_HIGH_WR_REG, (caddr_t)arg, mode);
788 break;
789 case MAX1617_CPU_TEMP:
790 err = set_temp_limit(unitp,
791 MAX1617_REMOTETEMP_HIGH_WR_REG, (caddr_t)arg, mode);
792 break;
793 default:
794 err = EINVAL;
795 }
796 break;
797
798 case MAX1617_SET_LOW_LIMIT:
799 switch (fcn) {
800 case MAX1617_AMB_TEMP:
801 err = set_temp_limit(unitp,
802 MAX1617_LOCALTEMP_LOW_WR_REG, (caddr_t)arg, mode);
803 break;
804 case MAX1617_CPU_TEMP:
805 err = set_temp_limit(unitp,
806 MAX1617_REMOTETEMP_LOW_WR_REG, (caddr_t)arg, mode);
807 break;
808 default:
809 err = EINVAL;
810 }
811 break;
812
813 case MAX1617_ONE_SHOT_CMD:
814 (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 0,
815 I2C_SLEEP);
816 i2ctp->i2c_version = I2C_XFER_REV;
817 i2ctp->i2c_flags = I2C_WR;
818 i2ctp->i2c_wbuf[0] = MAX1617_ONE_SHOT_CMD_REG;
819 if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) {
820 err = EIO;
821 }
822
823 i2c_transfer_free(unitp->max1617_hdl, i2ctp);
824 break;
825
826 default:
827 err = EINVAL;
828 }
829
830 done:
831
832 mutex_enter(&unitp->max1617_mutex);
833 unitp->max1617_flags = 0;
834 cv_signal(&unitp->max1617_cv);
835 mutex_exit(&unitp->max1617_mutex);
836
837 return (err);
838 }
839