The MAX30100 driver previously hardcoded the SPO2 pulse width to
1600us. This patch adds support for reading the pulse width from
device tree (`maxim,pulse-width-us`) and programming it into the SPO2
configuration register.
If no property is provided, the driver falls back to 1600us to
preserve existing behavior.
Testing:
Hardware: Raspberry Pi 3B + MAX30100 breakout
Verified DT property read in probe()
Confirmed SPO2_CONFIG register written correctly using regmap_read()
Signed-off-by: Shrikant Raskar <raskar.shree97@gmail.com>
Changes since v1:
Use FIELD_PREP() and define a pulse width bit mask.
Initialize default pulse_us before property read.
Use dev_err_probe() for error reporting.
Make pulse_width signed to handle negative return values.
Link to v1:
https://lore.kernel.org/all/20251004015623.7019-3-raskar.shree97@gmail.com/
---
drivers/iio/health/max30100.c | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index 814f521e47ae..50cd4fd13849 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -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>
@@ -54,6 +53,10 @@
#define MAX30100_REG_SPO2_CONFIG 0x07
#define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2)
#define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6)
+#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_LED_CONFIG 0x09
@@ -306,19 +309,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 pulse-width-us to 1600us */
+ 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 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 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;
--
2.43.0
On 10/7/25 10:17 PM, Shrikant Raskar wrote: ... > --- a/drivers/iio/health/max30100.c > +++ b/drivers/iio/health/max30100.c > @@ -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> > @@ -54,6 +53,10 @@ > #define MAX30100_REG_SPO2_CONFIG 0x07 > #define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2) > #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6) > +#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 Would make more sense to put this new code before BIT(2) to preserve the order of lowest to highest bits.
Hi Shrikant,
kernel test robot noticed the following build errors:
[auto build test ERROR on jic23-iio/togreg]
[also build test ERROR on robh/for-next v6.17]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Shrikant-Raskar/dt-bindings-iio-max30100-Add-pulse-width-property/20251010-102537
base: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
patch link: https://lore.kernel.org/r/20251008031737.7321-3-raskar.shree97%40gmail.com
patch subject: [PATCH v2 2/2] iio: health: max30100: Add pulse-width configuration via DT
config: csky-randconfig-001-20251010 (https://download.01.org/0day-ci/archive/20251011/202510110029.epOLovuF-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251011/202510110029.epOLovuF-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202510110029.epOLovuF-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/iio/health/max30100.c: In function 'max30100_chip_init':
>> drivers/iio/health/max30100.c:352:34: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
352 | FIELD_PREP(MAX30100_REG_SPO2_CONFIG_PW_MASK, pulse_width));
| ^~~~~~~~~~
vim +/FIELD_PREP +352 drivers/iio/health/max30100.c
327
328 static int max30100_chip_init(struct max30100_data *data)
329 {
330 int ret;
331 int pulse_width;
332 /* set default pulse-width-us to 1600us */
333 unsigned int pulse_us = 1600;
334 struct device *dev = &data->client->dev;
335
336 /* setup LED current settings */
337 ret = max30100_led_init(data);
338 if (ret)
339 return ret;
340
341 /* Read pulse-width-us from DT */
342 device_property_read_u32(dev, "maxim,pulse-width-us", &pulse_us);
343
344 pulse_width = max30100_get_pulse_width(pulse_us);
345 if (pulse_width < 0)
346 return dev_err_probe(dev, pulse_width, "invalid pulse-width %uus\n", pulse_us);
347
348 /* enable hi-res SPO2 readings at 100Hz */
349 ret = regmap_write(data->regmap, MAX30100_REG_SPO2_CONFIG,
350 MAX30100_REG_SPO2_CONFIG_HI_RES_EN |
351 MAX30100_REG_SPO2_CONFIG_100HZ |
> 352 FIELD_PREP(MAX30100_REG_SPO2_CONFIG_PW_MASK, pulse_width));
353 if (ret)
354 return ret;
355
356 /* enable SPO2 mode */
357 ret = regmap_update_bits(data->regmap, MAX30100_REG_MODE_CONFIG,
358 MAX30100_REG_MODE_CONFIG_MODE_MASK,
359 MAX30100_REG_MODE_CONFIG_MODE_HR_EN |
360 MAX30100_REG_MODE_CONFIG_MODE_SPO2_EN);
361 if (ret)
362 return ret;
363
364 /* enable FIFO interrupt */
365 return regmap_update_bits(data->regmap, MAX30100_REG_INT_ENABLE,
366 MAX30100_REG_INT_ENABLE_MASK,
367 MAX30100_REG_INT_ENABLE_FIFO_EN
368 << MAX30100_REG_INT_ENABLE_MASK_SHIFT);
369 }
370
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Shrikant,
Thanks for your patch.
On Wed, 2025-10-08 at 08:47 +0530, Shrikant Raskar wrote:
> The MAX30100 driver previously hardcoded the SPO2 pulse width to
> 1600us. This patch adds support for reading the pulse width from
> device tree (`maxim,pulse-width-us`) and programming it into the SPO2
> configuration register.
>
> If no property is provided, the driver falls back to 1600us to
> preserve existing behavior.
>
> Testing:
> Hardware: Raspberry Pi 3B + MAX30100 breakout
> Verified DT property read in probe()
> Confirmed SPO2_CONFIG register written correctly using regmap_read()
>
> Signed-off-by: Shrikant Raskar <raskar.shree97@gmail.com>
>
> Changes since v1:
> Use FIELD_PREP() and define a pulse width bit mask.
> Initialize default pulse_us before property read.
> Use dev_err_probe() for error reporting.
> Make pulse_width signed to handle negative return values.
>
> Link to v1:
> https://lore.kernel.org/all/20251004015623.7019-3-raskar.shree97@gmail.com/
As mentioned in the bindings patch, this is not place for changelog. With that
fixed:
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
> ---
> drivers/iio/health/max30100.c | 35 +++++++++++++++++++++++++++++++++--
> 1 file changed, 33 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
> index 814f521e47ae..50cd4fd13849 100644
> --- a/drivers/iio/health/max30100.c
> +++ b/drivers/iio/health/max30100.c
> @@ -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>
> @@ -54,6 +53,10 @@
> #define MAX30100_REG_SPO2_CONFIG 0x07
> #define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2)
> #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6)
> +#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_LED_CONFIG 0x09
> @@ -306,19 +309,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 pulse-width-us to 1600us */
> + 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 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 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;
>
On Thu, Oct 9, 2025 at 4:21 PM Nuno Sá <noname.nuno@gmail.com> wrote:
>
> Hi Shrikant,
>
> Thanks for your patch.
>
> On Wed, 2025-10-08 at 08:47 +0530, Shrikant Raskar wrote:
> > The MAX30100 driver previously hardcoded the SPO2 pulse width to
> > 1600us. This patch adds support for reading the pulse width from
> > device tree (`maxim,pulse-width-us`) and programming it into the SPO2
> > configuration register.
> >
> > If no property is provided, the driver falls back to 1600us to
> > preserve existing behavior.
> >
> > Testing:
> > Hardware: Raspberry Pi 3B + MAX30100 breakout
> > Verified DT property read in probe()
> > Confirmed SPO2_CONFIG register written correctly using regmap_read()
> >
> > Signed-off-by: Shrikant Raskar <raskar.shree97@gmail.com>
> >
> > Changes since v1:
> > Use FIELD_PREP() and define a pulse width bit mask.
> > Initialize default pulse_us before property read.
> > Use dev_err_probe() for error reporting.
> > Make pulse_width signed to handle negative return values.
> >
> > Link to v1:
> > https://lore.kernel.org/all/20251004015623.7019-3-raskar.shree97@gmail.com/
>
> As mentioned in the bindings patch, this is not place for changelog. With that
> fixed:
>
> Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Hello Nuno Sá,
Thanks for reviewing my patch.
I have removed the changelog from commit message and shared the v3
patch for review.
Thanks and Regards,
Shrikant
>
> > ---
> > drivers/iio/health/max30100.c | 35 +++++++++++++++++++++++++++++++++--
> > 1 file changed, 33 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
> > index 814f521e47ae..50cd4fd13849 100644
> > --- a/drivers/iio/health/max30100.c
> > +++ b/drivers/iio/health/max30100.c
> > @@ -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>
> > @@ -54,6 +53,10 @@
> > #define MAX30100_REG_SPO2_CONFIG 0x07
> > #define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2)
> > #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6)
> > +#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_LED_CONFIG 0x09
> > @@ -306,19 +309,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 pulse-width-us to 1600us */
> > + 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 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 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;
> >
© 2016 - 2025 Red Hat, Inc.