On Mon, 6 Mar 2023 11:23:50 +0200
Matti Vaittinen <mazziesaccount@xxxxxxxxx> wrote:
ROHM BU27034 is an ambient light sensor with 3 channels and 3 photo diodes
capable of detecting a very wide range of illuminance. Typical application
is adjusting LCD and backlight power of TVs and mobile phones.
Add initial support for the ROHM BU27034 ambient light sensor.
NOTE:
- Driver exposes 4 channels. One IIO_LIGHT channel providing the
calculated lux values based on measured data from diodes #0 and
#1. In addition, 3 IIO_INTENSITY channels are emitting the raw
register data from all diodes for more intense user-space
computations.
- Sensor has GAIN values that can be adjusted from 1x to 4096x.
- Sensor has adjustible measurement times of 5, 55, 100, 200 and
400 mS. Driver does not support 5 mS which has special
limitations.
- Driver exposes standard 'scale' adjustment which is
implemented by:
1) Trying to adjust only the GAIN
2) If GAIN adjustment alone can't provide requested
scale, adjusting both the time and the gain is
attempted.
- Driver exposes writable INT_TIME property that can be used
for adjusting the measurement time. Time adjustment will also
cause the driver to try to adjust the GAIN so that the
overall scale is kept as close to the original as possible.
Signed-off-by: Matti Vaittinen <mazziesaccount@xxxxxxxxx>
---
Please note: There are few "unfinished" discussions regarding at least:
- PROCESSED channel scale.
Hopefully the reply in the other thread covered this.
It's not PROCESSED as you need to apply the * 1000 so just
make it _RAW.
- Implementation details when avoiding division by zero.
I have implemented those for this version in a way that I see the best.
It would have been better to wait for discussions to finish - but I will
be away from the computer for a week - so I wanted to send out the v3
with fixes so that people who are interested can do a review while I am
away.
I'm getting behind with review anyway so a week delay on this sounds great to
me ;) I might get to your other series as a result though don't think I'll get there today.
+static int bu27034_calc_mlux(struct bu27034_data *data, __le16 *res, int *val)
+{
+ unsigned int gain0, gain1, meastime;
+ unsigned int d1_d0_ratio_scaled;
+ u16 ch0, ch1;
+ u64 helper64;
+ int ret;
+
+ /*
+ * We return 0 luxes if calculation fails. This should be reasonably
+ * easy to spot from the buffers especially if raw-data channels show
+ * valid values
+ */
+ *val = 0;
+
+ /* Avoid div by zero. */
+ if (!res[0])
+ ch0 = 1;
+ else
+ ch0 = le16_to_cpu(res[0]);
+
+ if (!res[1])
+ ch1 = 1;
+ else
+ ch1 = le16_to_cpu(res[1]);
+
As per other thread. Really don't like the check on 0 before
the endian conversion. Sure it can be done, but it's a micro optimization that
seems unnecessary.
...
+
+static int bu27034_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct bu27034_data *data = iio_priv(idev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = bu27034_get_int_time(data);
+ if (*val < 0)
+ return *val;
+
+ /*
+ * We use 50000 uS internally for all calculations and only
+ * convert it to 55000 before returning it to the user.
+ *
+ * This is because the data-sheet says the time is 55 mS - but
+ * vendor provided computations used 50 mS.
No chance of a clarification? would be lovely to not do this!
+ */
+ if (*val == 50000)
+ *val = 55000;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ return bu27034_get_scale(data, chan->channel, val, val2);
+
+ case IIO_CHAN_INFO_RAW:
+ {
+ if (chan->type != IIO_INTENSITY)
+ return -EINVAL;
+
+ if (chan->channel < BU27034_CHAN_DATA0 ||
+ chan->channel > BU27034_CHAN_DATA2)
+ return -EINVAL;
+
+ /* Don't mess with measurement enabling while buffering */
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->mutex);
+ /*
+ * Reading one channel at a time is ineffiecient but we don't
spell check comments.
+ * care here. Buffered version should be used if performance is
+ * an issue.
+ */
+ ret = bu27034_get_single_result(data, chan->channel, val);
+
+ mutex_unlock(&data->mutex);
+ iio_device_release_direct_mode(idev);
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+
+ case IIO_CHAN_INFO_PROCESSED:
+ if (chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ /* Don't mess with measurement enabling while buffering */
+ ret = iio_device_claim_direct_mode(idev);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->mutex);
+
+ ret = bu27034_get_mlux(data, val);
+
+ mutex_unlock(&data->mutex);
+ iio_device_release_direct_mode(idev);
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+
+ }
+
+ return ret;
I would hope you can't get here. If you can fix that so
that the lack of return here allows the compiler to know you didn't
intend to get here and hence complain about it.
+static int bu27034_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct bu27034_data *data;
+ struct regmap *regmap;
+ struct iio_dev *idev;
+ unsigned int part_id, reg;
+ int ret;
+
+ regmap = devm_regmap_init_i2c(i2c, &bu27034_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ idev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!idev)
+ return -ENOMEM;
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret && ret != -ENODEV)
Why the special -ENODEV handling?
You should get a stub regulator if one isn't provided by firmware.
If you don't get a stub, or a real regulator that's a failure so we should
return the error code and fail the probe.