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, 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
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,
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
560 int
get_temp_limit(struct max1617_unit * unitp,uchar_t reg,caddr_t arg,int mode)561 get_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
592 static int
max1617_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)593 max1617_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