1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * BU27034 ROHM Ambient Light Sensor |
4 | * |
5 | * Copyright (c) 2023, ROHM Semiconductor. |
6 | * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf |
7 | */ |
8 | |
9 | #include <linux/bitfield.h> |
10 | #include <linux/bits.h> |
11 | #include <linux/device.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/module.h> |
14 | #include <linux/property.h> |
15 | #include <linux/regmap.h> |
16 | #include <linux/regulator/consumer.h> |
17 | #include <linux/units.h> |
18 | |
19 | #include <linux/iio/buffer.h> |
20 | #include <linux/iio/iio.h> |
21 | #include <linux/iio/iio-gts-helper.h> |
22 | #include <linux/iio/kfifo_buf.h> |
23 | |
24 | #define BU27034_REG_SYSTEM_CONTROL 0x40 |
25 | #define BU27034_MASK_SW_RESET BIT(7) |
26 | #define BU27034_MASK_PART_ID GENMASK(5, 0) |
27 | #define BU27034_ID 0x19 |
28 | #define BU27034_REG_MODE_CONTROL1 0x41 |
29 | #define BU27034_MASK_MEAS_MODE GENMASK(2, 0) |
30 | |
31 | #define BU27034_REG_MODE_CONTROL2 0x42 |
32 | #define BU27034_MASK_D01_GAIN GENMASK(7, 3) |
33 | #define BU27034_MASK_D2_GAIN_HI GENMASK(7, 6) |
34 | #define BU27034_MASK_D2_GAIN_LO GENMASK(2, 0) |
35 | |
36 | #define BU27034_REG_MODE_CONTROL3 0x43 |
37 | #define BU27034_REG_MODE_CONTROL4 0x44 |
38 | #define BU27034_MASK_MEAS_EN BIT(0) |
39 | #define BU27034_MASK_VALID BIT(7) |
40 | #define BU27034_REG_DATA0_LO 0x50 |
41 | #define BU27034_REG_DATA1_LO 0x52 |
42 | #define BU27034_REG_DATA2_LO 0x54 |
43 | #define BU27034_REG_DATA2_HI 0x55 |
44 | #define BU27034_REG_MANUFACTURER_ID 0x92 |
45 | #define BU27034_REG_MAX BU27034_REG_MANUFACTURER_ID |
46 | |
47 | /* |
48 | * The BU27034 does not have interrupt to trigger the data read when a |
49 | * measurement has finished. Hence we poll the VALID bit in a thread. We will |
50 | * try to wake the thread BU27034_MEAS_WAIT_PREMATURE_MS milliseconds before |
51 | * the expected sampling time to prevent the drifting. |
52 | * |
53 | * If we constantly wake up a bit too late we would eventually skip a sample. |
54 | * And because the sleep can't wake up _exactly_ at given time this would be |
55 | * inevitable even if the sensor clock would be perfectly phase-locked to CPU |
56 | * clock - which we can't say is the case. |
57 | * |
58 | * This is still fragile. No matter how big advance do we have, we will still |
59 | * risk of losing a sample because things can in a rainy-day scenario be |
60 | * delayed a lot. Yet, more we reserve the time for polling, more we also lose |
61 | * the performance by spending cycles polling the register. So, selecting this |
62 | * value is a balancing dance between severity of wasting CPU time and severity |
63 | * of losing samples. |
64 | * |
65 | * In most cases losing the samples is not _that_ crucial because light levels |
66 | * tend to change slowly. |
67 | * |
68 | * Other option that was pointed to me would be always sleeping 1/2 of the |
69 | * measurement time, checking the VALID bit and just sleeping again if the bit |
70 | * was not set. That should be pretty tolerant against missing samples due to |
71 | * the scheduling delays while also not wasting much of cycles for polling. |
72 | * Downside is that the time-stamps would be very inaccurate as the wake-up |
73 | * would not really be tied to the sensor toggling the valid bit. This would also |
74 | * result 'jumps' in the time-stamps when the delay drifted so that wake-up was |
75 | * performed during the consecutive wake-ups (Or, when sensor and CPU clocks |
76 | * were very different and scheduling the wake-ups was very close to given |
77 | * timeout - and when the time-outs were very close to the actual sensor |
78 | * sampling, Eg. once in a blue moon, two consecutive time-outs would occur |
79 | * without having a sample ready). |
80 | */ |
81 | #define BU27034_MEAS_WAIT_PREMATURE_MS 5 |
82 | #define BU27034_DATA_WAIT_TIME_US 1000 |
83 | #define BU27034_TOTAL_DATA_WAIT_TIME_US (BU27034_MEAS_WAIT_PREMATURE_MS * 1000) |
84 | |
85 | #define BU27034_RETRY_LIMIT 18 |
86 | |
87 | enum { |
88 | BU27034_CHAN_ALS, |
89 | BU27034_CHAN_DATA0, |
90 | BU27034_CHAN_DATA1, |
91 | BU27034_CHAN_DATA2, |
92 | BU27034_NUM_CHANS |
93 | }; |
94 | |
95 | static const unsigned long bu27034_scan_masks[] = { |
96 | GENMASK(BU27034_CHAN_DATA2, BU27034_CHAN_ALS), 0 |
97 | }; |
98 | |
99 | /* |
100 | * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS |
101 | * Time impacts to gain: 1x, 2x, 4x, 8x. |
102 | * |
103 | * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768 |
104 | * |
105 | * Using NANO precision for scale we must use scale 64x corresponding gain 1x |
106 | * to avoid precision loss. (32x would result scale 976 562.5(nanos). |
107 | */ |
108 | #define BU27034_SCALE_1X 64 |
109 | |
110 | /* See the data sheet for the "Gain Setting" table */ |
111 | #define BU27034_GSEL_1X 0x00 /* 00000 */ |
112 | #define BU27034_GSEL_4X 0x08 /* 01000 */ |
113 | #define BU27034_GSEL_16X 0x0a /* 01010 */ |
114 | #define BU27034_GSEL_32X 0x0b /* 01011 */ |
115 | #define BU27034_GSEL_64X 0x0c /* 01100 */ |
116 | #define BU27034_GSEL_256X 0x18 /* 11000 */ |
117 | #define BU27034_GSEL_512X 0x19 /* 11001 */ |
118 | #define BU27034_GSEL_1024X 0x1a /* 11010 */ |
119 | #define BU27034_GSEL_2048X 0x1b /* 11011 */ |
120 | #define BU27034_GSEL_4096X 0x1c /* 11100 */ |
121 | |
122 | /* Available gain settings */ |
123 | static const struct iio_gain_sel_pair bu27034_gains[] = { |
124 | GAIN_SCALE_GAIN(1, BU27034_GSEL_1X), |
125 | GAIN_SCALE_GAIN(4, BU27034_GSEL_4X), |
126 | GAIN_SCALE_GAIN(16, BU27034_GSEL_16X), |
127 | GAIN_SCALE_GAIN(32, BU27034_GSEL_32X), |
128 | GAIN_SCALE_GAIN(64, BU27034_GSEL_64X), |
129 | GAIN_SCALE_GAIN(256, BU27034_GSEL_256X), |
130 | GAIN_SCALE_GAIN(512, BU27034_GSEL_512X), |
131 | GAIN_SCALE_GAIN(1024, BU27034_GSEL_1024X), |
132 | GAIN_SCALE_GAIN(2048, BU27034_GSEL_2048X), |
133 | GAIN_SCALE_GAIN(4096, BU27034_GSEL_4096X), |
134 | }; |
135 | |
136 | /* |
137 | * The IC has 5 modes for sampling time. 5 mS mode is exceptional as it limits |
138 | * the data collection to data0-channel only and cuts the supported range to |
139 | * 10 bit. It is not supported by the driver. |
140 | * |
141 | * "normal" modes are 55, 100, 200 and 400 mS modes - which do have direct |
142 | * multiplying impact to the register values (similar to gain). |
143 | * |
144 | * This means that if meas-mode is changed for example from 400 => 200, |
145 | * the scale is doubled. Eg, time impact to total gain is x1, x2, x4, x8. |
146 | */ |
147 | #define BU27034_MEAS_MODE_100MS 0 |
148 | #define BU27034_MEAS_MODE_55MS 1 |
149 | #define BU27034_MEAS_MODE_200MS 2 |
150 | #define BU27034_MEAS_MODE_400MS 4 |
151 | |
152 | static const struct iio_itime_sel_mul bu27034_itimes[] = { |
153 | GAIN_SCALE_ITIME_US(400000, BU27034_MEAS_MODE_400MS, 8), |
154 | GAIN_SCALE_ITIME_US(200000, BU27034_MEAS_MODE_200MS, 4), |
155 | GAIN_SCALE_ITIME_US(100000, BU27034_MEAS_MODE_100MS, 2), |
156 | GAIN_SCALE_ITIME_US(55000, BU27034_MEAS_MODE_55MS, 1), |
157 | }; |
158 | |
159 | #define BU27034_CHAN_DATA(_name, _ch2) \ |
160 | { \ |
161 | .type = IIO_INTENSITY, \ |
162 | .channel = BU27034_CHAN_##_name, \ |
163 | .channel2 = (_ch2), \ |
164 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
165 | BIT(IIO_CHAN_INFO_SCALE), \ |
166 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE), \ |
167 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ |
168 | .info_mask_shared_by_all_available = \ |
169 | BIT(IIO_CHAN_INFO_INT_TIME), \ |
170 | .address = BU27034_REG_##_name##_LO, \ |
171 | .scan_index = BU27034_CHAN_##_name, \ |
172 | .scan_type = { \ |
173 | .sign = 'u', \ |
174 | .realbits = 16, \ |
175 | .storagebits = 16, \ |
176 | .endianness = IIO_LE, \ |
177 | }, \ |
178 | .indexed = 1, \ |
179 | } |
180 | |
181 | static const struct iio_chan_spec bu27034_channels[] = { |
182 | { |
183 | .type = IIO_LIGHT, |
184 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
185 | BIT(IIO_CHAN_INFO_SCALE), |
186 | .channel = BU27034_CHAN_ALS, |
187 | .scan_index = BU27034_CHAN_ALS, |
188 | .scan_type = { |
189 | .sign = 'u', |
190 | .realbits = 32, |
191 | .storagebits = 32, |
192 | .endianness = IIO_CPU, |
193 | }, |
194 | }, |
195 | /* |
196 | * The BU27034 DATA0 and DATA1 channels are both on the visible light |
197 | * area (mostly). The data0 sensitivity peaks at 500nm, DATA1 at 600nm. |
198 | * These wave lengths are pretty much on the border of colours making |
199 | * these a poor candidates for R/G/B standardization. Hence they're both |
200 | * marked as clear channels |
201 | */ |
202 | BU27034_CHAN_DATA(DATA0, IIO_MOD_LIGHT_CLEAR), |
203 | BU27034_CHAN_DATA(DATA1, IIO_MOD_LIGHT_CLEAR), |
204 | BU27034_CHAN_DATA(DATA2, IIO_MOD_LIGHT_IR), |
205 | IIO_CHAN_SOFT_TIMESTAMP(4), |
206 | }; |
207 | |
208 | struct bu27034_data { |
209 | struct regmap *regmap; |
210 | struct device *dev; |
211 | /* |
212 | * Protect gain and time during scale adjustment and data reading. |
213 | * Protect measurement enabling/disabling. |
214 | */ |
215 | struct mutex mutex; |
216 | struct iio_gts gts; |
217 | struct task_struct *task; |
218 | __le16 raw[3]; |
219 | struct { |
220 | u32 mlux; |
221 | __le16 channels[3]; |
222 | s64 ts __aligned(8); |
223 | } scan; |
224 | }; |
225 | |
226 | struct bu27034_result { |
227 | u16 ch0; |
228 | u16 ch1; |
229 | u16 ch2; |
230 | }; |
231 | |
232 | static const struct regmap_range bu27034_volatile_ranges[] = { |
233 | { |
234 | .range_min = BU27034_REG_SYSTEM_CONTROL, |
235 | .range_max = BU27034_REG_SYSTEM_CONTROL, |
236 | }, { |
237 | .range_min = BU27034_REG_MODE_CONTROL4, |
238 | .range_max = BU27034_REG_MODE_CONTROL4, |
239 | }, { |
240 | .range_min = BU27034_REG_DATA0_LO, |
241 | .range_max = BU27034_REG_DATA2_HI, |
242 | }, |
243 | }; |
244 | |
245 | static const struct regmap_access_table bu27034_volatile_regs = { |
246 | .yes_ranges = &bu27034_volatile_ranges[0], |
247 | .n_yes_ranges = ARRAY_SIZE(bu27034_volatile_ranges), |
248 | }; |
249 | |
250 | static const struct regmap_range bu27034_read_only_ranges[] = { |
251 | { |
252 | .range_min = BU27034_REG_DATA0_LO, |
253 | .range_max = BU27034_REG_DATA2_HI, |
254 | }, { |
255 | .range_min = BU27034_REG_MANUFACTURER_ID, |
256 | .range_max = BU27034_REG_MANUFACTURER_ID, |
257 | } |
258 | }; |
259 | |
260 | static const struct regmap_access_table bu27034_ro_regs = { |
261 | .no_ranges = &bu27034_read_only_ranges[0], |
262 | .n_no_ranges = ARRAY_SIZE(bu27034_read_only_ranges), |
263 | }; |
264 | |
265 | static const struct regmap_config bu27034_regmap = { |
266 | .reg_bits = 8, |
267 | .val_bits = 8, |
268 | .max_register = BU27034_REG_MAX, |
269 | .cache_type = REGCACHE_RBTREE, |
270 | .volatile_table = &bu27034_volatile_regs, |
271 | .wr_table = &bu27034_ro_regs, |
272 | }; |
273 | |
274 | struct bu27034_gain_check { |
275 | int old_gain; |
276 | int new_gain; |
277 | int chan; |
278 | }; |
279 | |
280 | static int bu27034_get_gain_sel(struct bu27034_data *data, int chan) |
281 | { |
282 | int ret, val; |
283 | |
284 | switch (chan) { |
285 | case BU27034_CHAN_DATA0: |
286 | case BU27034_CHAN_DATA1: |
287 | { |
288 | int reg[] = { |
289 | [BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2, |
290 | [BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3, |
291 | }; |
292 | ret = regmap_read(map: data->regmap, reg: reg[chan], val: &val); |
293 | if (ret) |
294 | return ret; |
295 | |
296 | return FIELD_GET(BU27034_MASK_D01_GAIN, val); |
297 | } |
298 | case BU27034_CHAN_DATA2: |
299 | { |
300 | int d2_lo_bits = fls(BU27034_MASK_D2_GAIN_LO); |
301 | |
302 | ret = regmap_read(map: data->regmap, BU27034_REG_MODE_CONTROL2, val: &val); |
303 | if (ret) |
304 | return ret; |
305 | |
306 | /* |
307 | * The data2 channel gain is composed by 5 non continuous bits |
308 | * [7:6], [2:0]. Thus when we combine the 5-bit 'selector' |
309 | * from register value we must right shift the high bits by 3. |
310 | */ |
311 | return FIELD_GET(BU27034_MASK_D2_GAIN_HI, val) << d2_lo_bits | |
312 | FIELD_GET(BU27034_MASK_D2_GAIN_LO, val); |
313 | } |
314 | default: |
315 | return -EINVAL; |
316 | } |
317 | } |
318 | |
319 | static int bu27034_get_gain(struct bu27034_data *data, int chan, int *gain) |
320 | { |
321 | int ret, sel; |
322 | |
323 | ret = bu27034_get_gain_sel(data, chan); |
324 | if (ret < 0) |
325 | return ret; |
326 | |
327 | sel = ret; |
328 | |
329 | ret = iio_gts_find_gain_by_sel(gts: &data->gts, sel); |
330 | if (ret < 0) { |
331 | dev_err(data->dev, "chan %u: unknown gain value 0x%x\n" , chan, |
332 | sel); |
333 | |
334 | return ret; |
335 | } |
336 | |
337 | *gain = ret; |
338 | |
339 | return 0; |
340 | } |
341 | |
342 | static int bu27034_get_int_time(struct bu27034_data *data) |
343 | { |
344 | int ret, sel; |
345 | |
346 | ret = regmap_read(map: data->regmap, BU27034_REG_MODE_CONTROL1, val: &sel); |
347 | if (ret) |
348 | return ret; |
349 | |
350 | return iio_gts_find_int_time_by_sel(gts: &data->gts, |
351 | sel: sel & BU27034_MASK_MEAS_MODE); |
352 | } |
353 | |
354 | static int _bu27034_get_scale(struct bu27034_data *data, int channel, int *val, |
355 | int *val2) |
356 | { |
357 | int gain, ret; |
358 | |
359 | ret = bu27034_get_gain(data, chan: channel, gain: &gain); |
360 | if (ret) |
361 | return ret; |
362 | |
363 | ret = bu27034_get_int_time(data); |
364 | if (ret < 0) |
365 | return ret; |
366 | |
367 | return iio_gts_get_scale(gts: &data->gts, gain, time: ret, scale_int: val, scale_nano: val2); |
368 | } |
369 | |
370 | static int bu27034_get_scale(struct bu27034_data *data, int channel, int *val, |
371 | int *val2) |
372 | { |
373 | int ret; |
374 | |
375 | if (channel == BU27034_CHAN_ALS) { |
376 | *val = 0; |
377 | *val2 = 1000; |
378 | return IIO_VAL_INT_PLUS_MICRO; |
379 | } |
380 | |
381 | mutex_lock(&data->mutex); |
382 | ret = _bu27034_get_scale(data, channel, val, val2); |
383 | mutex_unlock(lock: &data->mutex); |
384 | if (ret) |
385 | return ret; |
386 | |
387 | return IIO_VAL_INT_PLUS_NANO; |
388 | } |
389 | |
390 | /* Caller should hold the lock to protect lux reading */ |
391 | static int bu27034_write_gain_sel(struct bu27034_data *data, int chan, int sel) |
392 | { |
393 | static const int reg[] = { |
394 | [BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2, |
395 | [BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3, |
396 | }; |
397 | int mask, val; |
398 | |
399 | if (chan != BU27034_CHAN_DATA0 && chan != BU27034_CHAN_DATA1) |
400 | return -EINVAL; |
401 | |
402 | val = FIELD_PREP(BU27034_MASK_D01_GAIN, sel); |
403 | |
404 | mask = BU27034_MASK_D01_GAIN; |
405 | |
406 | if (chan == BU27034_CHAN_DATA0) { |
407 | /* |
408 | * We keep the same gain for channel 2 as we set for channel 0 |
409 | * We can't allow them to be individually controlled because |
410 | * setting one will impact also the other. Also, if we don't |
411 | * always update both gains we may result unsupported bit |
412 | * combinations. |
413 | * |
414 | * This is not nice but this is yet another place where the |
415 | * user space must be prepared to surprizes. Namely, see chan 2 |
416 | * gain changed when chan 0 gain is changed. |
417 | * |
418 | * This is not fatal for most users though. I don't expect the |
419 | * channel 2 to be used in any generic cases - the intensity |
420 | * values provided by the sensor for IR area are not openly |
421 | * documented. Also, channel 2 is not used for visible light. |
422 | * |
423 | * So, if there is application which is written to utilize the |
424 | * channel 2 - then it is probably specifically targeted to this |
425 | * sensor and knows how to utilize those values. It is safe to |
426 | * hope such user can also cope with the gain changes. |
427 | */ |
428 | mask |= BU27034_MASK_D2_GAIN_LO; |
429 | |
430 | /* |
431 | * The D2 gain bits are directly the lowest bits of selector. |
432 | * Just do add those bits to the value |
433 | */ |
434 | val |= sel & BU27034_MASK_D2_GAIN_LO; |
435 | } |
436 | |
437 | return regmap_update_bits(map: data->regmap, reg: reg[chan], mask, val); |
438 | } |
439 | |
440 | static int bu27034_set_gain(struct bu27034_data *data, int chan, int gain) |
441 | { |
442 | int ret; |
443 | |
444 | /* |
445 | * We don't allow setting channel 2 gain as it messes up the |
446 | * gain for channel 0 - which shares the high bits |
447 | */ |
448 | if (chan != BU27034_CHAN_DATA0 && chan != BU27034_CHAN_DATA1) |
449 | return -EINVAL; |
450 | |
451 | ret = iio_gts_find_sel_by_gain(gts: &data->gts, gain); |
452 | if (ret < 0) |
453 | return ret; |
454 | |
455 | return bu27034_write_gain_sel(data, chan, sel: ret); |
456 | } |
457 | |
458 | /* Caller should hold the lock to protect data->int_time */ |
459 | static int bu27034_set_int_time(struct bu27034_data *data, int time) |
460 | { |
461 | int ret; |
462 | |
463 | ret = iio_gts_find_sel_by_int_time(gts: &data->gts, time); |
464 | if (ret < 0) |
465 | return ret; |
466 | |
467 | return regmap_update_bits(map: data->regmap, BU27034_REG_MODE_CONTROL1, |
468 | BU27034_MASK_MEAS_MODE, val: ret); |
469 | } |
470 | |
471 | /* |
472 | * We try to change the time in such way that the scale is maintained for |
473 | * given channels by adjusting gain so that it compensates the time change. |
474 | */ |
475 | static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) |
476 | { |
477 | struct bu27034_gain_check gains[] = { |
478 | { .chan = BU27034_CHAN_DATA0 }, |
479 | { .chan = BU27034_CHAN_DATA1 }, |
480 | }; |
481 | int numg = ARRAY_SIZE(gains); |
482 | int ret, int_time_old, i; |
483 | |
484 | mutex_lock(&data->mutex); |
485 | ret = bu27034_get_int_time(data); |
486 | if (ret < 0) |
487 | goto unlock_out; |
488 | |
489 | int_time_old = ret; |
490 | |
491 | if (!iio_gts_valid_time(gts: &data->gts, time_us)) { |
492 | dev_err(data->dev, "Unsupported integration time %u\n" , |
493 | time_us); |
494 | ret = -EINVAL; |
495 | |
496 | goto unlock_out; |
497 | } |
498 | |
499 | if (time_us == int_time_old) { |
500 | ret = 0; |
501 | goto unlock_out; |
502 | } |
503 | |
504 | for (i = 0; i < numg; i++) { |
505 | ret = bu27034_get_gain(data, chan: gains[i].chan, gain: &gains[i].old_gain); |
506 | if (ret) |
507 | goto unlock_out; |
508 | |
509 | ret = iio_gts_find_new_gain_by_old_gain_time(gts: &data->gts, |
510 | old_gain: gains[i].old_gain, |
511 | old_time: int_time_old, new_time: time_us, |
512 | new_gain: &gains[i].new_gain); |
513 | if (ret) { |
514 | int scale1, scale2; |
515 | bool ok; |
516 | |
517 | _bu27034_get_scale(data, channel: gains[i].chan, val: &scale1, val2: &scale2); |
518 | dev_dbg(data->dev, |
519 | "chan %u, can't support time %u with scale %u %u\n" , |
520 | gains[i].chan, time_us, scale1, scale2); |
521 | |
522 | if (gains[i].new_gain < 0) |
523 | goto unlock_out; |
524 | |
525 | /* |
526 | * If caller requests for integration time change and we |
527 | * can't support the scale - then the caller should be |
528 | * prepared to 'pick up the pieces and deal with the |
529 | * fact that the scale changed'. |
530 | */ |
531 | ret = iio_find_closest_gain_low(gts: &data->gts, |
532 | gain: gains[i].new_gain, in_range: &ok); |
533 | |
534 | if (!ok) |
535 | dev_dbg(data->dev, |
536 | "optimal gain out of range for chan %u\n" , |
537 | gains[i].chan); |
538 | |
539 | if (ret < 0) { |
540 | dev_dbg(data->dev, |
541 | "Total gain increase. Risk of saturation" ); |
542 | ret = iio_gts_get_min_gain(gts: &data->gts); |
543 | if (ret < 0) |
544 | goto unlock_out; |
545 | } |
546 | dev_dbg(data->dev, "chan %u scale changed\n" , |
547 | gains[i].chan); |
548 | gains[i].new_gain = ret; |
549 | dev_dbg(data->dev, "chan %u new gain %u\n" , |
550 | gains[i].chan, gains[i].new_gain); |
551 | } |
552 | } |
553 | |
554 | for (i = 0; i < numg; i++) { |
555 | ret = bu27034_set_gain(data, chan: gains[i].chan, gain: gains[i].new_gain); |
556 | if (ret) |
557 | goto unlock_out; |
558 | } |
559 | |
560 | ret = bu27034_set_int_time(data, time: time_us); |
561 | |
562 | unlock_out: |
563 | mutex_unlock(lock: &data->mutex); |
564 | |
565 | return ret; |
566 | } |
567 | |
568 | static int bu27034_set_scale(struct bu27034_data *data, int chan, |
569 | int val, int val2) |
570 | { |
571 | int ret, time_sel, gain_sel, i; |
572 | bool found = false; |
573 | |
574 | if (chan == BU27034_CHAN_DATA2) |
575 | return -EINVAL; |
576 | |
577 | if (chan == BU27034_CHAN_ALS) { |
578 | if (val == 0 && val2 == 1000000) |
579 | return 0; |
580 | |
581 | return -EINVAL; |
582 | } |
583 | |
584 | mutex_lock(&data->mutex); |
585 | ret = regmap_read(map: data->regmap, BU27034_REG_MODE_CONTROL1, val: &time_sel); |
586 | if (ret) |
587 | goto unlock_out; |
588 | |
589 | ret = iio_gts_find_gain_sel_for_scale_using_time(gts: &data->gts, time_sel, |
590 | scale_int: val, scale_nano: val2, gain_sel: &gain_sel); |
591 | if (ret) { |
592 | /* |
593 | * Could not support scale with given time. Need to change time. |
594 | * We still want to maintain the scale for all channels |
595 | */ |
596 | struct bu27034_gain_check gain; |
597 | int new_time_sel; |
598 | |
599 | /* |
600 | * Populate information for the other channel which should also |
601 | * maintain the scale. (Due to the HW limitations the chan2 |
602 | * gets the same gain as chan0, so we only need to explicitly |
603 | * set the chan 0 and 1). |
604 | */ |
605 | if (chan == BU27034_CHAN_DATA0) |
606 | gain.chan = BU27034_CHAN_DATA1; |
607 | else if (chan == BU27034_CHAN_DATA1) |
608 | gain.chan = BU27034_CHAN_DATA0; |
609 | |
610 | ret = bu27034_get_gain(data, chan: gain.chan, gain: &gain.old_gain); |
611 | if (ret) |
612 | goto unlock_out; |
613 | |
614 | /* |
615 | * Iterate through all the times to see if we find one which |
616 | * can support requested scale for requested channel, while |
617 | * maintaining the scale for other channels |
618 | */ |
619 | for (i = 0; i < data->gts.num_itime; i++) { |
620 | new_time_sel = data->gts.itime_table[i].sel; |
621 | |
622 | if (new_time_sel == time_sel) |
623 | continue; |
624 | |
625 | /* Can we provide requested scale with this time? */ |
626 | ret = iio_gts_find_gain_sel_for_scale_using_time( |
627 | gts: &data->gts, time_sel: new_time_sel, scale_int: val, scale_nano: val2, |
628 | gain_sel: &gain_sel); |
629 | if (ret) |
630 | continue; |
631 | |
632 | /* Can the other channel(s) maintain scale? */ |
633 | ret = iio_gts_find_new_gain_sel_by_old_gain_time( |
634 | gts: &data->gts, old_gain: gain.old_gain, old_time_sel: time_sel, |
635 | new_time_sel, new_gain: &gain.new_gain); |
636 | if (!ret) { |
637 | /* Yes - we found suitable time */ |
638 | found = true; |
639 | break; |
640 | } |
641 | } |
642 | if (!found) { |
643 | dev_dbg(data->dev, |
644 | "Can't set scale maintaining other channels\n" ); |
645 | ret = -EINVAL; |
646 | |
647 | goto unlock_out; |
648 | } |
649 | |
650 | ret = bu27034_set_gain(data, chan: gain.chan, gain: gain.new_gain); |
651 | if (ret) |
652 | goto unlock_out; |
653 | |
654 | ret = regmap_update_bits(map: data->regmap, BU27034_REG_MODE_CONTROL1, |
655 | BU27034_MASK_MEAS_MODE, val: new_time_sel); |
656 | if (ret) |
657 | goto unlock_out; |
658 | } |
659 | |
660 | ret = bu27034_write_gain_sel(data, chan, sel: gain_sel); |
661 | unlock_out: |
662 | mutex_unlock(lock: &data->mutex); |
663 | |
664 | return ret; |
665 | } |
666 | |
667 | /* |
668 | * for (D1/D0 < 0.87): |
669 | * lx = 0.004521097 * D1 - 0.002663996 * D0 + |
670 | * 0.00012213 * D1 * D1 / D0 |
671 | * |
672 | * => 115.7400832 * ch1 / gain1 / mt - |
673 | * 68.1982976 * ch0 / gain0 / mt + |
674 | * 0.00012213 * 25600 * (ch1 / gain1 / mt) * 25600 * |
675 | * (ch1 /gain1 / mt) / (25600 * ch0 / gain0 / mt) |
676 | * |
677 | * A = 0.00012213 * 25600 * (ch1 /gain1 / mt) * 25600 * |
678 | * (ch1 /gain1 / mt) / (25600 * ch0 / gain0 / mt) |
679 | * => 0.00012213 * 25600 * (ch1 /gain1 / mt) * |
680 | * (ch1 /gain1 / mt) / (ch0 / gain0 / mt) |
681 | * => 0.00012213 * 25600 * (ch1 / gain1) * (ch1 /gain1 / mt) / |
682 | * (ch0 / gain0) |
683 | * => 0.00012213 * 25600 * (ch1 / gain1) * (ch1 /gain1 / mt) * |
684 | * gain0 / ch0 |
685 | * => 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / mt /ch0 |
686 | * |
687 | * lx = (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) / |
688 | * mt + A |
689 | * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) / |
690 | * mt + 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / mt / |
691 | * ch0 |
692 | * |
693 | * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0 + |
694 | * 3.126528 * ch1 * ch1 * gain0 / gain1 / gain1 / ch0) / |
695 | * mt |
696 | * |
697 | * For (0.87 <= D1/D0 < 1.00) |
698 | * lx = (0.001331* D0 + 0.0000354 * D1) * ((D1/D0 – 0.87) * (0.385) + 1) |
699 | * => (0.001331 * 256 * 100 * ch0 / gain0 / mt + 0.0000354 * 256 * |
700 | * 100 * ch1 / gain1 / mt) * ((D1/D0 - 0.87) * (0.385) + 1) |
701 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
702 | * ((D1/D0 - 0.87) * (0.385) + 1) |
703 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
704 | * (0.385 * D1/D0 - 0.66505) |
705 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
706 | * (0.385 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) - 0.66505) |
707 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
708 | * (9856 * ch1 / gain1 / mt / (25600 * ch0 / gain0 / mt) + 0.66505) |
709 | * => 13.118336 * ch1 / (gain1 * mt) |
710 | * + 22.66064768 * ch0 / (gain0 * mt) |
711 | * + 8931.90144 * ch1 * ch1 * gain0 / |
712 | * (25600 * ch0 * gain1 * gain1 * mt) |
713 | * + 0.602694912 * ch1 / (gain1 * mt) |
714 | * |
715 | * => [0.3489024 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) |
716 | * + 22.66064768 * ch0 / gain0 |
717 | * + 13.721030912 * ch1 / gain1 |
718 | * ] / mt |
719 | * |
720 | * For (D1/D0 >= 1.00) |
721 | * |
722 | * lx = (0.001331* D0 + 0.0000354 * D1) * ((D1/D0 – 2.0) * (-0.05) + 1) |
723 | * => (0.001331* D0 + 0.0000354 * D1) * (-0.05D1/D0 + 1.1) |
724 | * => (0.001331 * 256 * 100 * ch0 / gain0 / mt + 0.0000354 * 256 * |
725 | * 100 * ch1 / gain1 / mt) * (-0.05D1/D0 + 1.1) |
726 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
727 | * (-0.05 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) + 1.1) |
728 | * => (34.0736 * ch0 / gain0 / mt + 0.90624 * ch1 / gain1 / mt) * |
729 | * (-1280 * ch1 / (gain1 * mt * 25600 * ch0 / gain0 / mt) + 1.1) |
730 | * => (34.0736 * ch0 * -1280 * ch1 * gain0 * mt /( gain0 * mt * gain1 * mt * 25600 * ch0) |
731 | * + 34.0736 * 1.1 * ch0 / (gain0 * mt) |
732 | * + 0.90624 * ch1 * -1280 * ch1 *gain0 * mt / (gain1 * mt *gain1 * mt * 25600 * ch0) |
733 | * + 1.1 * 0.90624 * ch1 / (gain1 * mt) |
734 | * => -43614.208 * ch1 / (gain1 * mt * 25600) |
735 | * + 37.48096 ch0 / (gain0 * mt) |
736 | * - 1159.9872 * ch1 * ch1 * gain0 / (gain1 * gain1 * mt * 25600 * ch0) |
737 | * + 0.996864 ch1 / (gain1 * mt) |
738 | * => [ |
739 | * - 0.045312 * ch1 * ch1 * gain0 / (gain1 * gain1 * ch0) |
740 | * - 0.706816 * ch1 / gain1 |
741 | * + 37.48096 ch0 /gain0 |
742 | * ] * mt |
743 | * |
744 | * |
745 | * So, the first case (D1/D0 < 0.87) can be computed to a form: |
746 | * |
747 | * lx = (3.126528 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + |
748 | * 115.7400832 * ch1 / gain1 + |
749 | * -68.1982976 * ch0 / gain0 |
750 | * / mt |
751 | * |
752 | * Second case (0.87 <= D1/D0 < 1.00) goes to form: |
753 | * |
754 | * => [0.3489024 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + |
755 | * 13.721030912 * ch1 / gain1 + |
756 | * 22.66064768 * ch0 / gain0 |
757 | * ] / mt |
758 | * |
759 | * Third case (D1/D0 >= 1.00) goes to form: |
760 | * => [-0.045312 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + |
761 | * -0.706816 * ch1 / gain1 + |
762 | * 37.48096 ch0 /(gain0 |
763 | * ] / mt |
764 | * |
765 | * This can be unified to format: |
766 | * lx = [ |
767 | * A * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) + |
768 | * B * ch1 / gain1 + |
769 | * C * ch0 / gain0 |
770 | * ] / mt |
771 | * |
772 | * For case 1: |
773 | * A = 3.126528, |
774 | * B = 115.7400832 |
775 | * C = -68.1982976 |
776 | * |
777 | * For case 2: |
778 | * A = 0.3489024 |
779 | * B = 13.721030912 |
780 | * C = 22.66064768 |
781 | * |
782 | * For case 3: |
783 | * A = -0.045312 |
784 | * B = -0.706816 |
785 | * C = 37.48096 |
786 | */ |
787 | |
788 | struct bu27034_lx_coeff { |
789 | unsigned int A; |
790 | unsigned int B; |
791 | unsigned int C; |
792 | /* Indicate which of the coefficients above are negative */ |
793 | bool is_neg[3]; |
794 | }; |
795 | |
796 | static inline u64 gain_mul_div_helper(u64 val, unsigned int gain, |
797 | unsigned int div) |
798 | { |
799 | /* |
800 | * Max gain for a channel is 4096. The max u64 (0xffffffffffffffffULL) |
801 | * divided by 4096 is 0xFFFFFFFFFFFFF (GENMASK_ULL(51, 0)) (floored). |
802 | * Thus, the 0xFFFFFFFFFFFFF is the largest value we can safely multiply |
803 | * with the gain, no matter what gain is set. |
804 | * |
805 | * So, multiplication with max gain may overflow if val is greater than |
806 | * 0xFFFFFFFFFFFFF (52 bits set).. |
807 | * |
808 | * If this is the case we divide first. |
809 | */ |
810 | if (val < GENMASK_ULL(51, 0)) { |
811 | val *= gain; |
812 | do_div(val, div); |
813 | } else { |
814 | do_div(val, div); |
815 | val *= gain; |
816 | } |
817 | |
818 | return val; |
819 | } |
820 | |
821 | static u64 bu27034_fixp_calc_t1_64bit(unsigned int coeff, unsigned int ch0, |
822 | unsigned int ch1, unsigned int gain0, |
823 | unsigned int gain1) |
824 | { |
825 | unsigned int helper; |
826 | u64 helper64; |
827 | |
828 | helper64 = (u64)coeff * (u64)ch1 * (u64)ch1; |
829 | |
830 | helper = gain1 * gain1; |
831 | if (helper > ch0) { |
832 | do_div(helper64, helper); |
833 | |
834 | return gain_mul_div_helper(val: helper64, gain: gain0, div: ch0); |
835 | } |
836 | |
837 | do_div(helper64, ch0); |
838 | |
839 | return gain_mul_div_helper(val: helper64, gain: gain0, div: helper); |
840 | |
841 | } |
842 | |
843 | static u64 bu27034_fixp_calc_t1(unsigned int coeff, unsigned int ch0, |
844 | unsigned int ch1, unsigned int gain0, |
845 | unsigned int gain1) |
846 | { |
847 | unsigned int helper, tmp; |
848 | |
849 | /* |
850 | * Here we could overflow even the 64bit value. Hence we |
851 | * multiply with gain0 only after the divisions - even though |
852 | * it may result loss of accuracy |
853 | */ |
854 | helper = coeff * ch1 * ch1; |
855 | tmp = helper * gain0; |
856 | |
857 | helper = ch1 * ch1; |
858 | |
859 | if (check_mul_overflow(helper, coeff, &helper)) |
860 | return bu27034_fixp_calc_t1_64bit(coeff, ch0, ch1, gain0, gain1); |
861 | |
862 | if (check_mul_overflow(helper, gain0, &tmp)) |
863 | return bu27034_fixp_calc_t1_64bit(coeff, ch0, ch1, gain0, gain1); |
864 | |
865 | return tmp / (gain1 * gain1) / ch0; |
866 | |
867 | } |
868 | |
869 | static u64 bu27034_fixp_calc_t23(unsigned int coeff, unsigned int ch, |
870 | unsigned int gain) |
871 | { |
872 | unsigned int helper; |
873 | u64 helper64; |
874 | |
875 | if (!check_mul_overflow(coeff, ch, &helper)) |
876 | return helper / gain; |
877 | |
878 | helper64 = (u64)coeff * (u64)ch; |
879 | do_div(helper64, gain); |
880 | |
881 | return helper64; |
882 | } |
883 | |
884 | static int bu27034_fixp_calc_lx(unsigned int ch0, unsigned int ch1, |
885 | unsigned int gain0, unsigned int gain1, |
886 | unsigned int meastime, int coeff_idx) |
887 | { |
888 | static const struct bu27034_lx_coeff coeff[] = { |
889 | { |
890 | .A = 31265280, /* 3.126528 */ |
891 | .B = 1157400832, /*115.7400832 */ |
892 | .C = 681982976, /* -68.1982976 */ |
893 | .is_neg = {false, false, true}, |
894 | }, { |
895 | .A = 3489024, /* 0.3489024 */ |
896 | .B = 137210309, /* 13.721030912 */ |
897 | .C = 226606476, /* 22.66064768 */ |
898 | /* All terms positive */ |
899 | }, { |
900 | .A = 453120, /* -0.045312 */ |
901 | .B = 7068160, /* -0.706816 */ |
902 | .C = 374809600, /* 37.48096 */ |
903 | .is_neg = {true, true, false}, |
904 | } |
905 | }; |
906 | const struct bu27034_lx_coeff *c = &coeff[coeff_idx]; |
907 | u64 res = 0, terms[3]; |
908 | int i; |
909 | |
910 | if (coeff_idx >= ARRAY_SIZE(coeff)) |
911 | return -EINVAL; |
912 | |
913 | terms[0] = bu27034_fixp_calc_t1(coeff: c->A, ch0, ch1, gain0, gain1); |
914 | terms[1] = bu27034_fixp_calc_t23(coeff: c->B, ch: ch1, gain: gain1); |
915 | terms[2] = bu27034_fixp_calc_t23(coeff: c->C, ch: ch0, gain: gain0); |
916 | |
917 | /* First, add positive terms */ |
918 | for (i = 0; i < 3; i++) |
919 | if (!c->is_neg[i]) |
920 | res += terms[i]; |
921 | |
922 | /* No positive term => zero lux */ |
923 | if (!res) |
924 | return 0; |
925 | |
926 | /* Then, subtract negative terms (if any) */ |
927 | for (i = 0; i < 3; i++) |
928 | if (c->is_neg[i]) { |
929 | /* |
930 | * If the negative term is greater than positive - then |
931 | * the darkness has taken over and we are all doomed! Eh, |
932 | * I mean, then we can just return 0 lx and go out |
933 | */ |
934 | if (terms[i] >= res) |
935 | return 0; |
936 | |
937 | res -= terms[i]; |
938 | } |
939 | |
940 | meastime *= 10; |
941 | do_div(res, meastime); |
942 | |
943 | return (int) res; |
944 | } |
945 | |
946 | static bool bu27034_has_valid_sample(struct bu27034_data *data) |
947 | { |
948 | int ret, val; |
949 | |
950 | ret = regmap_read(map: data->regmap, BU27034_REG_MODE_CONTROL4, val: &val); |
951 | if (ret) { |
952 | dev_err(data->dev, "Read failed %d\n" , ret); |
953 | |
954 | return false; |
955 | } |
956 | |
957 | return val & BU27034_MASK_VALID; |
958 | } |
959 | |
960 | /* |
961 | * Reading the register where VALID bit is clears this bit. (So does changing |
962 | * any gain / integration time configuration registers) The bit gets |
963 | * set when we have acquired new data. We use this bit to indicate data |
964 | * validity. |
965 | */ |
966 | static void bu27034_invalidate_read_data(struct bu27034_data *data) |
967 | { |
968 | bu27034_has_valid_sample(data); |
969 | } |
970 | |
971 | static int bu27034_read_result(struct bu27034_data *data, int chan, int *res) |
972 | { |
973 | int reg[] = { |
974 | [BU27034_CHAN_DATA0] = BU27034_REG_DATA0_LO, |
975 | [BU27034_CHAN_DATA1] = BU27034_REG_DATA1_LO, |
976 | [BU27034_CHAN_DATA2] = BU27034_REG_DATA2_LO, |
977 | }; |
978 | int valid, ret; |
979 | __le16 val; |
980 | |
981 | ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, |
982 | valid, (valid & BU27034_MASK_VALID), |
983 | BU27034_DATA_WAIT_TIME_US, 0); |
984 | if (ret) |
985 | return ret; |
986 | |
987 | ret = regmap_bulk_read(map: data->regmap, reg: reg[chan], val: &val, val_count: sizeof(val)); |
988 | if (ret) |
989 | return ret; |
990 | |
991 | *res = le16_to_cpu(val); |
992 | |
993 | return 0; |
994 | } |
995 | |
996 | static int bu27034_get_result_unlocked(struct bu27034_data *data, __le16 *res, |
997 | int size) |
998 | { |
999 | int ret = 0, retry_cnt = 0; |
1000 | |
1001 | retry: |
1002 | /* Get new value from sensor if data is ready */ |
1003 | if (bu27034_has_valid_sample(data)) { |
1004 | ret = regmap_bulk_read(map: data->regmap, BU27034_REG_DATA0_LO, |
1005 | val: res, val_count: size); |
1006 | if (ret) |
1007 | return ret; |
1008 | |
1009 | bu27034_invalidate_read_data(data); |
1010 | } else { |
1011 | /* No new data in sensor. Wait and retry */ |
1012 | retry_cnt++; |
1013 | |
1014 | if (retry_cnt > BU27034_RETRY_LIMIT) { |
1015 | dev_err(data->dev, "No data from sensor\n" ); |
1016 | |
1017 | return -ETIMEDOUT; |
1018 | } |
1019 | |
1020 | msleep(msecs: 25); |
1021 | |
1022 | goto retry; |
1023 | } |
1024 | |
1025 | return ret; |
1026 | } |
1027 | |
1028 | static int bu27034_meas_set(struct bu27034_data *data, bool en) |
1029 | { |
1030 | if (en) |
1031 | return regmap_set_bits(map: data->regmap, BU27034_REG_MODE_CONTROL4, |
1032 | BU27034_MASK_MEAS_EN); |
1033 | |
1034 | return regmap_clear_bits(map: data->regmap, BU27034_REG_MODE_CONTROL4, |
1035 | BU27034_MASK_MEAS_EN); |
1036 | } |
1037 | |
1038 | static int bu27034_get_single_result(struct bu27034_data *data, int chan, |
1039 | int *val) |
1040 | { |
1041 | int ret; |
1042 | |
1043 | if (chan < BU27034_CHAN_DATA0 || chan > BU27034_CHAN_DATA2) |
1044 | return -EINVAL; |
1045 | |
1046 | ret = bu27034_meas_set(data, en: true); |
1047 | if (ret) |
1048 | return ret; |
1049 | |
1050 | ret = bu27034_get_int_time(data); |
1051 | if (ret < 0) |
1052 | return ret; |
1053 | |
1054 | msleep(msecs: ret / 1000); |
1055 | |
1056 | return bu27034_read_result(data, chan, res: val); |
1057 | } |
1058 | |
1059 | /* |
1060 | * The formula given by vendor for computing luxes out of data0 and data1 |
1061 | * (in open air) is as follows: |
1062 | * |
1063 | * Let's mark: |
1064 | * D0 = data0/ch0_gain/meas_time_ms * 25600 |
1065 | * D1 = data1/ch1_gain/meas_time_ms * 25600 |
1066 | * |
1067 | * Then: |
1068 | * if (D1/D0 < 0.87) |
1069 | * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 3.45 + 1) |
1070 | * else if (D1/D0 < 1) |
1071 | * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 0.385 + 1) |
1072 | * else |
1073 | * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 2) * -0.05 + 1) |
1074 | * |
1075 | * We use it here. Users who have for example some colored lens |
1076 | * need to modify the calculation but I hope this gives a starting point for |
1077 | * those working with such devices. |
1078 | */ |
1079 | |
1080 | static int bu27034_calc_mlux(struct bu27034_data *data, __le16 *res, int *val) |
1081 | { |
1082 | unsigned int gain0, gain1, meastime; |
1083 | unsigned int d1_d0_ratio_scaled; |
1084 | u16 ch0, ch1; |
1085 | u64 helper64; |
1086 | int ret; |
1087 | |
1088 | /* |
1089 | * We return 0 lux if calculation fails. This should be reasonably |
1090 | * easy to spot from the buffers especially if raw-data channels show |
1091 | * valid values |
1092 | */ |
1093 | *val = 0; |
1094 | |
1095 | ch0 = max_t(u16, 1, le16_to_cpu(res[0])); |
1096 | ch1 = max_t(u16, 1, le16_to_cpu(res[1])); |
1097 | |
1098 | ret = bu27034_get_gain(data, chan: BU27034_CHAN_DATA0, gain: &gain0); |
1099 | if (ret) |
1100 | return ret; |
1101 | |
1102 | ret = bu27034_get_gain(data, chan: BU27034_CHAN_DATA1, gain: &gain1); |
1103 | if (ret) |
1104 | return ret; |
1105 | |
1106 | ret = bu27034_get_int_time(data); |
1107 | if (ret < 0) |
1108 | return ret; |
1109 | |
1110 | meastime = ret; |
1111 | |
1112 | d1_d0_ratio_scaled = (unsigned int)ch1 * (unsigned int)gain0 * 100; |
1113 | helper64 = (u64)ch1 * (u64)gain0 * 100LLU; |
1114 | |
1115 | if (helper64 != d1_d0_ratio_scaled) { |
1116 | unsigned int div = (unsigned int)ch0 * gain1; |
1117 | |
1118 | do_div(helper64, div); |
1119 | d1_d0_ratio_scaled = helper64; |
1120 | } else { |
1121 | d1_d0_ratio_scaled /= ch0 * gain1; |
1122 | } |
1123 | |
1124 | if (d1_d0_ratio_scaled < 87) |
1125 | ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, coeff_idx: 0); |
1126 | else if (d1_d0_ratio_scaled < 100) |
1127 | ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, coeff_idx: 1); |
1128 | else |
1129 | ret = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, coeff_idx: 2); |
1130 | |
1131 | if (ret < 0) |
1132 | return ret; |
1133 | |
1134 | *val = ret; |
1135 | |
1136 | return 0; |
1137 | |
1138 | } |
1139 | |
1140 | static int bu27034_get_mlux(struct bu27034_data *data, int chan, int *val) |
1141 | { |
1142 | __le16 res[3]; |
1143 | int ret; |
1144 | |
1145 | ret = bu27034_meas_set(data, en: true); |
1146 | if (ret) |
1147 | return ret; |
1148 | |
1149 | ret = bu27034_get_result_unlocked(data, res: &res[0], size: sizeof(res)); |
1150 | if (ret) |
1151 | return ret; |
1152 | |
1153 | ret = bu27034_calc_mlux(data, res, val); |
1154 | if (ret) |
1155 | return ret; |
1156 | |
1157 | ret = bu27034_meas_set(data, en: false); |
1158 | if (ret) |
1159 | dev_err(data->dev, "failed to disable measurement\n" ); |
1160 | |
1161 | return 0; |
1162 | } |
1163 | |
1164 | static int bu27034_read_raw(struct iio_dev *idev, |
1165 | struct iio_chan_spec const *chan, |
1166 | int *val, int *val2, long mask) |
1167 | { |
1168 | struct bu27034_data *data = iio_priv(indio_dev: idev); |
1169 | int ret; |
1170 | |
1171 | switch (mask) { |
1172 | case IIO_CHAN_INFO_INT_TIME: |
1173 | *val = 0; |
1174 | *val2 = bu27034_get_int_time(data); |
1175 | if (*val2 < 0) |
1176 | return *val2; |
1177 | |
1178 | return IIO_VAL_INT_PLUS_MICRO; |
1179 | |
1180 | case IIO_CHAN_INFO_SCALE: |
1181 | return bu27034_get_scale(data, channel: chan->channel, val, val2); |
1182 | |
1183 | case IIO_CHAN_INFO_RAW: |
1184 | { |
1185 | int (*result_get)(struct bu27034_data *data, int chan, int *val); |
1186 | |
1187 | if (chan->type == IIO_INTENSITY) |
1188 | result_get = bu27034_get_single_result; |
1189 | else if (chan->type == IIO_LIGHT) |
1190 | result_get = bu27034_get_mlux; |
1191 | else |
1192 | return -EINVAL; |
1193 | |
1194 | /* Don't mess with measurement enabling while buffering */ |
1195 | ret = iio_device_claim_direct_mode(indio_dev: idev); |
1196 | if (ret) |
1197 | return ret; |
1198 | |
1199 | mutex_lock(&data->mutex); |
1200 | /* |
1201 | * Reading one channel at a time is inefficient but we |
1202 | * don't care here. Buffered version should be used if |
1203 | * performance is an issue. |
1204 | */ |
1205 | ret = result_get(data, chan->channel, val); |
1206 | |
1207 | mutex_unlock(lock: &data->mutex); |
1208 | iio_device_release_direct_mode(indio_dev: idev); |
1209 | |
1210 | if (ret) |
1211 | return ret; |
1212 | |
1213 | return IIO_VAL_INT; |
1214 | } |
1215 | default: |
1216 | return -EINVAL; |
1217 | } |
1218 | } |
1219 | |
1220 | static int bu27034_write_raw_get_fmt(struct iio_dev *indio_dev, |
1221 | struct iio_chan_spec const *chan, |
1222 | long mask) |
1223 | { |
1224 | |
1225 | switch (mask) { |
1226 | case IIO_CHAN_INFO_SCALE: |
1227 | return IIO_VAL_INT_PLUS_NANO; |
1228 | case IIO_CHAN_INFO_INT_TIME: |
1229 | return IIO_VAL_INT_PLUS_MICRO; |
1230 | default: |
1231 | return -EINVAL; |
1232 | } |
1233 | } |
1234 | |
1235 | static int bu27034_write_raw(struct iio_dev *idev, |
1236 | struct iio_chan_spec const *chan, |
1237 | int val, int val2, long mask) |
1238 | { |
1239 | struct bu27034_data *data = iio_priv(indio_dev: idev); |
1240 | int ret; |
1241 | |
1242 | ret = iio_device_claim_direct_mode(indio_dev: idev); |
1243 | if (ret) |
1244 | return ret; |
1245 | |
1246 | switch (mask) { |
1247 | case IIO_CHAN_INFO_SCALE: |
1248 | ret = bu27034_set_scale(data, chan: chan->channel, val, val2); |
1249 | break; |
1250 | case IIO_CHAN_INFO_INT_TIME: |
1251 | if (!val) |
1252 | ret = bu27034_try_set_int_time(data, time_us: val2); |
1253 | else |
1254 | ret = -EINVAL; |
1255 | break; |
1256 | default: |
1257 | ret = -EINVAL; |
1258 | break; |
1259 | } |
1260 | |
1261 | iio_device_release_direct_mode(indio_dev: idev); |
1262 | |
1263 | return ret; |
1264 | } |
1265 | |
1266 | static int bu27034_read_avail(struct iio_dev *idev, |
1267 | struct iio_chan_spec const *chan, const int **vals, |
1268 | int *type, int *length, long mask) |
1269 | { |
1270 | struct bu27034_data *data = iio_priv(indio_dev: idev); |
1271 | |
1272 | switch (mask) { |
1273 | case IIO_CHAN_INFO_INT_TIME: |
1274 | return iio_gts_avail_times(gts: &data->gts, vals, type, length); |
1275 | case IIO_CHAN_INFO_SCALE: |
1276 | return iio_gts_all_avail_scales(gts: &data->gts, vals, type, length); |
1277 | default: |
1278 | return -EINVAL; |
1279 | } |
1280 | } |
1281 | |
1282 | static const struct iio_info bu27034_info = { |
1283 | .read_raw = &bu27034_read_raw, |
1284 | .write_raw = &bu27034_write_raw, |
1285 | .write_raw_get_fmt = &bu27034_write_raw_get_fmt, |
1286 | .read_avail = &bu27034_read_avail, |
1287 | }; |
1288 | |
1289 | static int bu27034_chip_init(struct bu27034_data *data) |
1290 | { |
1291 | int ret, sel; |
1292 | |
1293 | /* Reset */ |
1294 | ret = regmap_write_bits(map: data->regmap, BU27034_REG_SYSTEM_CONTROL, |
1295 | BU27034_MASK_SW_RESET, BU27034_MASK_SW_RESET); |
1296 | if (ret) |
1297 | return dev_err_probe(dev: data->dev, err: ret, fmt: "Sensor reset failed\n" ); |
1298 | |
1299 | msleep(msecs: 1); |
1300 | |
1301 | ret = regmap_reinit_cache(map: data->regmap, config: &bu27034_regmap); |
1302 | if (ret) { |
1303 | dev_err(data->dev, "Failed to reinit reg cache\n" ); |
1304 | return ret; |
1305 | } |
1306 | |
1307 | /* |
1308 | * Read integration time here to ensure it is in regmap cache. We do |
1309 | * this to speed-up the int-time acquisition in the start of the buffer |
1310 | * handling thread where longer delays could make it more likely we end |
1311 | * up skipping a sample, and where the longer delays make timestamps |
1312 | * less accurate. |
1313 | */ |
1314 | ret = regmap_read(map: data->regmap, BU27034_REG_MODE_CONTROL1, val: &sel); |
1315 | if (ret) |
1316 | dev_err(data->dev, "reading integration time failed\n" ); |
1317 | |
1318 | return 0; |
1319 | } |
1320 | |
1321 | static int bu27034_wait_for_data(struct bu27034_data *data) |
1322 | { |
1323 | int ret, val; |
1324 | |
1325 | ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, |
1326 | val, val & BU27034_MASK_VALID, |
1327 | BU27034_DATA_WAIT_TIME_US, |
1328 | BU27034_TOTAL_DATA_WAIT_TIME_US); |
1329 | if (ret) { |
1330 | dev_err(data->dev, "data polling %s\n" , |
1331 | !(val & BU27034_MASK_VALID) ? "timeout" : "fail" ); |
1332 | |
1333 | return ret; |
1334 | } |
1335 | |
1336 | ret = regmap_bulk_read(map: data->regmap, BU27034_REG_DATA0_LO, |
1337 | val: &data->scan.channels[0], |
1338 | val_count: sizeof(data->scan.channels)); |
1339 | if (ret) |
1340 | return ret; |
1341 | |
1342 | bu27034_invalidate_read_data(data); |
1343 | |
1344 | return 0; |
1345 | } |
1346 | |
1347 | static int bu27034_buffer_thread(void *arg) |
1348 | { |
1349 | struct iio_dev *idev = arg; |
1350 | struct bu27034_data *data; |
1351 | int wait_ms; |
1352 | |
1353 | data = iio_priv(indio_dev: idev); |
1354 | |
1355 | wait_ms = bu27034_get_int_time(data); |
1356 | wait_ms /= 1000; |
1357 | |
1358 | wait_ms -= BU27034_MEAS_WAIT_PREMATURE_MS; |
1359 | |
1360 | while (!kthread_should_stop()) { |
1361 | int ret; |
1362 | int64_t tstamp; |
1363 | |
1364 | msleep(msecs: wait_ms); |
1365 | ret = bu27034_wait_for_data(data); |
1366 | if (ret) |
1367 | continue; |
1368 | |
1369 | tstamp = iio_get_time_ns(indio_dev: idev); |
1370 | |
1371 | if (test_bit(BU27034_CHAN_ALS, idev->active_scan_mask)) { |
1372 | int mlux; |
1373 | |
1374 | ret = bu27034_calc_mlux(data, res: &data->scan.channels[0], |
1375 | val: &mlux); |
1376 | if (ret) |
1377 | dev_err(data->dev, "failed to calculate lux\n" ); |
1378 | |
1379 | /* |
1380 | * The maximum Milli lux value we get with gain 1x time |
1381 | * 55mS data ch0 = 0xffff ch1 = 0xffff fits in 26 bits |
1382 | * so there should be no problem returning int from |
1383 | * computations and casting it to u32 |
1384 | */ |
1385 | data->scan.mlux = (u32)mlux; |
1386 | } |
1387 | iio_push_to_buffers_with_timestamp(indio_dev: idev, data: &data->scan, timestamp: tstamp); |
1388 | } |
1389 | |
1390 | return 0; |
1391 | } |
1392 | |
1393 | static int bu27034_buffer_enable(struct iio_dev *idev) |
1394 | { |
1395 | struct bu27034_data *data = iio_priv(indio_dev: idev); |
1396 | struct task_struct *task; |
1397 | int ret; |
1398 | |
1399 | mutex_lock(&data->mutex); |
1400 | ret = bu27034_meas_set(data, en: true); |
1401 | if (ret) |
1402 | goto unlock_out; |
1403 | |
1404 | task = kthread_run(bu27034_buffer_thread, idev, |
1405 | "bu27034-buffering-%u" , |
1406 | iio_device_id(idev)); |
1407 | if (IS_ERR(ptr: task)) { |
1408 | ret = PTR_ERR(ptr: task); |
1409 | goto unlock_out; |
1410 | } |
1411 | |
1412 | data->task = task; |
1413 | |
1414 | unlock_out: |
1415 | mutex_unlock(lock: &data->mutex); |
1416 | |
1417 | return ret; |
1418 | } |
1419 | |
1420 | static int bu27034_buffer_disable(struct iio_dev *idev) |
1421 | { |
1422 | struct bu27034_data *data = iio_priv(indio_dev: idev); |
1423 | int ret; |
1424 | |
1425 | mutex_lock(&data->mutex); |
1426 | if (data->task) { |
1427 | kthread_stop(k: data->task); |
1428 | data->task = NULL; |
1429 | } |
1430 | |
1431 | ret = bu27034_meas_set(data, en: false); |
1432 | mutex_unlock(lock: &data->mutex); |
1433 | |
1434 | return ret; |
1435 | } |
1436 | |
1437 | static const struct iio_buffer_setup_ops bu27034_buffer_ops = { |
1438 | .postenable = &bu27034_buffer_enable, |
1439 | .predisable = &bu27034_buffer_disable, |
1440 | }; |
1441 | |
1442 | static int bu27034_probe(struct i2c_client *i2c) |
1443 | { |
1444 | struct device *dev = &i2c->dev; |
1445 | struct bu27034_data *data; |
1446 | struct regmap *regmap; |
1447 | struct iio_dev *idev; |
1448 | unsigned int part_id, reg; |
1449 | int ret; |
1450 | |
1451 | regmap = devm_regmap_init_i2c(i2c, &bu27034_regmap); |
1452 | if (IS_ERR(ptr: regmap)) |
1453 | return dev_err_probe(dev, err: PTR_ERR(ptr: regmap), |
1454 | fmt: "Failed to initialize Regmap\n" ); |
1455 | |
1456 | idev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
1457 | if (!idev) |
1458 | return -ENOMEM; |
1459 | |
1460 | ret = devm_regulator_get_enable(dev, id: "vdd" ); |
1461 | if (ret) |
1462 | return dev_err_probe(dev, err: ret, fmt: "Failed to get regulator\n" ); |
1463 | |
1464 | data = iio_priv(indio_dev: idev); |
1465 | |
1466 | ret = regmap_read(map: regmap, BU27034_REG_SYSTEM_CONTROL, val: ®); |
1467 | if (ret) |
1468 | return dev_err_probe(dev, err: ret, fmt: "Failed to access sensor\n" ); |
1469 | |
1470 | part_id = FIELD_GET(BU27034_MASK_PART_ID, reg); |
1471 | |
1472 | if (part_id != BU27034_ID) |
1473 | dev_warn(dev, "unknown device 0x%x\n" , part_id); |
1474 | |
1475 | ret = devm_iio_init_iio_gts(dev, BU27034_SCALE_1X, max_scale_nano: 0, gain_tbl: bu27034_gains, |
1476 | ARRAY_SIZE(bu27034_gains), tim_tbl: bu27034_itimes, |
1477 | ARRAY_SIZE(bu27034_itimes), gts: &data->gts); |
1478 | if (ret) |
1479 | return ret; |
1480 | |
1481 | mutex_init(&data->mutex); |
1482 | data->regmap = regmap; |
1483 | data->dev = dev; |
1484 | |
1485 | idev->channels = bu27034_channels; |
1486 | idev->num_channels = ARRAY_SIZE(bu27034_channels); |
1487 | idev->name = "bu27034" ; |
1488 | idev->info = &bu27034_info; |
1489 | |
1490 | idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; |
1491 | idev->available_scan_masks = bu27034_scan_masks; |
1492 | |
1493 | ret = bu27034_chip_init(data); |
1494 | if (ret) |
1495 | return ret; |
1496 | |
1497 | ret = devm_iio_kfifo_buffer_setup(dev, idev, &bu27034_buffer_ops); |
1498 | if (ret) |
1499 | return dev_err_probe(dev, err: ret, fmt: "buffer setup failed\n" ); |
1500 | |
1501 | ret = devm_iio_device_register(dev, idev); |
1502 | if (ret < 0) |
1503 | return dev_err_probe(dev, err: ret, |
1504 | fmt: "Unable to register iio device\n" ); |
1505 | |
1506 | return ret; |
1507 | } |
1508 | |
1509 | static const struct of_device_id bu27034_of_match[] = { |
1510 | { .compatible = "rohm,bu27034" }, |
1511 | { } |
1512 | }; |
1513 | MODULE_DEVICE_TABLE(of, bu27034_of_match); |
1514 | |
1515 | static struct i2c_driver bu27034_i2c_driver = { |
1516 | .driver = { |
1517 | .name = "bu27034-als" , |
1518 | .of_match_table = bu27034_of_match, |
1519 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
1520 | }, |
1521 | .probe = bu27034_probe, |
1522 | }; |
1523 | module_i2c_driver(bu27034_i2c_driver); |
1524 | |
1525 | MODULE_LICENSE("GPL" ); |
1526 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>" ); |
1527 | MODULE_DESCRIPTION("ROHM BU27034 ambient light sensor driver" ); |
1528 | MODULE_IMPORT_NS(IIO_GTS_HELPER); |
1529 | |