Skip to contentSkip to conversation

Support ROHM BU27034 ALS sensor

PATCH Superseded Matti Vaittinen 4 participants 36 messages Mar 2, 2023 – Mar 19, 2023

Subsystems (4)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore

Matti Vaittinen

author maintainer
#0 lore raw

v2 cover Support ROHM BU27034 ALS sensor

Support ROHM BU27034 ALS sensor

This series adds support for ROHM BU27034 Ambient Light Sensor.

The BU27034 has configurable gain and measurement (integration) time settings. Both of these have inversely proportional relation to the sensor's intensity channel scale.

Many users only set the scale, which means that many drivers attempt to 'guess' the best gain+time combination to meet the scale. Usually this is the biggest integration time which allows setting the requested scale. Typically, increasing the integration time has better accuracy than increasing the gain, which often amplifies the noise as well as the real signal.

However, there may be cases where more responsive sensors are needed. So, in some cases the longest integration times may not be what the user prefers. The driver has no way of knowing this.

Hence, the approach taken by this series is to allow user to set both the scale and the integration time with following logic:

1. When scale is set, the existing integration time is tried to be maintained as a first priority.
1a) If the requested scale can't be met by current time, then also
other time + gain combinations are searched. If scale can be met by some other integration time, then the new time may be applied. If the time setting is common for all channels, then also other channels must be able to maintain their scale with this new time (by changing their gain). The new times are scanned in the order of preference (typically the longest times first).
1b) If the requested scale can be met using current time, then only
the gain for the channel is changed.

2. When the integration time change - scale is tried to be maintained. When integration time change is requested also gain for all impacted channels is adjusted so that the scale is not changed, or is chaned as little as possible. This is different from the RFCv1 where the request was rejected if suitable gain couldn't be found for some channel(s).

This logic is simple. When total gain (either caused by time or hw-gain) is doubled, the scale gets halved. Also, the supported times are given a 'multiplier' value which tells how much they increase the total gain.

However, when I wrote this logic in bu27034 driver, I made quite a few errors on the way - and driver got pretty big. As I am writing drivers for two other sensors (RGB C/IR + flicker BU27010 and RGB C/IR BU27008) with similar gain-time-scale logic I thought that adding common helpers for these computations might be wise. I hope this way all the bugs will be concentrated in one place and not in every individual driver ;)

Hence, this series also intriduces IIO gain-time-scale helpers (abbreviated as gts-helpers) + a couple of KUnit tests for the most hairy parts.

I can't help thinking that there should've been simpler way of computing the gain-time-scale conversions. Also, pretty good speed improvements might be available if some of the do_div()s could be replaced by >>. This, however, is not a priority for my light-sensor use-case where speed demands are not that big.

Finally, these added helpers do provide some value also for drivers which only:
a) allow gain change
or
b) allow changing both the time and gain but so that the time-change is not reflected in register values.

For a) we provide the gain - selector (register value) table format + selector to gain look-ups, gain <-> scale conversions and the available scales helpers.

For latter case we also provide the time-tables, and actually all the APIs should be usable by setting the time multiplier to 1. (not testeted thoroughly though).

Revision history:
RFCv1 => v2:
dt-bindings:
- Fix binding file name and id by using comma instead of a hyphen to separate the vendor and part names.
gts-helpers:
- fix include guardian
- Improve kernel doc for iio_init_iio_gts.
- Add iio_gts_scale_to_total_gain
- Add iio_gts_total_gain_to_scale
- Fix review comments from Jonathan
- add documentation to few functions
- replace 0xffffffffffffffffLLU by U64_MAX
- some styling fixes
- drop unnecessary NULL checks
- order function arguments by in / out purpose
- drop GAIN_SCALE_ITIME_MS()
- Add helpers for available scales and times
- Rename to iio-gts-helpers
gts-tests:
- add tests for available scales/times helpers
- adapt to renamed iio-gts-helpers.h header
bu27034-driver:
- (really) protect read-only registers
- fix get and set gain
- buffered mode
- Protect the whole sequences including meas_en/meas_dis to avoid messing up the enable / disable order
- typofixes / doc improvements
- change dropped GAIN_SCALE_ITIME_MS() to GAIN_SCALE_ITIME_US()
- use more accurate scale for lux channel (milli lux)
- provide available scales / integration times (using helpers).
- adapt to renamed iio-gts-helpers.h file
- bu27034 - longer lines in Kconfig
- Drop bu27034_meas_en and bu27034_meas_dis wrappers.
- Change device-name from bu27034-als to bu27034
MAINTAINERS:
- Add iio-list

---

Matti Vaittinen (6):
dt-bindings: iio: light: Support ROHM BU27034
iio: light: Add gain-time-scale helpers
iio: test: test gain-time-scale helpers
MAINTAINERS: Add IIO gain-time-scale helpers
iio: light: ROHM BU27034 Ambient Light Sensor
MAINTAINERS: Add ROHM BU27034

 .../bindings/iio/light/rohm,bu27034.yaml      |   46 +
 MAINTAINERS                                   |   14 +
 drivers/iio/light/Kconfig                     |   15 +
 drivers/iio/light/Makefile                    |    2 +
 drivers/iio/light/iio-gts-helper.c            | 1152 +++++++++++++
 drivers/iio/light/iio-gts-helper.h            |  130 ++
 drivers/iio/light/rohm-bu27034.c              | 1491 +++++++++++++++++
 drivers/iio/test/Kconfig                      |   15 +
 drivers/iio/test/Makefile                     |    1 +
 drivers/iio/test/iio-test-gts.c               |  537 ++++++
 10 files changed, 3403 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml
 create mode 100644 drivers/iio/light/iio-gts-helper.c
 create mode 100644 drivers/iio/light/iio-gts-helper.h
 create mode 100644 drivers/iio/light/rohm-bu27034.c
 create mode 100644 drivers/iio/test/iio-test-gts.c

base-commit: c9c3395d5e3dcc6daee66c6908354d47bf98cb0c

Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
author maintainer
#1 lore raw

PATCH v2 1/6 dt-bindings: iio: light: Support ROHM BU27034

ROHM BU27034 is an ambient light sesnor 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 dt-bindings.

---

Changes since RFCv1:
- Fix binding file name and id by using comma instead of a hyphen to separate the vendor and part names.

---
 .../bindings/iio/light/rohm,bu27034.yaml      | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml
Documentation/devicetree/bindings/iio/light/rohm,bu27034.yaml new file +46 -0
new file mode 100644
index 000000000000..30a109a1bf3b
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/rohm,bu27034.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BU27034 ambient light sensor
+
+maintainers:
+  - Matti Vaittinen <[email protected]>
+
+description: |
+  ROHM BU27034 is an ambient light sesnor 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.
+  https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/light/bu27034nuc-e.pdf
+
+properties:
+  compatible:
+    const: rohm,bu27034
+
+  reg:
+    maxItems: 1
+
+  vdd-supply: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      light-sensor@38 {
+        compatible = "rohm,bu27034";
+        reg = <0x38>;
+        vdd-supply = <&vdd>;
+      };
+    };
+
+...
Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
author maintainer
#2 lore raw

PATCH v2 2/6 iio: light: Add gain-time-scale helpers

In reply to Matti Vaittinen

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once.

Add some gain-time-scale helpers in order to not dublicate errors in all drivers needing these computations.

---
Currently it is only BU27034 using these in this series. I am however working with drivers for RGB sensors BU27008 and BU27010 which have similar [gain - integration time - scale] - relation. I hope sending those follows soon after the BU27034 is done.

Changes since RFCv1:
- fix include guardian
- Improve kernel doc for iio_init_iio_gts.
- Add iio_gts_scale_to_total_gain
- Add iio_gts_total_gain_to_scale
- Fix review comments from Jonathan
- add documentation to few functions
- replace 0xffffffffffffffffLLU by U64_MAX
- some styling fixes
- drop unnecessary NULL checks
- order function arguments by in / out purpose
- drop GAIN_SCALE_ITIME_MS()
- Add helpers for available scales and times
- Rename to iio-gts-helpers

---
 drivers/iio/light/Kconfig          |    3 +
 drivers/iio/light/Makefile         |    1 +
 drivers/iio/light/iio-gts-helper.c | 1152 ++++++++++++++++++++++++++++
 drivers/iio/light/iio-gts-helper.h |  130 ++++
 4 files changed, 1286 insertions(+)
 create mode 100644 drivers/iio/light/iio-gts-helper.c
 create mode 100644 drivers/iio/light/iio-gts-helper.h
drivers/iio/light/Kconfig +3 -0
index 0d4447df7200..671d84f98c56 100644
@@ -183,6 +183,9 @@ config IIO_CROS_EC_LIGHT_PROX
 	  To compile this driver as a module, choose M here:
 	  the module will be called cros_ec_light_prox.
 
+config IIO_GTS_HELPER
+	tristate
+
 config GP2AP002
 	tristate "Sharp GP2AP002 Proximity/ALS sensor"
 	depends on I2C
drivers/iio/light/Makefile +1 -0
index 6f23817fae6f..82d14ebd3c11 100644
@@ -20,6 +20,7 @@ obj-$(CONFIG_CM3323)		+= cm3323.o
 obj-$(CONFIG_CM3605)		+= cm3605.o
 obj-$(CONFIG_CM36651)		+= cm36651.o
 obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += cros_ec_light_prox.o
+obj-$(CONFIG_IIO_GTS_HELPER)	+= iio-gts-helper.o
 obj-$(CONFIG_GP2AP002)		+= gp2ap002.o
 obj-$(CONFIG_GP2AP020A00F)	+= gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)	+= hid-sensor-als.o
drivers/iio/light/iio-gts-helper.c new file +1152 -0

1,152 lines not on this page · raw message

drivers/iio/light/iio-gts-helper.h new file +130 -0

130 lines not on this page · raw message

Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
#3 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 21 lines · Matti Vaittinen

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once.

Add some gain-time-scale helpers in order to not dublicate errors in all drivers needing these computations.

...

Quoted 1 line

+/*

Is it intentionally _not_ a kernel doc?

Quoted 3 lines

+ * iio_gts_get_gain - Convert scale to total gain

+ * Internal helper for converting scale to total gain.

Otherwise this line should go after the fields, I remember kernel doc warnings on the similar cases.

Quoted 1 line

+ * @max: Maximum linearized scale. As an example, when scale is creted in

creted?

IIRC I already pointed out to the very same mistake in your code in the past (sorry, if my memory doesn't serve me well).

Quoted 5 lines

+ * magnitude of NANOs and max scale is 64.1 - The linearized
+ * scale is 64 100 000 000.
+ * @scale: Linearized scale to compte the gain for.
+ *
+ * Return: (floored) gain corresponding to the scales. -EINVAL if scale

scales? (Plural?)

Quoted 2 lines

+ * is invalid.
+ */

Same remark to all of the comments.

drivers/iio/light/iio-gts-helper.c line 45

Quoted 12 lines
drivers/iio/light/iio-gts-helper.c new file +11 -0
+{
+	int tmp = 1;
+
+	if (scale > max || !scale)
+		return -EINVAL;
+
+	if (U64_MAX - max < scale) {
+		/* Risk of overflow */
+		if (max - scale < scale)
+			return 1;
 
+		while (max - scale > scale * (u64) tmp)

Space is not required after casting.

drivers/iio/light/iio-gts-helper.c line 48

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			tmp++;
+
+		return tmp + 1;

Wondering why you can't simplify this to

		max -= scale;
		tmp++;

drivers/iio/light/iio-gts-helper.c line 55

Quoted 7 lines
drivers/iio/light/iio-gts-helper.c new file +7 -0
+	}
+
+	while (max > scale * (u64) tmp)
+		tmp++;
+
+	return tmp;
+}

Missing blank line.

Quoted 8 lines

+/*
+ * gain_get_scale_fraction - get the gain or time based on scale and known one
+ *
+ * Internal helper for computing unknown fraction of total gain.
+ * Compute either gain or time based on scale and either the gain or time
+ * depending on which one is known.
+ *
+ * @max: Maximum linearized scale. As an example, when scale is creted in

creted?

Is it mistakenly stored in your spellcheck database? Or is it simply copy'n'paste typo?

Quoted 8 lines

+ * magnitude of NANOs and max scale is 64.1 - The linearized
+ * scale is 64 100 000 000.
+ * @scale: Linearized scale to compute the gain/time for.
+ * @known: Either integration time or gain depending on which one is known
+ * @unknown: Pointer to variable where the computed gain/time is stored
+ *
+ * Return: 0 on success
+ */

...

drivers/iio/light/iio-gts-helper.c line 91

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+static const struct iio_itime_sel_mul *
+			iio_gts_find_itime_by_time(struct iio_gts *gts, int time)

Strange indentation.

Ditto for all these types of cases.

...

drivers/iio/light/iio-gts-helper.c line 144

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+	*lin_scale = (u64) scale_whole * (u64)scaler + (u64)(scale_nano
+		     / (NANO / scaler));

Strange indentation. Split on the logical (math) parts better.

...

Quoted 1 line

+EXPORT_SYMBOL_GPL(iio_init_iio_gts);

I haven't noticed if you put these all exports into a proper namespace. If no, please do.

...

drivers/iio/light/iio-gts-helper.c line 297

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+		sort(gains[i], gts->num_hwgain, sizeof(int), iio_gts_gain_cmp,
+		     NULL);

One line is okay.

...

drivers/iio/light/iio-gts-helper.c line 309

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	all_gains = kcalloc(gts->num_itime * gts->num_hwgain, sizeof(int),

Something from overflow.h is very suitable here.

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			    GFP_KERNEL);
+	if (!all_gains)
+		return -ENOMEM;

...

drivers/iio/light/iio-gts-helper.c line 321

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	memcpy(all_gains, gains[gts->num_itime - 1], gts->num_hwgain * sizeof(int));

Maybe it's better to have a temporary which will be calculated as array_size() for allocation and reused here?

...

drivers/iio/light/iio-gts-helper.c line 324

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 2; i >= 0; i--)

Yeah, if you put this into temporary, like

	i = gts->num_itime - 1;

this becomes

	while (i--) {

Note, you missed {} for better reading.

Note, you may re-use that i (maybe renamed to something better in the memcpy() above as well).

Quoted 22 lines
drivers/iio/light/iio-gts-helper.c new file +22 -0
+		for (j = 0; j < gts->num_hwgain; j++) {
+			int candidate = gains[i][j];
+			int chk;
+
+			if (candidate > all_gains[new_idx - 1]) {
+				all_gains[new_idx] = candidate;
+				new_idx++;
+
+				continue;
+			}
+			for (chk = 0; chk < new_idx; chk++)
+				if (candidate <= all_gains[chk])
+					break;
+
+			if (candidate == all_gains[chk])
+				continue;
+
+			memmove(&all_gains[chk + 1], &all_gains[chk],
+				(new_idx - chk) * sizeof(int));
+			all_gains[chk] = candidate;
+			new_idx++;
+		}

...

drivers/iio/light/iio-gts-helper.c line 355

Quoted 6 lines
drivers/iio/light/iio-gts-helper.c new file +6 -0
+	gts->avail_all_scales_table = kcalloc(gts->num_avail_all_scales,
+					      2 * sizeof(int), GFP_KERNEL);
+	if (!gts->avail_all_scales_table)
+		ret = -ENOMEM;
+	else
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

		if (ret)
			break;

drivers/iio/light/iio-gts-helper.c line 364

Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	kfree(all_gains);
+	if (ret && gts->avail_all_scales_table)
+		kfree(gts->avail_all_scales_table);
+
+	return ret;

But Wouldn't be better to use goto labels?

...

drivers/iio/light/iio-gts-helper.c line 423

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	while (i) {

Instead of doing standard

	while (i--) {

drivers/iio/light/iio-gts-helper.c line 427

Quoted 4 lines
drivers/iio/light/iio-gts-helper.c new file +4 -0
+		/*
+		 * It does not matter if i'th alloc was not succesfull as
+		 * kfree(NULL) is safe.
+		 */

You add this comment, ...

drivers/iio/light/iio-gts-helper.c line 429

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+		kfree(per_time_gains[i]);
+		kfree(per_time_scales[i]);

...an additional loop, ...

drivers/iio/light/iio-gts-helper.c line 431

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+
+		i--;

...and a line of code.

Review

Quoted 1 line
(quoted diff) +1 -0
+	}

Why?

drivers/iio/light/iio-gts-helper.c line 497

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 1; i >= 0; i--) {
	i = gts->num_itime;

	while (i--) {
Quoted 15 lines
drivers/iio/light/iio-gts-helper.c new file +15 -0
+		int new = gts->itime_table[i].time_us;
+
+		if (times[idx] < new) {
+			times[idx++] = new;
+			continue;
+		}
+
+		for (j = 0; j <= idx; j++) {
+			if (times[j] > new) {
+				memmove(&times[j + 1], &times[j], (idx - j) * sizeof(int));
+				times[j] = new;
+				idx++;
+			}
+		}
+	}

...

drivers/iio/light/iio-gts-helper.c line 537

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+void iio_gts_purge_avail_time_table(struct iio_gts *gts)
+{
+	if (gts->num_avail_time_tables) {
	if (!...)
		return;
Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+		kfree(gts->avail_time_tables);
+		gts->avail_time_tables = NULL;
+		gts->num_avail_time_tables = 0;
+	}
+}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

			if (diff) {
				...
			} else {
				...
			}
Quoted 10 lines
drivers/iio/light/iio-gts-helper.c new file +10 -0
+				diff = gain - gts->hwgain_table[i].gain;
+				best = i;
+			} else {
+				int tmp = gain - gts->hwgain_table[i].gain;
+
+				if (tmp < diff) {
+					diff = tmp;
+					best = i;
+				}
+			}

...

drivers/iio/light/iio-gts-helper.c line 949

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+	ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain);
 
+

Redundant blank line.

drivers/iio/light/iio-gts-helper.c line 950

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	if (ret || !iio_gts_valid_gain(gts, *gain))

Why error code is shadowed?

Quoted 2 lines
(quoted diff) +2 -0
+		return -EINVAL;
+

...

drivers/iio/light/iio-gts-helper.c line 1134

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+	ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us,
+				       &scale);

Single line if fine.

drivers/iio/light/iio-gts-helper.c line 1139

Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	if (ret)
+		return ret;
+
+	ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul,
+				      new_gain);

Ditto.

Quoted 2 lines
(quoted diff) +2 -0
+	if (ret)
+		return -EINVAL;

...

drivers/iio/light/iio-gts-helper.h line 8

Quoted 2 lines
drivers/iio/light/iio-gts-helper.h new file +2 -0
+#ifndef __GAIN_TIME_SCALE_HELPER__
+#define __GAIN_TIME_SCALE_HELPER__

__IIO_... ?

Missing types.h (at least, haven't checked for more).

Missing some forward declarations, at least for struct device.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#4 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Thanks for the review Andy,

Quoted 20 lines · Andy Shevchenko
Quoted 19 lines · Matti Vaittinen

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once.

Quoted 8 lines
Quoted 2 lines

Add some gain-time-scale helpers in order to not dublicate errors in all drivers needing these computations.

...

Quoted 1 line

+/*

Is it intentionally _not_ a kernel doc?

yes.

Quoted 7 lines
Quoted 3 lines

+ * iio_gts_get_gain - Convert scale to total gain

+ * Internal helper for converting scale to total gain.

Otherwise this line should go after the fields, I remember kernel doc warnings on the similar cases.

Quoted 6 lines
Quoted 1 line

+ * @max: Maximum linearized scale. As an example, when scale is creted in

creted?

IIRC I already pointed out to the very same mistake in your code in the past (sorry, if my memory doesn't serve me well).

I Don't think you have previously reviewed this patch.

Quoted 15 lines

drivers/iio/light/iio-gts-helper.c line 45

Quoted 12 lines
drivers/iio/light/iio-gts-helper.c new file +11 -0
+{
+	int tmp = 1;
+
+	if (scale > max || !scale)
+		return -EINVAL;
+
+	if (U64_MAX - max < scale) {
+		/* Risk of overflow */
+		if (max - scale < scale)
+			return 1;
 
+		while (max - scale > scale * (u64) tmp)

Space is not required after casting.

Quoted 9 lines

drivers/iio/light/iio-gts-helper.c line 48

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			tmp++;
+
+		return tmp + 1;

Wondering why you can't simplify this to

		max -= scale;
		tmp++;

Sorry, but I don't follow. Can you please show me the complete suggestion? Exactly what should be replaced by the:

Quoted 21 lines
		max -= scale;
		tmp++;
Quoted 6 lines
drivers/iio/light/iio-gts-helper.c new file +6 -0
+	}
+
+	while (max > scale * (u64) tmp)
+		tmp++;
+
+	return tmp;

drivers/iio/light/iio-gts-helper.c line 63

Quoted 10 lines
drivers/iio/light/iio-gts-helper.c new file +9 -0
+}
 
+/*
+ * gain_get_scale_fraction - get the gain or time based on scale and known one
+ *
+ * Internal helper for computing unknown fraction of total gain.
+ * Compute either gain or time based on scale and either the gain or time
+ * depending on which one is known.
+ *
+ * @max:	Maximum linearized scale. As an example, when scale is creted in
Quoted 4 lines

creted?

Is it mistakenly stored in your spellcheck database? Or is it simply copy'n'paste typo?

Typo.

Quoted 9 lines
Quoted 8 lines

+ * magnitude of NANOs and max scale is 64.1 - The linearized
+ * scale is 64 100 000 000.
+ * @scale: Linearized scale to compute the gain/time for.
+ * @known: Either integration time or gain depending on which one is known
+ * @unknown: Pointer to variable where the computed gain/time is stored
+ *
+ * Return: 0 on success
+ */

Quoted 4 lines
Quoted 1 line

+EXPORT_SYMBOL_GPL(iio_init_iio_gts);

I haven't noticed if you put these all exports into a proper namespace. If no, please do.

I haven't. And in many cases I actually see very little to no value in doing so as collisions are unlikely when symbols are appropriately prefixed.

Anyways, it seems the IIO uses namespaces so let's play along. Any good suggestions for a name?

Quoted 12 lines

...

drivers/iio/light/iio-gts-helper.c line 309

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	all_gains = kcalloc(gts->num_itime * gts->num_hwgain, sizeof(int),

Something from overflow.h is very suitable here.

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			    GFP_KERNEL);
+	if (!all_gains)
+		return -ENOMEM;

...

Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 321

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	memcpy(all_gains, gains[gts->num_itime - 1], gts->num_hwgain * sizeof(int));

Maybe it's better to have a temporary which will be calculated as array_size() for allocation and reused here?

Good suggestion, thanks.

Quoted 6 lines

...

drivers/iio/light/iio-gts-helper.c line 324

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 2; i >= 0; i--)

Yeah, if you put this into temporary, like

Quoted 6 lines
	i = gts->num_itime - 1;

this becomes

	while (i--) {

I prefer for(). It looks clearer to me...

Quoted 1 line

Note, you may re-use that i (maybe renamed to something better in the

memcpy()

Quoted 1 line

above as well).

...but this makes sense so Ok.

Quoted 1 line

Note, you missed {} for better reading.

Didn't miss it but left it out intentionally. {} does not help me as indentiation makes it clear. Can add one for you though.

Quoted 35 lines
Quoted 23 lines
drivers/iio/light/iio-gts-helper.c new file +22 -0
+		for (j = 0; j < gts->num_hwgain; j++) {
+			int candidate = gains[i][j];
+			int chk;
+
+			if (candidate > all_gains[new_idx - 1]) {
+				all_gains[new_idx] = candidate;
+				new_idx++;
+
+				continue;
+			}
+			for (chk = 0; chk < new_idx; chk++)
+				if (candidate <= all_gains[chk])
+					break;
+
+			if (candidate == all_gains[chk])
+				continue;
+
+			memmove(&all_gains[chk + 1], &all_gains[chk],
+				(new_idx - chk) * sizeof(int));
+			all_gains[chk] = candidate;
+			new_idx++;
+		}

...

drivers/iio/light/iio-gts-helper.c line 355

Quoted 6 lines
drivers/iio/light/iio-gts-helper.c new file +6 -0
+	gts->avail_all_scales_table = kcalloc(gts->num_avail_all_scales,
+					      2 * sizeof(int), GFP_KERNEL);
+	if (!gts->avail_all_scales_table)
+		ret = -ENOMEM;
+	else
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

Quoted 8 lines

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

Quoted 8 lines

drivers/iio/light/iio-gts-helper.c line 364

Quoted 6 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	kfree(all_gains);
+	if (ret && gts->avail_all_scales_table)
+		kfree(gts->avail_all_scales_table);
+
+	return ret;

But Wouldn't be better to use goto labels?

I don't see benefit in this case. Handling return value and goto would require brackets. The current one is much simpler for me. I am just considering dropping that 'else' which is not needed.

Quoted 15 lines

...

drivers/iio/light/iio-gts-helper.c line 423

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	while (i) {

Instead of doing standard

	while (i--) {

drivers/iio/light/iio-gts-helper.c line 427

Quoted 4 lines
drivers/iio/light/iio-gts-helper.c new file +4 -0
+		/*
+		 * It does not matter if i'th alloc was not succesfull as
+		 * kfree(NULL) is safe.
+		 */

You add this comment, ...

Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 429

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+		kfree(per_time_gains[i]);
+		kfree(per_time_scales[i]);

...an additional loop, ...

The comment is there to explain what I think you missed. We have two arrays there. We don't know whether the allocation of first one was successful so we try freeing both.

Quoted 9 lines

drivers/iio/light/iio-gts-helper.c line 431

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+
+		i--;

...and a line of code.

Review

Quoted 1 line
(quoted diff) +1 -0
+	}

Why?

Because, as the comment says, it does not matter if allocation was succesfull. kfree(NULL) is safe.

Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 497

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 1; i >= 0; i--) {
	i = gts->num_itime;

	while (i--) {

I prefer for() when initializing a variable is needed. Furthermore, having var-- or --var in a condition is less clear.

Quoted 19 lines
Quoted 16 lines
drivers/iio/light/iio-gts-helper.c new file +15 -0
+		int new = gts->itime_table[i].time_us;
+
+		if (times[idx] < new) {
+			times[idx++] = new;
+			continue;
+		}
+
+		for (j = 0; j <= idx; j++) {
+			if (times[j] > new) {
+				memmove(&times[j + 1], &times[j], (idx - j) * sizeof(int));
+				times[j] = new;
+				idx++;
+			}
+		}
+	}

...

Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 537

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+void iio_gts_purge_avail_time_table(struct iio_gts *gts)
+{
+	if (gts->num_avail_time_tables) {
	if (!...)
		return;

Does not improve this as we only have just one small conditional block of code which we either execute or not. It is clear at a glance. Would make sense if we had longer function.

Quoted 11 lines
Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+		kfree(gts->avail_time_tables);
+		gts->avail_time_tables = NULL;
+		gts->num_avail_time_tables = 0;
+	}
+}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

Quoted 20 lines
			if (diff) {
				...
			} else {
				...
			}
Quoted 10 lines
drivers/iio/light/iio-gts-helper.c new file +10 -0
+				diff = gain - gts->hwgain_table[i].gain;
+				best = i;
+			} else {
+				int tmp = gain - gts->hwgain_table[i].gain;
+
+				if (tmp < diff) {
+					diff = tmp;
+					best = i;
+				}
+			}

...

Quoted 5 lines

drivers/iio/light/iio-gts-helper.c line 949

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+	ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain);
 
+

Redundant blank line.

Thanks.

Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 950

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	if (ret || !iio_gts_valid_gain(gts, *gain))

Why error code is shadowed?

Not sure what I thought of. Could have been because -EINVAL is in any case the only error I can think of. But yes, it is better to not 'shadow' the return value from gain_get_scale_fraction(); So, thanks.

Quoted 10 lines
Quoted 3 lines
(quoted diff) +2 -0
+		return -EINVAL;
+

...

drivers/iio/light/iio-gts-helper.c line 1134

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+	ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us,
+				       &scale);

Single line if fine.

I like to (mostly) keep the 80-column limit. Helps me to fit three editor windows next to each-others on my laptop screen.

Quoted 13 lines

drivers/iio/light/iio-gts-helper.c line 1139

Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	if (ret)
+		return ret;
+
+	ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul,
+				      new_gain);

Ditto.

Quoted 2 lines
(quoted diff) +2 -0
+	if (ret)
+		return -EINVAL;

...

Quoted 4 lines

drivers/iio/light/iio-gts-helper.h line 8

Quoted 2 lines
drivers/iio/light/iio-gts-helper.h new file +2 -0
+#ifndef __GAIN_TIME_SCALE_HELPER__
+#define __GAIN_TIME_SCALE_HELPER__

__IIO_... ?

Well spotted. Thanks. I renamed the file and forgot the old guardian.

By the way, I will be online only occasionally during the next week. So please don't think I ignore reviews if you don't hear of me.

Best Regards,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#5 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 21 lines
Quoted 21 lines

drivers/iio/light/iio-gts-helper.c line 45

Quoted 12 lines
drivers/iio/light/iio-gts-helper.c new file +11 -0
+{
+	int tmp = 1;
+
+	if (scale > max || !scale)
+		return -EINVAL;
+
+	if (U64_MAX - max < scale) {
+		/* Risk of overflow */
+		if (max - scale < scale)
+			return 1;
 
+		while (max - scale > scale * (u64) tmp)

Space is not required after casting.

drivers/iio/light/iio-gts-helper.c line 48

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			tmp++;
+
+		return tmp + 1;

Wondering why you can't simplify this to

Quoted 6 lines
Quoted 3 lines
		max -= scale;
		tmp++;

Sorry, but I don't follow. Can you please show me the complete suggestion? Exactly what should be replaced by the:

I don't understand. Do you see the blank lines I specifically added to show the piece of the code I'm commenting on?

For your convenience, the while loop and return statement may be replaced with two simple assignments.

Quoted 10 lines
Quoted 10 lines
		max -= scale;
		tmp++;
Quoted 7 lines
drivers/iio/light/iio-gts-helper.c new file +7 -0
+	}
+
+	while (max > scale * (u64) tmp)
+		tmp++;
+
+	return tmp;
+}

...

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

+EXPORT_SYMBOL_GPL(iio_init_iio_gts);

I haven't noticed if you put these all exports into a proper namespace. If no, please do.

I haven't. And in many cases I actually see very little to no value in doing so as collisions are unlikely when symbols are appropriately prefixed.

This is a benefit of not polluting (global) namespace with something that is rarely used. Please, try to utilize namespaces more in your nice kernel contribution (there is *no* sarcasm).

Quoted 2 lines

Anyways, it seems the IIO uses namespaces so let's play along. Any good suggestions for a name?

IIO_GTS ?

...

Quoted 4 lines
Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 324

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 2; i >= 0; i--)

Yeah, if you put this into temporary, like

Quoted 8 lines
Quoted 6 lines
	i = gts->num_itime - 1;

this becomes

	while (i--) {

I prefer for(). It looks clearer to me...

It has too many characters to parse. That's why I prefer while. Are we going to have principle disagreement on this one?

Quoted 5 lines
Quoted 1 line

Note, you may re-use that i (maybe renamed to something better in the

memcpy()

Quoted 1 line

above as well).

...but this makes sense so Ok.

...

Quoted 4 lines
Quoted 1 line

Note, you missed {} for better reading.

Didn't miss it but left it out intentionally. {} does not help me as indentiation makes it clear. Can add one for you though.

Not for me. For other people who would read 1+ screen long for-loop body (not everybody has 120+ lines of terminal.

...

Quoted 10 lines
Quoted 10 lines

drivers/iio/light/iio-gts-helper.c line 355

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

Quoted 5 lines
Quoted 2 lines
		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

It moves it to the regular pattern. Yours is not so distributed in the kernel.

...

Quoted 11 lines
Quoted 7 lines

drivers/iio/light/iio-gts-helper.c line 364

Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	kfree(all_gains);
+	if (ret && gts->avail_all_scales_table)
+		kfree(gts->avail_all_scales_table);
+
+	return ret;

But Wouldn't be better to use goto labels?

I don't see benefit in this case. Handling return value and goto would require brackets. The current one is much simpler for me. I am just considering dropping that 'else' which is not needed.

At least it would be consistent with the very same file style in another function. So, why there do you goto, and not here where it makes sense to me?

...

Quoted 28 lines
Quoted 13 lines

drivers/iio/light/iio-gts-helper.c line 423

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	while (i) {

Instead of doing standard

	while (i--) {

drivers/iio/light/iio-gts-helper.c line 427

Quoted 4 lines
drivers/iio/light/iio-gts-helper.c new file +4 -0
+		/*
+		 * It does not matter if i'th alloc was not succesfull as
+		 * kfree(NULL) is safe.
+		 */

You add this comment, ...

Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 429

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+		kfree(per_time_gains[i]);
+		kfree(per_time_scales[i]);

...an additional loop, ...

The comment is there to explain what I think you missed. We have two arrays there. We don't know whether the allocation of first one was successful so we try freeing both.

Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 431

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+
+		i--;

...and a line of code.

Quoted 6 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	}

Why?

Because, as the comment says, it does not matter if allocation was succesfull. kfree(NULL) is safe.

Wouldn't be better to avoid no-op kfree() by explicitly putting the call before hands?

	kfree(...[i]);
	while (i--) {
		...
	}

?

Much better to understand than what you wrote. I have to read comment on top of the code, with my proposal comment won't be needed.

...

Quoted 8 lines
Quoted 5 lines

drivers/iio/light/iio-gts-helper.c line 497

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 1; i >= 0; i--) {
	i = gts->num_itime;

	while (i--) {

I prefer for() when initializing a variable is needed. Furthermore, having var-- or --var in a condition is less clear.

	while (x--)

_is_ a pattern for cleaning up something. Your for-loop has a lot of additional (unnecessary) code lines that makes it harder to understand (by the people who are not familiar with the pattern).

Quoted 1 line
Quoted 1 line
Quoted 1 line
(quoted diff) +1 -0
+	}

...

Quoted 10 lines
Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 537

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+void iio_gts_purge_avail_time_table(struct iio_gts *gts)
+{
+	if (gts->num_avail_time_tables) {
	if (!...)
		return;

Does not improve this as we only have just one small conditional block of code which we either execute or not. It is clear at a glance. Would make sense if we had longer function.

I believe it makes sense to have like this even for this long function(s).

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+		kfree(gts->avail_time_tables);
+		gts->avail_time_tables = NULL;
+		gts->num_avail_time_tables = 0;
+	}
+}

...

Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Quoted 11 lines
Quoted 11 lines
			if (diff) {
				...
			} else {
				...
			}
Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+			} else {
 
+			}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#6 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 31 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 25 lines
Quoted 24 lines

drivers/iio/light/iio-gts-helper.c line 45

Quoted 12 lines
drivers/iio/light/iio-gts-helper.c new file +11 -0
+{
+	int tmp = 1;
+
+	if (scale > max || !scale)
+		return -EINVAL;
+
+	if (U64_MAX - max < scale) {
+		/* Risk of overflow */
+		if (max - scale < scale)
+			return 1;
 
+		while (max - scale > scale * (u64) tmp)

Space is not required after casting.

drivers/iio/light/iio-gts-helper.c line 48

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			tmp++;
+
+		return tmp + 1;

Wondering why you can't simplify this to

		max -= scale;
		tmp++;
Quoted 5 lines
Quoted 2 lines

Sorry, but I don't follow. Can you please show me the complete suggestion? Exactly what should be replaced by the:

I don't understand. Do you see the blank lines I specifically added to show the piece of the code I'm commenting on?

I saw. I, however, didn't see the point so I was thinking I misunderstood what you wanted to replace.

Quoted 6 lines

For your convenience, the while loop and return statement may be replaced with two simple assignments.

Quoted 2 lines
Quoted 2 lines
		max -= scale;
		tmp++;

Ah, thanks. Yes. I think that would yield the same result. Not sure if it makes the logic more or less obvious, but it would kill one return path which indeed (in my opinion) could make it look prettier.

That would require a local variable or dropping the const from max though. Not sure it's worth that though.

Quoted 10 lines

...

Quoted 8 lines
Quoted 8 lines

drivers/iio/light/iio-gts-helper.c line 324

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 2; i >= 0; i--)

Yeah, if you put this into temporary, like

	i = gts->num_itime - 1;

this becomes

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
	while (i--) {

I prefer for(). It looks clearer to me...

It has too many characters to parse. That's why I prefer while. Are we going to have principle disagreement on this one?

I think we have disagreed whether to prefer while() or for() also in the past. I am reluctant to switch for()s to while()s unless there are other obvious benefits. Especially I dislike the change if it involves -- or ++ in the condition. They tend to make it much more difficult (for me) to see what the value is when comparing and what the value is after exiting the loop. Yet, in this particular case I saw the value of re-using the temporary value in memcpy() as you suggest below.

Quoted 18 lines
Quoted 5 lines
Quoted 1 line

Note, you may re-use that i (maybe renamed to something better in the

memcpy()

Quoted 1 line

above as well).

...but this makes sense so Ok.

...

Quoted 10 lines
Quoted 10 lines

drivers/iio/light/iio-gts-helper.c line 355

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

It moves it to the regular pattern. Yours is not so distributed in the kernel.

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

Quoted 10 lines

...

Quoted 8 lines
Quoted 7 lines

drivers/iio/light/iio-gts-helper.c line 364

Quoted 5 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+	kfree(all_gains);
+	if (ret && gts->avail_all_scales_table)
+		kfree(gts->avail_all_scales_table);
+
+	return ret;

But Wouldn't be better to use goto labels?

Quoted 8 lines
Quoted 3 lines

I don't see benefit in this case. Handling return value and goto would require brackets. The current one is much simpler for me. I am just considering dropping that 'else' which is not needed.

At least it would be consistent with the very same file style in another function. So, why there do you goto, and not here where it makes sense to me?

Talking about the iio_gts_build_avail_scale_table()?

Difference is that the iio_gts_build_avail_scale_table() has multiple checks for "if this happens - error out". I think using goto has valid use-cases there.

To tell the truth - in the past I preferred "arrow code" pattern where I initialized return values to default errors and only entered deeper to nested code when checks were successful - changing error to succes only at the deepest nested level. That however seems to rub the wrong way most of the kernel developers. Hence I am adapted to use gotos for error handling when we have more than only a few failure points.

In any case, here we can just do with single if-else (and for) without even having the brackets. This is not a deeply nesting complex construct.

Quoted 45 lines

...

Quoted 28 lines
Quoted 13 lines

drivers/iio/light/iio-gts-helper.c line 423

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	while (i) {

Instead of doing standard

	while (i--) {

drivers/iio/light/iio-gts-helper.c line 427

Quoted 4 lines
drivers/iio/light/iio-gts-helper.c new file +4 -0
+		/*
+		 * It does not matter if i'th alloc was not succesfull as
+		 * kfree(NULL) is safe.
+		 */

You add this comment, ...

Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 429

Quoted 2 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+		kfree(per_time_gains[i]);
+		kfree(per_time_scales[i]);

...an additional loop, ...

The comment is there to explain what I think you missed. We have two arrays there. We don't know whether the allocation of first one was successful so we try freeing both.

Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 431

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +2 -0
+
+		i--;

...and a line of code.

Quoted 6 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+	}

Why?

Because, as the comment says, it does not matter if allocation was succesfull. kfree(NULL) is safe.

Wouldn't be better to avoid no-op kfree() by explicitly putting the call before hands?

	kfree(...[i]);
	while (i--) {
		...
	}
Quoted 4 lines

?

Much better to understand than what you wrote. I have to read comment on top of the code, with my proposal comment won't be needed.

True, I can add one kfree() before the loop. It still does not change the fact that we don't know if allocating the per_time_scales[i] was succesful - unless we also add another label there. Well, it is a few more LOC but avoids the kfree() and the comment so not really unbearable trade :)

Quoted 8 lines

...

Quoted 6 lines
Quoted 5 lines

drivers/iio/light/iio-gts-helper.c line 497

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+	for (i = gts->num_itime - 1; i >= 0; i--) {
	i = gts->num_itime;

	while (i--) {
Quoted 9 lines
Quoted 2 lines

I prefer for() when initializing a variable is needed. Furthermore, having var-- or --var in a condition is less clear.

	while (x--)

_is_ a pattern for cleaning up something. Your for-loop has a lot of additional (unnecessary) code lines that makes it harder to understand (by the people who are not familiar with the pattern).

I do strongly disagree with you regarding

while (x--)

being simpler to understand than respective for. -- in a condition is terrible - and I rarely use it.

I know I used it in v3 for the

while (time_idx--) {

and I am regretting that already.

Quoted 11 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
(quoted diff) +1 -0
+	}

...

Quoted 7 lines
Quoted 6 lines

drivers/iio/light/iio-gts-helper.c line 537

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+void iio_gts_purge_avail_time_table(struct iio_gts *gts)
+{
+	if (gts->num_avail_time_tables) {
	if (!...)
		return;
Quoted 5 lines
Quoted 3 lines

Does not improve this as we only have just one small conditional block of code which we either execute or not. It is clear at a glance. Would make sense if we had longer function.

I believe it makes sense to have like this even for this long function(s).

So, it seems like we do disagree with this too then. To me it is just obvious here to check if we have tables to free and free them.

Quoted 9 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/iio/light/iio-gts-helper.c new file +5 -0
+		kfree(gts->avail_time_tables);
+		gts->avail_time_tables = NULL;
+		gts->num_avail_time_tables = 0;
+	}
+}

...

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.

I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

Best Regards
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#7 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 4 lines

drivers/iio/light/iio-gts-helper.c line 355

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

Quoted 8 lines

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

Quoted 6 lines
Quoted 1 line

It moves it to the regular pattern. Yours is not so distributed in the kernel.

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

The problem is that your pattern is not so standard (distributed) and hence less maintainable.

...

Quoted 21 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.

I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

Quoted 5 lines

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

It's not a problem when it's a common pattern (like you mentioned if (!foo) return -ENOMEM; or alike), but in your case it's not. I would rather see if (diff == 0) which definitely shows the intention and I wouldn't tell a word against it.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#8 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 26 lines · Andy Shevchenko
Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 18 lines
Quoted 17 lines
Quoted 10 lines
Quoted 10 lines

drivers/iio/light/iio-gts-helper.c line 355

Quoted 1 line
drivers/iio/light/iio-gts-helper.c new file +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

drivers/iio/light/iio-gts-helper.c line 358

Quoted 3 lines
drivers/iio/light/iio-gts-helper.c new file +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

Quoted 5 lines
Quoted 2 lines
		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

It moves it to the regular pattern. Yours is not so distributed in the kernel.

Quoted 7 lines
Quoted 4 lines

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

The problem is that your pattern is not so standard (distributed) and hence less maintainable.

I am sorry but I can't really agree with you on this one. For me adding the break and brackets would just complicate the flow and thus decrease the maintainability.

Quoted 23 lines

...

Quoted 21 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.

I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

Quoted 8 lines
Quoted 5 lines

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

It's not a problem when it's a common pattern (like you mentioned if (!foo) return -ENOMEM; or alike), but in your case it's not.

I think we can find plenty of cases where the if (!foo) is used also for other type of checks. To me the argument about people easily missing the ! in if () just do not sound reasonable.

Quoted 2 lines

I would rather see if (diff == 0) which definitely shows the intention and I wouldn't tell a word against it.

I think this depends much of the corner of the kernel you have been working with. As far as I remember, in some parts the kernel the check (foo == 0) was actually discouraged, and check (!foo) was preferred.

Personally I like !foo much more - but I can tolerate the (foo == 0) in cases where the purpose is to really see if some measure equals to zero.

Other uses where I definitely don't want to use "== 0" are for example checking if a flag is clear, pointer is NULL or "magic value" is zero.

In this case we are checking for a magic value. Having this check written as: (diff == 0), would actually falsely suggest me we are checking for the difference of gains being zero. That would really be a clever obfuscation and I am certain the code readers would fall on that trap quite easily.

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#9 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 6 lines · Matti Vaittinen
Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

Review

Quoted 3 lines
(quoted diff) +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

It moves it to the regular pattern. Yours is not so distributed in the kernel.

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

Quoted 6 lines
Quoted 2 lines

The problem is that your pattern is not so standard (distributed) and hence less maintainable.

I am sorry but I can't really agree with you on this one. For me adding the break and brackets would just complicate the flow and thus decrease the maintainability.

So, we may start to have a "fundamental disagreements between Matti and Andy on the code style in the Linux kernel" document that we won't clash on this again. At least the amount of these disagreements seems not decreasing in time.

...

Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.
I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

Quoted 4 lines
Quoted 2 lines

It's not a problem when it's a common pattern (like you mentioned if (!foo) return -ENOMEM; or alike), but in your case it's not.

I think we can find plenty of cases where the if (!foo) is used also for

Pleading to the quantity and not quality is not an argument, right?

Quoted 2 lines

other type of checks. To me the argument about people easily missing the ! in if () just do not sound reasonable.

You may theoretically discuss this, I'm telling from my review background and real cases.

Quoted 6 lines
Quoted 2 lines

I would rather see if (diff == 0) which definitely shows the intention and I wouldn't tell a word against it.

I think this depends much of the corner of the kernel you have been working with. As far as I remember, in some parts the kernel the check (foo == 0) was actually discouraged, and check (!foo) was preferred.

Don't you use your common sense?

Quoted 10 lines

Personally I like !foo much more - but I can tolerate the (foo == 0) in cases where the purpose is to really see if some measure equals to zero.

Other uses where I definitely don't want to use "== 0" are for example checking if a flag is clear, pointer is NULL or "magic value" is zero.

In this case we are checking for a magic value. Having this check written
as: (diff == 0), would actually falsely suggest me we are checking for the difference of gains being zero. That would really be a clever obfuscation and I am certain the code readers would fall on that trap quite easily.

Testing with !diff sounds like it's a boolean kind and makes a false impression that all other values are almost the same meaning which is not the case. Am I right? That's why diff == 0 shows the exact intention here "I would like to check if diff is 0 because this is *special case*".

Making !diff creates less visibility on this.

Result: Fundamental disagreement between us.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#10 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 7 lines · Andy Shevchenko
Quoted 6 lines · Matti Vaittinen
Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 59 lines
Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.
I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

Quoted 4 lines
Quoted 2 lines

It's not a problem when it's a common pattern (like you mentioned if (!foo) return -ENOMEM; or alike), but in your case it's not.

I think we can find plenty of cases where the if (!foo) is used also for

Pleading to the quantity and not quality is not an argument, right?

Quoted 2 lines

other type of checks. To me the argument about people easily missing the ! in if () just do not sound reasonable.

You may theoretically discuss this, I'm telling from my review background and real cases.

Quoted 6 lines
Quoted 2 lines

I would rather see if (diff == 0) which definitely shows the intention and I wouldn't tell a word against it.

I think this depends much of the corner of the kernel you have been working with. As far as I remember, in some parts the kernel the check (foo == 0) was actually discouraged, and check (!foo) was preferred.

Don't you use your common sense?

Quoted 10 lines

Personally I like !foo much more - but I can tolerate the (foo == 0) in cases where the purpose is to really see if some measure equals to zero.

Other uses where I definitely don't want to use "== 0" are for example checking if a flag is clear, pointer is NULL or "magic value" is zero.

In this case we are checking for a magic value. Having this check written
as: (diff == 0), would actually falsely suggest me we are checking for the difference of gains being zero. That would really be a clever obfuscation and I am certain the code readers would fall on that trap quite easily.

Quoted 8 lines

Testing with !diff sounds like it's a boolean kind and makes a false impression that all other values are almost the same meaning which is not the case. Am I right? That's why diff == 0 shows the exact intention here "I would like to check if diff is 0 because this is *special case*".

Making !diff creates less visibility on this.

Result: Fundamental disagreement between us.

JFYI:

$ git grep -n 'diff.* == 0[^0-9]' -- drivers/ | wc -l
45

(It happens to have same variable name, but you can imagine that there are
much more cases with different variable names in use)

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#11 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

In reply to Andy Shevchenko
Quoted 36 lines · Andy Shevchenko
Quoted 6 lines · Matti Vaittinen
Quoted 5 lines · Andy Shevchenko
Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 4 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)

Much easier to read if you move this...

Quoted 8 lines

Review

Quoted 3 lines
(quoted diff) +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);

...here as

		if (ret)
			break;

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

Quoted 6 lines
Quoted 1 line

It moves it to the regular pattern. Yours is not so distributed in the kernel.

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

The problem is that your pattern is not so standard (distributed) and hence less maintainable.

Quoted 8 lines
Quoted 3 lines

I am sorry but I can't really agree with you on this one. For me adding the break and brackets would just complicate the flow and thus decrease the maintainability.

So, we may start to have a "fundamental disagreements between Matti and Andy on the code style in the Linux kernel" document that we won't clash on this again. At least the amount of these disagreements seems not decreasing in time.

:)

Quoted 28 lines

...

Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+			if (!diff) {

Why not positive conditional?

Because !diff is a special condition and we check explicitly for it.

And how my suggestion makes it different?

In example you gave we would be checking if the value is anything else but the specific value we are checking for. It is counter intuitive.

Quoted 2 lines

(Note, it's easy to miss the ! in the conditionals, that's why positive ones
are preferable.)

Thank you for explaining me the rationale behind the "positive checks". I didn't know missing '!' was seen as a thing.
I still don't think being afraid of missing '!' is a good reason to switch to counter intuitive checks. A check "if (!foo)" is a pattern in-kernel if anything and in my opinion people really should be aware of it.

(I would much more say that having a constant value on left side of a "equality" check is beneficial as people do really occasionally miss one '=' when meaning '=='. Still, this is not strong enough reason to make counter-intuitive checks. In my books 'avoiding negative checks' is much less of a reason as people (in my experience) do not really miss the '!'.)

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

It's not a problem when it's a common pattern (like you mentioned if (!foo) return -ENOMEM; or alike), but in your case it's not.

I think we can find plenty of cases where the if (!foo) is used also for

Pleading to the quantity and not quality is not an argument, right?

Eh. I think it has been you who has quite often used that as an argument, right?

Quoted 5 lines
Quoted 2 lines

other type of checks. To me the argument about people easily missing the ! in if () just do not sound reasonable.

You may theoretically discuss this, I'm telling from my review background and real cases.

I think we all have been reading the code for quite a few years. Thus, also my statements are done based on real cases, or lack of them thereof. Hence a "Shut up, I have the reviewing experience" is not such a strong argument in my books ;)

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

I would rather see if (diff == 0) which definitely shows the intention and I wouldn't tell a word against it.

I think this depends much of the corner of the kernel you have been working with. As far as I remember, in some parts the kernel the check (foo == 0) was actually discouraged, and check (!foo) was preferred.

Don't you use your common sense?

I try. I believe this is why I so often clash with people who are just more or less blindly following their preferred idioms.

Quoted 11 lines
Quoted 10 lines

Personally I like !foo much more - but I can tolerate the (foo == 0) in cases where the purpose is to really see if some measure equals to zero.

Other uses where I definitely don't want to use "== 0" are for example checking if a flag is clear, pointer is NULL or "magic value" is zero.

In this case we are checking for a magic value. Having this check written
as: (diff == 0), would actually falsely suggest me we are checking for the difference of gains being zero. That would really be a clever obfuscation and I am certain the code readers would fall on that trap quite easily.

Quoted 4 lines

Testing with !diff sounds like it's a boolean kind and makes a false impression that all other values are almost the same meaning which is not the case. Am I right? That's why diff == 0 shows the exact intention here "I would like to check if diff is 0 because this is *special case*".

To me the diff == 0 would definitely read "difference of gains is zero". And this is NOT what this check is here for. And no, using !var is _not_ a sign of a boolean for me. It might be if this pattern was not used throughout the kernel for checking if something is _not set_, successful, NULL and yes, often also to see it something is non zero.

Quoted 3 lines

Making !diff creates less visibility on this.

Result: Fundamental disagreement between us.

We agree on that :)

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#12 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

In reply to Matti Vaittinen
Quoted 32 lines · On Tue, 14 Mar 2023 12:28:43 +0200 Matti Vaittinen <[email protected]>…
Quoted 31 lines · Andy Shevchenko
Quoted 4 lines · Matti Vaittinen
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Matti
Quoted 1 line · Andy Shevchenko

On Thu, Mar 02, 2023 at 12:57:54PM +0200, Matti Vaittinen wrote:

...

Quoted 22 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+		for (i = 0; !ret && i < gts->num_avail_all_scales; i++)  

Much easier to read if you move this...

Review

Quoted 3 lines
(quoted diff) +3 -0
+			ret = iio_gts_total_gain_to_scale(gts, all_gains[i],
+					&gts->avail_all_scales_table[i * 2],
+					&gts->avail_all_scales_table[i * 2 + 1]);  

...here as

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
		if (ret)
			break;  

I think the !ret in loop condition is obvious. Adding break and brackets would not improve this.

It moves it to the regular pattern. Yours is not so distributed in the kernel.

I believe we can find examples of both patterns in kernel. I don't think the "many people use different pattern" is a great reason to add break + brackets which (in my eyes) give no additional value to code I am planning to keep reading also in the future...

Quoted 6 lines
Quoted 2 lines

The problem is that your pattern is not so standard (distributed) and hence less maintainable.

I am sorry but I can't really agree with you on this one. For me adding the break and brackets would just complicate the flow and thus decrease the maintainability.

I'm with the if (ret) break;
school of thought on this one. Never like for loops with complex conditions, I guess because I've trained my eyes to ignore them ;)

maintainer
#13 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

In reply to Matti Vaittinen
Quoted 16 lines · On Thu, 2 Mar 2023 12:57:54 +0200 Matti Vaittinen <[email protected]>…

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

Quoted 7 lines

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once.

Add some gain-time-scale helpers in order to not dublicate errors in all drivers needing these computations.

Probably makes sense to put the exports in their own namespace.

I've been meaning to finish namespacing the rest of IIO but not gotten around to it yet.
As this is a separate library probably makes sense to have a unique namespace for it that the users opt in on.
Perhaps IIO_GTS makes sense?

Otherwise, as Andy's done a detailed review of this version I'll let you update it for those comments and take another look at v3.

Thanks,

Jonathan

author maintainer
#14 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Hi Jonathan, all

Quoted 22 lines · Jonathan Cameron
Quoted 19 lines · On Thu, 2 Mar 2023 12:57:54 +0200 Matti Vaittinen <[email protected]>…

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once.

Quoted 6 lines
Quoted 4 lines

Add some gain-time-scale helpers in order to not dublicate errors in all drivers needing these computations.

Probably makes sense to put the exports in their own namespace.

Andy asked for that as well. And, while I do not really see the usefulness of the namespaces when all symbols are properly prefixed (I only see added complexity there) - I agreed to use one.

Quoted 6 lines

I've been meaning to finish namespacing the rest of IIO but not gotten around to it yet.
As this is a separate library probably makes sense to have a unique namespace for it that the users opt in on.
Perhaps IIO_GTS makes sense?

Thanks. I think I'll use that. Although, as all of the symbols are prefixed with iio_gts - if I really saw a risk of symbol clash it would probably make more sense to use just about anything else ;) This because if someone else were prefixing symbols with iio_gts - he would likely be using the exactly same namespace.

Quoted 2 lines

Otherwise, as Andy's done a detailed review of this version I'll let you update it for those comments and take another look at v3.

This suits me fine. I have v3 almost prepared - but I'll be very much away from the computer next week so it may be the v3 will not be out until later. It may be I won't continue work with this until about after a week.

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#15 lore raw

Re: [PATCH v2 2/6] iio: light: Add gain-time-scale helpers

Quoted 2 lines · Matti Vaittinen
Quoted 1 line · Jonathan Cameron

On Thu, 2 Mar 2023 12:57:54 +0200

...

Quoted 11 lines
Quoted 5 lines

I've been meaning to finish namespacing the rest of IIO but not gotten around to it yet.
As this is a separate library probably makes sense to have a unique namespace for it that the users opt in on.
Perhaps IIO_GTS makes sense?

Thanks. I think I'll use that. Although, as all of the symbols are prefixed with iio_gts - if I really saw a risk of symbol clash it would probably make more sense to use just about anything else ;) This because if someone else were prefixing symbols with iio_gts - he would likely be using the exactly same namespace.

There is another aspect, i.e. global namespace pollution. This saves memory if not used.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#16 lore raw

PATCH v2 3/6 iio: test: test gain-time-scale helpers

In reply to Matti Vaittinen

Some light sensors can adjust both the HW-gain and integration time. There are cases where adjusting the integration time has similar impact to the scale of the reported values as gain setting has.

IIO users do typically expect to handle scale by a single writable 'scale' entry. Driver should then adjust the gain/time accordingly.

It however is difficult for a driver to know whether it should change gain or integration time to meet the requested scale. Usually it is preferred to have longer integration time which usually improves accuracy, but there may be use-cases where long measurement times can be an issue. Thus it can be preferable to allow also changing the integration time - but mitigate the scale impact by also changing the gain underneath. Eg, if integration time change doubles the measured values, the driver can reduce the HW-gain to half.

The theory of the computations of gain-time-scale is simple. However, some people (undersigned) got that implemented wrong for more than once. Hence some gain-time-scale helpers were introduced.

Add some simple tests to verify the most hairy functions.

---
Changes since RFCv1
- add tests for available scales/times helpers
- adapt to renamed iio-gts-helpers.h header

---
 drivers/iio/test/Kconfig        |  15 +
 drivers/iio/test/Makefile       |   1 +
 drivers/iio/test/iio-test-gts.c | 537 ++++++++++++++++++++++++++++++++
 3 files changed, 553 insertions(+)
 create mode 100644 drivers/iio/test/iio-test-gts.c
drivers/iio/test/Kconfig +15 -0
index 0b6e4e278a2f..b57f1fc440e6 100644
@@ -4,6 +4,19 @@
 #
 
 # Keep in alphabetical order
+config IIO_GTS_KUNIT_TEST
+	tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	select IIO_GTS_HELPER
+	default KUNIT_ALL_TESTS
+	help
+	  build unit tests for the IIO light sensor gain-time-scale helpers.
+
+	  For more information on KUnit and unit tests in general, please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N. Keep in alphabetical order
+
 config IIO_RESCALE_KUNIT_TEST
 	tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS
 	depends on KUNIT && IIO_RESCALE
@@ -27,3 +40,5 @@ config IIO_FORMAT_KUNIT_TEST
 	  to the KUnit documentation in Documentation/dev-tools/kunit/.
 
 	  If unsure, say N.
+
+
drivers/iio/test/Makefile +1 -0
index d76eaf36da82..e9a4cf1ff57f 100644
@@ -6,4 +6,5 @@
 # Keep in alphabetical order
 obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o
 obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o
+obj-$(CONFIG_IIO_GTS_KUNIT_TEST) += iio-test-gts.o
 CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN)
drivers/iio/test/iio-test-gts.c new file +537 -0

537 lines not on this page · raw message

Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
author maintainer
#17 lore raw

PATCH v2 4/6 MAINTAINERS: Add IIO gain-time-scale helpers

In reply to Matti Vaittinen

Add myself as a maintainer for IIO light sensor helpers (helpers for maintaining the scale while adjusting intergration time or gain) and related Kunit tests.

---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)
MAINTAINERS +8 -0
index 135d93368d36..af8516d5df36 100644
@@ -10059,6 +10059,14 @@ F:	Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
 F:	Documentation/devicetree/bindings/iio/adc/envelope-detector.yaml
 F:	drivers/iio/adc/envelope-detector.c
 
+IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS
+M:	Matti Vaittinen <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/iio/light/gain-time-scale-helper.c
+F:	drivers/iio/light/gain-time-scale-helper.h
+F:	drivers/iio/test/iio-test-gts.c
+
 IIO MULTIPLEXER
 M:	Peter Rosin <[email protected]>
 L:	[email protected]
Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
author maintainer
#18 lore raw

PATCH v2 5/6 iio: light: ROHM BU27034 Ambient Light Sensor

In reply to Matti Vaittinen

ROHM BU27034 is an ambient light sesnor 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. Additionally 3 IIO_INTENSITY channels are emitting the raw register data from all diodes for more intense user-space computations.
- Sensor has adjustible GAIN values ranging from 1x to 4096x.
- Sensor has adjustible measurement times 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 only can't provide requested scale, adjusting both the time and the gain is attempted.
- Driver exposes writable INT_TIME property which can be used for adjusting the measurement time. Time adjustment will also cause the driver to adjust the GAIN so that the overall scale is not changed.
- Runtime PM is not implemented.
- Driver starts the measurement on the background when it is probed. This improves the respnse time to read-requests compared to starting the read only when data is requested. When the most accurate 400 mS measurement time is used, data reads would last quite long if measurement was started only on demand. This, however, is not appealing for users who would prefere power saving over measurement response time.

---
Changes since RFCv1
- (really) protect read-only registers
- fix get and set gain
- buffered mode
- Protect the whole sequences including meas_en/meas_dis to avoid messing up the enable / disable order
- typofixes / doc improvements
- change dropped GAIN_SCALE_ITIME_MS() to GAIN_SCALE_ITIME_US()
- use more accurate scale for lux channel (milli lux)
- provide available scales / integration times (using helpers).
- adapt to renamed iio-gts-helpers.h file
- bu27034 - longer lines in Kconfig
- Drop bu27034_meas_en and bu27034_meas_dis wrappers.
- Change device-name from bu27034-als to bu27034

---
 drivers/iio/light/Kconfig        |   12 +
 drivers/iio/light/Makefile       |    1 +
 drivers/iio/light/rohm-bu27034.c | 1491 ++++++++++++++++++++++++++++++
 3 files changed, 1504 insertions(+)
 create mode 100644 drivers/iio/light/rohm-bu27034.c
drivers/iio/light/Kconfig +12 -0
index 671d84f98c56..14e03732f57d 100644
@@ -292,6 +292,18 @@ config JSA1212
 	  To compile this driver as a module, choose M here:
 	  the module will be called jsa1212.
 
+config ROHM_BU27034
+	tristate "ROHM BU27034 ambient light sensor"
+	depends on I2C
+	select REGMAP_I2C
+	select IIO_GTS_HELPER
+	help
+	  Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034
+	  is an ambient light sesnor 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.
+
 config RPR0521
 	tristate "ROHM RPR0521 ALS and proximity sensor driver"
 	depends on I2C
drivers/iio/light/Makefile +1 -0
index 82d14ebd3c11..e81c5ce60ccd 100644
@@ -39,6 +39,7 @@ obj-$(CONFIG_MAX44009)		+= max44009.o
 obj-$(CONFIG_NOA1305)		+= noa1305.o
 obj-$(CONFIG_OPT3001)		+= opt3001.o
 obj-$(CONFIG_PA12203001)	+= pa12203001.o
+obj-$(CONFIG_ROHM_BU27034)	+= rohm-bu27034.o
 obj-$(CONFIG_RPR0521)		+= rpr0521.o
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
 obj-$(CONFIG_SI1133)		+= si1133.o
drivers/iio/light/rohm-bu27034.c new file +1491 -0

1,491 lines not on this page · raw message

Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 
author maintainer
#19 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

to 2. maalisk. 2023 klo 12.59 Matti Vaittinen
([email protected]) kirjoitti:

Quoted 22 lines

ROHM BU27034 is an ambient light sesnor 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. Additionally 3 IIO_INTENSITY channels are emitting the raw register data from all diodes for more intense user-space computations.
- Sensor has adjustible GAIN values ranging from 1x to 4096x.
- Sensor has adjustible measurement times 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 only can't provide requested scale, adjusting both the time and the gain is

Quoted 8 lines

attempted.
- Driver exposes writable INT_TIME property which can be used for adjusting the measurement time. Time adjustment will also cause the driver to adjust the GAIN so that the overall scale is not changed.
- Runtime PM is not implemented.
- Driver starts the measurement on the background when it is probed. This improves the respnse time to read-requests

Seems like I forgot to update the commit message. Note to self: change this when preparing the v3

,,,

drivers/iio/light/Kconfig config JSA1212 · line 299

Quoted 5 lines
drivers/iio/light/Kconfig +5 -0
+config ROHM_BU27034
+       tristate "ROHM BU27034 ambient light sensor"
+       depends on I2C
+       select REGMAP_I2C
+       select IIO_GTS_HELPER

And, judging some other fixes - it seems this one would also need the select IIO_BUFFER and IIO_KFIFO_BUF now...

Signature · 8 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~

Discuss - Estimate - Plan - Report and finally accomplish this:
void do_work(int time) __attribute__ ((const));
#20 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

In reply to Matti Vaittinen
Quoted 34 lines · Matti Vaittinen

ROHM BU27034 is an ambient light sesnor 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. Additionally 3 IIO_INTENSITY channels are emitting the raw register data from all diodes for more intense user-space computations.
- Sensor has adjustible GAIN values ranging from 1x to 4096x.
- Sensor has adjustible measurement times 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 only can't provide requested scale, adjusting both the time and the gain is attempted.
- Driver exposes writable INT_TIME property which can be used for adjusting the measurement time. Time adjustment will also cause the driver to adjust the GAIN so that the overall scale is not changed.
- Runtime PM is not implemented.
- Driver starts the measurement on the background when it is probed. This improves the respnse time to read-requests compared to starting the read only when data is requested. When the most accurate 400 mS measurement time is used, data reads would last quite long if measurement was started only on demand. This, however, is not appealing for users who would prefere power saving over measurement response time.

...

drivers/iio/light/Kconfig config JSA1212 · line 297

Quoted 4 lines
drivers/iio/light/Kconfig +3 -0
+config ROHM_BU27034
+	tristate "ROHM BU27034 ambient light sensor"
 
+	depends on I2C

How? I do not see a such.

drivers/iio/light/Kconfig config JSA1212 · line 305

Quoted 8 lines
drivers/iio/light/Kconfig +8 -0
+	select REGMAP_I2C
+	select IIO_GTS_HELPER
+	help
+	  Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034
+	  is an ambient light sesnor 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.

Module name?

...

Quoted 4 lines

obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o

+obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o

If you see, most of the components are without vendor prefix, why rohm is special? Like you are expecting the very same filename for something else?

Quoted 3 lines

obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1133) += si1133.o

...

drivers/iio/light/rohm-bu27034.c line 20

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>

Sorted?

...

drivers/iio/light/rohm-bu27034.c line 44

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#define BU27034_REG_DATA0_LO		0x50
+#define BU27034_REG_DATA1_LO		0x52
+#define BU27034_REG_DATA2_LO		0x54

I would drop _LO in all these

Quoted 1 line

+#define BU27034_REG_DATA2_HI 0x55

and rename somehow this to something like _END / _MAX (similar to the fields. Perhaps you would need _START / _MIN above.

...

Quoted 11 lines
drivers/iio/light/rohm-bu27034.c new file +11 -0
+/*
+ * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS
+ * Time impacts to gain: 1x, 2x, 4x, 8x.
+ *
+ * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768
+ *
+ * Using NANO precision for scale we must use scale 64x corresponding gain 1x
+ * to avoid precision loss. (32x would result scale 976 562.5(nanos).
+ */
+#define BU27034_SCALE_1X	64
+

drivers/iio/light/rohm-bu27034.c line 107

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+#define BU27034_GSEL_1X		0x00
+#define BU27034_GSEL_4X		0x08
+#define BU27034_GSEL_16X	0x0a
+#define BU27034_GSEL_32X	0x0b
+#define BU27034_GSEL_64X	0x0c
+#define BU27034_GSEL_256X	0x18
+#define BU27034_GSEL_512X	0x19
+#define BU27034_GSEL_1024X	0x1a
+#define BU27034_GSEL_2048X	0x1b
+#define BU27034_GSEL_4096X	0x1c

Shouldn't the values be in plain decimal?

Otherwise I would like to understand bit mapping inside these hex values.

...

drivers/iio/light/rohm-bu27034.c line 165

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	.indexed = 1							\

+ Comma at the end.

...

drivers/iio/light/rohm-bu27034.c line 389

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	static const int reg[] = {
+		[BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2,
+		[BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3,
+		[BU27034_CHAN_DATA2] = BU27034_REG_MODE_CONTROL2

Ditto.

Quoted 1 line
(quoted diff) +1 -0
+	};

...

drivers/iio/light/rohm-bu27034.c line 445

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	struct bu27034_gain_check gains[3] = {
+		{ .chan = BU27034_CHAN_DATA0, },
+		{ .chan = BU27034_CHAN_DATA1, },

Inner commas are not needed.

drivers/iio/light/rohm-bu27034.c line 446

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+		{ .chan = BU27034_CHAN_DATA2 }

But here the outer one is good to have.

Quoted 1 line
(quoted diff) +1 -0
+	};

...

drivers/iio/light/rohm-bu27034.c line 547

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (chan == BU27034_CHAN_ALS) {
+		if (val == 0 && val2 == 1000)
+			return 0;
+		else

Redundant 'else'. And probably here is better to use standard pattern for "checking for error first".

Quoted 2 lines
(quoted diff) +2 -0
+			return -EINVAL;
+	}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+		if (helper64 < 0xFFFFFFFFFFFFFLLU) {

Perhaps this needs a definition.

drivers/iio/light/rohm-bu27034.c line 825

Quoted 9 lines
drivers/iio/light/rohm-bu27034.c new file +7 -0
+			helper64 *= gain0;
+			do_div(helper64, ch0);
+		} else {
+			do_div(helper64, ch0);
+			helper64 *= gain0;
+		}
 
 
+	/* Same overflow check here */

Why not a helper function?

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +7 -0
+	if (helper64 < 0xFFFFFFFFFFFFFLLU) {
+		helper64 *= gain0;
+		do_div(helper64, helper);
+	} else {
+		do_div(helper64, helper);
+		helper64 *= gain0;
+	}

...

drivers/iio/light/rohm-bu27034.c line 924

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	return (val & BU27034_MASK_VALID);

Unneeded parentheses.

...

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+retry:
+	/* Get new value from sensor if data is ready */
+	if (bu27034_has_valid_sample(data)) {
+		ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO,

drivers/iio/light/rohm-bu27034.c line 981

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+				       res, size);
+		if (ret)
+			return ret;
+
+		bu27034_invalidate_read_data(data);
+	} else {
+		/* No new data in sensor. Wait and retry */
+		msleep(25);
+
+		goto retry;

There is no way out. What might go wrong?

Quoted 1 line
(quoted diff) +1 -0
+	}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+	ret = bu27034_get_int_time(data);

_get_int_time_us() ? (Looking at the below code)

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (ret < 0)
+		return ret;
+
+	msleep(ret / 1000);

...

drivers/iio/light/rohm-bu27034.c line 1053

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	 * Avoid div by zeroi. Not using max() as the data may not be in

zeroi?

...

drivers/iio/light/rohm-bu27034.c line 1056

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	if (!res[0])

Positive conditional?

drivers/iio/light/rohm-bu27034.c line 1062

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+		ch0 = 1;
+	else
+		ch0 = le16_to_cpu(res[0]);
+
+	if (!res[1])
+		ch1 = 1;

Ditto.

Review

Quoted 2 lines
(quoted diff) +2 -0
+	else
+		ch1 = le16_to_cpu(res[1]);

But why not to read and convert first and then check. This at least will correctly compare 0 to the LE16 0 (yes, it's the same for 0, but strictly speaking the bits order of lvalue and rvalue is different).

...

drivers/iio/light/rohm-bu27034.c line 1256

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		return iio_gts_avail_times(&data->gts, vals, type, length);
+	case IIO_CHAN_INFO_SCALE:
+		return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+	default:
+		break;
+	}
+
+	return -EINVAL;

You may do it from default case.

...

drivers/iio/light/rohm-bu27034.c line 1299

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+	ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4,
+				       val, (val & BU27034_MASK_VALID),

Redundant parentheses.

drivers/iio/light/rohm-bu27034.c line 1304

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+				       BU27034_DATA_WAIT_TIME_US,
+				       BU27034_TOTAL_DATA_WAIT_TIME_US);
+	if (ret) {
+		dev_err(data->dev, "data polling %s\n",
+			!(val & BU27034_MASK_VALID) ? "timeout" : "fail");

Why not positive conditional in ternary?

Quoted 2 lines
(quoted diff) +2 -0
+		return ret;
+	}

...

drivers/iio/light/rohm-bu27034.c line 1417

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	fwnode = dev_fwnode(dev);
+	if (!fwnode)
+		return -ENODEV;

So, you deliberately disable a possibility to instantiate this from user space, why?

...

drivers/iio/light/rohm-bu27034.c line 1466

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	ret = devm_iio_kfifo_buffer_setup(dev, idev, &bu27034_buffer_ops);
+
+	ret = devm_iio_device_register(dev, idev);

Don't you find something strange in between?

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+				     "Unable to register iio device\n");

...

drivers/iio/light/rohm-bu27034.c line 1475

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	{ .compatible = "rohm,bu27034", },

Inner comma is not needed.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#21 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Hi Andy,

Thanks again for the review. Some nice catches there.

Quoted 36 lines · Andy Shevchenko
Quoted 26 lines · Matti Vaittinen

ROHM BU27034 is an ambient light sesnor 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. Additionally 3 IIO_INTENSITY channels are emitting the raw register data from all diodes for more intense user-space computations.
- Sensor has adjustible GAIN values ranging from 1x to 4096x.
- Sensor has adjustible measurement times 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 only can't provide requested scale, adjusting both the time and the gain is attempted.
- Driver exposes writable INT_TIME property which can be used for adjusting the measurement time. Time adjustment will also cause the driver to adjust the GAIN so that the overall scale is not changed.

Quoted 8 lines

- Runtime PM is not implemented.
- Driver starts the measurement on the background when it is probed. This improves the respnse time to read-requests compared to starting the read only when data is requested. When the most accurate 400 mS measurement time is used, data reads would last quite long if measurement was started only on demand. This, however, is not appealing for users who would prefere power saving over measurement response time.

Quoted 8 lines

...

drivers/iio/light/Kconfig config JSA1212 · line 297

Quoted 4 lines
drivers/iio/light/Kconfig +3 -0
+config ROHM_BU27034
+	tristate "ROHM BU27034 ambient light sensor"
 
+	depends on I2C

How? I do not see a such.

I have assumed we need this because:

We select REGMAP_I2C which depends on I2C.
What happens if I2C=n and we select REGMAP_I2C? I may be wrong but I guess the I2C stays 'n' while REGMAP_I2C becomes y/m (?) I think that would be unfortunate - but I can't claim I am confident with how config dependencies are handled. I can drop this depends on if you're sure that's not a problem.

Quoted 10 lines

drivers/iio/light/Kconfig config JSA1212 · line 305

Quoted 8 lines
drivers/iio/light/Kconfig +8 -0
+	select REGMAP_I2C
+	select IIO_GTS_HELPER
+	help
+	  Enable support for the ROHM BU27034 ambient light sensor. ROHM BU27034
+	  is an ambient light sesnor 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.

Module name?

I am having a deja-vu.
https://lore.kernel.org/all/[email protected]/

Module name is completely irrelevant when selecting a kernel configuration.

Quoted 9 lines

...

Quoted 4 lines
  obj-$(CONFIG_OPT3001)		+= opt3001.o
  obj-$(CONFIG_PA12203001)	+= pa12203001.o

+obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o

If you see, most of the components are without vendor prefix, why rohm is special? Like you are expecting the very same filename for something else?

No. I don't.

Using the vendor prefix in _file name_ was suggested to me by Lee already a few years ago. And I am actually grateful he did. I've found that _very_ useful as it simplifies finding the files I am looking for. What comes to the config option name, being able to easily search for the configs by vendor name has also been helpful.

Quoted 7 lines

...

drivers/iio/light/rohm-bu27034.c line 20

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>

Sorted?

Sure, thanks.

Quoted 9 lines

...

drivers/iio/light/rohm-bu27034.c line 44

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#define BU27034_REG_DATA0_LO		0x50
+#define BU27034_REG_DATA1_LO		0x52
+#define BU27034_REG_DATA2_LO		0x54

I would drop _LO in all these

Quoted 4 lines
Quoted 1 line

+#define BU27034_REG_DATA2_HI 0x55

and rename somehow this to something like _END / _MAX (similar to the fields. Perhaps you would need _START / _MIN above.

I don't think this would improve anything. The _LO / _HI are descriptive as we have only two registers for each channel, _LO and _HI being more or less standard abbreviations for low and high.

Quoted 17 lines

...

Quoted 15 lines
drivers/iio/light/rohm-bu27034.c new file +15 -0
+/*
+ * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS
+ * Time impacts to gain: 1x, 2x, 4x, 8x.
+ *
+ * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768
+ *
+ * Using NANO precision for scale we must use scale 64x corresponding gain 1x
+ * to avoid precision loss. (32x would result scale 976 562.5(nanos).
+ */
+#define BU27034_SCALE_1X	64
+
+#define BU27034_GSEL_1X		0x00
+#define BU27034_GSEL_4X		0x08
+#define BU27034_GSEL_16X	0x0a
+#define BU27034_GSEL_32X	0x0b
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 107

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+#define BU27034_GSEL_64X	0x0c
+#define BU27034_GSEL_256X	0x18
+#define BU27034_GSEL_512X	0x19
+#define BU27034_GSEL_1024X	0x1a
+#define BU27034_GSEL_2048X	0x1b
+#define BU27034_GSEL_4096X	0x1c

Shouldn't the values be in plain decimal?

Why?

Quoted 1 line

Otherwise I would like to understand bit mapping inside these hex values.

I like having register values in hex. It makes it obvious they don't necessarily directly match any 'real world' human-readable values.

Quoted 5 lines

...

drivers/iio/light/rohm-bu27034.c line 165

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	.indexed = 1							\

+ Comma at the end.

ok.

Quoted 9 lines

...

drivers/iio/light/rohm-bu27034.c line 389

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	static const int reg[] = {
+		[BU27034_CHAN_DATA0] = BU27034_REG_MODE_CONTROL2,
+		[BU27034_CHAN_DATA1] = BU27034_REG_MODE_CONTROL3,
+		[BU27034_CHAN_DATA2] = BU27034_REG_MODE_CONTROL2

Ditto.

ok.

Quoted 11 lines
Quoted 2 lines
(quoted diff) +1 -0
+	};

...

drivers/iio/light/rohm-bu27034.c line 445

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	struct bu27034_gain_check gains[3] = {
+		{ .chan = BU27034_CHAN_DATA0, },
+		{ .chan = BU27034_CHAN_DATA1, },

Inner commas are not needed.

Quoted 6 lines

drivers/iio/light/rohm-bu27034.c line 446

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+		{ .chan = BU27034_CHAN_DATA2 }

But here the outer one is good to have.

Review

Quoted 1 line
(quoted diff) +1 -0
+	};

ok

Quoted 8 lines

...

drivers/iio/light/rohm-bu27034.c line 547

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (chan == BU27034_CHAN_ALS) {
+		if (val == 0 && val2 == 1000)
+			return 0;
+		else

Redundant 'else'

Thanks for pointing out the unnecessary else. Killing it makes this nicer.

Quoted 2 lines

. And probably here is better to use standard pattern for "checking for error first".

I prefer to check for this one specific exactly supported case for ALS channel. Cheking for 'all other possibilities but what we are expecting' would be counter intuitive.

Quoted 9 lines
Quoted 3 lines
(quoted diff) +2 -0
+			return -EINVAL;
+	}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+		if (helper64 < 0xFFFFFFFFFFFFFLLU) {

Perhaps this needs a definition.

I like seeing the value here. It makes this less obfuscating. Comment makes the purpose obvious so adding a define would not really give any extra advantage.

Quoted 11 lines

drivers/iio/light/rohm-bu27034.c line 825

Quoted 9 lines
drivers/iio/light/rohm-bu27034.c new file +7 -0
+			helper64 *= gain0;
+			do_div(helper64, ch0);
+		} else {
+			do_div(helper64, ch0);
+			helper64 *= gain0;
+		}
 
 
+	/* Same overflow check here */

Why not a helper function?

I actually was thinking of it - but the check is smallish, only done twice and felt a tad too specific to warrant own function. I am not really against adding a function if you feel strongly about this :)

Quoted 11 lines
Quoted 8 lines
drivers/iio/light/rohm-bu27034.c new file +7 -0
+	if (helper64 < 0xFFFFFFFFFFFFFLLU) {
+		helper64 *= gain0;
+		do_div(helper64, helper);
+	} else {
+		do_div(helper64, helper);
+		helper64 *= gain0;
+	}

...

Quoted 3 lines

drivers/iio/light/rohm-bu27034.c line 924

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	return (val & BU27034_MASK_VALID);

Unneeded parentheses.

ok.

Quoted 19 lines

...

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+retry:
+	/* Get new value from sensor if data is ready */
+	if (bu27034_has_valid_sample(data)) {
+		ret = regmap_bulk_read(data->regmap, BU27034_REG_DATA0_LO,

drivers/iio/light/rohm-bu27034.c line 981

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+				       res, size);
+		if (ret)
+			return ret;
+
+		bu27034_invalidate_read_data(data);
+	} else {
+		/* No new data in sensor. Wait and retry */
+		msleep(25);
+
+		goto retry;

There is no way out. What might go wrong?

Beyond hanging the user process? :)

I think you have a point here. I'll add a timeout.

Quoted 20 lines
Quoted 2 lines
(quoted diff) +1 -0
+	}

...

Review

Quoted 1 line
(quoted diff) +1 -0
+	ret = bu27034_get_int_time(data);

_get_int_time_us() ? (Looking at the below code)

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (ret < 0)
+		return ret;
+
+	msleep(ret / 1000);

...

drivers/iio/light/rohm-bu27034.c line 1053

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	 * Avoid div by zeroi. Not using max() as the data may not be in

zeroi?

Quoted 5 lines

...

drivers/iio/light/rohm-bu27034.c line 1056

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	if (!res[0])

Positive conditional?

No. Again, we check for the very specific case where res has all bits zeroed. Inverse condition is counter intuitive.

Quoted 10 lines

drivers/iio/light/rohm-bu27034.c line 1062

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+		ch0 = 1;
+	else
+		ch0 = le16_to_cpu(res[0]);
+
+	if (!res[1])
+		ch1 = 1;

Ditto.

Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	else
+		ch1 = le16_to_cpu(res[1]);

But why not to read and convert first and then check.

Because conversion is not needed if channel data is zero.

Quoted 3 lines

This at least will
correctly compare 0 to the LE16 0 (yes, it's the same for 0, but strictly speaking the bits order of lvalue and rvalue is different).

and hence we check for !res[0]

Quoted 16 lines

...

drivers/iio/light/rohm-bu27034.c line 1256

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		return iio_gts_avail_times(&data->gts, vals, type, length);
+	case IIO_CHAN_INFO_SCALE:
+		return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+	default:
+		break;
+	}
+
+	return -EINVAL;

You may do it from default case.

I think we have discussed this one in the past too. I like having return at the end of a non void function.

Quoted 6 lines

...

drivers/iio/light/rohm-bu27034.c line 1299

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+	ret = regmap_read_poll_timeout(data->regmap, BU27034_REG_MODE_CONTROL4,
+				       val, (val & BU27034_MASK_VALID),

Redundant parentheses.

ok

Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 1304

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+				       BU27034_DATA_WAIT_TIME_US,
+				       BU27034_TOTAL_DATA_WAIT_TIME_US);
+	if (ret) {
+		dev_err(data->dev, "data polling %s\n",
+			!(val & BU27034_MASK_VALID) ? "timeout" : "fail");

Why not positive conditional in ternary?

Because I check this for a specific case: "Was it a timeout?" - not for unspecified "Was it something else but timeout?"

Quoted 6 lines
Quoted 3 lines
(quoted diff) +2 -0
+		return ret;
+	}

...

Quoted 6 lines

drivers/iio/light/rohm-bu27034.c line 1417

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	fwnode = dev_fwnode(dev);
+	if (!fwnode)
+		return -ENODEV;

So, you deliberately disable a possibility to instantiate this from user space, why?

Thanks! (And Sorry. Jonathan pointed this out to me already in the RFC.) I thought I already fixed this.

Quoted 8 lines

...

drivers/iio/light/rohm-bu27034.c line 1466

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	ret = devm_iio_kfifo_buffer_setup(dev, idev, &bu27034_buffer_ops);
+
+	ret = devm_iio_device_register(dev, idev);

Don't you find something strange in between?

Thanks!

Quoted 10 lines
Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+				     "Unable to register iio device\n");

...

drivers/iio/light/rohm-bu27034.c line 1475

Quoted 1 line
drivers/iio/light/rohm-bu27034.c new file +1 -0
+	{ .compatible = "rohm,bu27034", },

Inner comma is not needed.

ok

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#22 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

A few follow up comments.

Jonathan

Quoted 9 lines
Quoted 8 lines
Quoted 5 lines
  
  obj-$(CONFIG_OPT3001)		+= opt3001.o
  obj-$(CONFIG_PA12203001)	+= pa12203001.o  

+obj-$(CONFIG_ROHM_BU27034) += rohm-bu27034.o

If you see, most of the components are without vendor prefix, why rohm is special? Like you are expecting the very same filename for something else?

Quoted 7 lines

No. I don't.

Using the vendor prefix in _file name_ was suggested to me by Lee already a few years ago. And I am actually grateful he did. I've found that _very_ useful as it simplifies finding the files I am looking for. What comes to the config option name, being able to easily search for the configs by vendor name has also been helpful.

For filenames I've no strong preference - though perhaps if I'd been starting out today I might have decided the convention was to always add a vendor because of the slight risk of a naming clash.

Quoted 20 lines
Quoted 8 lines

...

drivers/iio/light/rohm-bu27034.c line 20

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>  

Sorted?

Sure, thanks.

Quoted 9 lines

...

drivers/iio/light/rohm-bu27034.c line 44

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+#define BU27034_REG_DATA0_LO		0x50
+#define BU27034_REG_DATA1_LO		0x52
+#define BU27034_REG_DATA2_LO		0x54  

I would drop _LO in all these

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

+#define BU27034_REG_DATA2_HI 0x55

and rename somehow this to something like _END / _MAX (similar to the fields. Perhaps you would need _START / _MIN above.

I don't think this would improve anything. The _LO / _HI are descriptive as we have only two registers for each channel, _LO and _HI being more or less standard abbreviations for low and high.

Whilst it might be fairly obvious that we are going to do double reg reads against these, having the register names match the datasheet is useful.

But in this case the datasheet register map does given them a top level label without the LO, HI so either option would be easy to find.

Quoted 27 lines
Quoted 18 lines

...

Quoted 15 lines
drivers/iio/light/rohm-bu27034.c new file +15 -0
+/*
+ * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS
+ * Time impacts to gain: 1x, 2x, 4x, 8x.
+ *
+ * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768
+ *
+ * Using NANO precision for scale we must use scale 64x corresponding gain 1x
+ * to avoid precision loss. (32x would result scale 976 562.5(nanos).
+ */
+#define BU27034_SCALE_1X	64
+
+#define BU27034_GSEL_1X		0x00
+#define BU27034_GSEL_4X		0x08
+#define BU27034_GSEL_16X	0x0a
+#define BU27034_GSEL_32X	0x0b
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 107

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+#define BU27034_GSEL_64X	0x0c
+#define BU27034_GSEL_256X	0x18
+#define BU27034_GSEL_512X	0x19
+#define BU27034_GSEL_1024X	0x1a
+#define BU27034_GSEL_2048X	0x1b
+#define BU27034_GSEL_4096X	0x1c  

Shouldn't the values be in plain decimal?

Quoted 1 line

Why?

Normally go with datasheet on this as it makes reviewer simpler. But datasheet is in binary so meh.

Quoted 5 lines
Quoted 2 lines

Otherwise I would like to understand bit mapping inside these hex values.

I like having register values in hex. It makes it obvious they don't necessarily directly match any 'real world' human-readable values.

Perhaps a cross reference to the table in the spec is appropriate here?

whilst there are some patterns they aren't terribly consistent so probably best to just point at the table in the spec.

Quoted 7 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+		if (helper64 < 0xFFFFFFFFFFFFFLLU) {  

Perhaps this needs a definition.

I like seeing the value here. It makes this less obfuscating. Comment makes the purpose obvious so adding a define would not really give any extra advantage.

It's not immediately obvious why it is that many f's. Perhaps change to refer to number of bits (which is what matters really I think) and then use GENMASK() to fill this in? I think it's 52 bits?

Quoted 26 lines
Quoted 11 lines

drivers/iio/light/rohm-bu27034.c line 819

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+			helper64 *= gain0;
+			do_div(helper64, ch0);
+		} else {
+			do_div(helper64, ch0);
+			helper64 *= gain0;
+		}  

...> >> + if (!res[0])

Quoted 1 line

Positive conditional?

No. Again, we check for the very specific case where res has all bits zeroed. Inverse condition is counter intuitive.

Quoted 10 lines

drivers/iio/light/rohm-bu27034.c line 1062

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+		ch0 = 1;
+	else
+		ch0 = le16_to_cpu(res[0]);
+
+	if (!res[1])
+		ch1 = 1;  

Ditto.

Quoted 6 lines
Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	else
+		ch1 = le16_to_cpu(res[1]);  

But why not to read and convert first and then check.

Because conversion is not needed if channel data is zero.

Conversion is trivial. I agree with Andy here that the logic would look a bit simpler as (taking it a little further)

	ch0 = max(1, le16_to_cpu(res[0]));
Quoted 24 lines
Quoted 4 lines

This at least will
correctly compare 0 to the LE16 0 (yes, it's the same for 0, but strictly speaking the bits order of lvalue and rvalue is different).

and hence we check for !res[0]

Quoted 16 lines

...

drivers/iio/light/rohm-bu27034.c line 1256

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		return iio_gts_avail_times(&data->gts, vals, type, length);
+	case IIO_CHAN_INFO_SCALE:
+		return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+	default:
+		break;
+	}
+
+	return -EINVAL;  

You may do it from default case.

Quoted 2 lines

I think we have discussed this one in the past too. I like having return at the end of a non void function.

Given all the earlier returns and the fact that the compiler will shout at you if it you can get here and it is missing, I'd also suggest just putting it in the switch statement.

author maintainer
#23 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 32 lines · Jonathan Cameron
Quoted 26 lines
Quoted 17 lines

...

Quoted 15 lines
drivers/iio/light/rohm-bu27034.c new file +15 -0
+/*
+ * Available scales with gain 1x - 4096x, timings 55, 100, 200, 400 mS
+ * Time impacts to gain: 1x, 2x, 4x, 8x.
+ *
+ * => Max total gain is HWGAIN * gain by integration time (8 * 4096) = 32768
+ *
+ * Using NANO precision for scale we must use scale 64x corresponding gain 1x
+ * to avoid precision loss. (32x would result scale 976 562.5(nanos).
+ */
+#define BU27034_SCALE_1X	64
+
+#define BU27034_GSEL_1X		0x00
+#define BU27034_GSEL_4X		0x08
+#define BU27034_GSEL_16X	0x0a
+#define BU27034_GSEL_32X	0x0b
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 107

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+#define BU27034_GSEL_64X	0x0c
+#define BU27034_GSEL_256X	0x18
+#define BU27034_GSEL_512X	0x19
+#define BU27034_GSEL_1024X	0x1a
+#define BU27034_GSEL_2048X	0x1b
+#define BU27034_GSEL_4096X	0x1c

Shouldn't the values be in plain decimal?

Quoted 1 line

Why?

Normally go with datasheet on this as it makes reviewer simpler. But datasheet is in binary so meh.

Quoted 1 line
Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Otherwise I would like to understand bit mapping inside these hex values.

I like having register values in hex. It makes it obvious they don't necessarily directly match any 'real world' human-readable values.

Perhaps a cross reference to the table in the spec is appropriate here?

I think adding a reference to the table in the data-sheet is good. Although - I gave some feedback about the data-sheet inside the company. It may be we will eventually see another version of it...

Quoted 8 lines

whilst there are some patterns they aren't terribly consistent so probably best to just point at the table in the spec.

Quoted 4 lines
Quoted 3 lines

Review

Quoted 1 line
(quoted diff) +1 -0
+		if (helper64 < 0xFFFFFFFFFFFFFLLU) {

Perhaps this needs a definition.

Quoted 7 lines
Quoted 3 lines

I like seeing the value here. It makes this less obfuscating. Comment makes the purpose obvious so adding a define would not really give any extra advantage.

It's not immediately obvious why it is that many f's. Perhaps change to refer to number of bits (which is what matters really I think) and then use GENMASK() to fill this in? I think it's 52 bits?

I am personally not used to the GENMASK(). I am always wondering whether the parameters were start + end bits, or star bit + number of set bits or ... It's somehow easier for me to understand the hex values - (especially when they are composed of all fff's or 1, 3, 7 or 2, 4, 8 ... ).

Well, I understand that is not universally true though so GENMASK() can for sure be simpler for most others - and it does not hide the value as define would do. So yes, GENMASK() could make sense here.

Quoted 30 lines
Quoted 30 lines
Quoted 11 lines

drivers/iio/light/rohm-bu27034.c line 819

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+			helper64 *= gain0;
+			do_div(helper64, ch0);
+		} else {
+			do_div(helper64, ch0);
+			helper64 *= gain0;
+		}

...> >> + if (!res[0])

Positive conditional?

No. Again, we check for the very specific case where res has all bits zeroed. Inverse condition is counter intuitive.

Quoted 14 lines

drivers/iio/light/rohm-bu27034.c line 1062

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+		ch0 = 1;
+	else
+		ch0 = le16_to_cpu(res[0]);
+
+	if (!res[1])
+		ch1 = 1;

Ditto.

Review

Quoted 2 lines
(quoted diff) +2 -0
+	else
+		ch1 = le16_to_cpu(res[1]);

But why not to read and convert first and then check.

Quoted 6 lines
Quoted 1 line

Because conversion is not needed if channel data is zero.

Conversion is trivial. I agree with Andy here that the logic would look a bit simpler as (taking it a little further)

	ch0 = max(1, le16_to_cpu(res[0]));

It's strange how differently we read the code. For me:

if (!val)

	ch = 1;
else
	ch =  le16_to_cpu(val);

tells what is happening at a glance whereas the:
ch0 = max(1, le16_to_cpu(res[0]));

really requires some focusing to see what is going on. For me it is both less clear and less efficient :(

But alas, if this is what is preferred by both of you, then I guess that's what it will look like.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

drivers/iio/light/rohm-bu27034.c line 1256

Quoted 11 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		return iio_gts_avail_times(&data->gts, vals, type, length);
+	case IIO_CHAN_INFO_SCALE:
+		return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+	default:
+		break;
+	}
+
+	return -EINVAL;

You may do it from default case.

Quoted 6 lines
Quoted 2 lines

I think we have discussed this one in the past too. I like having return at the end of a non void function.

Given all the earlier returns and the fact that the compiler will shout at you if it you can get here and it is missing, I'd also suggest just putting it in the switch statement.

Ok. IIO is your territory. If the roles were switched I would definitely ask for having the returns at the end of the function - and at the end of the function only (when possible w/o lot of extra complication).

So perhaps I just have to accept that you want to have it your way with IIO :)

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#24 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

In reply to Matti Vaittinen
Quoted 18 lines · On Thu, 2 Mar 2023 12:58:59 +0200 Matti Vaittinen <[email protected]>…

ROHM BU27034 is an ambient light sesnor 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. Additionally 3 IIO_INTENSITY channels are emitting the raw register data from all diodes for more intense user-space computations.
- Sensor has adjustible GAIN values ranging from 1x to 4096x.
- Sensor has adjustible measurement times 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:

Quoted 8 lines

1) Trying to adjust only the GAIN
2) If GAIN adjustment only can't provide requested scale, adjusting both the time and the gain is attempted.
- Driver exposes writable INT_TIME property which can be used for adjusting the measurement time. Time adjustment will also cause the driver to adjust the GAIN so that the overall scale is not changed.

Probably want a 'where possible' note here.

Quoted 1 line

- Runtime PM is not implemented.

I wouldn't bother noting things that are not implemented. That's a long list!

Quoted 2 lines

- Driver starts the measurement on the background when it is probed. This improves the respnse time to read-requests

Spell check. (I often forget to do this myself)

Quoted 5 lines

compared to starting the read only when data is requested. When the most accurate 400 mS measurement time is used, data reads would last quite long if measurement was started only on demand. This, however, is not appealing for users who would prefere power saving over measurement response time.

As you noted this needs updating

Quoted 2 lines

Some comments inline to add to Andy's review.#
It's a big driver so we may well need a few more versions to converge completely.

Jonathan

Quoted 23 lines

---
Changes since RFCv1
- (really) protect read-only registers
- fix get and set gain
- buffered mode
- Protect the whole sequences including meas_en/meas_dis to avoid messing up the enable / disable order
- typofixes / doc improvements
- change dropped GAIN_SCALE_ITIME_MS() to GAIN_SCALE_ITIME_US()
- use more accurate scale for lux channel (milli lux)
- provide available scales / integration times (using helpers).
- adapt to renamed iio-gts-helpers.h file
- bu27034 - longer lines in Kconfig
- Drop bu27034_meas_en and bu27034_meas_dis wrappers.
- Change device-name from bu27034-als to bu27034
---

drivers/iio/light/rohm-bu27034.c

Quoted 1 line
drivers/iio/light/rohm-bu27034.c +0 -0

new file mode 100644
index 000000000000..b8ca29af22e7

drivers/iio/light/rohm-bu27034.c line 54

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
@@ -0,0 +1,1491 @@
 
+/*
+ * The BU27034 does not have interrupt or any other mechanism of triggering
+ * the data read when measurement has finished. Hence we poll the VALID bit in
+ * a thread. We will try to wake the thread BU27034_MEAS_WAIT_PREMATURE_MS
+ * milliseconds before the expected sampling time to prevent the drifting. Eg,
+ * If we constantly wake up a bit too late we would eventually skip a sample.

Lazier approach would be to just sent the sampling frequency at twice the expected frequency and you'll never miss a sample unless you the wake up is delayed massively for some reason. Particularly 'fresh' data might not matter enough that half a cycle late is a problem.

Quoted 14 lines

+ * And because the sleep can't wake up _exactly_ at given time this would be
+ * inevitable even if the sensor clock would be perfectly phase-locked to CPU
+ * clock - which we can't say is the case.
+ *
+ * This is still fragile. No matter how big advance do we have, we will still
+ * risk of losing a sample because things can in a rainy-day skenario be
+ * delayed a lot. Yet, more we reserve the time for polling, more we also lose
+ * the performance by spending cycles polling the register. So, selecting this
+ * value is a balancing dance between severity of wasting CPU time and severity
+ * of losing samples.
+ *
+ * In most cases losing the samples is not _that_ crucial because light levels
+ * tend to change slowly.
+ */

drivers/iio/light/rohm-bu27034.c line 72

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+#define BU27034_MEAS_WAIT_PREMATURE_MS	5
+#define BU27034_DATA_WAIT_TIME_US	1000
+#define BU27034_TOTAL_DATA_WAIT_TIME_US (BU27034_MEAS_WAIT_PREMATURE_MS * 1000)
+

Single blank line is enough to separate sections.

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+
+enum {
+	BU27034_CHAN_ALS,
+	BU27034_CHAN_DATA0,
+	BU27034_CHAN_DATA1,

drivers/iio/light/rohm-bu27034.c

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +8 -0
+	BU27034_CHAN_DATA2,
+	BU27034_NUM_CHANS
+};
 
 
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),

What is this scale for?
Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 26 lines
drivers/iio/light/rohm-bu27034.c new file +24 -0
+		.channel = BU27034_CHAN_ALS,
+		.scan_index = BU27034_CHAN_ALS,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 32,
+			.storagebits = 32,
+			.endianness = IIO_CPU,
+		},
+	},
+	/*
+	 * The BU27034 DATA0 and DATA1 channels are both on the visible light
+	 * area (mostly). The data0 sensitivity peaks at 500nm, DATA1 at 600nm.
+	 * These wave lengths are pretty much on the border of colours making
+	 * these a poor candidates for R/G/B standardization. Hence they're both
+	 * marked as clear channels
+	 */
+	BU27034_CHAN_DATA(DATA0, IIO_MOD_LIGHT_CLEAR),
+	BU27034_CHAN_DATA(DATA1, IIO_MOD_LIGHT_CLEAR),
+	BU27034_CHAN_DATA(DATA2, IIO_MOD_LIGHT_IR),
+	IIO_CHAN_SOFT_TIMESTAMP(4),
+};
 
 
+/* Caller should hold the lock to protect data->int_time */
+static int bu27034_set_int_time(struct bu27034_data *data, int time)
+{

drivers/iio/light/rohm-bu27034.c

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	int ret;
+
+	ret = iio_gts_find_sel_by_int_time(&data->gts, time);
+	if (ret < 0)
+		return ret;
+
+	return regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1,
+				 BU27034_MASK_MEAS_MODE, ret);
+
+	return time;

? Never get to this.

Quoted 48 lines
drivers/iio/light/rohm-bu27034.c new file +48 -0
+}
+
+/*
+ * We try to change the time in such way that the scale is maintained for
+ * given channels by adjusting gain so that it compensates the time change.
+ */
+static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us)
+{
+	int ret, int_time_old, int_time_new, i;
+	struct bu27034_gain_check gains[3] = {
+		{ .chan = BU27034_CHAN_DATA0, },
+		{ .chan = BU27034_CHAN_DATA1, },
+		{ .chan = BU27034_CHAN_DATA2 }
+	};
+	int numg = ARRAY_SIZE(gains);
+
+	mutex_lock(&data->mutex);
+	ret = bu27034_get_int_time(data);
+	if (ret < 0)
+		goto unlock_out;
+
+	int_time_old = ret;
+
+	ret = bu27034_validate_int_time(data, time_us);
+	if (ret < 0) {
+		dev_err(data->dev, "Unsupported integration time %u\n",
+			time_us);
+
+		goto unlock_out;
+	}
+
+	int_time_new = ret;
+
+	if (int_time_new == int_time_old) {
+		ret = 0;
+		goto unlock_out;
+	}
+
+	for (i = 0; i < numg; i++) {
+		ret = bu27034_get_gain(data, gains[i].chan,
+				       &gains[i].old_gain);
+		if (ret)
+			goto unlock_out;
+
+		gains[i].new_gain = gains[i].old_gain * int_time_old /
+				    int_time_new;
+
+		if (!iio_gts_valid_gain(&data->gts, gains[i].new_gain)) {

drivers/iio/light/rohm-bu27034.c line 491

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+			int scale1, scale2;
+			bool ok;
+
+			_bu27034_get_scale(data, gains[i].chan, &scale1, &scale2);
+			dev_dbg(data->dev,
+				"chan %u, can't support time %u with scale %u %u\n",
+				gains[i].chan, time_us, scale1, scale2);
+
+			/*
+			 * As Jonathan put it, if caller requests for

Probably don't reference me directly in a driver. Keep the 'blame' for the email threads :) Comment is fine otherwise.

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+			 * integration time change and we can't support the
+			 * scale - then the caller should be prepared to
+			 * 'pick up the pieces and deal with the fact that the
+			 * scale changed'.
+			 */
+			ret = iio_find_closest_gain_low(&data->gts,

drivers/iio/light/rohm-bu27034.c line 507

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+							gains[i].new_gain, &ok);
+
+			if (!ok) {
+				dev_dbg(data->dev,
+					"optimal gain out of range for chan %u\n",
+					gains[i].chan);
+			}
+			if (ret < 0) {
+				dev_warn(data->dev,
+					 "Total gain increase. Risk of saturation");

dev_dbg()

drivers/iio/light/rohm-bu27034.c line 513

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+				ret = iio_gts_get_min_gain(&data->gts);
+				if (ret < 0)
+					goto unlock_out;
+			}
+			dev_warn(data->dev, "chan %u scale changed\n",
+				 gains[i].chan);

dev_dbg()

We shouldn't convey this sort of info via the kernel log. Most users would never see it anyway!.

drivers/iio/light/rohm-bu27034.c line 522

Quoted 9 lines
drivers/iio/light/rohm-bu27034.c new file +9 -0
+			gains[i].new_gain = ret;
+			dev_dbg(data->dev, "chan %u new gain %u\n",
+				gains[i].chan, gains[i].new_gain);
+		}
+	}
+
+	/*
+	 * The new integration time can be supported while keeping the scale of
+	 * channels intact by tuning the gains.

This comment is in a path that is hit event if we go through the warnings above that say this isn't true.

Quoted 28 lines
drivers/iio/light/rohm-bu27034.c new file +28 -0
+	 */
+	for (i = 0; i < numg; i++) {
+		ret = bu27034_set_gain(data, gains[i].chan, gains[i].new_gain);
+		if (ret)
+			goto unlock_out;
+	}
+
+	ret = bu27034_set_int_time(data, int_time_new);
+
+unlock_out:
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int bu27034_set_scale(struct bu27034_data *data, int chan,
+			    int val, int val2)
+{
+	int ret, time_sel, gain_sel, i;
+	bool found = false;
+
+	if (chan == BU27034_CHAN_ALS) {
+		if (val == 0 && val2 == 1000)
+			return 0;
+		else
+			return -EINVAL;
+	}
+

drivers/iio/light/rohm-bu27034.c line 560

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	mutex_lock(&data->mutex);
+	ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL1, &time_sel);
+	if (ret)
+		goto unlock_out;
+
+	ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
+						val, val2 * 1000, &gain_sel);
+	if (ret) {
+		/*
+		 * Could'n support scale with given time. Need to change time.

Could not

Quoted 54 lines
drivers/iio/light/rohm-bu27034.c new file +54 -0
+		 * We still want to maintain the scale for all channels
+		 */
+		int new_time_sel;
+		struct bu27034_gain_check gains[2];
+
+		/*
+		 * Populate information for the two other channels which should
+		 * maintain the scale.
+		 */
+		if (chan == BU27034_CHAN_DATA0) {
+			gains[0].chan = BU27034_CHAN_DATA1;
+			gains[1].chan = BU27034_CHAN_DATA2;
+		} else if (chan == BU27034_CHAN_DATA1) {
+			gains[0].chan = BU27034_CHAN_DATA0;
+			gains[1].chan = BU27034_CHAN_DATA2;
+		} else {
+			gains[0].chan = BU27034_CHAN_DATA0;
+			gains[1].chan = BU27034_CHAN_DATA1;
+		}
+
+		for (i = 0; i < 2; i++) {
+			ret = bu27034_get_gain(data, gains[i].chan,
+					       &gains[i].old_gain);
+			if (ret)
+				goto unlock_out;
+		}
+
+		/*
+		 * Iterate through all the times to see if we find one which
+		 * can support requested scale for requested channel, while
+		 * maintaining the scale for other channels
+		 */
+		for (i = 0; i < data->gts.num_itime; i++) {
+			new_time_sel = data->gts.itime_table[i].sel;
+
+			if (new_time_sel == time_sel)
+				continue;
+
+			/* Can we provide requested scale with this time? */
+			ret = iio_gts_find_gain_sel_for_scale_using_time(
+				&data->gts, new_time_sel, val, val2 * 1000,
+				&gain_sel);
+			if (ret)
+				continue;
+
+			/* Can the two other channels maintain scales? */
+			ret = iio_gts_find_new_gain_sel_by_old_gain_time(
+				&data->gts, gains[0].old_gain, time_sel,
+				new_time_sel, &gains[0].new_gain);
+			if (ret)
+				continue;
+
+			ret = iio_gts_find_new_gain_sel_by_old_gain_time(
+				&data->gts, gains[1].old_gain, time_sel,

drivers/iio/light/rohm-bu27034.c line 624

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+				new_time_sel, &gains[1].new_gain);
+			if (!ret) {
+				/* Yes - we found suitable time */
+				found = true;
+				break;
+			}
+		}
+		if (!found) {
+			dev_err(data->dev,
+				"Can't set scale maintaining other channels\n");

We shouldn't print an error to the log in a path like this as we just gave userspace an easy way to overflow the log. Just return -EINVAL without the print. Fine to add it as dev_dbg() though if you like.

Quoted 24 lines
drivers/iio/light/rohm-bu27034.c new file +24 -0
+			ret = -EINVAL;
+
+			goto unlock_out;
+		}
+
+		for (i = 0; i < 2; i++) {
+			ret = bu27034_set_gain(data, gains[i].chan,
+						gains[i].new_gain);
+			if (ret)
+				goto unlock_out;
+		}
+
+		ret = regmap_update_bits(data->regmap, BU27034_REG_MODE_CONTROL1,
+				  BU27034_MASK_MEAS_MODE, new_time_sel);
+		if (ret)
+			goto unlock_out;
+	}
+
+	ret = bu27034_write_gain_sel(data, chan, gain_sel);
+unlock_out:
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}

...

drivers/iio/light/rohm-bu27034.c line 922

Quoted 8 lines
drivers/iio/light/rohm-bu27034.c new file +8 -0
+
+static bool bu27034_has_valid_sample(struct bu27034_data *data)
+{
+	int ret, val;
+
+	ret = regmap_read(data->regmap, BU27034_REG_MODE_CONTROL4, &val);
+	if (ret)
+		dev_err(data->dev, "Read failed %d\n", ret);

Don't use the value if error occurred as unknown state. Just do return false in that path.

drivers/iio/light/rohm-bu27034.c line 924

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+
+	return (val & BU27034_MASK_VALID);

No brackets needed.

Quoted 1 line

+}

...

drivers/iio/light/rohm-bu27034.c line 1002

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+static int bu27034_get_single_result(struct bu27034_data *data, int chan,
+				     int *val)
+{
+	int ret;
+
+

One blank line is enough!

Quoted 25 lines
drivers/iio/light/rohm-bu27034.c new file +25 -0
+	ret = bu27034_meas_set(data, true);
+	if (ret)
+		return ret;
+
+	ret = bu27034_get_int_time(data);
+	if (ret < 0)
+		return ret;
+
+	msleep(ret / 1000);
+
+	return bu27034_read_result(data, chan, val);
+}
+
+/*
+ * The formula given by vendor for computing luxes out of data0 and data1
+ * (in open air) is as follows:
+ *
+ * Let's mark:
+ * D0 = data0/ch0_gain/meas_time_ms * 25600
+ * D1 = data1/ch1_gain/meas_time_ms * 25600
+ *
+ * Then:
+ * if (D1/D0 < 0.87)
+ *	lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 3.45 + 1)
+ * else if (D1/D0 < 1)

drivers/iio/light/rohm-bu27034.c line 1037

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+ *	lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 0.87) * 0.385 + 1)
+ * else
+ *	lx = (0.001331 * D0 + 0.0000354 * D1) * ((D1 / D0 - 2) * -0.05 + 1)
+ *
+ * We use it here. Users who have for example some colored lens
+ * need to modify the calculation but I hope this gives a starting point for
+ * those working with such devices.
+ */
+
+static int bu27034_calc_lux(struct bu27034_data *data, __le16 *res, int *val)

As you are going to put it in the buffer, make val a fixed size integer. The current approach of calculate in an int and copy to a u32 is a bit nasty. Of course if there is a chance of a large enough value you'll have to be careful for the unsigned to signed conversion on 32 bit platforms. I doubt there is, but a comment saying why not would be great in the code that is hit from read_raw()

Quoted 12 lines
drivers/iio/light/rohm-bu27034.c new file +12 -0
+{
+	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
+	 */

drivers/iio/light/rohm-bu27034.c line 1059

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	*val = 0;
+
+	/*
+	 * Avoid div by zeroi. Not using max() as the data may not be in
+	 * native endianes
+	 */
+	if (!res[0])
+		ch0 = 1;
+	else
+		ch0 = le16_to_cpu(res[0]);

As per other branch of the thread.

	ch0 = max(1, le16_to_cpu(res[0]);

would be cleaner.

Quoted 86 lines
drivers/iio/light/rohm-bu27034.c new file +86 -0
+
+	if (!res[1])
+		ch1 = 1;
+	else
+		ch1 = le16_to_cpu(res[1]);
+
+
+	ret = bu27034_get_gain(data, BU27034_CHAN_DATA0, &gain0);
+	if (ret)
+		return ret;
+
+	ret = bu27034_get_gain(data, BU27034_CHAN_DATA1, &gain1);
+	if (ret)
+		return ret;
+
+	ret = bu27034_get_int_time(data);
+	if (ret < 0)
+		return ret;
+
+	meastime = ret;
+
+	d1_d0_ratio_scaled = (unsigned int)ch1 * (unsigned int)gain0 * 100;
+	helper64 = (u64)ch1 * (u64)gain0 * 100LLU;
+
+	if (helper64 != d1_d0_ratio_scaled) {
+		unsigned int div = (unsigned int)ch0 * gain1;
+
+		do_div(helper64, div);
+		d1_d0_ratio_scaled = helper64;
+	} else {
+		d1_d0_ratio_scaled /= ch0 * gain1;
+	}
+
+	if (d1_d0_ratio_scaled < 87)
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 0);
+	else if (d1_d0_ratio_scaled < 100)
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 1);
+	else
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 2);
+
+	return 0;
+
+}
+
+
+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.
+		 */
+		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;

drivers/iio/light/rohm-bu27034.c line 1166

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+
+		mutex_lock(&data->mutex);
+		/*
+		 * Reading one channel at a time is ineffiecient but we don't
+		 * care here. Buffered version should be used if performance is
+		 * an issue.
+		 */
+		ret = bu27034_get_single_result(data, chan->channel, val);
+		if (ret)
+			goto release_err_out;

Move the if (ret) after the locks are released then you don't need the messy goto.

Quoted 7 lines
drivers/iio/light/rohm-bu27034.c new file +7 -0
+
+		mutex_unlock(&data->mutex);
+		iio_device_release_direct_mode(idev);
+
+		return IIO_VAL_INT;
+	}
+

drivers/iio/light/rohm-bu27034.c line 1183

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	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);

See below. I would factor out the rest of this so that you can unconditionally unlock and then check the return value.

Quoted 16 lines
drivers/iio/light/rohm-bu27034.c new file +16 -0
+		ret = bu27034_meas_set(data, true);
+		if (ret)
+			goto release_err_out;
+
+		ret = bu27034_get_lux(data, val);
+		if (ret)
+			goto release_err_out;
+
+		ret = bu27034_meas_set(data, false);
+		if (ret)
+			dev_err(data->dev, "failed to disable measurement\n");
+
+		mutex_unlock(&data->mutex);
+		iio_device_release_direct_mode(idev);
+
+		return IIO_VAL_INT;

drivers/iio/light/rohm-bu27034.c line 1209

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+
+	default:
+		return -EINVAL;
+
+	}
+
+release_err_out:
+	mutex_unlock(&data->mutex);
+	iio_device_release_direct_mode(idev);
+

Having goto targets that are outside of case statements within the arms of a switch is usually a strong hint that it makes sense to factor out the code

drivers/iio/light/rohm-bu27034.c line 304

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+	return ret;
+}
+

blank line here.

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+static const struct iio_info bu27034_info = {
+	.read_raw = &bu27034_read_raw,
+	.write_raw = &bu27034_write_raw,
+	.read_avail = &bu27034_read_avail,
+};
+

...

Quoted 9 lines
drivers/iio/light/rohm-bu27034.c new file +9 -0
+
+static int bu27034_probe(struct i2c_client *i2c)
+{
+	struct device *dev = &i2c->dev;
+	struct fwnode_handle *fwnode;
+	struct bu27034_data *data;
+	struct regmap *regmap;
+	struct iio_dev *idev;
+	unsigned int part_id;

drivers/iio/light/rohm-bu27034.c line 1417

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	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");
+
+	fwnode = dev_fwnode(dev);
+	if (!fwnode)
+		return -ENODEV;

You've already noted this shouldn't be here.

drivers/iio/light/rohm-bu27034.c line 1429

Quoted 12 lines
drivers/iio/light/rohm-bu27034.c new file +12 -0
+
+	idev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!idev)
+		return -ENOMEM;
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret && ret != -ENODEV)
+		return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+	data = iio_priv(idev);
+
+	ret = regmap_read(regmap, BU27034_REG_SYSTEM_CONTROL, &part_id);

As it's not all of the register I'd rename the temporary variable to val or reg or something along those lines.

drivers/iio/light/rohm-bu27034.c line 1433

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+	part_id &= BU27034_MASK_PART_ID;

FIELD_GET() even when it's lower bits as then there is no need for a reviewer to confirm that it is the lower bits.
Then you can just do

	if (FIELD_GET(BU27034_MASK_PART_ID, reg) != BU27034_ID)

drivers/iio/light/rohm-bu27034.c line 1436

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+
+	if (part_id != BU27034_ID)
+		dev_warn(dev, "unsupported device 0x%x\n", part_id);

I'd adjust that to "unknown device" or "unrecognised device" as it might well be supported just fine based on the compatible fallback, we just have no way of knowing if it is.

Quoted 18 lines
drivers/iio/light/rohm-bu27034.c new file +18 -0
+
+	ret = iio_init_iio_gts(BU27034_SCALE_1X, 0, bu27034_gains,
+			       ARRAY_SIZE(bu27034_gains), bu27034_itimes,
+			       ARRAY_SIZE(bu27034_itimes), &data->gts);
+	if (ret)
+		return ret;
+
+	ret = devm_iio_gts_build_avail_tables(dev, &data->gts);
+	if (ret)
+		return ret;
+
+	mutex_init(&data->mutex);
+	data->regmap = regmap;
+	data->dev = dev;
+
+	idev->channels = bu27034_channels;
+	idev->num_channels = ARRAY_SIZE(bu27034_channels);
+	idev->name = "bu27034";

drivers/iio/light/rohm-bu27034.c line 1464

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	idev->info = &bu27034_info;
+
+	idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+	idev->available_scan_masks = bu27034_scan_masks;
+
+	ret = bu27034_chip_init(data);
+	if (ret)
+		return ret;
+
+	ret = devm_iio_kfifo_buffer_setup(dev, idev, &bu27034_buffer_ops);

check ret and error out on failure.

Quoted 11 lines
drivers/iio/light/rohm-bu27034.c new file +11 -0
+
+	ret = devm_iio_device_register(dev, idev);
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+				     "Unable to register iio device\n");
+
+	return ret;
+}
+
+static const struct of_device_id bu27034_of_match[] = {
+	{ .compatible = "rohm,bu27034", },

drivers/iio/light/rohm-bu27034.c line 1485

Quoted 10 lines
drivers/iio/light/rohm-bu27034.c new file +10 -0
+	{ }
+};
+MODULE_DEVICE_TABLE(of, bu27034_of_match);
+
+static struct i2c_driver bu27034_i2c_driver = {
+	.driver = {
+		.name  = "bu27034-als",
+		.of_match_table = bu27034_of_match,
+	  },
+	.probe_new    = bu27034_probe,

I'd just use a single space in all cases before the =
Attempts to align the values in this structure don't really help readability and often end up messier over time.

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+};
+module_i2c_driver(bu27034_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matti Vaittinen <[email protected]>");
+MODULE_DESCRIPTION("ROHM BU27034 ambient light sensor driver");
author maintainer
#25 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 10 lines · Jonathan Cameron
Quoted 6 lines · On Thu, 2 Mar 2023 12:58:59 +0200 Matti Vaittinen <[email protected]>…

+/*
+ * The BU27034 does not have interrupt or any other mechanism of triggering
+ * the data read when measurement has finished. Hence we poll the VALID bit in
+ * a thread. We will try to wake the thread BU27034_MEAS_WAIT_PREMATURE_MS
+ * milliseconds before the expected sampling time to prevent the drifting. Eg,
+ * If we constantly wake up a bit too late we would eventually skip a sample.

Quoted 4 lines

Lazier approach would be to just sent the sampling frequency at twice the expected frequency and you'll never miss a sample unless you the wake up is delayed massively for some reason. Particularly 'fresh' data might not matter enough that half a cycle late is a problem.

Hmm. Do I read this right - You suggest we drop the polling loop for valid bit and just always sleep for int_time / 2 if data was not valid?

I don't know. That would probably make the time-stamps for buffered results to be jumping quite a bit - especially with the longer integration times.

Quoted 18 lines
Quoted 17 lines

+ * And because the sleep can't wake up _exactly_ at given time this would be
+ * inevitable even if the sensor clock would be perfectly phase-locked to CPU
+ * clock - which we can't say is the case.
+ *
+ * This is still fragile. No matter how big advance do we have, we will still
+ * risk of losing a sample because things can in a rainy-day skenario be
+ * delayed a lot. Yet, more we reserve the time for polling, more we also lose
+ * the performance by spending cycles polling the register. So, selecting this
+ * value is a balancing dance between severity of wasting CPU time and severity
+ * of losing samples.
+ *
+ * In most cases losing the samples is not _that_ crucial because light levels
+ * tend to change slowly.
+ */

drivers/iio/light/rohm-bu27034.c new file +3 -0
+#define BU27034_MEAS_WAIT_PREMATURE_MS	5
+#define BU27034_DATA_WAIT_TIME_US	1000
+#define BU27034_TOTAL_DATA_WAIT_TIME_US (BU27034_MEAS_WAIT_PREMATURE_MS * 1000)
Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+			/*
+			 * As Jonathan put it, if caller requests for

Probably don't reference me directly in a driver. Keep the 'blame' for the email threads :) Comment is fine otherwise.

Okay, okay :) I just liked the expression and didn't want to take the credit for it ;)

Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 522

Quoted 4 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+
+	/*
+	 * The new integration time can be supported while keeping the scale of
+	 * channels intact by tuning the gains.

This comment is in a path that is hit event if we go through the warnings above that say this isn't true.

Oh! Valid point! This changed when I allowed gain to be changed - need to drop the comment. Thanks!

Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 1037

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+
+static int bu27034_calc_lux(struct bu27034_data *data, __le16 *res, int *val)

As you are going to put it in the buffer, make val a fixed size integer. The current approach of calculate in an int and copy to a u32 is a bit nasty. Of course if there is a chance of a large enough value you'll have to be careful for the unsigned to signed conversion on 32 bit platforms. I doubt there is, but a comment saying why not would be great in the code that is hit from read_raw()

This same ..._calc_lux() is used also from the read_raw. I'd rather keep this using ints so there would be no need for involving u32 in read_raw() path. However, you are correct in that the current calling from buffered read where we pass pointer to u32 here - is nasty. I'll add temporary int in the calling function there, and add casting with a comment when storing value to scan.lux. Thanks for pointing this out! There was also missing an error return problem - see below.

Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 1099

Quoted 8 lines
drivers/iio/light/rohm-bu27034.c new file +8 -0
+
+	if (d1_d0_ratio_scaled < 87)
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 0);
+	else if (d1_d0_ratio_scaled < 100)
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 1);
+	else
+		*val = bu27034_fixp_calc_lx(ch0, ch1, gain0, gain1, meastime, 2);
+

The bu27034_fixp_calc_lx() might return -EINVAL - which we missed here. I'll fix also this one.

Quoted 6 lines
Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +6 -0
+
+	case IIO_CHAN_INFO_PROCESSED:
+		if (chan->type != IIO_LIGHT)
+			return -EINVAL;
+
+		/* Don't mess with measurement enabling while buffering */
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 1158

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+		ret = iio_device_claim_direct_mode(idev);
+		if (ret)
+			return ret;
+
+		mutex_lock(&data->mutex);

See below. I would factor out the rest of this so that you can unconditionally unlock and then check the return value.

Yes. moving measurement start/stop in bu27034_get_lux() makes this much nicer. I wonder how I didn't see that myself - thanks.

Quoted 5 lines

drivers/iio/light/rohm-bu27034.c line 1429

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+
+	ret = regmap_read(regmap, BU27034_REG_SYSTEM_CONTROL, &part_id);

As it's not all of the register I'd rename the temporary variable to val or reg or something along those lines.

I still like having the variable named part_id - as it makes the check obvious. What I did was adding another temporary variable 'reg' and doing:

part_id = FIELD_GET(BU27034_MASK_PART_ID, reg);

and then using the part_id in if() and dev_warn().

Quoted 12 lines

drivers/iio/light/rohm-bu27034.c line 1433

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +4 -0
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to access sensor\n");
+
+	part_id &= BU27034_MASK_PART_ID;

FIELD_GET() even when it's lower bits as then there is no need for a reviewer to confirm that it is the lower bits.
Then you can just do

	if (FIELD_GET(BU27034_MASK_PART_ID, reg) != BU27034_ID)
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 1436

Quoted 3 lines
drivers/iio/light/rohm-bu27034.c new file +3 -0
+
+	if (part_id != BU27034_ID)
+		dev_warn(dev, "unsupported device 0x%x\n", part_id);

I'd adjust that to "unknown device" or "unrecognised device" as it might well be supported just fine based on the compatible fallback, we just have no way of knowing if it is.

Hmm. Won't promise but maybe I have the time to finish v3 tonight. We can then continue discussions towards the v4 :)

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#26 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 11 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 10 lines · Jonathan Cameron
Quoted 6 lines · On Thu, 2 Mar 2023 12:58:59 +0200 Matti Vaittinen <[email protected]>…

+/*
+ * The BU27034 does not have interrupt or any other mechanism of triggering
+ * the data read when measurement has finished. Hence we poll the VALID bit in
+ * a thread. We will try to wake the thread BU27034_MEAS_WAIT_PREMATURE_MS
+ * milliseconds before the expected sampling time to prevent the drifting. Eg,
+ * If we constantly wake up a bit too late we would eventually skip a sample.

Quoted 7 lines
Quoted 4 lines

Lazier approach would be to just sent the sampling frequency at twice the expected frequency and you'll never miss a sample unless you the wake up is delayed massively for some reason. Particularly 'fresh' data might not matter enough that half a cycle late is a problem.

Hmm. Do I read this right - You suggest we drop the polling loop for valid bit and just always sleep for int_time / 2 if data was not valid?

Yes. There are costs to both methods, but the advantage here is that the chance of being so late you miss becomes much less.

Quoted 4 lines

I don't know. That would probably make the time-stamps for buffered results to be jumping quite a bit - especially with the longer integration times.

True enough. They are probably fairly noisy either way but this would make them worse.

Quoted 29 lines
Quoted 19 lines
Quoted 18 lines

+ * And because the sleep can't wake up _exactly_ at given time this would be
+ * inevitable even if the sensor clock would be perfectly phase-locked to CPU
+ * clock - which we can't say is the case.
+ *
+ * This is still fragile. No matter how big advance do we have, we will still
+ * risk of losing a sample because things can in a rainy-day skenario be
+ * delayed a lot. Yet, more we reserve the time for polling, more we also lose
+ * the performance by spending cycles polling the register. So, selecting this
+ * value is a balancing dance between severity of wasting CPU time and severity
+ * of losing samples.
+ *
+ * In most cases losing the samples is not _that_ crucial because light levels
+ * tend to change slowly.
+ */

drivers/iio/light/rohm-bu27034.c new file +3 -0
+#define BU27034_MEAS_WAIT_PREMATURE_MS	5
+#define BU27034_DATA_WAIT_TIME_US	1000
+#define BU27034_TOTAL_DATA_WAIT_TIME_US (BU27034_MEAS_WAIT_PREMATURE_MS * 1000)  
Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),  

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 7 lines
Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux? Or return it as INFO_RAW - thus making it clear that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

In the rare case where you do get SCALE and PROCESSED it's there to allow for changes in the underlying signal measurement that are eaten up in the computation needed to get to PROCESSED - that is they have no visible affect (beyond range changes etc).

...

Quoted 6 lines
Quoted 5 lines

drivers/iio/light/rohm-bu27034.c line 1429

Quoted 2 lines
drivers/iio/light/rohm-bu27034.c new file +2 -0
+
+	ret = regmap_read(regmap, BU27034_REG_SYSTEM_CONTROL, &part_id);  

As it's not all of the register I'd rename the temporary variable to val or reg or something along those lines.

Quoted 6 lines

I still like having the variable named part_id - as it makes the check obvious. What I did was adding another temporary variable 'reg' and doing:

part_id = FIELD_GET(BU27034_MASK_PART_ID, reg);

and then using the part_id in if() and dev_warn().

Looks good.

Jonathan

author maintainer
#27 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 7 lines · Jonathan Cameron
Quoted 4 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 3 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

// snip

Quoted 13 lines
Quoted 13 lines
Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 6 lines
Quoted 4 lines

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux?

That's what I did originally have. But then I noticed we can get slightly better accuracy than that. Hence I switched to mLux and added the scale.

Quoted 3 lines

Or return it as INFO_RAW - thus making it clear
that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

Ah. This makes sense then. Maybe it would be worth adding a warning to IIO-core if drivers set both the SCALE and PROCESSED info bits?

So, I need to select between the simplicity or better accuracy here? :/ I really hate ending up making choices like this without knowing all the real use-cases :( And it happens a lot for me. Well, I guess I'll drop the scale, use luxes and go with the PROCESSED data. My understanding is that the "thing" with the sensor is a wide-range for wavelengths, not the accuracy. So, maybe luxes are just good enough - and again, users needing something more accurate can utilize the raw intensity channels.

Quoted 5 lines

In the rare case where you do get SCALE and PROCESSED it's there to allow for changes in the underlying signal measurement that are eaten up in the computation needed to get to PROCESSED - that is they have no visible affect (beyond range changes etc).

Oh, Ok. So there is a valid case for setting both SCALE and PROCESSED. Then we can't add teh warning I assume :(

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#28 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 35 lines · On Mon, 13 Mar 2023 11:39:06 +0200 Matti Vaittinen <[email protected]>…
Quoted 7 lines · Jonathan Cameron
Quoted 4 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 3 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

// snip

Quoted 13 lines
Quoted 13 lines
Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),  

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 6 lines
Quoted 4 lines

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux?

That's what I did originally have. But then I noticed we can get slightly better accuracy than that. Hence I switched to mLux and added the scale.

Quoted 6 lines
Quoted 3 lines

Or return it as INFO_RAW - thus making it clear
that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

Ah. This makes sense then. Maybe it would be worth adding a warning to IIO-core if drivers set both the SCALE and PROCESSED info bits?

Hmm. I'm not sure that we don't have valid users of it even if they are unusual. We also have some historical messes that do RAW + SCALE + PROCESSED so we can't really have a warning on it.

Warning generally is that the test tools that come with the kernel will give you the wrong reading. :)

Quoted 8 lines

So, I need to select between the simplicity or better accuracy here? :/ I really hate ending up making choices like this without knowing all the real use-cases :( And it happens a lot for me. Well, I guess I'll drop the scale, use luxes and go with the PROCESSED data. My understanding is that the "thing" with the sensor is a wide-range for wavelengths, not the accuracy. So, maybe luxes are just good enough - and again, users needing something more accurate can utilize the raw intensity channels.

Hmm. For the sysfs case you could use VAL_INT_PLUS_MICRO but that doesn't then work well with the buffered path.

It is perfectly valid to just have this as _RAW and keep your _SCALE so that's probably the best option
_RAW doesn't have to mean totally raw, it just means userspace is expected to applying a linear conversion to get a reading in the 'base' units for the channel.

Quoted 9 lines
Quoted 6 lines

In the rare case where you do get SCALE and PROCESSED it's there to allow for changes in the underlying signal measurement that are eaten up in the computation needed to get to PROCESSED - that is they have no visible affect (beyond range changes etc).

Oh, Ok. So there is a valid case for setting both SCALE and PROCESSED. Then we can't add teh warning I assume :(

They are obscure but IIRC there are some.

Jonathan

Quoted 5 lines

Yours,
-- Matti

author maintainer
#29 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 61 lines · Jonathan Cameron
Quoted 35 lines · On Mon, 13 Mar 2023 11:39:06 +0200 Matti Vaittinen <[email protected]>…
Quoted 7 lines · Jonathan Cameron
Quoted 4 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 3 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

// snip

Quoted 13 lines
Quoted 13 lines
Quoted 7 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 5 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 6 lines
Quoted 4 lines

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux?

That's what I did originally have. But then I noticed we can get slightly better accuracy than that. Hence I switched to mLux and added the scale.

Quoted 6 lines
Quoted 3 lines

Or return it as INFO_RAW - thus making it clear
that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

Ah. This makes sense then. Maybe it would be worth adding a warning to IIO-core if drivers set both the SCALE and PROCESSED info bits?

Hmm. I'm not sure that we don't have valid users of it even if they are unusual. We also have some historical messes that do RAW + SCALE + PROCESSED so we can't really have a warning on it.

Warning generally is that the test tools that come with the kernel will give you the wrong reading. :)

Quoted 8 lines

So, I need to select between the simplicity or better accuracy here? :/ I really hate ending up making choices like this without knowing all the real use-cases :( And it happens a lot for me. Well, I guess I'll drop the scale, use luxes and go with the PROCESSED data. My understanding is that the "thing" with the sensor is a wide-range for wavelengths, not the accuracy. So, maybe luxes are just good enough - and again, users needing something more accurate can utilize the raw intensity channels.

Quoted 7 lines

Hmm. For the sysfs case you could use VAL_INT_PLUS_MICRO but that doesn't then work well with the buffered path.

It is perfectly valid to just have this as _RAW and keep your _SCALE so that's probably the best option
_RAW doesn't have to mean totally raw, it just means userspace is expected to applying a linear conversion to get a reading in the 'base' units for the channel.

Thanks for the insight!

I'll return the scale and switch to RAW for v5 :)

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
author maintainer
#30 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

In reply to Jonathan Cameron
Quoted 6 lines · Jonathan Cameron
Quoted 3 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 2 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

//snip

Quoted 14 lines
Quoted 14 lines
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 9 lines
Quoted 4 lines

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux? Or return it as INFO_RAW - thus making it clear that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

I just noticed a thing. I used the iio_generic_buffer to test the changes - and it got the channel values scaled to luxes even for the PROCESSED channel. So, it seems to me the iio_generic_buffer does apply the scale for PROCESSED channels too. I think that is slightly misleading. Oh, and this is not intended to be a complaint - just a report that there might be some room for an improvement :)

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
maintainer
#31 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 34 lines · On Tue, 14 Mar 2023 11:39:22 +0200 Matti Vaittinen <[email protected]>…
Quoted 6 lines · Jonathan Cameron
Quoted 3 lines · On Sun, 5 Mar 2023 14:22:51 +0200 Matti Vaittinen <[email protected]>…
Quoted 2 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

//snip

Quoted 14 lines
Quoted 14 lines
Quoted 8 lines

drivers/iio/light/rohm-bu27034.c line 172

Quoted 6 lines
drivers/iio/light/rohm-bu27034.c new file +5 -0
+static const struct iio_chan_spec bu27034_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_SCALE),  

What is this scale for?

The scale is to inform users that we return data using milli lux.

Quoted 2 lines

Given the channel is computed from various different inputs, is there a clear definition of how it is scaled? What does a write to it mean?

Quoted 9 lines
Quoted 4 lines

Nothing. writing anything else but milli lux scale fails with -EINVAL.

I guess I am doing something in an unusual way here :) Do you have a suggestion for me?

Return data in lux? Or return it as INFO_RAW - thus making it clear that the reading is not in expected units and a conversion must be applied by userspace. SCALE is not applied to PROCESSED by userspace.

Quoted 6 lines

I just noticed a thing. I used the iio_generic_buffer to test the changes - and it got the channel values scaled to luxes even for the PROCESSED channel. So, it seems to me the iio_generic_buffer does apply the scale for PROCESSED channels too. I think that is slightly misleading. Oh, and this is not intended to be a complaint - just a report that there might be some room for an improvement :)

Ah. Looks like the code doesn't have any check on whether the sysfs read is _raw or _processed which is kind of understandable.

This may be the first case where those have both applied on a channel that is available via buffered route.

Given processed channels are rarely IIO_VAL_INT which is kind of necessary to poke it in the buffered route, that may well be true.

Jonathan

Quoted 4 lines

Yours,
-- Matti

author maintainer
#32 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

In reply to Jonathan Cameron
Quoted 7 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

As per other branch of the thread.

	ch0 = max(1, le16_to_cpu(res[0]);
Quoted 1 line

would be cleaner.

I tried this out. Comparing u16 to literal 1 results comparison of values with different sizes:

./include/linux/minmax.h:20:28: warning: comparison of distinct pointer types lacks a cast
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))

                            ^
./include/linux/minmax.h:26:4: note: in expansion of macro ‘__typecheck’
   (__typecheck(x, y) && __no_side_effects(x, y))
    ^~~~~~~~~~~
./include/linux/minmax.h:36:24: note: in expansion of macro ‘__safe_cmp’
  __builtin_choose_expr(__safe_cmp(x, y), \
                        ^~~~~~~~~~
./include/linux/minmax.h:74:19: note: in expansion of macro ‘__careful_cmp’
 #define max(x, y) __careful_cmp(x, y, >)
                   ^~~~~~~~~~~~~

drivers/iio/light/rohm-bu27034.c:1057:8: note: in expansion of macro ‘max’
ch0 = max(1, ch0);

I could work around this by doing:

const u16 min_ch_val = 1;

...

ch0 = max(min_ch_val, le16_to_cpu(res[0]));

but I think that would really be obfuscating the meaning. I assume

ch0 = max((u16)1, le16_to_cpu(res[0]));

might work too - but to me it's pretty ugly.

The more I am looking at this, the stronger I feel we should really just write this as it was. Check if res[0] contains the only unsafe data "!res[0]" - and if yes, set it to 1. The comment above it will clarify it to a reader wondering what happens.

I will leave it like it was in v2 for v3. If you still feel strong about it then we need to continue rubbing it.

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#33 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 35 lines · Matti Vaittinen
Quoted 7 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

As per other branch of the thread.

	ch0 = max(1, le16_to_cpu(res[0]);
Quoted 1 line

would be cleaner.

I tried this out. Comparing u16 to literal 1 results comparison of values with different sizes:

./include/linux/minmax.h:20:28: warning: comparison of distinct pointer types lacks a cast
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))

                            ^
./include/linux/minmax.h:26:4: note: in expansion of macro ‘__typecheck’
   (__typecheck(x, y) && __no_side_effects(x, y))
    ^~~~~~~~~~~
./include/linux/minmax.h:36:24: note: in expansion of macro ‘__safe_cmp’
  __builtin_choose_expr(__safe_cmp(x, y), \
                        ^~~~~~~~~~
./include/linux/minmax.h:74:19: note: in expansion of macro ‘__careful_cmp’
 #define max(x, y) __careful_cmp(x, y, >)
                   ^~~~~~~~~~~~~

drivers/iio/light/rohm-bu27034.c:1057:8: note: in expansion of macro ‘max’
ch0 = max(1, ch0);

I could work around this by doing:

const u16 min_ch_val = 1;

...

Quoted 7 lines

ch0 = max(min_ch_val, le16_to_cpu(res[0]));

but I think that would really be obfuscating the meaning. I assume

ch0 = max((u16)1, le16_to_cpu(res[0]));

might work too - but to me it's pretty ugly.

That's why we have max_t() and clamp_val().
And you know that.

Quoted 8 lines

The more I am looking at this, the stronger I feel we should really just write this as it was. Check if res[0] contains the only unsafe data "!res[0]" - and if yes, set it to 1. The comment above it will clarify it to a reader wondering what happens.

I will leave it like it was in v2 for v3. If you still feel strong about it then we need to continue rubbing it.

You need to convert bit ordering first, then check for 0. It would at least make more sense. (Today is 0 you are comparing with, tomorrow it might be 0xfffe, which is different to 0x7fff).

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#34 lore raw

Re: [PATCH v2 5/6] iio: light: ROHM BU27034 Ambient Light Sensor

Quoted 38 lines · Andy Shevchenko
Quoted 37 lines · Matti Vaittinen
Quoted 7 lines · Jonathan Cameron

On Thu, 2 Mar 2023 12:58:59 +0200
Matti Vaittinen <[email protected]> wrote:

As per other branch of the thread.

	ch0 = max(1, le16_to_cpu(res[0]);
Quoted 1 line

would be cleaner.

I tried this out. Comparing u16 to literal 1 results comparison of values with different sizes:

./include/linux/minmax.h:20:28: warning: comparison of distinct pointer types lacks a cast
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))

                             ^
./include/linux/minmax.h:26:4: note: in expansion of macro ‘__typecheck’
    (__typecheck(x, y) && __no_side_effects(x, y))
     ^~~~~~~~~~~
./include/linux/minmax.h:36:24: note: in expansion of macro ‘__safe_cmp’
   __builtin_choose_expr(__safe_cmp(x, y), \
                         ^~~~~~~~~~
./include/linux/minmax.h:74:19: note: in expansion of macro ‘__careful_cmp’
  #define max(x, y) __careful_cmp(x, y, >)
                    ^~~~~~~~~~~~~

drivers/iio/light/rohm-bu27034.c:1057:8: note: in expansion of macro ‘max’
ch0 = max(1, ch0);

I could work around this by doing:

const u16 min_ch_val = 1;

...

ch0 = max(min_ch_val, le16_to_cpu(res[0]));

Quoted 8 lines
Quoted 5 lines

but I think that would really be obfuscating the meaning. I assume

ch0 = max((u16)1, le16_to_cpu(res[0]));

might work too - but to me it's pretty ugly.

That's why we have max_t() and clamp_val().
And you know that.

Thanks for pointing out the max_t(). I really missed that. I didn't think of the clamp_val() either. clamp_val() would "explain" better what we do here - but as we don't have the upper limit using that would (IMO) be slightly more confusing.

Quoted 11 lines
Quoted 7 lines

The more I am looking at this, the stronger I feel we should really just write this as it was. Check if res[0] contains the only unsafe data "!res[0]" - and if yes, set it to 1. The comment above it will clarify it to a reader wondering what happens.

I will leave it like it was in v2 for v3. If you still feel strong about it then we need to continue rubbing it.

You need to convert bit ordering first, then check for 0. It would at least make more sense. (Today is 0 you are comparing with, tomorrow it might be 0xfffe, which is different to 0x7fff).

I don't think being prepared for any other check but the check for 0 is meaningful here. Every other value except 0 is valid for this sensor and can be accepted as such. Preparing for something that may never realize (new sensor with less than 16bits of data) is likely to just make things more complicated.

Well, as both You and Jonathan do think we should not just do if(!res[0]) - I'll try using the max_t() as you suggested. I still really dislike it because it makes it harder (for me) to capture what happens here. Well, I try to survive with this and hopefully just read the comment above if puzzled when I need to get back to this code.

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
author maintainer
#35 lore raw

PATCH v2 6/6 MAINTAINERS: Add ROHM BU27034

In reply to Matti Vaittinen

Add myself as a maintainer for ROHM BU27034 ALS driver.

---
Changes since RFCv1:
- Add iio-list

---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)
MAINTAINERS +6 -0
index af8516d5df36..f75b38e6052d 100644
@@ -18102,6 +18102,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/iio/light/bh1750.yaml
 F:	drivers/iio/light/bh1750.c
 
+ROHM BU27034 AMBIENT LIGHT SENSOR DRIVER
+M:	Matti Vaittinen <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/iio/light/rohm-bu27034.c
+
 ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
 M:	Marek Vasut <[email protected]>
 L:	[email protected]
Signature · 14 lines
2.39.2


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =]