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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * I2C leaf driver for the PCF8591
28 */
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/signal.h>
33 #include <sys/errno.h>
34 #include <sys/file.h>
35 #include <sys/termio.h>
36 #include <sys/termios.h>
37 #include <sys/cmn_err.h>
38 #include <sys/stream.h>
39 #include <sys/strsun.h>
40 #include <sys/stropts.h>
41 #include <sys/strtty.h>
42 #include <sys/debug.h>
43 #include <sys/eucioctl.h>
44 #include <sys/cred.h>
45 #include <sys/uio.h>
46 #include <sys/stat.h>
47 #include <sys/kmem.h>
48
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include <sys/obpdefs.h>
52 #include <sys/conf.h>
53 #include <sys/modctl.h>
54 #include <sys/stat.h>
55 #include <sys/open.h>
56 #include <sys/uio.h>
57
58 #include <sys/i2c/misc/i2c_svc.h>
59 #include <sys/envctrl_gen.h>
60 #include <sys/netract_gen.h>
61 #include <sys/pcf8591_nct.h>
62
63
64 /*
65 * CONTROL OF CHIP
66 * PCF8591 Temp sensing control register definitions
67 *
68 * ---------------------------------------------
69 * | 0 | AOE | X | X | 0 | AIF | X | X |
70 * ---------------------------------------------
71 * AOE = Analog out enable.. not used on out implementation
72 * 5 & 4 = Analog Input Programming.. see data sheet for bits..
73 *
74 * AIF = Auto increment flag
75 * bits 1 & 0 are for the Chennel number.
76 */
77
78
79 #define I2CTRANS_DATA 0
80 #define I2CRAW_DATA 1
81 #define TEMP_TABLE_SIZE 256
82
83 #define SHUTDOWN_TEMP_MIN 55
84 #define SHUTDOWN_TEMP_MAX 85
85
86 #ifdef DEBUG
87 #define dbg_print(level, str) cmn_err(level, str);
88 #else
89 #define dbg_print(level, str) {; }
90 #endif
91
92
93 extern int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran);
94 static uchar_t _cpu_temps[TEMP_TABLE_SIZE + 4]; /* see attach */
95
96 static void *pcf8591_soft_statep;
97
98 /*
99 * cb ops (only need ioctl)
100 */
101 static int pcf8591_open(dev_t *, int, int, cred_t *);
102 static int pcf8591_close(dev_t, int, int, cred_t *);
103 static int pcf8591_read(dev_t dev, struct uio *uiop, cred_t *cred_p);
104 static int pcf8591_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
105
106 static struct cb_ops pcf8591_cbops = {
107 pcf8591_open, /* open */
108 pcf8591_close, /* close */
109 nodev, /* strategy */
110 nodev, /* print */
111 nodev, /* dump */
112 pcf8591_read, /* read */
113 nodev, /* write */
114 pcf8591_ioctl, /* ioctl */
115 nodev, /* devmap */
116 nodev, /* mmap */
117 nodev, /* segmap */
118 nochpoll, /* poll */
119 ddi_prop_op, /* cb_prop_op */
120 NULL, /* streamtab */
121 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
122 CB_REV, /* rev */
123 nodev, /* int (*cb_aread)() */
124 nodev /* int (*cb_awrite)() */
125 };
126
127 /*
128 * dev ops
129 */
130 static int pcf8591_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
131 void **result);
132 static int pcf8591_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
133 static int pcf8591_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
134
135 /* kstat routines */
136 static int pcf8591_add_kstats(struct pcf8591_unit *);
137 static void pcf8591_delete_kstats(struct pcf8591_unit *);
138 static int pcf8591_temp_kstat_update(kstat_t *, int);
139 static int pcf8591_read_chip(struct pcf8591_unit *, uint8_t, int);
140 static int pcf8591_read_props(struct pcf8591_unit *unitp);
141
142 static struct dev_ops pcf8591_ops = {
143 DEVO_REV,
144 0,
145 pcf8591_info,
146 nulldev,
147 nulldev,
148 pcf8591_attach,
149 pcf8591_detach,
150 nodev,
151 &pcf8591_cbops,
152 NULL,
153 NULL,
154 ddi_quiesce_not_supported, /* devo_quiesce */
155 };
156
157 extern struct mod_ops mod_driverops;
158
159 static struct modldrv pcf8591_modldrv = {
160 &mod_driverops, /* type of module - driver */
161 "Netract pcf8591 (adio)",
162 &pcf8591_ops,
163 };
164
165 static struct modlinkage pcf8591_modlinkage = {
166 MODREV_1,
167 &pcf8591_modldrv,
168 0
169 };
170
171 char _depends_on[] = "misc/i2c_svc";
172
173 int pcf8591_debug = 0x02;
174 static uint8_t translate_cputemp(uint8_t value);
175
176 int
_init(void)177 _init(void)
178 {
179 register int error;
180
181 error = mod_install(&pcf8591_modlinkage);
182 if (error == 0) {
183 (void) ddi_soft_state_init(&pcf8591_soft_statep,
184 sizeof (struct pcf8591_unit), PCF8591_MAX_DEVS);
185 }
186
187 return (error);
188 }
189
190 int
_fini(void)191 _fini(void)
192 {
193 register int error;
194
195 error = mod_remove(&pcf8591_modlinkage);
196 if (error == 0) {
197 ddi_soft_state_fini(&pcf8591_soft_statep);
198 }
199
200 return (error);
201 }
202
203 int
_info(struct modinfo * modinfop)204 _info(struct modinfo *modinfop)
205 {
206 return (mod_info(&pcf8591_modlinkage, modinfop));
207 }
208
209 /*ARGSUSED*/
210 static int
pcf8591_open(dev_t * devp,int flags,int otyp,cred_t * credp)211 pcf8591_open(dev_t *devp, int flags, int otyp, cred_t *credp)
212 {
213 int err = 0;
214 struct pcf8591_unit *unitp;
215 minor_t minor = getminor(*devp);
216
217 int instance = PCF8591_MINOR_TO_DEVINST(minor);
218 int channel = PCF8591_MINOR_TO_CHANNEL(minor);
219
220 if (instance < 0) {
221 return (ENXIO);
222 }
223
224 unitp = (struct pcf8591_unit *)
225 ddi_get_soft_state(pcf8591_soft_statep, instance);
226
227 if (unitp == NULL) {
228 return (ENXIO);
229 }
230
231 if (otyp != OTYP_CHR) {
232 return (EINVAL);
233 }
234
235 mutex_enter(&unitp->umutex);
236
237 if (flags & FEXCL) {
238 if (unitp->pcf8591_oflag[channel] != 0) {
239 err = EBUSY;
240 } else {
241 unitp->pcf8591_oflag[channel] = FEXCL;
242 }
243 } else {
244 if (unitp->pcf8591_oflag[channel] == FEXCL) {
245 err = EBUSY;
246 } else {
247 unitp->pcf8591_oflag[channel] = FOPEN;
248 }
249 }
250
251 mutex_exit(&unitp->umutex);
252
253 return (err);
254 }
255
256 /*ARGSUSED*/
257 static int
pcf8591_close(dev_t devp,int flags,int otyp,cred_t * credp)258 pcf8591_close(dev_t devp, int flags, int otyp, cred_t *credp)
259 {
260 struct pcf8591_unit *unitp;
261 minor_t minor = getminor(devp);
262
263 int instance = PCF8591_MINOR_TO_DEVINST(minor);
264 int channel = PCF8591_MINOR_TO_CHANNEL(minor);
265
266 #ifdef lint
267 flags = flags;
268 otyp = otyp;
269 #endif
270
271 if (instance < 0) {
272 return (ENXIO);
273 }
274
275 unitp = (struct pcf8591_unit *)
276 ddi_get_soft_state(pcf8591_soft_statep, instance);
277
278 if (unitp == NULL) {
279 return (ENXIO);
280 }
281
282 mutex_enter(&unitp->umutex);
283
284 unitp->pcf8591_oflag[channel] = 0;
285
286 mutex_exit(&unitp->umutex);
287
288 return (DDI_SUCCESS);
289 }
290
291 static int
pcf8591_io(dev_t dev,struct uio * uiop,int rw)292 pcf8591_io(dev_t dev, struct uio *uiop, int rw)
293 {
294 int err = 0;
295 struct pcf8591_unit *unitp;
296 minor_t minor = getminor(dev);
297
298 int instance = PCF8591_MINOR_TO_DEVINST(minor);
299 int channel = PCF8591_MINOR_TO_CHANNEL(minor);
300
301 int bytes_to_rw;
302 int translate = 0;
303
304 /*
305 * At this point we don't have a write operation to pcf8591.
306 */
307 if (rw == B_WRITE) {
308 return (EACCES);
309 }
310
311 if (instance < 0) {
312 return (ENXIO);
313 }
314
315 unitp = (struct pcf8591_unit *)
316 ddi_get_soft_state(pcf8591_soft_statep, instance);
317 if (unitp == NULL) {
318 return (ENXIO);
319 }
320
321 if ((bytes_to_rw = uiop->uio_resid) > PCF8591_TRAN_SIZE) {
322 return (EINVAL);
323 }
324
325 /*
326 * Need to serialize all read operations, since there is a single
327 * i2c_transfer_t structure allocated for all read and write ops.
328 * We can't share the i2c bus among multiple transactions anyway,
329 * so this does not affect performance.
330 */
331 mutex_enter(&unitp->umutex);
332 while (unitp->pcf8591_flags == PCF8591_BUSY) {
333 if (cv_wait_sig(&unitp->pcf8591_cv, &unitp->umutex) <= 0) {
334 mutex_exit(&unitp->umutex);
335
336 return (EINTR);
337 }
338 }
339 unitp->pcf8591_flags = PCF8591_BUSY;
340 mutex_exit(&unitp->umutex);
341
342 if (bytes_to_rw == 1)
343 translate = 1;
344 /*
345 * Event sequence:
346 * 1. set up the control register write, for now we'll always read
347 * channel 0, which is the only active 8591 port on the Nordica
348 * TODO: We'll need a minor node for each port that is used.
349 * 2. increment read count to read the throw-away byte
350 * 3. start the write/read of control/data registers
351 * 4. throw the first byte away
352 * 5. then return the data
353 */
354
355 unitp->i2c_tran->i2c_flags = I2C_WR_RD;
356 unitp->i2c_tran->i2c_wlen = 1;
357 unitp->i2c_tran->i2c_wbuf[0] = (unitp->pcf8591_inprog |
358 channel);
359 /*
360 * read extra byte to throw away the first, (PCF8591 datasheet)
361 */
362 unitp->i2c_tran->i2c_rlen = bytes_to_rw + 1;
363
364 if (nct_i2c_transfer(unitp->pcf8591_hdl,
365 unitp->i2c_tran) != I2C_SUCCESS) {
366 err = EIO;
367 } else {
368 /*
369 * Throw away the first byte according to PCF8591 datasheet
370 * If translating, use the second byte.
371 */
372 if (translate) {
373 unitp->i2c_tran->i2c_rbuf[0] =
374 translate_cputemp(unitp->i2c_tran->i2c_rbuf[1]);
375 } else {
376 unitp->i2c_tran->i2c_rbuf[0] =
377 unitp->i2c_tran->i2c_rbuf[1];
378 unitp->i2c_tran->i2c_rbuf[1] = 0;
379 }
380
381 err = uiomove(unitp->i2c_tran->i2c_rbuf,
382 bytes_to_rw,
383 UIO_READ,
384 uiop);
385 }
386 mutex_enter(&unitp->umutex);
387 unitp->pcf8591_flags = 0;
388 cv_signal(&unitp->pcf8591_cv);
389 mutex_exit(&unitp->umutex);
390
391 return (err);
392 }
393
394 /*ARGSUSED*/
395 static int
pcf8591_read(dev_t dev,struct uio * uiop,cred_t * cred_p)396 pcf8591_read(dev_t dev, struct uio *uiop, cred_t *cred_p)
397 {
398 return (pcf8591_io(dev, uiop, B_READ));
399 }
400
401 static int
call_copyin(caddr_t arg,struct pcf8591_unit * unitp,int mode)402 call_copyin(caddr_t arg, struct pcf8591_unit *unitp, int mode)
403 {
404 uchar_t *wbuf;
405 uchar_t *rbuf;
406 i2c_transfer_t i2ct;
407 i2c_transfer_t *i2ctp = unitp->i2c_tran;
408
409
410 if (ddi_copyin((void *)arg, (caddr_t)&i2ct,
411 sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) {
412 return (I2C_FAILURE);
413 }
414
415 /*
416 * Save the read and write buffer pointers in the transfer
417 * structure, otherwise these will get overwritten when we
418 * do a bcopy. Restore once done.
419 */
420
421 wbuf = i2ctp->i2c_wbuf;
422 rbuf = i2ctp->i2c_rbuf;
423
424 bcopy(&i2ct, i2ctp, sizeof (i2c_transfer_t));
425
426 i2ctp->i2c_wbuf = wbuf;
427 i2ctp->i2c_rbuf = rbuf;
428
429 /*
430 * copyin the read and write buffers to the saved buffers.
431 */
432
433 if (i2ct.i2c_wlen != 0) {
434 if (ddi_copyin(i2ct.i2c_wbuf, (caddr_t)i2ctp->i2c_wbuf,
435 i2ct.i2c_wlen, mode) != DDI_SUCCESS) {
436 return (I2C_FAILURE);
437 }
438 }
439
440 return (I2C_SUCCESS);
441 }
442
443 static int
call_copyout(caddr_t arg,struct pcf8591_unit * unitp,int mode)444 call_copyout(caddr_t arg, struct pcf8591_unit *unitp, int mode)
445 {
446 i2c_transfer_t i2ct;
447 i2c_transfer_t *i2ctp = unitp->i2c_tran;
448 uint16_t i2c_actlen;
449
450 /*
451 * We will copyout the last three fields only, skipping
452 * the remaining ones, before copying the rbuf to the
453 * user buffer.
454 */
455
456 int uskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t),
457 kskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t);
458
459 /*
460 * First copyin the user structure to the temporary i2ct,
461 * so that we have the wbuf and rbuf addresses in it.
462 */
463
464 uskip = sizeof (i2c_transfer_t) - 3 * (sizeof (uint16_t));
465
466 /*
467 * copyout the last three out fields now.
468 */
469
470 if (ddi_copyout((void *)((intptr_t)i2ctp+kskip), (void *)
471 ((intptr_t)arg + uskip), 3*sizeof (uint16_t), mode)
472 != DDI_SUCCESS) {
473 return (I2C_FAILURE);
474 }
475
476 /*
477 * In case we have something to write, get the address of the read
478 * buffer.
479 */
480
481 if (i2ctp->i2c_rlen - i2ctp->i2c_r_resid > 0) {
482
483 if (ddi_copyin((void *)arg, &i2ct,
484 sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) {
485 return (I2C_FAILURE);
486 }
487
488 /*
489 * copyout the read buffer to the saved user buffer in i2ct.
490 */
491
492 i2c_actlen = i2ctp->i2c_rlen - i2ctp->i2c_r_resid;
493 if (ddi_copyout(i2ctp->i2c_rbuf, i2ct.i2c_rbuf,
494 i2c_actlen, mode) != DDI_SUCCESS) {
495 return (I2C_FAILURE);
496 }
497 }
498
499 return (I2C_SUCCESS);
500 }
501
502 /*
503 * The ioctls will use the same name as the Javelin ioctls. We
504 * will have a very restricted set for MC, and unlike Javelin
505 * will not have a envctrl_chip structure to return values
506 * from the driver. All we will have is a uint8_t value to
507 * get or set values from the driver. Also, unlike the Javelin,
508 * where 'index' is used to specify the input port from where
509 * temperature is collected, here different minor nodes will be
510 * created by the driver for each port, eliminating the need for
511 * 'index' - leaving us with only the value to pass.
512 */
513
514 /*ARGSUSED*/
515 static int
pcf8591_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)516 pcf8591_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
517 cred_t *credp, int *rvalp)
518 {
519 int err = 0;
520 struct pcf8591_unit *unitp;
521 minor_t minor = getminor(dev);
522
523 int instance = PCF8591_MINOR_TO_DEVINST(minor);
524 int channel = PCF8591_MINOR_TO_CHANNEL(minor);
525
526 unitp = (struct pcf8591_unit *)
527 ddi_get_soft_state(pcf8591_soft_statep, instance);
528
529 mutex_enter(&unitp->umutex);
530 while (unitp->pcf8591_flags == PCF8591_BUSY) {
531 if (cv_wait_sig(&unitp->pcf8591_cv, &unitp->umutex) <= 0) {
532 mutex_exit(&unitp->umutex);
533
534 return (EINTR);
535 }
536 }
537 unitp->pcf8591_flags = PCF8591_BUSY;
538 mutex_exit(&unitp->umutex);
539
540 switch (cmd) {
541
542 case ENVC_IOC_GETTEMP: {
543 /*
544 * Read the status byte from pcf8591 chip. The value will
545 * be already converted to Celcius by translate_cputemp.
546 */
547 (void) pcf8591_read_chip(unitp, channel, 1);
548 if (ddi_copyout(unitp->i2c_tran->i2c_rbuf,
549 (caddr_t)arg, sizeof (uint8_t), mode) != DDI_SUCCESS) {
550 err = EFAULT;
551 }
552 break;
553 }
554
555 case ENVC_IOC_GETMODE: {
556 uint8_t curr_mode = unitp->current_mode;
557
558 if (ddi_copyout((caddr_t)&curr_mode, (caddr_t)arg,
559 sizeof (uint8_t), mode) != DDI_SUCCESS) {
560 err = EFAULT;
561 }
562 break;
563 }
564
565 case ENVC_IOC_SETMODE: {
566 uint8_t curr_mode;
567 if (ddi_copyin((caddr_t)arg, (caddr_t)&curr_mode,
568 sizeof (uint8_t), mode) != DDI_SUCCESS) {
569 err = EFAULT;
570 break;
571 }
572 if (curr_mode == ENVCTRL_DIAG_MODE ||
573 curr_mode == ENVCTRL_NORMAL_MODE) {
574 unitp->current_mode = curr_mode; /* Don't do anything */
575 }
576 break;
577 }
578
579 /* Testing, may be removed */
580 case I2CDEV_TRAN:
581 if (call_copyin((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
582 err = EFAULT;
583 break;
584 }
585 if (nct_i2c_transfer(unitp->pcf8591_hdl, unitp->i2c_tran)
586 != I2C_SUCCESS) {
587 err = EFAULT;
588 break;
589 }
590 if (call_copyout((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
591 err = EFAULT;
592 break;
593 }
594 break;
595
596 /*
597 * TESTING TRANSLATION from "adc" "table" property
598 * translate thermistor index into temp Celcius
599 */
600 case I2CDEV_GETTEMP: {
601 struct i2c_transfer *tp;
602 if (call_copyin((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
603 err = EFAULT;
604 break;
605 }
606 tp = unitp->i2c_tran;
607 if (tp->i2c_rlen != 1) {
608 err = EINVAL;
609 break;
610 }
611 /*
612 * Throw away the first byte according to PCF8591 datasheet,
613 * so read two bytes
614 */
615 tp->i2c_rlen = 2;
616 if (nct_i2c_transfer(unitp->pcf8591_hdl, unitp->i2c_tran)
617 != I2C_SUCCESS) {
618 err = EFAULT;
619 break;
620 }
621 #ifdef DEBUG
622 if (pcf8591_debug & 0x0010)
623 cmn_err(CE_NOTE,
624 "pcf8591_ioctl: i2c_rlen=%d; "
625 "i2c_rbuf[0,1]=0x%x,0x%x\n",
626 tp->i2c_rlen, tp->i2c_rbuf[0], tp->i2c_rbuf[1]);
627 #endif /* DEBUG */
628 /*
629 * Throw away the first byte according to PCF8591 datasheet
630 */
631 if ((tp->i2c_rbuf[0] = translate_cputemp(tp->i2c_rbuf[1]))
632 == 0) {
633 err = EINVAL;
634 break;
635 }
636 tp->i2c_rbuf[1] = 0;
637
638 if (call_copyout((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
639 err = EFAULT;
640 break;
641 }
642 break;
643 }
644
645 case I2CDEV_GETTABLES: {
646 break;
647 }
648 default:
649 err = EINVAL;
650 }
651
652 mutex_enter(&unitp->umutex);
653 unitp->pcf8591_flags = 0;
654 cv_signal(&unitp->pcf8591_cv);
655 mutex_exit(&unitp->umutex);
656
657 return (err);
658 }
659
660 static int
pcf8591_do_detach(dev_info_t * dip)661 pcf8591_do_detach(dev_info_t *dip)
662 {
663 register struct pcf8591_unit *unitp;
664 int instance;
665 uint_t attach_flag;
666
667 instance = ddi_get_instance(dip);
668 unitp = ddi_get_soft_state(pcf8591_soft_statep, instance);
669 attach_flag = unitp->attach_flag;
670
671 if (attach_flag & PCF8591_KSTAT_INIT) {
672 pcf8591_delete_kstats(unitp);
673 }
674
675 if (attach_flag & PCF8591_LOCK_INIT) {
676 mutex_destroy(&unitp->umutex);
677 cv_destroy(&unitp->pcf8591_cv);
678 }
679
680 /*
681 * Restore the lengths of the rbuf and wbuf, which was originally
682 * allocated so that the appropriate amount of rbuf and wbuf are
683 * freed.
684 */
685 if (attach_flag & PCF8591_ALLOC_TRANSFER) {
686 unitp->i2c_tran->i2c_wlen = MAX_WLEN;
687 unitp->i2c_tran->i2c_rlen = MAX_RLEN;
688 i2c_transfer_free(unitp->pcf8591_hdl, unitp->i2c_tran);
689 }
690
691 if (attach_flag & PCF8591_REGISTER_CLIENT) {
692 i2c_client_unregister(unitp->pcf8591_hdl);
693 }
694
695 if (attach_flag & PCF8591_MINORS_CREATED) {
696 ddi_remove_minor_node(dip, NULL);
697 }
698
699 /*
700 * Free the memory allocated for the properties.
701 */
702 if (attach_flag & PCF8591_PROPS_READ) {
703 ddi_prop_free(unitp->props.name);
704 if (unitp->props.num_chans_used) {
705 ddi_prop_free(unitp->props.channels_in_use);
706 }
707
708 if (unitp->props.channels_description) {
709 ddi_prop_free(unitp->props.channels_description);
710 }
711 }
712
713 if (attach_flag & PCF8591_SOFT_STATE_ALLOC) {
714 ddi_soft_state_free(pcf8591_soft_statep, instance);
715 }
716
717 return (DDI_SUCCESS);
718 }
719
720 static int
pcf8591_do_suspend(dev_info_t * dip)721 pcf8591_do_suspend(dev_info_t *dip)
722 {
723 int instance = ddi_get_instance(dip);
724 struct pcf8591_unit *unitp = (struct pcf8591_unit *)
725 ddi_get_soft_state(pcf8591_soft_statep, instance);
726
727 if (unitp == NULL) {
728 return (ENXIO);
729 }
730
731 /*
732 * Set the busy flag so that future transactions block
733 * until resume.
734 */
735 mutex_enter(&unitp->umutex);
736 while (unitp->pcf8591_flags == PCF8591_BUSY) {
737 if (cv_wait_sig(&unitp->pcf8591_cv,
738 &unitp->umutex) <= 0) {
739 mutex_exit(&unitp->umutex);
740
741 return (DDI_FAILURE);
742 }
743 }
744 unitp->pcf8591_flags = PCF8591_BUSY;
745 mutex_exit(&unitp->umutex);
746
747 return (DDI_SUCCESS);
748 }
749
750 static int
pcf8591_do_resume(dev_info_t * dip)751 pcf8591_do_resume(dev_info_t *dip)
752 {
753 int instance = ddi_get_instance(dip);
754 struct pcf8591_unit *unitp = (struct pcf8591_unit *)
755 ddi_get_soft_state(pcf8591_soft_statep, instance);
756 if (unitp == NULL) {
757 return (ENXIO);
758 }
759
760 mutex_enter(&unitp->umutex);
761 unitp->pcf8591_flags = 0;
762 cv_signal(&unitp->pcf8591_cv);
763 mutex_exit(&unitp->umutex);
764
765 return (DDI_SUCCESS);
766 }
767
768 static int
pcf8591_do_attach(dev_info_t * dip)769 pcf8591_do_attach(dev_info_t *dip)
770 {
771 register struct pcf8591_unit *unitp;
772 int i, instance;
773 char name[MAXNAMELEN];
774 minor_t minor;
775
776 instance = ddi_get_instance(dip);
777
778 if (ddi_soft_state_zalloc(pcf8591_soft_statep, instance) != 0) {
779 return (DDI_FAILURE);
780 }
781
782 unitp = ddi_get_soft_state(pcf8591_soft_statep, instance);
783
784 if (unitp == NULL) {
785 return (DDI_FAILURE);
786 }
787
788 unitp->dip = dip;
789
790 unitp->attach_flag = PCF8591_SOFT_STATE_ALLOC;
791
792 if (pcf8591_read_props(unitp) != DDI_PROP_SUCCESS) {
793 (void) pcf8591_do_detach(dip);
794 return (DDI_FAILURE);
795 }
796
797 unitp->attach_flag |= PCF8591_PROPS_READ;
798
799 /*
800 * Set the current operating mode to NORMAL_MODE.
801 */
802 unitp->current_mode = ENVCTRL_NORMAL_MODE; /* normal mode */
803
804 (void) snprintf(unitp->pcf8591_name, PCF8591_NAMELEN,
805 "%s%d", ddi_driver_name(dip), instance);
806
807 /*
808 * Create a minor node corresponding to channel 0 to 3
809 */
810 for (i = 0; i < PCF8591_MAX_CHANS; i++) {
811 if (i == 0) {
812 (void) sprintf(name, "cputemp");
813 } else {
814 (void) sprintf(name, "%d", i);
815 }
816 minor = PCF8591_MINOR_NUM(instance, i);
817 if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
818 PCF8591_NODE_TYPE, NULL) == DDI_FAILURE) {
819 ddi_remove_minor_node(dip, NULL);
820 (void) pcf8591_do_detach(dip);
821 return (DDI_FAILURE);
822 }
823 }
824
825 unitp->attach_flag |= PCF8591_MINORS_CREATED;
826
827 if (i2c_client_register(dip, &unitp->pcf8591_hdl)
828 != I2C_SUCCESS) {
829 (void) pcf8591_do_detach(dip);
830 return (DDI_FAILURE);
831 }
832
833 unitp->attach_flag |= PCF8591_REGISTER_CLIENT;
834
835 /*
836 * We allocate a single i2c_transfer_t structure for all
837 * i2c transactions.
838 */
839 if (i2c_transfer_alloc(unitp->pcf8591_hdl, &unitp->i2c_tran,
840 MAX_WLEN, MAX_RLEN, KM_SLEEP) != I2C_SUCCESS) {
841 (void) pcf8591_do_detach(dip);
842 return (DDI_FAILURE);
843 }
844
845 unitp->attach_flag |= PCF8591_ALLOC_TRANSFER;
846
847 /*
848 * The flags will be set to I2C_WR because for all reads from
849 * the 8591 we need to also write the control byte.
850 */
851 unitp->i2c_tran->i2c_flags = I2C_WR;
852 unitp->i2c_tran->i2c_version = I2C_XFER_REV;
853
854
855 /*
856 * Set the analog programming mode to default. Upper nibble
857 * in control byte. Four single ended inputs, output not enabled.
858 */
859 unitp->pcf8591_inprog = PCF8591_4SINGLE | PCF8591_ANALOG_INPUT_EN;
860
861 /*
862 * Set the open flag for each channel to 0.
863 */
864 for (i = 0; i < PCF8591_MAX_CHANS; i++) {
865 unitp->pcf8591_oflag[i] = 0;
866 }
867
868 /*
869 * Set the busy flag to 0.
870 */
871 unitp->pcf8591_flags = 0;
872
873 mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER, NULL);
874 cv_init(&unitp->pcf8591_cv, NULL, CV_DRIVER, NULL);
875
876 unitp->attach_flag |= PCF8591_LOCK_INIT;
877
878 if (pcf8591_add_kstats(unitp) != DDI_SUCCESS) {
879 (void) pcf8591_do_detach(dip);
880 return (DDI_FAILURE);
881 }
882
883 unitp->attach_flag |= PCF8591_KSTAT_INIT;
884
885 ddi_report_dev(dip);
886
887 return (DDI_SUCCESS);
888 }
889
890 /* ARGSUSED */
891 static int
pcf8591_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)892 pcf8591_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
893 {
894 dev_t dev;
895 int instance;
896
897 if (infocmd == DDI_INFO_DEVT2INSTANCE) {
898 dev = (dev_t)arg;
899 instance = PCF8591_MINOR_TO_DEVINST(getminor(dev));
900 *result = (void *)(uintptr_t)instance;
901 return (DDI_SUCCESS);
902 }
903 return (DDI_FAILURE);
904 }
905
906 static int
pcf8591_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)907 pcf8591_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
908 {
909 switch (cmd) {
910 case DDI_ATTACH:
911 return (pcf8591_do_attach(dip));
912 case DDI_RESUME:
913 return (pcf8591_do_resume(dip));
914 default:
915 return (DDI_FAILURE);
916 }
917 }
918
919 static int
pcf8591_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)920 pcf8591_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
921 {
922 switch (cmd) {
923 case DDI_DETACH:
924 return (pcf8591_do_detach(dip));
925 case DDI_SUSPEND:
926 return (pcf8591_do_suspend(dip));
927 default:
928 return (DDI_FAILURE);
929 }
930 }
931
932 static uint8_t
translate_cputemp(uint8_t value)933 translate_cputemp(uint8_t value)
934 {
935 return (_cpu_temps[value]);
936 }
937
938 static int
pcf8591_add_kstats(struct pcf8591_unit * unitp)939 pcf8591_add_kstats(struct pcf8591_unit *unitp)
940 {
941 if ((unitp->tempksp = kstat_create(I2C_PCF8591_NAME,
942 unitp->instance, I2C_KSTAT_CPUTEMP, "misc",
943 KSTAT_TYPE_RAW, sizeof (unitp->temp_kstats),
944 KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
945
946 return (DDI_FAILURE);
947 }
948
949 /*
950 * The kstat fields are already initialized in the attach routine..
951 */
952
953 unitp->tempksp->ks_update = pcf8591_temp_kstat_update;
954 unitp->tempksp->ks_private = (void *)unitp;
955
956 (void) strcpy(unitp->temp_kstats.label,
957 unitp->props.channels_description[0]);
958 unitp->temp_kstats.type = ENVC_NETRACT_CPU_SENSOR;
959
960 kstat_install(unitp->tempksp);
961
962 return (DDI_SUCCESS);
963 }
964
965 static void
pcf8591_delete_kstats(struct pcf8591_unit * unitp)966 pcf8591_delete_kstats(struct pcf8591_unit *unitp)
967 {
968 kstat_delete(unitp->tempksp);
969 }
970
971 static int
pcf8591_temp_kstat_update(kstat_t * ksp,int rw)972 pcf8591_temp_kstat_update(kstat_t *ksp, int rw)
973 {
974 struct pcf8591_unit *unitp;
975 char *kstatp;
976 int err = 0;
977 int channel = 0;
978 int warn_temp = 0;
979 int shutdown_temp = 0;
980
981 unitp = (struct pcf8591_unit *)ksp->ks_private;
982
983 mutex_enter(&unitp->umutex);
984 while (unitp->pcf8591_flags == PCF8591_BUSY) {
985 if (cv_wait_sig(&unitp->pcf8591_cv,
986 &unitp->umutex) <= 0) {
987 mutex_exit(&unitp->umutex);
988
989 return (EINTR);
990 }
991 }
992
993 unitp->pcf8591_flags = PCF8591_BUSY;
994 mutex_exit(&unitp->umutex);
995
996 kstatp = (char *)ksp->ks_data;
997
998 if (rw == KSTAT_WRITE) {
999
1000 /* check for the size of buffer */
1001 if (ksp->ks_data_size != sizeof (unitp->temp_kstats)) {
1002 err = EIO;
1003 goto bail;
1004 }
1005
1006 warn_temp = ((envctrl_temp_t *)kstatp)->warning_threshold;
1007 shutdown_temp = ((envctrl_temp_t *)kstatp)->shutdown_threshold;
1008
1009 if (shutdown_temp < SHUTDOWN_TEMP_MIN || shutdown_temp >
1010 SHUTDOWN_TEMP_MAX) {
1011 err = EIO;
1012 goto bail;
1013 }
1014
1015 if (warn_temp < 0 || shutdown_temp <= warn_temp) {
1016 err = EIO;
1017 goto bail;
1018 }
1019
1020 /* write into kstat fields */
1021 unitp->temp_kstats.warning_threshold = warn_temp;
1022 unitp->temp_kstats.shutdown_threshold = shutdown_temp;
1023
1024 } else {
1025 (void) pcf8591_read_chip(unitp, channel, 1);
1026 unitp->temp_kstats.value =
1027 unitp->i2c_tran->i2c_rbuf[0];
1028 bcopy((caddr_t)&unitp->temp_kstats, kstatp,
1029 sizeof (unitp->temp_kstats));
1030 }
1031
1032 bail:
1033
1034 mutex_enter(&unitp->umutex);
1035 unitp->pcf8591_flags = 0;
1036 cv_signal(&unitp->pcf8591_cv);
1037 mutex_exit(&unitp->umutex);
1038
1039 return (err);
1040 }
1041
1042 static int
pcf8591_read_chip(struct pcf8591_unit * unitp,uint8_t channel,int size)1043 pcf8591_read_chip(struct pcf8591_unit *unitp, uint8_t channel,
1044 int size)
1045 {
1046 int retval = I2C_SUCCESS;
1047
1048 /*
1049 * We need to read an extra byte, since as per specification
1050 * the first byte read should be discarded.
1051 */
1052 i2c_transfer_t *tp = unitp->i2c_tran;
1053 tp->i2c_flags = I2C_WR_RD;
1054 tp->i2c_rlen = size+1;
1055 tp->i2c_wlen = 1;
1056 tp->i2c_wbuf[0] = (unitp->pcf8591_inprog |
1057 channel);
1058
1059 retval = nct_i2c_transfer(unitp->pcf8591_hdl, tp);
1060 if (retval == I2C_SUCCESS) {
1061 tp->i2c_rbuf[0] = translate_cputemp(tp->i2c_rbuf[1]);
1062 }
1063
1064 if (tp->i2c_rbuf[0] == 0) {
1065 retval = I2C_FAILURE;
1066 }
1067
1068 return (retval);
1069 }
1070
1071 /*
1072 * Reads the properties of the pcf8591 device.
1073 */
1074 static int
pcf8591_read_props(struct pcf8591_unit * unitp)1075 pcf8591_read_props(struct pcf8591_unit *unitp)
1076 {
1077 dev_info_t *dip = unitp->dip;
1078 int i, retval = 0, prop_len;
1079 int instance = ddi_get_instance(dip);
1080 int warning_temp, shutdown_temp;
1081 uint32_t *prop_value = NULL;
1082 uchar_t *creg_prop;
1083 char *function;
1084 uint_t tblsz;
1085
1086 #ifdef lint
1087 instance = instance;
1088 #endif
1089 /*
1090 * Check for the pcf8591_function property, and make sure it's
1091 * cputemp.
1092 */
1093 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1094 "pcf8591_function", &function) != DDI_SUCCESS) {
1095 dbg_print(CE_WARN, "Couldn't find pcf8591_function property");
1096
1097 return (DDI_FAILURE);
1098 }
1099
1100 if (strcmp(function, "cputemp") != 0) {
1101 dbg_print(CE_WARN, "pcf8591_function is not cputemp");
1102 ddi_prop_free(function);
1103
1104 return (DDI_FAILURE);
1105 }
1106
1107 ddi_prop_free(function);
1108
1109 retval = ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1110 "name", &unitp->props.name);
1111 if (retval != DDI_PROP_SUCCESS) {
1112
1113 return (retval);
1114 }
1115 #ifdef DEBUG
1116 else if (pcf8591_debug & 0x02)
1117 cmn_err(CE_NOTE,
1118 "pcf8591_read_props:ddi_prop_lookup_string(%s): \
1119 found %s ", "name", unitp->props.name);
1120 #endif /* DEBUG */
1121
1122 retval = ddi_getlongprop(DDI_DEV_T_ANY, dip,
1123 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP,
1124 "reg", (caddr_t)&prop_value, &prop_len);
1125 if (retval == DDI_PROP_SUCCESS) {
1126 unitp->props.i2c_bus = (uint16_t)prop_value[0];
1127 unitp->props.slave_address = (uint16_t)prop_value[1];
1128 kmem_free(prop_value, prop_len);
1129 #ifdef DEBUG
1130 if (pcf8591_debug & 0x02)
1131 cmn_err(CE_NOTE,
1132 "pcf8591:ddi_getlongprop(%s) returns %d,"
1133 " i2c_bus,slave=0x%x,0x%x",
1134 "reg", retval, unitp->props.i2c_bus,
1135 unitp->props.slave_address);
1136 #endif /* DEBUG */
1137 } else {
1138 unitp->props.i2c_bus = (uint16_t)-1;
1139 unitp->props.slave_address = (uint16_t)-1;
1140 #ifdef DEBUG
1141 cmn_err(CE_WARN,
1142 "pcf8591_read_props:ddi_getlongprop(%s) returns %d,"
1143 " default it to 0x%x:0x%X",
1144 "reg", retval, unitp->props.i2c_bus,
1145 unitp->props.slave_address);
1146 #endif /* DEBUG */
1147 }
1148 (void) ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1149 "channels-in-use", &prop_len);
1150 retval = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY,
1151 dip, DDI_PROP_DONTPASS,
1152 "channels-in-use",
1153 (uchar_t **)&unitp->props.channels_in_use,
1154 &unitp->props.num_chans_used);
1155 if (retval == DDI_PROP_SUCCESS) {
1156 unitp->props.num_chans_used /= sizeof (pcf8591_channel_t);
1157 } else {
1158 unitp->props.num_chans_used = 0;
1159 }
1160
1161 #ifdef DEBUG
1162 if (pcf8591_debug & 0x0002)
1163 cmn_err(CE_NOTE,
1164 "pcf8591_read_props:ddi_prop_lookup_byte_array(%s)"
1165 "returns %d\n"
1166 "\t\tlength=%d, #elements=%d",
1167 "channels-in-use", retval,
1168 prop_len, unitp->props.num_chans_used);
1169 #endif /* DEBUG */
1170
1171 retval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
1172 DDI_PROP_DONTPASS, "channels-description",
1173 (char ***)&unitp->props.channels_description,
1174 (uint_t *)&prop_len);
1175
1176 if (retval != DDI_PROP_SUCCESS) {
1177 prop_len = 0;
1178 unitp->props.channels_description = NULL;
1179 }
1180
1181 #ifdef DEBUG
1182 if (pcf8591_debug & 0x0002) {
1183 cmn_err(CE_NOTE,
1184 "pcf8591_read_props:ddi_prop_lookup_string_array(%s)"
1185 "returns %d, length=%d",
1186 "channels-description", retval, prop_len);
1187 for (i = 0; i < prop_len; ++i) {
1188 cmn_err(CE_NOTE, "channels-description[%d]=<%s>",
1189 i, unitp->props.channels_description[i]);
1190 }
1191 }
1192 #endif /* DEBUG */
1193
1194 /*
1195 * The following code was borrowed from envctrltwo.c
1196 * I haven't yet investigated why the copy target is index + 2
1197 */
1198 retval = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
1199 DDI_PROP_DONTPASS, "tables", &creg_prop, (uint_t *)&prop_len);
1200
1201 if (retval != DDI_PROP_SUCCESS) {
1202 #ifdef DEBUG
1203 cmn_err(CE_WARN, "%s%d: Unable to read pcf8591 tables property",
1204 ddi_get_name(dip), instance);
1205 #endif /* DEBUG */
1206
1207 return (DDI_NOT_WELL_FORMED);
1208 }
1209
1210 tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
1211 if (prop_len <= tblsz) {
1212 for (i = 0; i < prop_len; i++) {
1213 _cpu_temps[i] = creg_prop[i];
1214 }
1215 }
1216 #ifdef DEBUG
1217 if (pcf8591_debug & 0x0002)
1218 cmn_err(CE_NOTE, "pcf8591_read_props: _cpu_temps size=%d; "
1219 "tables prop_len=%d\n", tblsz, prop_len);
1220 #endif /* DEBUG */
1221
1222 ddi_prop_free(creg_prop);
1223
1224 /*
1225 * Read shutdown temp and warning temp properties.
1226 */
1227 warning_temp = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
1228 DDI_PROP_DONTPASS, "warning-temp", PCF8591_WARNING_TEMP);
1229
1230 shutdown_temp = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
1231 DDI_PROP_DONTPASS, "shutdown-temp", PCF8591_SHUTDOWN_TEMP);
1232
1233 /*
1234 * Fill up the warning and shutdown temp values in kstat structure.
1235 */
1236 unitp->temp_kstats.warning_threshold = warning_temp;
1237 unitp->temp_kstats.shutdown_threshold = shutdown_temp;
1238
1239 return (DDI_PROP_SUCCESS);
1240 }
1241