Skip to contentSkip to conversation

Support ROHM BU27008 RGB sensor

PATCH In review Matti Vaittinen 4 participants 11 messages May 8, 2023 – Jun 12, 2023

Subsystems (3)
lore
Share & tools
lore

Matti Vaittinen

author maintainer
#0 lore raw

v5 cover Support ROHM BU27008 RGB sensor

Add support for ROHM BU27008 RGB sensor.

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

This series supports reading the RGBC and IR channels using IIO framework. However, only two of the BC+IR can be enabled at the same time. Series adds also support for scale and integration time configuration, where scale consists of impact of both the integration time and hardware gain. The gain and time support is backed by the newly introduced IIO GTS helper. This series depends on GTS helper patches added in BU27034 support series which is already merged in iio/togreg which this series is based on.

The hardware allows configuring gain setting by writing a 5-bit gain selector value to a register. Part of the gain setting is common for all channels (RGBC + IR) but part of the selector value can be set separately for RGBC and IR:

MODE_CONTROL2 REG:
bit 7 6 5 4 3 2 1 0
-----------------------------------------------------------------

|	RGB	selector		|
+---------------------------------------+
-----------------------------------------------------------------
| high bits IR	|			| low bits IR selector	|
+---------------+			+-----------------------+

In theory it would be possible to set certain separate gain values for RGBC and IR channels, but this gets pretty confusing because there are a few 'unsupported' selector values. If only RGBC or IR was set, some extra handling should be done to prevent the other channel from getting unsupported value due to change in high-bits. Furthermore, allowing the channels to be set different gain values (in some cases when gains are such the HW supports it) would make the cases where also integration time is changed to achieve correct scale ... interesting. It might also be confusing for user to try predicting when setting different scales succeeds and when it does not. Furthermore, if for example the scale setting for RGBC caused IR selector to be invalid - it could also cause the IR scale to "jump" very far from previous value.

To make the code simpler and more predictable for users, the current logic is as follows:

1. Prevent setting IR scale. (My assumption is IR is less used than RGBC)
2. When RGBC scale is set, set also the IR-selector to the same value. This prevents unsupported selector values and makes the IR scale changes predictable.

The 2) could mean we effectively have the same scale for all channels. Unfortunately, the HW design is slightly peculiar and selector 0 means gain 1X on RGBC but gain 2X on IR. Rest of the selectors equal same gain values on RGBC and IR. The result is that while changin selector from 0 => 1 causes RGBC gain to go from 1X => 4X, it causes IR gain to go from 2X => 4X.

So, the driver provides separate scale entries for all channels (also RGB and C will have separate gain entries because these channels are of same type as IR channel). This makes it possible for user applications to go read the scales for all channels after setting scale for one (in order to detect the IR scale difference).

Having the separate IR scale entry which applications can read to detect "arbitrary scale changes" makes it possible for applications to be written so they can cope if we need to implement the 'allow setting some different gains for IR and RGBC' - later.

Finally, the scales_available is also provided for all other channels except the IR channel, which does not allow the scale to be changed.

The sensor provides a data-ready IRQ and the driver implements a triggered buffer mode using this IRQ as a trigger.

Finally, the series introduces generic iio_validate_own_trigger() helper which can be used as a validate_trigger callback for drivers which require the trigger and iio-device to be parented by same device. The KX022A driver is converted to use this new callback instead of rolling it's own function. The new helper and KX022A can be merged in as independent changes if need be.

Revision history
v3 => v4:
iio_validate_own_trigger:
- kernel-doc fix
bu27008 driver fixes:
- re-enable IRQ in trigger renable-callback
- do trigger setup on own function
- drop regmap lock
- configure channels in appropriate callback
v3 => v4:
bu27008 driver fixes:
- Drop thread from device IRQ handler
- Styling and some minor improvements
- Use kernel-doc for enums
- Correctly order entries in Makefile
v2 => v3:
dt-bindings:
- No changes
iio_validate_own_trigger:
- subject fix
bu27008:
- Mostly styling based on comments from Andy and Andi

More accurate changelog in individual patches

v1 => v2:
dt-bindings:
- Fix issues pointed by Krzysztof.
bu27008 driver:
- Fix issues pointed by Jonathan
Add new helper for validating own trigger

More accurate changelog in individual patches

---

Matti Vaittinen (5):
dt-bindings: iio: light: ROHM BU27008
iio: trigger: Add simple trigger_validation helper
iio: kx022a: Use new iio_validate_own_trigger()
iio: light: ROHM BU27008 color sensor
MAINTAINERS: Add ROHM BU27008

 .../bindings/iio/light/rohm,bu27008.yaml      |   49 +
 MAINTAINERS                                   |    3 +-
 drivers/iio/accel/kionix-kx022a.c             |   13 +-
 drivers/iio/industrialio-trigger.c            |   22 +-
 drivers/iio/light/Kconfig                     |   14 +
 drivers/iio/light/Makefile                    |    1 +
 drivers/iio/light/rohm-bu27008.c              | 1026 +++++++++++++++++
 include/linux/iio/trigger.h                   |    1 +
 8 files changed, 1115 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml
 create mode 100644 drivers/iio/light/rohm-bu27008.c
Signature · 14 lines
2.40.1


-- 
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 v5 1/5 dt-bindings: iio: light: ROHM BU27008

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Add BU27008 dt-bindings.

---
Revision history:
v2 => No changes

v1 => v2:
- fix binding file name
- fix binding id
- drop unnecessary '|' from description

---
 .../bindings/iio/light/rohm,bu27008.yaml      | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml
Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml new file +49 -0
new file mode 100644
index 000000000000..4f66fd47b016
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/rohm,bu27008.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BU27008 color sensor
+
+maintainers:
+  - Matti Vaittinen <[email protected]>
+
+description:
+  The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear
+  and IR) with four configurable channels. Red and green being always
+  available and two out of the rest three (blue, clear, IR) can be
+  selected to be simultaneously measured. Typical application is adjusting
+  LCD backlight of TVs, mobile phones and tablet PCs.
+
+properties:
+  compatible:
+    const: rohm,bu27008
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-supply: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      light-sensor@38 {
+        compatible = "rohm,bu27008";
+        reg = <0x38>;
+      };
+    };
+
+...
Signature · 14 lines
2.40.1


-- 
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 v5 2/5 iio: trigger: Add simple trigger_validation helper

In reply to Matti Vaittinen

Some triggers can only be attached to the IIO device that corresponds to the same physical device. Implement generic helper which can be used as a validate_trigger callback for such devices.

---
Revision history
v4: => v5:
- fix kernel-doc case
v2: => v3:
- Fix title (space after iio:)
v2: New patch

---
 drivers/iio/industrialio-trigger.c | 22 +++++++++++++++++++++-
 include/linux/iio/trigger.h        |  1 +
 2 files changed, 22 insertions(+), 1 deletion(-)
drivers/iio/industrialio-trigger.c +21 -1
index 784dc1e00310..f207e36b12cc 100644
@@ -322,7 +322,7 @@ int iio_trigger_attach_poll_func(struct iio_trigger *trig,
 	 * this is the case if the IIO device and the trigger device share the
 	 * same parent device.
 	 */
-	if (pf->indio_dev->dev.parent == trig->dev.parent)
+	if (iio_validate_own_trigger(pf->indio_dev, trig))
 		trig->attached_own_device = true;
 
 	return ret;
@@ -728,6 +728,26 @@ bool iio_trigger_using_own(struct iio_dev *indio_dev)
 }
 EXPORT_SYMBOL(iio_trigger_using_own);
 
+/**
+ * iio_validate_own_trigger - Check if a trigger and IIO device belong to
+ *  the same device
+ * @idev: the IIO device to check
+ * @trig: the IIO trigger to check
+ *
+ * This function can be used as the validate_trigger callback for triggers that
+ * can only be attached to their own device.
+ *
+ * Return: 0 if both the trigger and the IIO device belong to the same
+ * device, -EINVAL otherwise.
+ */
+int iio_validate_own_trigger(struct iio_dev *idev, struct iio_trigger *trig)
+{
+	if (idev->dev.parent != trig->dev.parent)
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iio_validate_own_trigger);
+
 /**
  * iio_trigger_validate_own_device - Check if a trigger and IIO device belong to
  *  the same device
include/linux/iio/trigger.h +1 -0
index 51f52c5c6092..bce3b1788199 100644
@@ -171,6 +171,7 @@ void iio_trigger_free(struct iio_trigger *trig);
  */
 bool iio_trigger_using_own(struct iio_dev *indio_dev);
 
+int iio_validate_own_trigger(struct iio_dev *idev, struct iio_trigger *trig);
 int iio_trigger_validate_own_device(struct iio_trigger *trig,
 				     struct iio_dev *indio_dev);
 
Signature · 14 lines
2.40.1


-- 
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
#3 lore raw

PATCH v5 3/5 iio: kx022a: Use new iio_validate_own_trigger()

In reply to Matti Vaittinen

The new generic iio_validate_own_trigger() can be used as validate_trigger callback for verifying the used trigger belongs to same device as the iio_dev.

Use the generic function instead of rolling own one.

---
Revision history
v2: New patch

---
 drivers/iio/accel/kionix-kx022a.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/iio/accel/kionix-kx022a.c +1 -12
index f98393d74666..09814881f513 100644
@@ -516,17 +516,6 @@ static int kx022a_read_raw(struct iio_dev *idev,
 	return -EINVAL;
 };
 
-static int kx022a_validate_trigger(struct iio_dev *idev,
-				   struct iio_trigger *trig)
-{
-	struct kx022a_data *data = iio_priv(idev);
-
-	if (data->trig != trig)
-		return -EINVAL;
-
-	return 0;
-}
-
 static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
 {
 	struct kx022a_data *data = iio_priv(idev);
@@ -725,7 +714,7 @@ static const struct iio_info kx022a_info = {
 	.write_raw = &kx022a_write_raw,
 	.read_avail = &kx022a_read_avail,
 
-	.validate_trigger	= kx022a_validate_trigger,
+	.validate_trigger	= iio_validate_own_trigger,
 	.hwfifo_set_watermark	= kx022a_set_watermark,
 	.hwfifo_flush_to_buffer	= kx022a_fifo_flush,
 };
Signature · 14 lines
2.40.1


-- 
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
#4 lore raw

PATCH v5 4/5 iio: light: ROHM BU27008 color sensor

In reply to Matti Vaittinen

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Add initial support for the ROHM BU27008 color sensor.
- raw_read() of RGB and clear channels
- triggered buffer w/ DRDY interrtupt

---

Please, check the way trigger handling is now implemented. I've verified it works for one user-space user, but I am no longer confident on how the triggers are intended to be used.

When testing the trigger passing iio_trigger_generic_data_rdy_poll() as a handler in devm_request_irq() I saw an IRQ storm. The threaded handler given in devm_iio_triggered_buffer_setup() [bu27008_trigger_handler()] got never called and system hung just looping in iio_trigger_generic_data_rdy_poll(). Hence, this version disables the IRQ in the handler registered at devm_request_irq(), before cascading into iio_trigger_poll(). IRQ is now re-enabled in trigger's .reenable callback. Feedback is appreciated!

Revision history
v4 => v5:
- do trigger setup on own function
- fix kerneldoc for enum bu27008_chan
- minor stylings
- drop regmap lock
- probe asynchronously
- re-enable IRQ in trigger reenable callback.
- configure channels in appropriate callback.
- styling

v3 => v4:
- use regmap_write_bits() for SWRESET
- reorder Makefile entries
- styling + impoved comments
- drop bu27008_irq_thread_handler() and call iio_trigger_poll() from IRQ top half
- use devm_request_irq() instead of devm_request_threaded_irq()
- Explicitly disable the IRQ from top-half instead of thread + IRQF_ONESHOT
- drop print severity
- reinit regmap cache after reset
- avoid unnecessary division when waiting measurement to complete
- use kernel-doc for enums

v2 => v3:
- drop bits.h
- drop unnecessary comma after compatible
- Styling / cleaning
- Simplify sleep time computation
- rename bu27008_get_int_time() => bu27008_get_int_time_us()

v1 => v2:
- Fix buffered data demuxing
- Use generic trigger functions instead of rolling own ones
- Drop unnecessary locking
- Use generic iio_validate_own_trigger()
- Some other more trivial fixes for review comments
- use defines for [enable/disable] [measurement/data-ready IRQ] reg values and use regmap_update_bits() directly instead of regamap_[set/clear]_bits()

---
 drivers/iio/light/Kconfig        |   14 +
 drivers/iio/light/Makefile       |    1 +
 drivers/iio/light/rohm-bu27008.c | 1026 ++++++++++++++++++++++++++++++
 3 files changed, 1041 insertions(+)
 create mode 100644 drivers/iio/light/rohm-bu27008.c
drivers/iio/light/Kconfig +14 -0
index 6fa31fcd71a1..7888fc439b2f 100644
@@ -289,6 +289,20 @@ config JSA1212
 	  To compile this driver as a module, choose M here:
 	  the module will be called jsa1212.
 
+config ROHM_BU27008
+	tristate "ROHM BU27008 color (RGB+C/IR) sensor"
+	depends on I2C
+	select REGMAP_I2C
+	select IIO_GTS_HELPER
+	help
+	  Enable support for the ROHM BU27008 color sensor.
+	  The ROHM BU27008 is a sensor with 5 photodiodes (red, green,
+	  blue, clear and IR) with four configurable channels. Red and
+	  green being always available and two out of the rest three
+	  (blue, clear, IR) can be selected to be simultaneously measured.
+	  Typical application is adjusting LCD backlight of TVs,
+	  mobile phones and tablet PCs.
+
 config ROHM_BU27034
 	tristate "ROHM BU27034 ambient light sensor"
 	depends on I2C
drivers/iio/light/Makefile +1 -0
index 985f6feaccd4..82dec50a7e19 100644
@@ -38,6 +38,7 @@ obj-$(CONFIG_MAX44009)		+= max44009.o
 obj-$(CONFIG_NOA1305)		+= noa1305.o
 obj-$(CONFIG_OPT3001)		+= opt3001.o
 obj-$(CONFIG_PA12203001)	+= pa12203001.o
+obj-$(CONFIG_ROHM_BU27008)	+= rohm-bu27008.o
 obj-$(CONFIG_ROHM_BU27034)	+= rohm-bu27034.o
 obj-$(CONFIG_RPR0521)		+= rpr0521.o
 obj-$(CONFIG_SI1133)		+= si1133.o
drivers/iio/light/rohm-bu27008.c new file +1026 -0

1,026 lines not on this page · raw message

Signature · 14 lines
2.40.1


-- 
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 =] 
maintainer
#5 lore raw

Re: [PATCH v5 4/5] iio: light: ROHM BU27008 color sensor

Quoted 18 lines · On Mon, 8 May 2023 13:39:29 +0300 Matti Vaittinen <[email protected]>…

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Add initial support for the ROHM BU27008 color sensor.
- raw_read() of RGB and clear channels
- triggered buffer w/ DRDY interrtupt

---

Please, check the way trigger handling is now implemented. I've verified it works for one user-space user, but I am no longer confident on how the triggers are intended to be used.

Quoted 8 lines

When testing the trigger passing iio_trigger_generic_data_rdy_poll() as a handler in devm_request_irq() I saw an IRQ storm. The threaded handler given in devm_iio_triggered_buffer_setup() [bu27008_trigger_handler()] got never called and system hung just looping in iio_trigger_generic_data_rdy_poll(). Hence, this version disables the IRQ in the handler registered at devm_request_irq(), before cascading into iio_trigger_poll(). IRQ is now re-enabled in trigger's .reenable callback. Feedback is appreciated!

What you have makes sense to me.

A few trivial things inline I'll tidy up whilst applying.

drivers/iio/light/rohm-bu27008.c line 798

Quoted 5 lines
drivers/iio/light/rohm-bu27008.c new file +5 -0
+static int bu27008_trigger_set_state(struct iio_trigger *trig,
+				     bool state)
+{
+	struct bu27008_data *data = iio_trigger_get_drvdata(trig);
+	int ret = 0;

No need to initialize ret.

Quoted 14 lines
drivers/iio/light/rohm-bu27008.c new file +14 -0
+
+	if (state)
+		ret = bu27008_set_drdy_irq(data, BU27008_INT_EN);
+	else
+		ret = bu27008_set_drdy_irq(data, BU27008_INT_DIS);
+	if (ret)
+		dev_err(data->dev, "Failed to set trigger state\n");
+
+	return ret;
+}
+
+static void bu27008_trigger_reenable(struct iio_trigger *trig)
+{
+	struct bu27008_data *data = iio_trigger_get_drvdata(trig);

drivers/iio/light/rohm-bu27008.c line 878

Quoted 10 lines
drivers/iio/light/rohm-bu27008.c new file +8 -0
+
+	enable_irq(data->irq);
+}
 
 
+static irqreturn_t bu27008_data_rdy_poll(int irq, void *private)
+{
+	/*
+	 * The BU27008 keeps IRQ asserted until we read the VALID bit from
+	 * a register. We need to keep the IRQ disabled until this

Half sentence. If this is all that comes up I'll change it to.

We need to keep the IRQ disable until then.

Quoted 50 lines
drivers/iio/light/rohm-bu27008.c new file +50 -0
+	 */
+	disable_irq_nosync(irq);
+	iio_trigger_poll(private);
+
+	return IRQ_HANDLED;
+}
+
+static int bu27008_setup_trigger(struct bu27008_data *data, struct iio_dev *idev)
+{
+	struct iio_trigger *itrig;
+	char *name;
+	int ret;
+
+	ret = devm_iio_triggered_buffer_setup(data->dev, idev,
+					      &iio_pollfunc_store_time,
+					      bu27008_trigger_handler,
+					      &bu27008_buffer_ops);
+	if (ret)
+		return dev_err_probe(data->dev, ret,
+			     "iio_triggered_buffer_setup_ext FAIL\n");
+
+	itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d",
+				       idev->name, iio_device_id(idev));
+	if (!itrig)
+		return -ENOMEM;
+
+	data->trig = itrig;
+
+	itrig->ops = &bu27008_trigger_ops;
+	iio_trigger_set_drvdata(itrig, data);
+
+	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bu27008",
+			      dev_name(data->dev));
+
+	ret = devm_request_irq(data->dev, data->irq,
+			       &bu27008_data_rdy_poll,
+			       0, name, itrig);
+	if (ret)
+		return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
+
+	ret = devm_iio_trigger_register(data->dev, itrig);
+	if (ret)
+		return dev_err_probe(data->dev, ret,
+				     "Trigger registration failed\n");
+
+	/* set default trigger */
+	idev->trig = iio_trigger_get(itrig);
+
+	return 0;
+}
author maintainer
#6 lore raw

PATCH v5 5/5 MAINTAINERS: Add ROHM BU27008

In reply to Matti Vaittinen

Add myself as a maintainer for ROHM BU27008 color sensor driver.

---
Revision history:
No changes since v1

---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
MAINTAINERS +2 -1
index 32772c383ab7..c02e3d2ec348 100644
@@ -18198,10 +18198,11 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/iio/light/bh1750.yaml
 F:	drivers/iio/light/bh1750.c
 
-ROHM BU27034 AMBIENT LIGHT SENSOR DRIVER
+ROHM BU270xx LIGHT SENSOR DRIVERs
 M:	Matti Vaittinen <[email protected]>
 L:	[email protected]
 S:	Supported
+F:	drivers/iio/light/rohm-bu27008.c
 F:	drivers/iio/light/rohm-bu27034.c
 
 ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
Signature · 14 lines
2.40.1


-- 
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 =] 
maintainer
#7 lore raw
In reply to Matti Vaittinen
Quoted 1 line · On Mon, 8 May 2023 13:30:28 +0300 Matti Vaittinen <[email protected]>…

Add support for ROHM BU27008 RGB sensor.

Series applied to the togreg branch of iio.git and pushed out initially as testing for all the normal reasons.

Thanks,

Jonathan

Quoted 139 lines

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

This series supports reading the RGBC and IR channels using IIO framework. However, only two of the BC+IR can be enabled at the same time. Series adds also support for scale and integration time configuration, where scale consists of impact of both the integration time and hardware gain. The gain and time support is backed by the newly introduced IIO GTS helper. This series depends on GTS helper patches added in BU27034 support series which is already merged in iio/togreg which this series is based on.

The hardware allows configuring gain setting by writing a 5-bit gain selector value to a register. Part of the gain setting is common for all channels (RGBC + IR) but part of the selector value can be set separately for RGBC and IR:

MODE_CONTROL2 REG:
bit 7 6 5 4 3 2 1 0
-----------------------------------------------------------------

|	RGB	selector		|
+---------------------------------------+
-----------------------------------------------------------------
| high bits IR	|			| low bits IR selector	|
+---------------+			+-----------------------+

In theory it would be possible to set certain separate gain values for RGBC and IR channels, but this gets pretty confusing because there are a few 'unsupported' selector values. If only RGBC or IR was set, some extra handling should be done to prevent the other channel from getting unsupported value due to change in high-bits. Furthermore, allowing the channels to be set different gain values (in some cases when gains are such the HW supports it) would make the cases where also integration time is changed to achieve correct scale ... interesting. It might also be confusing for user to try predicting when setting different scales succeeds and when it does not. Furthermore, if for example the scale setting for RGBC caused IR selector to be invalid - it could also cause the IR scale to "jump" very far from previous value.

To make the code simpler and more predictable for users, the current logic is as follows:

1. Prevent setting IR scale. (My assumption is IR is less used than RGBC)
2. When RGBC scale is set, set also the IR-selector to the same value. This prevents unsupported selector values and makes the IR scale changes predictable.

The 2) could mean we effectively have the same scale for all channels. Unfortunately, the HW design is slightly peculiar and selector 0 means gain 1X on RGBC but gain 2X on IR. Rest of the selectors equal same gain values on RGBC and IR. The result is that while changin selector from 0 => 1 causes RGBC gain to go from 1X => 4X, it causes IR gain to go from 2X => 4X.

So, the driver provides separate scale entries for all channels (also RGB and C will have separate gain entries because these channels are of same type as IR channel). This makes it possible for user applications to go read the scales for all channels after setting scale for one (in order to detect the IR scale difference).

Having the separate IR scale entry which applications can read to detect "arbitrary scale changes" makes it possible for applications to be written so they can cope if we need to implement the 'allow setting some different gains for IR and RGBC' - later.

Finally, the scales_available is also provided for all other channels except the IR channel, which does not allow the scale to be changed.

The sensor provides a data-ready IRQ and the driver implements a triggered buffer mode using this IRQ as a trigger.

Finally, the series introduces generic iio_validate_own_trigger() helper which can be used as a validate_trigger callback for drivers which require the trigger and iio-device to be parented by same device. The KX022A driver is converted to use this new callback instead of rolling it's own function. The new helper and KX022A can be merged in as independent changes if need be.

Revision history
v3 => v4:
iio_validate_own_trigger:
- kernel-doc fix
bu27008 driver fixes:
- re-enable IRQ in trigger renable-callback
- do trigger setup on own function
- drop regmap lock
- configure channels in appropriate callback
v3 => v4:
bu27008 driver fixes:
- Drop thread from device IRQ handler
- Styling and some minor improvements
- Use kernel-doc for enums
- Correctly order entries in Makefile
v2 => v3:
dt-bindings:
- No changes
iio_validate_own_trigger:
- subject fix
bu27008:
- Mostly styling based on comments from Andy and Andi

More accurate changelog in individual patches

v1 => v2:
dt-bindings:
- Fix issues pointed by Krzysztof.
bu27008 driver:
- Fix issues pointed by Jonathan
Add new helper for validating own trigger

More accurate changelog in individual patches

---

Matti Vaittinen (5):
dt-bindings: iio: light: ROHM BU27008
iio: trigger: Add simple trigger_validation helper
iio: kx022a: Use new iio_validate_own_trigger()
iio: light: ROHM BU27008 color sensor
MAINTAINERS: Add ROHM BU27008

 .../bindings/iio/light/rohm,bu27008.yaml      |   49 +
 MAINTAINERS                                   |    3 +-
 drivers/iio/accel/kionix-kx022a.c             |   13 +-
 drivers/iio/industrialio-trigger.c            |   22 +-
 drivers/iio/light/Kconfig                     |   14 +
 drivers/iio/light/Makefile                    |    1 +
 drivers/iio/light/rohm-bu27008.c              | 1026 +++++++++++++++++
 include/linux/iio/trigger.h                   |    1 +
 8 files changed, 1115 insertions(+), 14 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/light/rohm,bu27008.yaml
 create mode 100644 drivers/iio/light/rohm-bu27008.c
author maintainer
#8 lore raw
In reply to Matti Vaittinen
Quoted 8 lines · Matti Vaittinen

Add support for ROHM BU27008 RGB sensor.

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Quoted 8 lines

This series supports reading the RGBC and IR channels using IIO framework. However, only two of the BC+IR can be enabled at the same time. Series adds also support for scale and integration time configuration, where scale consists of impact of both the integration time and hardware gain. The gain and time support is backed by the newly introduced IIO GTS helper. This series depends on GTS helper patches added in BU27034 support series which is already merged in iio/togreg which this series is based on.

I started adding support for the BU27010 RGBC + flickering sensor to the BU27008 driver. While at it, I wrote some test(s) which try using also the 'insane' gain settings.

What I found out is that the scale setting for BU27008 is broken for smallest scales: 0.007812500 0.003906250 0.001953125

Reason is the accuracy.

The GTS helpers were made to use NANO scale accuracy. 999999999 is still fitting in an 32 bit integer after all :) This allows to handle greater "total gains".

The IIO scale setting interface towards the drivers seems to crop the val2 to micros (6 digits). This means that when user writes scale 0.001953125 via sysfs - the driver will get val = 0, val2 = 1953. Currently the BU27008 driver (and probably also the BU27035 which I have not yet checked) will pass this value to GTS-helpers - which try to use it in computations where scale is tried to be converted to gain + integration time settings. This will fail because of rounding error this leads to.

Regarding the BU27* drivers I see this bug as annoying rather than urgent. Bug will appear only with the very smallest of scales - which means gains of magnitude ~1000X with the longest integration times - and as someone once said - 1000X gains sound pretty insane as errors will probably get quite big... Still, this is a bug - and it bothers me :)

What comes to fixing this - my first thought regarding "the right thing to do" would be improving the IIO scale setting accuracy. I wonder if there has been some heavy reason(s) to only provide 6 digits of val2? (I haven't yet looked how IIO formats the val2 from user input so I may be very ignorant here). For userland this fix should be relatively invisible - the write of for example 0.001953125 is seemingly successful from the user-space POV. IIO does not warn about the excess accuracy.

I am not saying this change would be risk-free. For sure there is an application somewhere passing this kind of 'high accuracy' scale values to sysfs. And it may be we have a driver which is going to have a hiccup is such value is passed to it - but I'd argue the driver should be fixed then. It's easier for a driver to drop the excess digits by a division - than it is to generate the missing digits...

...which leads us to the other potential way of papering over this issue. We could go on defining a set of "magic scale values" in the bu27008 driver, namely the 1953, 3906 and 7812 - and when these are used as val2 just assume it means 001953125, 003906250 and 007812500 respectively. This would be quick and simple fix - but it would also mean this is a driver specific hack.

Finally, we could dive into GTS helpers and drop the accuracy of those to MIRCO scale instead of the NANO. If this was to be done it might be best to change the BU27008 and BU27034 intensity channel scales to start from bigger integers. Yes, it would potentially break any existing user of those intensity channels - but I suspect the amount of such users is still 0.

Finally, if we really want to keep the accuracy of scales in micros and not support nanos, then we probably should adjust the available scales displaying to not accept IIO_VAL_INT_PLUS_NANO type lists...

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
Quoted 46 lines · On Fri, 9 Jun 2023 15:46:21 +0300 Matti Vaittinen <[email protected]>…
Quoted 8 lines · Matti Vaittinen

Add support for ROHM BU27008 RGB sensor.

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Quoted 8 lines

This series supports reading the RGBC and IR channels using IIO framework. However, only two of the BC+IR can be enabled at the same time. Series adds also support for scale and integration time configuration, where scale consists of impact of both the integration time and hardware gain. The gain and time support is backed by the newly introduced IIO GTS helper. This series depends on GTS helper patches added in BU27034 support series which is already merged in iio/togreg which this series is based on.

I started adding support for the BU27010 RGBC + flickering sensor to the BU27008 driver. While at it, I wrote some test(s) which try using also the 'insane' gain settings.

What I found out is that the scale setting for BU27008 is broken for smallest scales: 0.007812500 0.003906250 0.001953125

Reason is the accuracy.

The GTS helpers were made to use NANO scale accuracy. 999999999 is still fitting in an 32 bit integer after all :) This allows to handle greater "total gains".

The IIO scale setting interface towards the drivers seems to crop the val2 to micros (6 digits). This means that when user writes scale 0.001953125 via sysfs - the driver will get val = 0, val2 = 1953. Currently the BU27008 driver (and probably also the BU27035 which I have not yet checked) will pass this value to GTS-helpers - which try to use it in computations where scale is tried to be converted to gain + integration time settings. This will fail because of rounding error this leads to.

Regarding the BU27* drivers I see this bug as annoying rather than urgent. Bug will appear only with the very smallest of scales - which means gains of magnitude ~1000X with the longest integration times - and as someone once said - 1000X gains sound pretty insane as errors will probably get quite big... Still, this is a bug - and it bothers me :)

Quoted 3 lines

What comes to fixing this - my first thought regarding "the right thing to do" would be improving the IIO scale setting accuracy. I wonder if there has been some heavy reason(s) to only provide 6 digits of val2?

History...

Quoted 5 lines

(I
haven't yet looked how IIO formats the val2 from user input so I may be very ignorant here). For userland this fix should be relatively invisible - the write of for example 0.001953125 is seemingly successful from the user-space POV. IIO does not warn about the excess accuracy.

IIO_VAL_INTO_PLUS_NANO might solve this
and you'll need to provide the callback write_raw_get_fmt() if you aren't already so that the conversion from string to val and val2 takes into account that the driver expects val2 to be *10^-9

Quoted 8 lines

I am not saying this change would be risk-free. For sure there is an application somewhere passing this kind of 'high accuracy' scale values to sysfs. And it may be we have a driver which is going to have a hiccup is such value is passed to it - but I'd argue the driver should be fixed then. It's easier for a driver to drop the excess digits by a division - than it is to generate the missing digits...

Quoted 6 lines

...which leads us to the other potential way of papering over this issue. We could go on defining a set of "magic scale values" in the bu27008 driver, namely the 1953, 3906 and 7812 - and when these are used as val2 just assume it means 001953125, 003906250 and 007812500 respectively. This would be quick and simple fix - but it would also mean this is a driver specific hack.

It's common for drivers to round to nearest to allow for subtle differences due to precision. That may make sense here.

Quoted 11 lines

Finally, we could dive into GTS helpers and drop the accuracy of those to MIRCO scale instead of the NANO. If this was to be done it might be best to change the BU27008 and BU27034 intensity channel scales to start from bigger integers. Yes, it would potentially break any existing user of those intensity channels - but I suspect the amount of such users is still 0.

Finally, if we really want to keep the accuracy of scales in micros and not support nanos, then we probably should adjust the available scales displaying to not accept IIO_VAL_INT_PLUS_NANO type lists...

Given that I think you just need to have the driver tell the core it wants IIO_VAL_INT_PLUS_NANO. Problem still occurs, but several orders of magnitude smaller.

But I may be miss understanding.

Jonathan

Quoted 4 lines

Yours,
-- Matti

#10 lore raw
Quoted 61 lines · Jonathan Cameron
Quoted 46 lines · On Fri, 9 Jun 2023 15:46:21 +0300 Matti Vaittinen <[email protected]>…
Quoted 8 lines · Matti Vaittinen

Add support for ROHM BU27008 RGB sensor.

The ROHM BU27008 is a sensor with 5 photodiodes (red, green, blue, clear and IR) with four configurable channels. Red and green being always available and two out of the rest three (blue, clear, IR) can be selected to be simultaneously measured. Typical application is adjusting LCD backlight of TVs, mobile phones and tablet PCs.

Quoted 8 lines

This series supports reading the RGBC and IR channels using IIO framework. However, only two of the BC+IR can be enabled at the same time. Series adds also support for scale and integration time configuration, where scale consists of impact of both the integration time and hardware gain. The gain and time support is backed by the newly introduced IIO GTS helper. This series depends on GTS helper patches added in BU27034 support series which is already merged in iio/togreg which this series is based on.

I started adding support for the BU27010 RGBC + flickering sensor to the BU27008 driver. While at it, I wrote some test(s) which try using also the 'insane' gain settings.

What I found out is that the scale setting for BU27008 is broken for smallest scales: 0.007812500 0.003906250 0.001953125

Reason is the accuracy.

The GTS helpers were made to use NANO scale accuracy. 999999999 is still fitting in an 32 bit integer after all :) This allows to handle greater "total gains".

The IIO scale setting interface towards the drivers seems to crop the val2 to micros (6 digits). This means that when user writes scale 0.001953125 via sysfs - the driver will get val = 0, val2 = 1953. Currently the BU27008 driver (and probably also the BU27035 which I have not yet checked) will pass this value to GTS-helpers - which try to use it in computations where scale is tried to be converted to gain + integration time settings. This will fail because of rounding error this leads to.

Regarding the BU27* drivers I see this bug as annoying rather than urgent. Bug will appear only with the very smallest of scales - which means gains of magnitude ~1000X with the longest integration times - and as someone once said - 1000X gains sound pretty insane as errors will probably get quite big... Still, this is a bug - and it bothers me :)

Quoted 3 lines

What comes to fixing this - my first thought regarding "the right thing to do" would be improving the IIO scale setting accuracy. I wonder if there has been some heavy reason(s) to only provide 6 digits of val2?

History...

Quoted 5 lines

(I
haven't yet looked how IIO formats the val2 from user input so I may be very ignorant here). For userland this fix should be relatively invisible - the write of for example 0.001953125 is seemingly successful from the user-space POV. IIO does not warn about the excess accuracy.

Quoted 5 lines

IIO_VAL_INTO_PLUS_NANO might solve this
and you'll need to provide the callback write_raw_get_fmt() if you aren't already so that the conversion from string to val and val2 takes into account that the driver expects val2 to be *10^-9

It seems the biggest problem (once again) was my ignorance :) I didn't know of write_raw_get_fmt(). I think You just really saved my day! After a quick glance it seems to me that all I need to do is indeed just to implement the write_raw_get_fmt() callback in BU27xxx drivers.

I was already getting a bit uncomfortable as I have promised to do few other things and I just hit this issue - which seemed much bigger that it now is. On top of this I'll be in Embedded Linux Conf for the last week of June (I hope to meet some of you guys there!) - and after that I plan to take a month off... So, things started to pile up once again. Now, Jonathan just lifted off a rock from my shoulders - big thanks!

I hope I'll be able to cook some patches Today or tomorrow.

Quoted 4 lines

Given that I think you just need to have the driver tell the core it wants IIO_VAL_INT_PLUS_NANO. Problem still occurs, but several orders of magnitude smaller.

Several magnitudes indeed!

Quoted 1 line

But I may be miss understanding.

No :) It was me who didn't (once again) see all the cool things provided by 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! ~~