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