1
1
/* Copyright (c) 2024 Daniel Kampert
2
- * Author: Daniel Kampert <DanielKampert@kampis-Elektroecke .de>
2
+ * Author: Daniel Kampert <DanielKampert@kampis-elektroecke .de>
3
3
*/
4
4
5
5
#include <zephyr/device.h>
45
45
46
46
LOG_MODULE_REGISTER (avago_apds9306 , CONFIG_SENSOR_LOG_LEVEL );
47
47
48
+ /* Array length for the measurement period values. Aligned with avago,apds9306.yaml */
49
+ static const uint8_t AVAGO_APDS_9306_MEASUREMENT_PERIOD_ARRAY_LENGTH = 7 ;
50
+
51
+ /* Array length for the resolution values. Aligned with avago,apds9306.yaml */
52
+ static const uint8_t AVAGO_APDS_9306_RESOLUTION_ARRAY_LENGTH = 6 ;
53
+
54
+ /* See datasheet for the values. Aligned with avago,apds9306.yaml */
55
+ static const uint8_t avago_apds9306_gain [] = {1 , 3 , 6 , 9 , 18 };
56
+ static const uint8_t AVAGO_APDS_9306_GAIN_ARRAY_LENGTH = ARRAY_SIZE (avago_apds9306_gain );
57
+
58
+ /* See datasheet for the values. */
59
+ /* Last value is rounded up to prevent floating point operations. */
60
+ static const uint16_t avago_apds9306_integration_time [] = {400 , 200 , 100 , 50 , 25 , 4 };
61
+
62
+ /* These values represent the gain based on the integration time. */
63
+ /* A gain of 1 is used for a time of 3.125 ms (13 bits). */
64
+ /* This results in a gain of 8 (2^3) for a time if 25 ms (16 bits), etc. */
65
+ static const uint16_t avago_apds9306_integration_time_gain [] = {128 , 64 , 32 , 16 , 8 , 1 };
66
+
48
67
struct apds9306_data {
49
68
uint32_t light ;
69
+ uint8_t measurement_period_idx ; /* This field holds the index of the current */
70
+ /* period measurement */
71
+ uint8_t gain_idx ; /* This field holds the index of the current sampling gain. */
72
+ uint8_t resolution_idx ; /* This field holds the index of the current sampling */
73
+ /* resolution.*/
74
+ uint8_t chip_id ;
50
75
};
51
76
52
77
struct apds9306_config {
53
78
struct i2c_dt_spec i2c ;
54
- uint8_t resolution ;
55
- uint16_t frequency ;
56
- uint8_t gain ;
79
+ uint8_t resolution_idx ;
80
+ uint8_t measurement_period_idx ;
81
+ uint8_t gain_idx ;
57
82
};
58
83
59
84
struct apds9306_worker_item_t {
60
85
struct k_work_delayable dwork ;
61
86
const struct device * dev ;
62
87
} apds9306_worker_item ;
63
88
64
- static uint32_t apds9306_get_time_for_resolution (uint8_t value )
65
- {
66
- switch (value ) {
67
- case 0 :
68
- return 400 ;
69
- case 1 :
70
- return 200 ;
71
- case 2 :
72
- return 100 ;
73
- case 3 :
74
- return 50 ;
75
- case 4 :
76
- return 25 ;
77
- case 5 :
78
- return 4 ;
79
- default :
80
- return 100 ;
81
- }
82
- }
83
-
84
89
static int apds9306_enable (const struct device * dev )
85
90
{
86
91
const struct apds9306_config * config = dev -> config ;
@@ -128,7 +133,41 @@ static void apds9306_worker(struct k_work *p_work)
128
133
}
129
134
130
135
data -> light = sys_get_le24 (buffer );
136
+ LOG_DBG ("Last raw measurement: %u" , data -> light );
137
+
138
+ /* Based on the formula from the APDS-9309 datasheet, page 4:
139
+ * https://docs.broadcom.com/doc/AV02-3689EN
140
+ *
141
+ * Illuminance [Lux] = Data * (1 / (Gain * Integration Time)) * Factor [Lux]
142
+ *
143
+ * The factor is calculated with the given values from the
144
+ * APDS-9306 datasheet, page 4.
145
+ * 1. Convert the E value from uW/sqcm to Lux
146
+ * - 340.134 for the APDS-9306
147
+ * - 293.69 for the APDS-9306-065
148
+ * 2. Use the formula from the APDS-9309 datasheet to get the factor by using
149
+ * - Gain = 3
150
+ * - Integration time = 100 ms
151
+ * Caution: The unit is ms. We need a unit without a dimension to prevent wrong
152
+ * units. So it must be converted into a value without dimension. This is done by converting
153
+ * it into a bit value based on the resolution gain (=32).
154
+ * - ADC count = 2000
155
+ * 3. Repeat it for both sensor types to get the factors (converted for integer operations)
156
+ * - APDS-9306: 16
157
+ * - APDS-9306-065: 14
158
+ */
159
+ uint32_t gain = avago_apds9306_gain [data -> gain_idx ];
160
+ uint32_t integration_time = avago_apds9306_integration_time_gain [data -> resolution_idx ];
161
+ uint32_t factor = 16 ;
162
+
163
+ if (data -> chip_id == APDS_9306_065_CHIP_ID ) {
164
+ factor = 14 ;
165
+ }
131
166
167
+ data -> light = (data -> light * factor ) / (gain * integration_time );
168
+
169
+ LOG_DBG ("Gain: %u" , gain );
170
+ LOG_DBG ("Integration time: %u" , integration_time );
132
171
LOG_DBG ("Last measurement: %u" , data -> light );
133
172
}
134
173
@@ -139,20 +178,30 @@ static int apds9306_attr_set(const struct device *dev, enum sensor_channel chann
139
178
uint8_t mask ;
140
179
uint8_t temp ;
141
180
const struct apds9306_config * config = dev -> config ;
181
+ struct apds9306_data * data = dev -> data ;
142
182
143
- if (channel != SENSOR_CHAN_LIGHT ) {
183
+ if (( channel != SENSOR_CHAN_ALL ) && ( channel != SENSOR_CHAN_LIGHT ) ) {
144
184
return - ENOTSUP ;
145
185
}
146
186
147
187
if (attribute == SENSOR_ATTR_SAMPLING_FREQUENCY ) {
188
+ if (value -> val1 > (AVAGO_APDS_9306_MEASUREMENT_PERIOD_ARRAY_LENGTH - 1 )) {
189
+ return - EINVAL ;
190
+ }
148
191
reg = APDS9306_REGISTER_ALS_MEAS_RATE ;
149
192
mask = GENMASK (2 , 0 );
150
193
temp = FIELD_PREP (0x07 , value -> val1 );
151
194
} else if (attribute == SENSOR_ATTR_GAIN ) {
195
+ if (value -> val1 > (AVAGO_APDS_9306_GAIN_ARRAY_LENGTH - 1 )) {
196
+ return - EINVAL ;
197
+ }
152
198
reg = APDS9306_REGISTER_ALS_GAIN ;
153
199
mask = GENMASK (2 , 0 );
154
200
temp = FIELD_PREP (0x07 , value -> val1 );
155
201
} else if (attribute == SENSOR_ATTR_RESOLUTION ) {
202
+ if (value -> val1 > (AVAGO_APDS_9306_RESOLUTION_ARRAY_LENGTH - 1 )) {
203
+ return - EINVAL ;
204
+ }
156
205
reg = APDS9306_REGISTER_ALS_MEAS_RATE ;
157
206
mask = GENMASK (7 , 4 );
158
207
temp = FIELD_PREP (0x07 , value -> val1 ) << 0x04 ;
@@ -165,51 +214,44 @@ static int apds9306_attr_set(const struct device *dev, enum sensor_channel chann
165
214
return - EFAULT ;
166
215
}
167
216
217
+ /* We only save the new values when no error occurs to prevent invalid settings. */
218
+ if (attribute == SENSOR_ATTR_SAMPLING_FREQUENCY ) {
219
+ data -> measurement_period_idx = value -> val1 ;
220
+ } else if (attribute == SENSOR_ATTR_GAIN ) {
221
+ data -> gain_idx = value -> val1 ;
222
+ } else if (attribute == SENSOR_ATTR_RESOLUTION ) {
223
+ data -> resolution_idx = value -> val1 ;
224
+ }
225
+
168
226
return 0 ;
169
227
}
170
228
171
229
static int apds9306_attr_get (const struct device * dev , enum sensor_channel channel ,
172
230
enum sensor_attribute attribute , struct sensor_value * value )
173
231
{
174
- uint8_t mask ;
175
- uint8_t temp ;
176
- uint8_t reg ;
177
- const struct apds9306_config * config = dev -> config ;
232
+ struct apds9306_data * data = dev -> data ;
178
233
179
- if (channel != SENSOR_CHAN_LIGHT ) {
234
+ if (( channel != SENSOR_CHAN_ALL ) && ( channel != SENSOR_CHAN_LIGHT ) ) {
180
235
return - ENOTSUP ;
181
236
}
182
237
183
238
if (attribute == SENSOR_ATTR_SAMPLING_FREQUENCY ) {
184
- reg = APDS9306_REGISTER_ALS_MEAS_RATE ;
185
- mask = 0x00 ;
239
+ value -> val1 = data -> measurement_period_idx ;
186
240
} else if (attribute == SENSOR_ATTR_GAIN ) {
187
- reg = APDS9306_REGISTER_ALS_GAIN ;
188
- mask = 0x00 ;
241
+ value -> val1 = data -> gain_idx ;
189
242
} else if (attribute == SENSOR_ATTR_RESOLUTION ) {
190
- reg = APDS9306_REGISTER_ALS_MEAS_RATE ;
191
- mask = 0x04 ;
243
+ value -> val1 = data -> resolution_idx ;
192
244
} else {
193
245
return - ENOTSUP ;
194
246
}
195
247
196
- if (i2c_reg_read_byte_dt (& config -> i2c , reg , & temp )) {
197
- LOG_ERR ("Failed to read sensor attribute!" );
198
- return - EFAULT ;
199
- }
200
-
201
- value -> val1 = (temp >> mask ) & 0x07 ;
202
- value -> val2 = 0 ;
203
-
204
248
return 0 ;
205
249
}
206
250
207
251
static int apds9306_sample_fetch (const struct device * dev , enum sensor_channel channel )
208
252
{
209
- uint8_t buffer ;
210
- uint8_t resolution ;
211
253
uint16_t delay ;
212
- const struct apds9306_config * config = dev -> config ;
254
+ struct apds9306_data * data = dev -> data ;
213
255
214
256
if ((channel != SENSOR_CHAN_ALL ) && (channel != SENSOR_CHAN_LIGHT )) {
215
257
return - ENOTSUP ;
@@ -221,17 +263,10 @@ static int apds9306_sample_fetch(const struct device *dev, enum sensor_channel c
221
263
return - EFAULT ;
222
264
}
223
265
224
- /* Get the measurement resolution. */
225
- if (i2c_reg_read_byte_dt (& config -> i2c , APDS9306_REGISTER_ALS_MEAS_RATE , & buffer )) {
226
- LOG_ERR ("Failed reading resolution" );
227
- return - EFAULT ;
228
- }
229
-
230
266
/* Convert the resolution into a delay time and wait for the result. */
231
- resolution = (buffer >> 4 ) & 0x07 ;
232
- delay = apds9306_get_time_for_resolution (resolution );
233
- LOG_DBG ("Measurement resolution: %u" , resolution );
234
- LOG_DBG ("Wait for %u ms" , delay );
267
+ delay = avago_apds9306_integration_time [data -> resolution_idx ];
268
+ LOG_DBG ("Measurement resolution index: %u" , data -> resolution_idx );
269
+ LOG_DBG ("Wait for %d ms" , delay );
235
270
236
271
/* We add a bit more delay to cover the startup time etc. */
237
272
if (!k_work_delayable_is_pending (& apds9306_worker_item .dwork )) {
@@ -252,13 +287,15 @@ static int apds9306_channel_get(const struct device *dev, enum sensor_channel ch
252
287
{
253
288
struct apds9306_data * data = dev -> data ;
254
289
255
- if (channel != SENSOR_CHAN_LIGHT ) {
290
+ switch (channel ) {
291
+ case SENSOR_CHAN_LIGHT :
292
+ value -> val1 = data -> light ;
293
+ value -> val2 = 0 ;
294
+ break ;
295
+ default :
256
296
return - ENOTSUP ;
257
297
}
258
298
259
- value -> val1 = data -> light ;
260
- value -> val2 = 0 ;
261
-
262
299
return 0 ;
263
300
}
264
301
@@ -267,6 +304,7 @@ static int apds9306_sensor_setup(const struct device *dev)
267
304
uint32_t now ;
268
305
uint8_t temp ;
269
306
const struct apds9306_config * config = dev -> config ;
307
+ struct apds9306_data * data = dev -> data ;
270
308
271
309
/* Wait for the device to become ready after a possible power cycle. */
272
310
now = k_uptime_get_32 ();
@@ -285,19 +323,19 @@ static int apds9306_sensor_setup(const struct device *dev)
285
323
k_msleep (10 );
286
324
} while (temp & APDS9306_BIT_POWER_ON_STATUS );
287
325
288
- if (i2c_reg_read_byte_dt (& config -> i2c , APDS9306_REGISTER_PART_ID , & temp )) {
326
+ if (i2c_reg_read_byte_dt (& config -> i2c , APDS9306_REGISTER_PART_ID , & data -> chip_id )) {
289
327
LOG_ERR ("Failed reading chip id!" );
290
328
return - EFAULT ;
291
329
}
292
330
293
- if ((temp != APDS_9306_CHIP_ID ) && (temp != APDS_9306_065_CHIP_ID )) {
294
- LOG_ERR ("Invalid chip id! Found 0x%X!" , temp );
331
+ if ((data -> chip_id != APDS_9306_CHIP_ID ) && (data -> chip_id != APDS_9306_065_CHIP_ID )) {
332
+ LOG_ERR ("Invalid chip id! Found 0x%X!" , data -> chip_id );
295
333
return - EFAULT ;
296
334
}
297
335
298
- if (temp == APDS_9306_CHIP_ID ) {
336
+ if (data -> chip_id == APDS_9306_CHIP_ID ) {
299
337
LOG_DBG ("APDS-9306 found!" );
300
- } else if (temp == APDS_9306_065_CHIP_ID ) {
338
+ } else if (data -> chip_id == APDS_9306_065_CHIP_ID ) {
301
339
LOG_DBG ("APDS-9306-065 found!" );
302
340
}
303
341
@@ -316,6 +354,7 @@ static int apds9306_init(const struct device *dev)
316
354
{
317
355
uint8_t value ;
318
356
const struct apds9306_config * config = dev -> config ;
357
+ struct apds9306_data * data = dev -> data ;
319
358
320
359
LOG_DBG ("Start to initialize APDS9306..." );
321
360
@@ -329,16 +368,18 @@ static int apds9306_init(const struct device *dev)
329
368
return - EFAULT ;
330
369
}
331
370
332
- value = ((config -> resolution & 0x07 ) << 4 ) | (config -> frequency & 0x0F );
371
+ data -> measurement_period_idx = config -> measurement_period_idx ;
372
+ data -> resolution_idx = config -> resolution_idx ;
373
+ value = ((data -> resolution_idx & 0x07 ) << 4 ) | (data -> measurement_period_idx & 0x07 );
333
374
LOG_DBG ("Write configuration 0x%x to register 0x%x" , value ,
334
375
APDS9306_REGISTER_ALS_MEAS_RATE );
335
376
if (i2c_reg_write_byte_dt (& config -> i2c , APDS9306_REGISTER_ALS_MEAS_RATE , value )) {
336
377
return - EFAULT ;
337
378
}
338
379
339
- value = config -> gain ;
380
+ data -> gain_idx = config -> gain_idx ;
340
381
LOG_DBG ("Write configuration 0x%x to register 0x%x" , value , APDS9306_REGISTER_ALS_GAIN );
341
- if (i2c_reg_write_byte_dt (& config -> i2c , APDS9306_REGISTER_ALS_GAIN , value )) {
382
+ if (i2c_reg_write_byte_dt (& config -> i2c , APDS9306_REGISTER_ALS_GAIN , data -> gain_idx )) {
342
383
return - EFAULT ;
343
384
}
344
385
@@ -358,9 +399,9 @@ static DEVICE_API(sensor, apds9306_driver_api) = {
358
399
static struct apds9306_data apds9306_data_##inst; \
359
400
static const struct apds9306_config apds9306_config_##inst = { \
360
401
.i2c = I2C_DT_SPEC_INST_GET(inst), \
361
- .resolution = DT_INST_PROP (inst, resolution), \
362
- .gain = DT_INST_PROP (inst, gain), \
363
- .frequency = DT_INST_PROP (inst, frequency), \
402
+ .resolution_idx = DT_INST_ENUM_IDX (inst, resolution), \
403
+ .gain_idx = DT_INST_ENUM_IDX (inst, gain), \
404
+ .measurement_period_idx = DT_INST_ENUM_IDX (inst, measurement_period), \
364
405
}; \
365
406
\
366
407
SENSOR_DEVICE_DT_INST_DEFINE(inst, apds9306_init, NULL, &apds9306_data_##inst, \
0 commit comments