• Home
  • Raw
  • Download

Lines Matching +full:sensor +full:- +full:gain

1 // SPDX-License-Identifier: GPL-2.0-only
3 * BU27034 ROHM Ambient Light Sensor
6 * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf
21 #include <linux/iio/iio-gts-helper.h>
55 * inevitable even if the sensor clock would be perfectly phase-locked to CPU
56 * clock - which we can't say is the case.
59 * risk of losing a sample because things can in a rainy-day scenario be
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
100 * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS
101 * Time impacts to gain: 1x, 2x, 4x, 8x.
103 * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768
105 * Using NANO precision for scale we must use scale 64x corresponding gain 1x
110 /* See the data sheet for the "Gain Setting" table */
122 /* Available gain settings */
138 * the data collection to data0-channel only and cuts the supported range to
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).
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.
212 * Protect gain and time during scale adjustment and data reading.
292 ret = regmap_read(data->regmap, reg[chan], &val); in bu27034_get_gain_sel()
302 ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL2, &val); in bu27034_get_gain_sel()
307 * The data2 channel gain is composed by 5 non continuous bits in bu27034_get_gain_sel()
308 * [7:6], [2:0]. Thus when we combine the 5-bit 'selector' in bu27034_get_gain_sel()
315 return -EINVAL; in bu27034_get_gain_sel()
319 static int bu27034_get_gain(struct bu27034_data *data, int chan, int *gain) in bu27034_get_gain() argument
329 ret = iio_gts_find_gain_by_sel(&data->gts, sel); in bu27034_get_gain()
331 dev_err(data->dev, "chan %u: unknown gain value 0x%x\n", chan, in bu27034_get_gain()
337 *gain = ret; in bu27034_get_gain()
346 ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &sel); in bu27034_get_int_time()
350 return iio_gts_find_int_time_by_sel(&data->gts, in bu27034_get_int_time()
357 int gain, ret; in _bu27034_get_scale() local
359 ret = bu27034_get_gain(data, channel, &gain); in _bu27034_get_scale()
367 return iio_gts_get_scale(&data->gts, gain, ret, val, val2); in _bu27034_get_scale()
381 mutex_lock(&data->mutex); in bu27034_get_scale()
383 mutex_unlock(&data->mutex); in bu27034_get_scale()
400 return -EINVAL; in bu27034_write_gain_sel()
408 * We keep the same gain for channel 2 as we set for channel 0 in bu27034_write_gain_sel()
416 * gain changed when chan 0 gain is changed. in bu27034_write_gain_sel()
419 * channel 2 to be used in any generic cases - the intensity in bu27034_write_gain_sel()
420 * values provided by the sensor for IR area are not openly in bu27034_write_gain_sel()
424 * channel 2 - then it is probably specifically targeted to this in bu27034_write_gain_sel()
425 * sensor and knows how to utilize those values. It is safe to in bu27034_write_gain_sel()
426 * hope such user can also cope with the gain changes. in bu27034_write_gain_sel()
431 * The D2 gain bits are directly the lowest bits of selector. in bu27034_write_gain_sel()
437 return regmap_update_bits(data->regmap, reg[chan], mask, val); in bu27034_write_gain_sel()
440 static int bu27034_set_gain(struct bu27034_data *data, int chan, int gain) in bu27034_set_gain() argument
445 * We don't allow setting channel 2 gain as it messes up the in bu27034_set_gain()
446 * gain for channel 0 - which shares the high bits in bu27034_set_gain()
449 return -EINVAL; in bu27034_set_gain()
451 ret = iio_gts_find_sel_by_gain(&data->gts, gain); in bu27034_set_gain()
458 /* Caller should hold the lock to protect data->int_time */
463 ret = iio_gts_find_sel_by_int_time(&data->gts, time); in bu27034_set_int_time()
467 return regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, in bu27034_set_int_time()
473 * given channels by adjusting gain so that it compensates the time change.
484 mutex_lock(&data->mutex); in bu27034_try_set_int_time()
491 if (!iio_gts_valid_time(&data->gts, time_us)) { in bu27034_try_set_int_time()
492 dev_err(data->dev, "Unsupported integration time %u\n", in bu27034_try_set_int_time()
494 ret = -EINVAL; in bu27034_try_set_int_time()
509 ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, in bu27034_try_set_int_time()
518 dev_dbg(data->dev, in bu27034_try_set_int_time()
527 * can't support the scale - then the caller should be in bu27034_try_set_int_time()
531 ret = iio_find_closest_gain_low(&data->gts, in bu27034_try_set_int_time()
535 dev_dbg(data->dev, in bu27034_try_set_int_time()
536 "optimal gain out of range for chan %u\n", in bu27034_try_set_int_time()
540 dev_dbg(data->dev, in bu27034_try_set_int_time()
541 "Total gain increase. Risk of saturation"); in bu27034_try_set_int_time()
542 ret = iio_gts_get_min_gain(&data->gts); in bu27034_try_set_int_time()
546 dev_dbg(data->dev, "chan %u scale changed\n", in bu27034_try_set_int_time()
549 dev_dbg(data->dev, "chan %u new gain %u\n", in bu27034_try_set_int_time()
563 mutex_unlock(&data->mutex); in bu27034_try_set_int_time()
575 return -EINVAL; in bu27034_set_scale()
581 return -EINVAL; in bu27034_set_scale()
584 mutex_lock(&data->mutex); in bu27034_set_scale()
585 ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel); in bu27034_set_scale()
589 ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel, in bu27034_set_scale()
596 struct bu27034_gain_check gain; in bu27034_set_scale() local
602 * gets the same gain as chan0, so we only need to explicitly in bu27034_set_scale()
606 gain.chan = BU27034_CHAN_DATA1; in bu27034_set_scale()
608 gain.chan = BU27034_CHAN_DATA0; in bu27034_set_scale()
610 ret = bu27034_get_gain(data, gain.chan, &gain.old_gain); in bu27034_set_scale()
619 for (i = 0; i < data->gts.num_itime; i++) { in bu27034_set_scale()
620 new_time_sel = data->gts.itime_table[i].sel; in bu27034_set_scale()
627 &data->gts, new_time_sel, val, val2, in bu27034_set_scale()
634 &data->gts, gain.old_gain, time_sel, in bu27034_set_scale()
635 new_time_sel, &gain.new_gain); in bu27034_set_scale()
637 /* Yes - we found suitable time */ in bu27034_set_scale()
643 dev_dbg(data->dev, in bu27034_set_scale()
645 ret = -EINVAL; in bu27034_set_scale()
650 ret = bu27034_set_gain(data, gain.chan, gain.new_gain); in bu27034_set_scale()
654 ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1, in bu27034_set_scale()
662 mutex_unlock(&data->mutex); in bu27034_set_scale()
669 * lx = 0.004521097 * D1 - 0.002663996 * D0 +
672 * => 115.7400832 * ch1 / gain1 / mt -
687 * lx = (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) /
689 * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0) /
693 * => (115.7400832 * ch1 / gain1 - 68.1982976 * ch0 / gain0 +
700 * 100 * ch1 / gain1 / mt) * ((D1/D0 - 0.87) * (0.385) + 1)
702 * ((D1/D0 - 0.87) * (0.385) + 1)
704 * (0.385 * D1/D0 - 0.66505)
706 * (0.385 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) - 0.66505)
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)
725 * 100 * ch1 / gain1 / mt) * (-0.05D1/D0 + 1.1)
727 * (-0.05 * 256 * 100 * ch1 / gain1 / mt / (256 * 100 * ch0 / gain0 / mt) + 1.1)
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)
732 * + 0.90624 * ch1 * -1280 * ch1 *gain0 * mt / (gain1 * mt *gain1 * mt * 25600 * ch0)
734 * => -43614.208 * ch1 / (gain1 * mt * 25600)
736 * - 1159.9872 * ch1 * ch1 * gain0 / (gain1 * gain1 * mt * 25600 * ch0)
739 * - 0.045312 * ch1 * ch1 * gain0 / (gain1 * gain1 * ch0)
740 * - 0.706816 * ch1 / gain1
749 * -68.1982976 * ch0 / gain0
760 * => [-0.045312 * ch1 * ch1 * gain0 / (ch0 * gain1 * gain1) +
761 * -0.706816 * ch1 / gain1 +
775 * C = -68.1982976
783 * A = -0.045312
784 * B = -0.706816
796 static inline u64 gain_mul_div_helper(u64 val, unsigned int gain, in gain_mul_div_helper() argument
800 * Max gain for a channel is 4096. The max u64 (0xffffffffffffffffULL) in gain_mul_div_helper()
803 * with the gain, no matter what gain is set. in gain_mul_div_helper()
805 * So, multiplication with max gain may overflow if val is greater than in gain_mul_div_helper()
811 val *= gain; in gain_mul_div_helper()
815 val *= gain; in gain_mul_div_helper()
851 * multiply with gain0 only after the divisions - even though in bu27034_fixp_calc_t1()
870 unsigned int gain) in bu27034_fixp_calc_t23() argument
876 return helper / gain; in bu27034_fixp_calc_t23()
879 do_div(helper64, gain); in bu27034_fixp_calc_t23()
892 .C = 681982976, /* -68.1982976 */ in bu27034_fixp_calc_lx()
900 .A = 453120, /* -0.045312 */ in bu27034_fixp_calc_lx()
901 .B = 7068160, /* -0.706816 */ in bu27034_fixp_calc_lx()
911 return -EINVAL; in bu27034_fixp_calc_lx()
913 terms[0] = bu27034_fixp_calc_t1(c->A, ch0, ch1, gain0, gain1); in bu27034_fixp_calc_lx()
914 terms[1] = bu27034_fixp_calc_t23(c->B, ch1, gain1); in bu27034_fixp_calc_lx()
915 terms[2] = bu27034_fixp_calc_t23(c->C, ch0, gain0); in bu27034_fixp_calc_lx()
919 if (!c->is_neg[i]) in bu27034_fixp_calc_lx()
928 if (c->is_neg[i]) { in bu27034_fixp_calc_lx()
930 * If the negative term is greater than positive - then in bu27034_fixp_calc_lx()
937 res -= terms[i]; in bu27034_fixp_calc_lx()
950 ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL4, &val); in bu27034_has_valid_sample()
952 dev_err(data->dev, "Read failed %d\n", ret); in bu27034_has_valid_sample()
962 * any gain / integration time configuration registers) The bit gets
981 ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, in bu27034_read_result()
987 ret = regmap_bulk_read(data->regmap, reg[chan], &val, sizeof(val)); in bu27034_read_result()
1002 /* Get new value from sensor if data is ready */ in bu27034_get_result_unlocked()
1004 ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO, in bu27034_get_result_unlocked()
1011 /* No new data in sensor. Wait and retry */ in bu27034_get_result_unlocked()
1015 dev_err(data->dev, "No data from sensor\n"); in bu27034_get_result_unlocked()
1017 return -ETIMEDOUT; in bu27034_get_result_unlocked()
1031 return regmap_set_bits(data->regmap, BU27034_REG_MODE_CONTROL4, in bu27034_meas_set()
1034 return regmap_clear_bits(data->regmap, BU27034_REG_MODE_CONTROL4, in bu27034_meas_set()
1044 return -EINVAL; in bu27034_get_single_result()
1069 * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 3.45 + 1)
1071 * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 0.385 + 1)
1073 * lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 2) * -0.05 + 1)
1090 * easy to spot from the buffers especially if raw-data channels show in bu27034_calc_mlux()
1159 dev_err(data->dev, "failed to disable measurement\n"); in bu27034_get_mlux()
1181 return bu27034_get_scale(data, chan->channel, val, val2); in bu27034_read_raw()
1187 if (chan->type == IIO_INTENSITY) in bu27034_read_raw()
1189 else if (chan->type == IIO_LIGHT) in bu27034_read_raw()
1192 return -EINVAL; in bu27034_read_raw()
1199 mutex_lock(&data->mutex); in bu27034_read_raw()
1205 ret = result_get(data, chan->channel, val); in bu27034_read_raw()
1207 mutex_unlock(&data->mutex); in bu27034_read_raw()
1216 return -EINVAL; in bu27034_read_raw()
1231 return -EINVAL; in bu27034_write_raw_get_fmt()
1248 ret = bu27034_set_scale(data, chan->channel, val, val2); in bu27034_write_raw()
1254 ret = -EINVAL; in bu27034_write_raw()
1257 ret = -EINVAL; in bu27034_write_raw()
1274 return iio_gts_avail_times(&data->gts, vals, type, length); in bu27034_read_avail()
1276 return iio_gts_all_avail_scales(&data->gts, vals, type, length); in bu27034_read_avail()
1278 return -EINVAL; in bu27034_read_avail()
1294 ret = regmap_write_bits(data->regmap, BU27034_REG_SYSTEM_CONTROL, in bu27034_chip_init()
1297 return dev_err_probe(data->dev, ret, "Sensor reset failed\n"); in bu27034_chip_init()
1301 ret = regmap_reinit_cache(data->regmap, &bu27034_regmap); in bu27034_chip_init()
1303 dev_err(data->dev, "Failed to reinit reg cache\n"); in bu27034_chip_init()
1309 * this to speed-up the int-time acquisition in the start of the buffer in bu27034_chip_init()
1314 ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &sel); in bu27034_chip_init()
1316 dev_err(data->dev, "reading integration time failed\n"); in bu27034_chip_init()
1325 ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4, in bu27034_wait_for_data()
1330 dev_err(data->dev, "data polling %s\n", in bu27034_wait_for_data()
1336 ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO, in bu27034_wait_for_data()
1337 &data->scan.channels[0], in bu27034_wait_for_data()
1338 sizeof(data->scan.channels)); in bu27034_wait_for_data()
1358 wait_ms -= BU27034_MEAS_WAIT_PREMATURE_MS; in bu27034_buffer_thread()
1371 if (test_bit(BU27034_CHAN_ALS, idev->active_scan_mask)) { in bu27034_buffer_thread()
1374 ret = bu27034_calc_mlux(data, &data->scan.channels[0], in bu27034_buffer_thread()
1377 dev_err(data->dev, "failed to calculate lux\n"); in bu27034_buffer_thread()
1380 * The maximum Milli lux value we get with gain 1x time in bu27034_buffer_thread()
1385 data->scan.mlux = (u32)mlux; in bu27034_buffer_thread()
1387 iio_push_to_buffers_with_timestamp(idev, &data->scan, tstamp); in bu27034_buffer_thread()
1399 mutex_lock(&data->mutex); in bu27034_buffer_enable()
1405 "bu27034-buffering-%u", in bu27034_buffer_enable()
1412 data->task = task; in bu27034_buffer_enable()
1415 mutex_unlock(&data->mutex); in bu27034_buffer_enable()
1425 mutex_lock(&data->mutex); in bu27034_buffer_disable()
1426 if (data->task) { in bu27034_buffer_disable()
1427 kthread_stop(data->task); in bu27034_buffer_disable()
1428 data->task = NULL; in bu27034_buffer_disable()
1432 mutex_unlock(&data->mutex); in bu27034_buffer_disable()
1444 struct device *dev = &i2c->dev; in bu27034_probe()
1458 return -ENOMEM; in bu27034_probe()
1468 return dev_err_probe(dev, ret, "Failed to access sensor\n"); in bu27034_probe()
1477 ARRAY_SIZE(bu27034_itimes), &data->gts); in bu27034_probe()
1481 mutex_init(&data->mutex); in bu27034_probe()
1482 data->regmap = regmap; in bu27034_probe()
1483 data->dev = dev; in bu27034_probe()
1485 idev->channels = bu27034_channels; in bu27034_probe()
1486 idev->num_channels = ARRAY_SIZE(bu27034_channels); in bu27034_probe()
1487 idev->name = "bu27034"; in bu27034_probe()
1488 idev->info = &bu27034_info; in bu27034_probe()
1490 idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; in bu27034_probe()
1491 idev->available_scan_masks = bu27034_scan_masks; in bu27034_probe()
1517 .name = "bu27034-als",
1527 MODULE_DESCRIPTION("ROHM BU27034 ambient light sensor driver");