Annotation of sys/arch/sparc64/dev/pcf8591_ofw.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pcf8591_ofw.c,v 1.4 2007/06/24 05:34:35 dlg Exp $ */
2:
3: /*
4: * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/device.h>
22: #include <sys/sensors.h>
23:
24: #include <dev/ofw/openfirm.h>
25: #include <dev/i2c/i2cvar.h>
26:
27: #define PCF8591_CHANNELS 4
28:
29: struct pcfadc_channel {
30: u_int chan_num;
31: struct ksensor chan_sensor;
32: };
33:
34: struct pcfadc_softc {
35: struct device sc_dev;
36: i2c_tag_t sc_tag;
37: i2c_addr_t sc_addr;
38: u_char sc_xlate[256];
39: u_int sc_nchan;
40: struct pcfadc_channel sc_channels[PCF8591_CHANNELS];
41: struct ksensordev sc_sensordev;
42: };
43:
44: int pcfadc_match(struct device *, void *, void *);
45: void pcfadc_attach(struct device *, struct device *, void *);
46: void pcfadc_refresh(void *);
47:
48: struct cfattach pcfadc_ca = {
49: sizeof(struct pcfadc_softc), pcfadc_match, pcfadc_attach
50: };
51:
52: struct cfdriver pcfadc_cd = {
53: NULL, "pcfadc", DV_DULL
54: };
55:
56: int
57: pcfadc_match(struct device *parent, void *match, void *aux)
58: {
59: struct i2c_attach_args *ia = aux;
60:
61: if (strcmp(ia->ia_name, "i2cpcf,8591") != 0)
62: return (0);
63:
64: return (1);
65: }
66:
67: void
68: pcfadc_attach(struct device *parent, struct device *self, void *aux)
69: {
70: struct pcfadc_softc *sc = (struct pcfadc_softc *)self;
71: u_char chanuse[PCF8591_CHANNELS * 4], desc[PCF8591_CHANNELS * 32];
72: u_char *cp;
73: u_int8_t junk[PCF8591_CHANNELS + 1];
74: u_int32_t transinfo[PCF8591_CHANNELS * 4];
75: struct i2c_attach_args *ia = aux;
76: int dlen, clen, tlen, node = *(int *)ia->ia_cookie;
77: u_int i;
78:
79: if ((dlen = OF_getprop(node, "channels-description", desc,
80: sizeof(desc))) < 0) {
81: printf(": couldn't find \"channels-description\" property\n");
82: return;
83: }
84: if (dlen > sizeof(desc) || desc[dlen - 1] != '\0') {
85: printf(": bad \"channels-description\" property\n");
86: return;
87: }
88: if ((clen = OF_getprop(node, "channels-in-use", chanuse,
89: sizeof(chanuse))) < 0) {
90: printf(": couldn't find \"channels-in-use\" property\n");
91: return;
92: }
93: if ((clen % 4) != 0) {
94: printf(": invalid \"channels-in-use\" length %d\n", clen);
95: return;
96: }
97: sc->sc_nchan = clen / 4;
98: if (sc->sc_nchan > PCF8591_CHANNELS) {
99: printf(": invalid number of channels (%d)\n", sc->sc_nchan);
100: return;
101: }
102:
103: if ((tlen = OF_getprop(node, "tables", sc->sc_xlate,
104: sizeof(sc->sc_xlate))) < 0) {
105: printf(": couldn't find \"tables\" property\n");
106: return;
107: }
108: /* We only support complete, single width tables */
109: if (tlen != 256) {
110: printf(": invalid \"tables\" length %d\n", tlen);
111: return;
112: }
113:
114: if ((tlen = OF_getprop(node, "translation", transinfo,
115: sizeof(transinfo))) < 0) {
116: printf(": couldn't find \"translation\" property\n");
117: return;
118: }
119: if (tlen != (sc->sc_nchan * 4 * 4)) {
120: printf(": invalid \"translation\" length %d\n", tlen);
121: return;
122: }
123:
124: cp = desc;
125: for (i = 0; i < sc->sc_nchan; i++) {
126: struct pcfadc_channel *chp = &sc->sc_channels[i];
127:
128: chp->chan_sensor.type = SENSOR_TEMP;
129:
130: if (cp >= desc + dlen) {
131: printf(": invalid \"channels-description\"\n");
132: return;
133: }
134: strlcpy(chp->chan_sensor.desc, cp,
135: sizeof(chp->chan_sensor.desc));
136: cp += strlen(cp) + 1;
137:
138: /*
139: * We only support input temperature channels, with
140: * valid channel numbers, and basic (unscaled) translation
141: *
142: * XXX TODO: support voltage (type 2) channels and type 4
143: * (scaled) translation tables
144: */
145: if (chanuse[(i * 4)] > PCF8591_CHANNELS || /* channel # */
146: chanuse[(i * 4) + 1] != 0 || /* dir == input */
147: chanuse[(i * 4) + 2] != 1 || /* type == temp */
148: transinfo[(i * 4)] != 3 || /* xlate == table */
149: transinfo[(i * 4) + 2] != 0 || /* no xlate offset */
150: transinfo[(i * 4) + 3] != 0x100) { /* xlate tbl length */
151: printf(": unsupported sensor %d\n", i);
152: return;
153: }
154: chp->chan_num = chanuse[(i * 4)];
155: }
156:
157: sc->sc_tag = ia->ia_tag;
158: sc->sc_addr = ia->ia_addr;
159:
160: iic_acquire_bus(sc->sc_tag, 0);
161:
162: /* Try a read now, so we can fail if it doesn't work */
163: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
164: NULL, 0, junk, sc->sc_nchan + 1, 0)) {
165: printf(": read failed\n");
166: iic_release_bus(sc->sc_tag, 0);
167: return;
168: }
169:
170: iic_release_bus(sc->sc_tag, 0);
171:
172: /* Initialize sensor data. */
173: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
174: sizeof(sc->sc_sensordev.xname));
175:
176: for (i = 0; i < sc->sc_nchan; i++)
177: if (!(sc->sc_channels[i].chan_sensor.flags & SENSOR_FINVALID))
178: sensor_attach(&sc->sc_sensordev,
179: &sc->sc_channels[i].chan_sensor);
180:
181: if (sensor_task_register(sc, pcfadc_refresh, 5) == NULL) {
182: printf(": unable to register update task\n");
183: return;
184: }
185:
186: sensordev_install(&sc->sc_sensordev);
187:
188: printf("\n");
189: }
190:
191: void
192: pcfadc_refresh(void *arg)
193: {
194: struct pcfadc_softc *sc = arg;
195: u_int i;
196: u_int8_t data[PCF8591_CHANNELS + 1];
197:
198: iic_acquire_bus(sc->sc_tag, 0);
199: /* NB: first byte out is stale, so read num_channels + 1 */
200: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
201: NULL, 0, data, PCF8591_CHANNELS + 1, 0)) {
202: iic_release_bus(sc->sc_tag, 0);
203: return;
204: }
205: iic_release_bus(sc->sc_tag, 0);
206:
207: /* XXX: so far this only supports temperature channels */
208: for (i = 0; i < sc->sc_nchan; i++) {
209: struct pcfadc_channel *chp = &sc->sc_channels[i];
210:
211: if ((chp->chan_sensor.flags & SENSOR_FINVALID) != 0)
212: continue;
213: chp->chan_sensor.value = 273150000 + 1000000 *
214: sc->sc_xlate[data[1 + chp->chan_num]];
215: }
216: }
217:
CVSweb