Annotation of sys/dev/i2c/tsl2560.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: tsl2560.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Mark Kettenis
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/i2c/i2cvar.h>
25:
26: /* TSL2560/61 registers */
27: #define TSL2560_REG_CONTROL 0x80
28: #define TSL2560_CONTROL_POWER 0x03
29: #define TSL2560_REG_TIMING 0x81
30: #define TSL2560_TIMING_GAIN 0x10 /* high gain (16x) */
31: #define TSL2560_TIMING_INTEG0 0x00 /* 13.7ms */
32: #define TSL2560_TIMING_INTEG1 0x01 /* 101ms */
33: #define TSL2560_TIMING_INTEG2 0x02 /* 402ms */
34: #define TSL2560_REG_ID 0x8a
35: #define TSL2560_REG_DATA0 0xac
36: #define TSL2560_REG_DATA1 0xae
37:
38: struct tsl_softc {
39: struct device sc_dev;
40: i2c_tag_t sc_tag;
41: i2c_addr_t sc_addr;
42:
43: struct ksensor sc_sensor;
44: struct ksensordev sc_sensordev;
45: };
46:
47: int tsl_match(struct device *, void *, void *);
48: void tsl_attach(struct device *, struct device *, void *);
49:
50: void tsl_refresh(void *);
51: u_int64_t tsl_lux(u_int32_t, u_int32_t);
52:
53: struct cfattach tsl_ca = {
54: sizeof(struct tsl_softc), tsl_match, tsl_attach
55: };
56:
57: struct cfdriver tsl_cd = {
58: NULL, "tsl", DV_DULL
59: };
60:
61: int
62: tsl_match(struct device *parent, void *match, void *aux)
63: {
64: struct i2c_attach_args *ia = aux;
65:
66: if (strcmp(ia->ia_name, "tsl2560") == 0)
67: return (1);
68: return (0);
69: }
70:
71: void
72: tsl_attach(struct device *parent, struct device *self, void *aux)
73: {
74: struct tsl_softc *sc = (struct tsl_softc *)self;
75: struct i2c_attach_args *ia = aux;
76: u_int8_t cmd, data;
77:
78: sc->sc_tag = ia->ia_tag;
79: sc->sc_addr = ia->ia_addr;
80:
81: iic_acquire_bus(sc->sc_tag, 0);
82: cmd = TSL2560_REG_CONTROL; data = TSL2560_CONTROL_POWER;
83: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
84: sc->sc_addr, &cmd, 1, &data, 1, 0)) {
85: iic_release_bus(sc->sc_tag, 0);
86: printf(": power up failed\n");
87: return;
88: }
89: cmd = TSL2560_REG_TIMING;
90: data = TSL2560_TIMING_GAIN | TSL2560_TIMING_INTEG2;
91: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
92: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
93: iic_release_bus(sc->sc_tag, 0);
94: printf(": cannot write timing register\n");
95: return;
96: }
97: cmd = TSL2560_REG_ID;
98: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
99: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
100: iic_release_bus(sc->sc_tag, 0);
101: printf(": cannot read ID register\n");
102: return;
103: }
104: iic_release_bus(sc->sc_tag, 0);
105:
106: switch (data >> 4) {
107: case 0:
108: printf(": TSL2560 rev %x", data & 0x0f);
109: break;
110: case 1:
111: printf(": TSL2561 rev %x", data & 0x0f);
112: break;
113: default:
114: printf(": unknown part number %x", data >> 4);
115: break;
116: }
117:
118: /* Initialize sensor data. */
119: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
120: sizeof(sc->sc_sensordev.xname));
121: sc->sc_sensor.type = SENSOR_LUX;
122:
123: if (sensor_task_register(sc, tsl_refresh, 5) == NULL) {
124: printf(": unable to register update task\n");
125: return;
126: }
127:
128: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
129: sensordev_install(&sc->sc_sensordev);
130:
131: printf("\n");
132: }
133:
134: void
135: tsl_refresh(void *arg)
136: {
137: struct tsl_softc *sc = arg;
138: u_int8_t cmd, data[2];
139: u_int16_t chan0, chan1;
140:
141: iic_acquire_bus(sc->sc_tag, 0);
142: cmd = TSL2560_REG_DATA0;
143: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
144: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
145: iic_release_bus(sc->sc_tag, 0);
146: sc->sc_sensor.flags |= SENSOR_FINVALID;
147: return;
148: }
149: chan0 = data[1] << 8 | data[0];
150: cmd = TSL2560_REG_DATA1;
151: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
152: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
153: iic_release_bus(sc->sc_tag, 0);
154: sc->sc_sensor.flags |= SENSOR_FINVALID;
155: return;
156: }
157: chan1 = data[1] << 8 | data[0];
158: iic_release_bus(sc->sc_tag, 0);
159:
160: sc->sc_sensor.value = tsl_lux(chan0, chan1);
161: sc->sc_sensor.flags &= ~SENSOR_FINVALID;
162: }
163:
164: /* Precision for fixed-point math. */
165: #define TSL2560_RATIO_SCALE 9
166: #define TSL2560_LUX_SCALE 14
167:
168: /*
169: * The TSL2560/2561 comes in a ChipScale or TMB-6 package and the
170: * calibration is slightly different for each package. The constants
171: * below are for the TMB-6 package.
172: */
173:
174: #define TSL2560_K1T 0x0040 /* 0.125 * (1 << TSL2560_RATIO_SCALE) */
175: #define TSL2560_B1T 0x01f2 /* 0.0304 * (1 << TSL2560_LUX_SCALE) */
176: #define TSL2560_M1T 0x01be /* 0.0272 * (1 << TSL2560_LUX_SCALE) */
177:
178: #define TSL2560_K2T 0x0080 /* 0.250 * (1 << TSL2560_RATIO_SCALE) */
179: #define TSL2560_B2T 0x0214 /* 0.0324 * (1 << TSL2560_LUX_SCALE) */
180: #define TSL2560_M2T 0x02d1 /* 0.0440 * (1 << TSL2560_LUX_SCALE) */
181:
182: #define TSL2560_K3T 0x00c0 /* 0.375 * (1 << TSL2560_RATIO_SCALE) */
183: #define TSL2560_B3T 0x023f /* 0.0351 * (1 << TSL2560_LUX_SCALE) */
184: #define TSL2560_M3T 0x037b /* 0.0544 * (1 << TSL2560_LUX_SCALE) */
185:
186: #define TSL2560_K4T 0x0080 /* 0.50 * (1 << TSL2560_RATIO_SCALE) */
187: #define TSL2560_B4T 0x0214 /* 0.0381 * (1 << TSL2560_LUX_SCALE) */
188: #define TSL2560_M4T 0x02d1 /* 0.0624 * (1 << TSL2560_LUX_SCALE) */
189:
190: #define TSL2560_K5T 0x0138 /* 0.61 * (1 << TSL2560_RATIO_SCALE) */
191: #define TSL2560_B5T 0x016f /* 0.0224 * (1 << TSL2560_LUX_SCALE) */
192: #define TSL2560_M5T 0x01fc /* 0.0310 * (1 << TSL2560_LUX_SCALE) */
193:
194: #define TSL2560_K6T 0x0100 /* 0.80 * (1 << TSL2560_RATIO_SCALE) */
195: #define TSL2560_B6T 0x0270 /* 0.0128 * (1 << TSL2560_LUX_SCALE) */
196: #define TSL2560_M6T 0x03fe /* 0.0153 * (1 << TSL2560_LUX_SCALE) */
197:
198: #define TSL2560_K7T 0x019a /* 1.3 * (1 << TSL2560_RATIO_SCALE) */
199: #define TSL2560_B7T 0x0018 /* 0.00146 * (1 << TSL2560_LUX_SCALE) */
200: #define TSL2560_M7T 0x0012 /* 0.00112 * (1 << TSL2560_LUX_SCALE) */
201:
202: u_int64_t
203: tsl_lux(u_int32_t chan0, u_int32_t chan1)
204: {
205: u_int32_t ratio, ratio1;
206: u_int32_t b, m;
207: int64_t lux;
208:
209: ratio1 = 0;
210: if (chan0 != 0)
211: ratio1 = (chan1 << (TSL2560_RATIO_SCALE + 1)) / chan0;
212: ratio = (ratio1 + 1) >> 1;
213:
214: b = 0, m = 0;
215: if (ratio <= TSL2560_K1T)
216: b = TSL2560_B1T, m = TSL2560_M1T;
217: else if (ratio <= TSL2560_K2T)
218: b = TSL2560_B2T, m = TSL2560_M2T;
219: else if (ratio <= TSL2560_K3T)
220: b = TSL2560_B3T, m = TSL2560_M3T;
221: else if (ratio <= TSL2560_K4T)
222: b = TSL2560_B4T, m = TSL2560_M4T;
223: else if (ratio <= TSL2560_K5T)
224: b = TSL2560_B5T, m = TSL2560_M5T;
225: else if (ratio <= TSL2560_K6T)
226: b = TSL2560_B6T, m = TSL2560_M6T;
227: else if (ratio <= TSL2560_K7T)
228: b = TSL2560_B7T, m = TSL2560_M7T;
229:
230: lux = b * chan0 - m * chan1;
231: if (lux < 0)
232: lux = 0;
233: return ((lux * 1000000) >> TSL2560_LUX_SCALE);
234: }
CVSweb