1 /*
2  * Copyright (c) 2022, Hiroki Tada
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Datasheet:
7  * https://datasheetspdf.com/pdf/1323325/Hamamatsu/S11059-02DT/1
8  */
9 
10 #define DT_DRV_COMPAT hamamatsu_s11059
11 
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/sensor.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/sys/util.h>
19 
20 LOG_MODULE_REGISTER(S11059, CONFIG_SENSOR_LOG_LEVEL);
21 
22 /* register address */
23 #define S11059_REG_ADDR_CONTROL	      0x00
24 #define S11059_REG_ADDR_MANUAL_TIMING 0x01
25 #define S11059_REG_ADDR_DATA	      0x03
26 
27 /* control bit */
28 #define S11059_CONTROL_GAIN	       3
29 #define S11059_CONTROL_STANDBY_MONITOR 5
30 #define S11059_CONTROL_STADBY	       6
31 #define S11059_CONTROL_ADC_RESET       7
32 
33 /* bit mask for control */
34 #define S11059_BIT_MASK_INTEGRATION_TIME	0x03
35 #define S11059_BIT_MASK_CONTROL_STANDBY_MONITOR 0x20
36 
37 /* factors for converting sensor samples to Lux */
38 #define S11059_CONVERT_FACTOR_LOW_RED	 (112)
39 #define S11059_CONVERT_FACTOR_LOW_GREEN	 (83)
40 #define S11059_CONVERT_FACTOR_LOW_BLUE	 (44)
41 #define S11059_CONVERT_FACTOR_LOW_IR	 (3 * 10)
42 #define S11059_CONVERT_FACTOR_HIGH_RED	 (117 * 10)
43 #define S11059_CONVERT_FACTOR_HIGH_GREEN (85 * 10)
44 #define S11059_CONVERT_FACTOR_HIGH_BLUE	 (448)
45 #define S11059_CONVERT_FACTOR_HIGH_IR	 (30 * 10)
46 
47 #define S11059_INTEGRATION_TIME_MODE_00 175
48 #define S11059_INTEGRATION_TIME_MODE_01 2800
49 #define S11059_INTEGRATION_TIME_MODE_10 44800
50 #define S11059_INTEGRATION_TIME_MODE_11 358400
51 
52 #define S11059_WAIT_PER_LOOP	 400
53 #define S11059_INITIAL_CONTROL	 0x04
54 #define S11059_MAX_MANUAL_TIMING UINT16_MAX
55 #define S11059_CARRY_UP		 10000
56 
57 #define S11059_NUM_GAIN_MODE 2
58 
59 enum s11059_channel {
60 	RED,
61 	GREEN,
62 	BLUE,
63 	IR,
64 	NUM_OF_COLOR_CHANNELS
65 };
66 
67 struct s11059_dev_config {
68 	struct i2c_dt_spec bus;
69 	uint8_t gain;
70 	int64_t integration_time; /* integration period (unit: us) */
71 };
72 
73 struct s11059_data {
74 	uint16_t samples[NUM_OF_COLOR_CHANNELS];
75 };
76 
77 static const uint16_t convert_factors[S11059_NUM_GAIN_MODE][NUM_OF_COLOR_CHANNELS] = {
78 	{S11059_CONVERT_FACTOR_LOW_RED, S11059_CONVERT_FACTOR_LOW_GREEN,
79 	 S11059_CONVERT_FACTOR_LOW_BLUE, S11059_CONVERT_FACTOR_LOW_IR},
80 	{S11059_CONVERT_FACTOR_HIGH_RED, S11059_CONVERT_FACTOR_HIGH_GREEN,
81 	 S11059_CONVERT_FACTOR_HIGH_BLUE, S11059_CONVERT_FACTOR_HIGH_IR}};
82 
83 /* Integration timing in Manual integration mode */
84 static const uint32_t integ_time_factor[] = {
85 	S11059_INTEGRATION_TIME_MODE_00, S11059_INTEGRATION_TIME_MODE_01,
86 	S11059_INTEGRATION_TIME_MODE_10, S11059_INTEGRATION_TIME_MODE_11};
87 
s11059_convert_channel_to_index(enum sensor_channel chan)88 static int s11059_convert_channel_to_index(enum sensor_channel chan)
89 {
90 	switch (chan) {
91 	case SENSOR_CHAN_RED:
92 		return RED;
93 	case SENSOR_CHAN_GREEN:
94 		return GREEN;
95 	case SENSOR_CHAN_BLUE:
96 		return BLUE;
97 	default:
98 		return IR;
99 	}
100 }
101 
s11059_samples_read(const struct device * dev,uint8_t addr,uint16_t * val,uint32_t size)102 static int s11059_samples_read(const struct device *dev, uint8_t addr, uint16_t *val, uint32_t size)
103 {
104 	const struct s11059_dev_config *cfg = dev->config;
105 	int rc;
106 
107 	if (size < NUM_OF_COLOR_CHANNELS * 2) {
108 		return -EINVAL;
109 	}
110 
111 	rc = i2c_burst_read_dt(&cfg->bus, addr, (uint8_t *)val, size);
112 	if (rc < 0) {
113 		return rc;
114 	}
115 
116 	for (size_t i = 0; i < NUM_OF_COLOR_CHANNELS; i++) {
117 		val[i] = sys_be16_to_cpu(val[i]);
118 	}
119 
120 	return 0;
121 }
122 
s11059_control_write(const struct device * dev,uint8_t control)123 static int s11059_control_write(const struct device *dev, uint8_t control)
124 {
125 	const struct s11059_dev_config *cfg = dev->config;
126 	const uint8_t opcode[] = {S11059_REG_ADDR_CONTROL, control};
127 
128 	return i2c_write_dt(&cfg->bus, opcode, sizeof(opcode));
129 }
130 
s11059_manual_timing_write(const struct device * dev,uint16_t manual_time)131 static int s11059_manual_timing_write(const struct device *dev, uint16_t manual_time)
132 {
133 	const struct s11059_dev_config *cfg = dev->config;
134 	const uint8_t opcode[] = {S11059_REG_ADDR_MANUAL_TIMING, manual_time >> 8,
135 				  manual_time & 0xFF};
136 
137 	return i2c_write_dt(&cfg->bus, opcode, sizeof(opcode));
138 }
139 
s11059_start_measurement(const struct device * dev)140 static int s11059_start_measurement(const struct device *dev)
141 {
142 	const struct s11059_dev_config *cfg = dev->config;
143 	uint8_t control;
144 	int rc;
145 
146 	/* read current control */
147 	rc = i2c_reg_read_byte_dt(&cfg->bus, S11059_REG_ADDR_CONTROL, &control);
148 	if (rc < 0) {
149 		LOG_ERR("%s, Failed to read current control.", dev->name);
150 		return rc;
151 	}
152 
153 	/* reset adc block */
154 	WRITE_BIT(control, S11059_CONTROL_ADC_RESET, 1);
155 	WRITE_BIT(control, S11059_CONTROL_STADBY, 0);
156 	rc = s11059_control_write(dev, control);
157 	if (rc < 0) {
158 		LOG_ERR("%s, Failed to reset adc.", dev->name);
159 		return rc;
160 	}
161 
162 	/* start device */
163 	WRITE_BIT(control, S11059_CONTROL_ADC_RESET, 0);
164 	rc = s11059_control_write(dev, control);
165 	if (rc < 0) {
166 		LOG_ERR("%s, Failed to start device.", dev->name);
167 		return rc;
168 	}
169 
170 	return 0;
171 }
172 
s11059_integ_time_calculate(const struct device * dev,uint16_t * manual_time,uint8_t * mode)173 static int s11059_integ_time_calculate(const struct device *dev, uint16_t *manual_time,
174 				       uint8_t *mode)
175 {
176 	const struct s11059_dev_config *cfg = dev->config;
177 	int64_t tmp;
178 
179 	if (cfg->integration_time < integ_time_factor[0]) {
180 		*mode = 0;
181 		*manual_time = 1;
182 	} else {
183 		*manual_time = S11059_MAX_MANUAL_TIMING;
184 		for (uint8_t i = 0; i < ARRAY_SIZE(integ_time_factor); i++) {
185 			*mode = i;
186 			tmp = cfg->integration_time / integ_time_factor[i];
187 			if (tmp < S11059_MAX_MANUAL_TIMING) {
188 				*manual_time = (uint16_t)tmp;
189 				break;
190 			}
191 		}
192 	}
193 
194 	return 0;
195 }
196 
s11059_sample_fetch(const struct device * dev,enum sensor_channel chan)197 static int s11059_sample_fetch(const struct device *dev, enum sensor_channel chan)
198 {
199 	const struct s11059_dev_config *cfg = dev->config;
200 	struct s11059_data *drv_data = dev->data;
201 	uint16_t values[NUM_OF_COLOR_CHANNELS];
202 	uint8_t control;
203 	int rc;
204 
205 	if (chan != SENSOR_CHAN_ALL) {
206 		LOG_ERR("%s, Unsupported sensor channel", dev->name);
207 		return -ENOTSUP;
208 	}
209 
210 	rc = s11059_start_measurement(dev);
211 	if (rc < 0) {
212 		LOG_ERR("%s, Failed to start measurement.", dev->name);
213 		return rc;
214 	}
215 
216 	do {
217 		rc = i2c_reg_read_byte_dt(&cfg->bus, S11059_REG_ADDR_CONTROL, &control);
218 		if (rc < 0) {
219 			LOG_ERR("%s, Failed to read control.", dev->name);
220 			return rc;
221 		}
222 		k_usleep(S11059_WAIT_PER_LOOP);
223 
224 	} while (!(control & S11059_BIT_MASK_CONTROL_STANDBY_MONITOR));
225 
226 	rc = s11059_samples_read(dev, S11059_REG_ADDR_DATA, values, sizeof(values));
227 	if (rc < 0) {
228 		LOG_ERR("%s, Failed to get sample.", dev->name);
229 		return rc;
230 	}
231 
232 	for (size_t i = 0; i < NUM_OF_COLOR_CHANNELS; i++) {
233 		drv_data->samples[i] = values[i];
234 	}
235 
236 	return 0;
237 }
238 
s11059_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)239 static int s11059_channel_get(const struct device *dev, enum sensor_channel chan,
240 			      struct sensor_value *val)
241 {
242 	const struct s11059_dev_config *cfg = dev->config;
243 	struct s11059_data *drv_data = dev->data;
244 	const uint8_t index = s11059_convert_channel_to_index(chan);
245 	const uint16_t factor = convert_factors[cfg->gain][index];
246 	uint32_t meas_value;
247 
248 	meas_value = drv_data->samples[index] * S11059_CARRY_UP / factor;
249 	val->val1 = meas_value / (S11059_CARRY_UP / 10);
250 	val->val2 = meas_value % (S11059_CARRY_UP / 10);
251 
252 	return 0;
253 }
254 
s11059_init(const struct device * dev)255 static int s11059_init(const struct device *dev)
256 {
257 	const struct s11059_dev_config *cfg = dev->config;
258 	uint8_t control = S11059_INITIAL_CONTROL;
259 	uint16_t manual_time;
260 	uint8_t timing_mode;
261 	int rc;
262 
263 	/* device set */
264 	if (!i2c_is_ready_dt(&cfg->bus)) {
265 		LOG_ERR("%s, device is not ready.", dev->name);
266 		return -ENODEV;
267 	}
268 
269 	rc = s11059_integ_time_calculate(dev, &manual_time, &timing_mode);
270 	if (rc < 0) {
271 		LOG_ERR("%s, Failed to calculate manual timing.", dev->name);
272 		return rc;
273 	}
274 
275 	rc = s11059_manual_timing_write(dev, manual_time);
276 	if (rc < 0) {
277 		LOG_ERR("%s, Failed to set manual timing.", dev->name);
278 		return rc;
279 	}
280 
281 	/* set integration time mode and gain*/
282 	control |= timing_mode & S11059_BIT_MASK_INTEGRATION_TIME;
283 	WRITE_BIT(control, S11059_CONTROL_GAIN, cfg->gain);
284 	rc = s11059_control_write(dev, control);
285 	if (rc < 0) {
286 		LOG_ERR("%s, Failed to set gain and integration time.", dev->name);
287 		return rc;
288 	}
289 
290 	return 0;
291 }
292 
293 static const struct sensor_driver_api s11059_driver_api = {
294 	.sample_fetch = s11059_sample_fetch,
295 	.channel_get = s11059_channel_get,
296 };
297 
298 #define S11059_INST(inst)                                                                          \
299 	static struct s11059_data s11059_data_##inst;                                              \
300 	static const struct s11059_dev_config s11059_config_##inst = {                             \
301 		.bus = I2C_DT_SPEC_INST_GET(inst),                                                 \
302 		.gain = DT_INST_PROP(inst, high_gain),                                             \
303 		.integration_time = DT_INST_PROP(inst, integration_time)};                         \
304 	SENSOR_DEVICE_DT_INST_DEFINE(inst, s11059_init, NULL, &s11059_data_##inst,                 \
305 				     &s11059_config_##inst, POST_KERNEL,                           \
306 				     CONFIG_SENSOR_INIT_PRIORITY, &s11059_driver_api);
307 
308 DT_INST_FOREACH_STATUS_OKAY(S11059_INST)
309