]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iio: health: max30100: Make LED pulse-width configurable via DT
authorShrikant Raskar <raskar.shree97@gmail.com>
Sun, 12 Oct 2025 17:30:35 +0000 (23:00 +0530)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 19 Oct 2025 10:59:22 +0000 (11:59 +0100)
The required LED pulse width depends on board-specific optical and
mechanical design, which affects measurement accuracy and power use.
Making it configurable via Device Tree allows each platform to define
an appropriate value instead of relying on a hardcoded default.

If unspecified, the driver defaults to 1600 us for backward compatibility.

Tested on: Raspberry Pi 3B + MAX30100 breakout board.

Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: Shrikant Raskar <raskar.shree97@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/health/max30100.c

index 814f521e47aef46b56dd7b7c70e6bf2336190d3e..3d441013893c767022fc81144773bcc6fc2b5c94 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 2015, 2018
  * Author: Matt Ranostay <matt.ranostay@konsulko.com>
  *
- * TODO: enable pulse length controls via device tree properties
  */
 
 #include <linux/module.h>
@@ -18,6 +17,7 @@
 #include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
+#include <linux/bitfield.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
 #include <linux/iio/kfifo_buf.h>
 #define MAX30100_REG_MODE_CONFIG_PWR           BIT(7)
 
 #define MAX30100_REG_SPO2_CONFIG               0x07
+#define MAX30100_REG_SPO2_CONFIG_PW_MASK       GENMASK(1, 0)
+#define MAX30100_REG_SPO2_CONFIG_200US         0x0
+#define MAX30100_REG_SPO2_CONFIG_400US         0x1
+#define MAX30100_REG_SPO2_CONFIG_800US         0x2
+#define MAX30100_REG_SPO2_CONFIG_1600US                0x3
 #define MAX30100_REG_SPO2_CONFIG_100HZ         BIT(2)
 #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN     BIT(6)
-#define MAX30100_REG_SPO2_CONFIG_1600US                0x3
 
 #define MAX30100_REG_LED_CONFIG                        0x09
 #define MAX30100_REG_LED_CONFIG_LED_MASK       0x0f
@@ -306,19 +310,47 @@ static int max30100_led_init(struct max30100_data *data)
                MAX30100_REG_LED_CONFIG_LED_MASK, reg);
 }
 
+static int max30100_get_pulse_width(unsigned int pwidth_us)
+{
+       switch (pwidth_us) {
+       case 200:
+               return MAX30100_REG_SPO2_CONFIG_200US;
+       case 400:
+               return MAX30100_REG_SPO2_CONFIG_400US;
+       case 800:
+               return MAX30100_REG_SPO2_CONFIG_800US;
+       case 1600:
+               return MAX30100_REG_SPO2_CONFIG_1600US;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int max30100_chip_init(struct max30100_data *data)
 {
        int ret;
+       int pulse_width;
+       /* set default LED pulse-width to 1600 us */
+       unsigned int pulse_us = 1600;
+       struct device *dev = &data->client->dev;
 
        /* setup LED current settings */
        ret = max30100_led_init(data);
        if (ret)
                return ret;
 
+       /* Read LED pulse-width-us from DT */
+       device_property_read_u32(dev, "maxim,pulse-width-us", &pulse_us);
+
+       pulse_width = max30100_get_pulse_width(pulse_us);
+       if (pulse_width < 0)
+               return dev_err_probe(dev, pulse_width, "invalid LED pulse-width %uus\n", pulse_us);
+
        /* enable hi-res SPO2 readings at 100Hz */
        ret = regmap_write(data->regmap, MAX30100_REG_SPO2_CONFIG,
                                 MAX30100_REG_SPO2_CONFIG_HI_RES_EN |
-                                MAX30100_REG_SPO2_CONFIG_100HZ);
+                                MAX30100_REG_SPO2_CONFIG_100HZ |
+                                FIELD_PREP(MAX30100_REG_SPO2_CONFIG_PW_MASK, pulse_width));
        if (ret)
                return ret;