1 /* $OpenBSD: tsl2560.c,v 1.8 2022/04/06 18:59:28 naddy 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 const 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, sizeof cmd, &data, sizeof data, 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 } 235