1 /*
2  * Copyright (c) 2023, Gustavo Silva
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ams_tsl2561
8 
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/__assert.h>
16 
17 LOG_MODULE_REGISTER(TSL2561, CONFIG_SENSOR_LOG_LEVEL);
18 
19 #define TSL2561_CHIP_ID 0x05
20 
21 #define TSL2561_GAIN_1X  0x00
22 #define TSL2561_GAIN_16X 0x01
23 
24 #define TSL2561_INTEGRATION_13MS  0x00
25 #define TSL2561_INTEGRATION_101MS 0x01
26 #define TSL2561_INTEGRATION_402MS 0x02
27 
28 /* Register set */
29 #define TSL2561_REG_CONTROL        0x00
30 #define TSL2561_REG_TIMING         0x01
31 #define TSL2561_REG_THRESHLOWLOW   0x02
32 #define TSL2561_REG_THRESHLOWHIGH  0x03
33 #define TSL2561_REG_THRESHHIGHLOW  0x04
34 #define TSL2561_REG_THRESHHIGHHIGH 0x05
35 #define TSL2561_REG_INTERRUPT      0x06
36 #define TSL2561_REG_ID             0x0A
37 #define TSL2561_REG_DATA0LOW       0x0C
38 #define TSL2561_REG_DATA0HIGH      0x0D
39 #define TSL2561_REG_DATA1LOW       0x0E
40 #define TSL2561_REG_DATA1HIGH      0x0F
41 
42 /* Command register fields */
43 #define TSL2561_COMMAND_CMD  BIT(7)
44 #define TSL2561_COMMAND_WORD BIT(5)
45 
46 /* Control register fields */
47 #define TSL2561_CONTROL_POWER_UP   0x03
48 #define TSL2561_CONTROL_POWER_DOWN 0x00
49 
50 /* Timing register fields */
51 #define TSL2561_TIMING_GAIN  BIT(4)
52 #define TSL2561_TIMING_INTEG GENMASK(1, 0)
53 
54 /* ID register part number mask */
55 #define TSL2561_ID_PARTNO GENMASK(7, 4)
56 
57 /* Lux calculation constants */
58 #define TSL2561_LUX_SCALE     14U
59 #define TSL2561_RATIO_SCALE   9U
60 #define TSL2561_CH_SCALE      10U
61 #define TSL2561_CHSCALE_TINT0 0x7517
62 #define TSL2561_CHSCALE_TINT1 0x0FE7
63 
64 #define TSL2561_LUX_K1T 0X0040 /* 0.125   * 2^RATIO_SCALE */
65 #define TSL2561_LUX_B1T 0X01F2 /* 0.0304  * 2^LUX_SCALE   */
66 #define TSL2561_LUX_M1T 0X01BE /* 0.0272  * 2^LUX_SCALE   */
67 #define TSL2561_LUX_K2T 0X0080 /* 0.250   * 2^RATIO_SCALE */
68 #define TSL2561_LUX_B2T 0X0214 /* 0.0325  * 2^LUX_SCALE   */
69 #define TSL2561_LUX_M2T 0X02D1 /* 0.0440  * 2^LUX_SCALE   */
70 #define TSL2561_LUX_K3T 0X00C0 /* 0.375   * 2^RATIO_SCALE */
71 #define TSL2561_LUX_B3T 0X023F /* 0.0351  * 2^LUX_SCALE   */
72 #define TSL2561_LUX_M3T 0X037B /* 0.0544  * 2^LUX_SCALE   */
73 #define TSL2561_LUX_K4T 0X0100 /* 0.50    * 2^RATIO_SCALE */
74 #define TSL2561_LUX_B4T 0X0270 /* 0.0381  * 2^LUX_SCALE   */
75 #define TSL2561_LUX_M4T 0X03FE /* 0.0624  * 2^LUX_SCALE   */
76 #define TSL2561_LUX_K5T 0X0138 /* 0.61    * 2^RATIO_SCALE */
77 #define TSL2561_LUX_B5T 0X016F /* 0.0224  * 2^LUX_SCALE   */
78 #define TSL2561_LUX_M5T 0X01FC /* 0.0310  * 2^LUX_SCALE   */
79 #define TSL2561_LUX_K6T 0X019A /* 0.80    * 2^RATIO_SCALE */
80 #define TSL2561_LUX_B6T 0X00D2 /* 0.0128  * 2^LUX_SCALE   */
81 #define TSL2561_LUX_M6T 0X00FB /* 0.0153  * 2^LUX_SCALE   */
82 #define TSL2561_LUX_K7T 0X029A /* 1.3     * 2^RATIO_SCALE */
83 #define TSL2561_LUX_B7T 0X0018 /* 0.00146 * 2^LUX_SCALE   */
84 #define TSL2561_LUX_M7T 0X0012 /* 0.00112 * 2^LUX_SCALE   */
85 #define TSL2561_LUX_K8T 0X029A /* 1.3     * 2^RATIO_SCALE */
86 #define TSL2561_LUX_B8T 0X0000 /* 0.000   * 2^LUX_SCALE   */
87 #define TSL2561_LUX_M8T 0X0000 /* 0.000   * 2^LUX_SCALE   */
88 
89 struct tsl2561_config {
90 	struct i2c_dt_spec i2c;
91 	uint16_t integration_time;
92 	uint8_t gain;
93 };
94 
95 struct tsl2561_data {
96 	uint16_t ch0;
97 	uint16_t ch1;
98 	uint32_t ch_scale;
99 };
100 
tsl2561_reg_read(const struct device * dev,uint8_t reg,uint8_t * buf,uint8_t size)101 static int tsl2561_reg_read(const struct device *dev, uint8_t reg, uint8_t *buf, uint8_t size)
102 {
103 	int ret;
104 	const struct tsl2561_config *config = dev->config;
105 	uint8_t cmd = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg);
106 
107 	ret = i2c_write_read_dt(&config->i2c, &cmd, 1U, buf, size);
108 	if (ret < 0) {
109 		LOG_ERR("Failed reading register 0x%02x", reg);
110 		return ret;
111 	}
112 
113 	return 0;
114 }
115 
tsl2561_reg_write(const struct device * dev,uint8_t reg,uint8_t val)116 static int tsl2561_reg_write(const struct device *dev, uint8_t reg, uint8_t val)
117 {
118 	int ret;
119 	const struct tsl2561_config *config = dev->config;
120 	uint8_t buf[2];
121 
122 	buf[0] = (TSL2561_COMMAND_CMD | TSL2561_COMMAND_WORD | reg);
123 	buf[1] = val;
124 
125 	ret = i2c_write_dt(&config->i2c, buf, 2U);
126 	if (ret < 0) {
127 		LOG_ERR("Failed writing register 0x%02x", reg);
128 		return ret;
129 	}
130 
131 	return 0;
132 }
133 
tsl2561_sample_fetch(const struct device * dev,enum sensor_channel chan)134 static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel chan)
135 {
136 	const struct tsl2561_config *config = dev->config;
137 	struct tsl2561_data *data = dev->data;
138 	uint8_t bytes[2];
139 	int ret;
140 
141 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) {
142 		LOG_ERR("Unsupported sensor channel");
143 		return -ENOTSUP;
144 	}
145 
146 	ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_UP);
147 	if (ret < 0) {
148 		LOG_ERR("Failed to power up device");
149 		return ret;
150 	}
151 
152 	/* Short sleep after power up. Not in the datasheet, but found by trial and error */
153 	k_msleep(5);
154 
155 	k_msleep(config->integration_time);
156 
157 	/* Read data register's lower and upper bytes consecutively */
158 	ret = tsl2561_reg_read(dev, TSL2561_REG_DATA0LOW, bytes, 2U);
159 	if (ret < 0) {
160 		LOG_ERR("Failed reading channel0 data");
161 		return ret;
162 	}
163 	data->ch0 = bytes[1] << 8 | bytes[0];
164 
165 	ret = tsl2561_reg_read(dev, TSL2561_REG_DATA1LOW, bytes, 2U);
166 	if (ret < 0) {
167 		LOG_ERR("Failed reading channel1 data");
168 		return ret;
169 	}
170 	data->ch1 = bytes[1] << 8 | bytes[0];
171 
172 	ret = tsl2561_reg_write(dev, TSL2561_REG_CONTROL, TSL2561_CONTROL_POWER_DOWN);
173 	if (ret < 0) {
174 		LOG_ERR("Failed to power down device");
175 		return ret;
176 	}
177 
178 	LOG_DBG("channel0: 0x%x; channel1: 0x%x", data->ch0, data->ch1);
179 
180 	return 0;
181 }
182 
tsl2561_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)183 static int tsl2561_channel_get(const struct device *dev, enum sensor_channel chan,
184 			       struct sensor_value *val)
185 {
186 	struct tsl2561_data *data = dev->data;
187 	uint32_t channel0;
188 	uint32_t channel1;
189 
190 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) {
191 		return -ENOTSUP;
192 	}
193 
194 	channel0 = (data->ch0 * data->ch_scale) >> TSL2561_CH_SCALE;
195 	channel1 = (data->ch1 * data->ch_scale) >> TSL2561_CH_SCALE;
196 
197 	uint32_t ratio1 = 0;
198 
199 	if (channel0 != 0) {
200 		ratio1 = (channel1 << (TSL2561_RATIO_SCALE + 1)) / channel0;
201 	}
202 
203 	/* Round the ratio value */
204 	uint32_t ratio = (ratio1 + 1) >> 1;
205 
206 	uint32_t b = 0;
207 	uint32_t m = 0;
208 
209 	if (ratio <= TSL2561_LUX_K1T) {
210 		b = TSL2561_LUX_B1T;
211 		m = TSL2561_LUX_M1T;
212 	} else if (ratio <= TSL2561_LUX_K2T) {
213 		b = TSL2561_LUX_B2T;
214 		m = TSL2561_LUX_M2T;
215 	} else if (ratio <= TSL2561_LUX_K3T) {
216 		b = TSL2561_LUX_B3T;
217 		m = TSL2561_LUX_M3T;
218 	} else if (ratio <= TSL2561_LUX_K4T) {
219 		b = TSL2561_LUX_B4T;
220 		m = TSL2561_LUX_M4T;
221 	} else if (ratio <= TSL2561_LUX_K5T) {
222 		b = TSL2561_LUX_B5T;
223 		m = TSL2561_LUX_M5T;
224 	} else if (ratio <= TSL2561_LUX_K6T) {
225 		b = TSL2561_LUX_B6T;
226 		m = TSL2561_LUX_M6T;
227 	} else if (ratio <= TSL2561_LUX_K7T) {
228 		b = TSL2561_LUX_B7T;
229 		m = TSL2561_LUX_M7T;
230 	} else if (ratio > TSL2561_LUX_K8T) {
231 		b = TSL2561_LUX_B8T;
232 		m = TSL2561_LUX_M8T;
233 	}
234 
235 	int32_t tmp = ((channel0 * b) - (channel1 * m));
236 
237 	/* Round LSB (2^(LUX_SCALE−1)) */
238 	tmp += (1 << (TSL2561_LUX_SCALE - 1));
239 
240 	/* Strip off fractional portion */
241 	val->val1 = tmp >> TSL2561_LUX_SCALE;
242 
243 	val->val2 = 0;
244 
245 	return 0;
246 }
247 
248 static const struct sensor_driver_api tsl2561_driver_api = {
249 	.sample_fetch = tsl2561_sample_fetch,
250 	.channel_get = tsl2561_channel_get
251 };
252 
tsl2561_sensor_setup(const struct device * dev)253 static int tsl2561_sensor_setup(const struct device *dev)
254 {
255 	const struct tsl2561_config *config = dev->config;
256 	struct tsl2561_data *data = dev->data;
257 	uint8_t timing_reg;
258 	uint8_t chip_id;
259 	uint8_t tmp;
260 	int ret;
261 
262 	ret = tsl2561_reg_read(dev, TSL2561_REG_ID, &chip_id, 1U);
263 	if (ret < 0) {
264 		LOG_ERR("Failed reading chip ID");
265 		return ret;
266 	}
267 
268 	if (FIELD_GET(TSL2561_ID_PARTNO, chip_id) != TSL2561_CHIP_ID) {
269 		LOG_ERR("Chip ID is invalid! Device @%02x is not TSL2561!", config->i2c.addr);
270 		return -EIO;
271 	}
272 
273 	switch (config->integration_time) {
274 	case 13:
275 		tmp = TSL2561_INTEGRATION_13MS;
276 		data->ch_scale = TSL2561_CHSCALE_TINT0;
277 		break;
278 	case 101:
279 		tmp = TSL2561_INTEGRATION_101MS;
280 		data->ch_scale = TSL2561_CHSCALE_TINT1;
281 		break;
282 	case 402:
283 		tmp = TSL2561_INTEGRATION_402MS;
284 		data->ch_scale = (1 << TSL2561_CH_SCALE);
285 		break;
286 	default:
287 		LOG_ERR("Invalid integration time");
288 		return -EINVAL;
289 	}
290 
291 	timing_reg = TSL2561_TIMING_INTEG & tmp;
292 
293 	switch (config->gain) {
294 	case 1:
295 		tmp = TSL2561_GAIN_1X;
296 		data->ch_scale = data->ch_scale << 4;
297 		break;
298 	case 16:
299 		tmp = TSL2561_GAIN_16X;
300 		break;
301 	default:
302 		LOG_ERR("Invalid ADC gain");
303 		return -EINVAL;
304 	}
305 
306 	timing_reg |= FIELD_PREP(TSL2561_TIMING_GAIN, tmp);
307 
308 	ret = tsl2561_reg_write(dev, TSL2561_REG_TIMING, timing_reg);
309 	if (ret < 0) {
310 		LOG_ERR("Failed setting timing register");
311 		return ret;
312 	}
313 
314 	return 0;
315 }
316 
tsl2561_init(const struct device * dev)317 static int tsl2561_init(const struct device *dev)
318 {
319 	const struct tsl2561_config *config = dev->config;
320 	int ret;
321 
322 	if (!i2c_is_ready_dt(&config->i2c)) {
323 		LOG_ERR("I2C dev %s not ready", config->i2c.bus->name);
324 		return -ENODEV;
325 	}
326 
327 	ret = tsl2561_sensor_setup(dev);
328 	if (ret < 0) {
329 		LOG_ERR("Failed to configure device");
330 		return ret;
331 	}
332 
333 	return 0;
334 }
335 
336 #define TSL2561_INIT_INST(n)                                                                       \
337 	static struct tsl2561_data tsl2561_data_##n;                                               \
338 	static const struct tsl2561_config tsl2561_config_##n = {                                  \
339 		.i2c = I2C_DT_SPEC_INST_GET(n),                                                    \
340 		.integration_time = DT_INST_PROP(n, integration_time),                             \
341 		.gain = DT_INST_PROP(n, gain)};                                                    \
342 	SENSOR_DEVICE_DT_INST_DEFINE(n, tsl2561_init, NULL, &tsl2561_data_##n,                     \
343 				     &tsl2561_config_##n, POST_KERNEL,                             \
344 				     CONFIG_SENSOR_INIT_PRIORITY, &tsl2561_driver_api);
345 
346 DT_INST_FOREACH_STATUS_OKAY(TSL2561_INIT_INST)
347